diff --git a/src/views/products/Detail/Header.jsx b/src/views/products/Detail/Header.jsx
index 796ec99..ed1c218 100644
--- a/src/views/products/Detail/Header.jsx
+++ b/src/views/products/Detail/Header.jsx
@@ -15,7 +15,7 @@ import VendorSelector from '@/components/VendorSelector';
import AuditStateSelector from '@/components/AuditStateSelector';
import NewProductModal from './NewProductModal';
-import AgencyContract from './../Print/AgencyContract';
+import AgencyContract from '../Print/AgencyContract_v0903';
import { saveAs } from "file-saver";
import { Packer } from "docx";
diff --git a/src/views/products/Detail/ProductInfoForm.jsx b/src/views/products/Detail/ProductInfoForm.jsx
index 65e6e0d..b470b8a 100644
--- a/src/views/products/Detail/ProductInfoForm.jsx
+++ b/src/views/products/Detail/ProductInfoForm.jsx
@@ -29,6 +29,8 @@ const InfoForm = ({ onSubmit, onReset, onValuesChange, editablePerm, infoEditabl
const filedsets = useProductsTypesFieldsets(editingProduct?.info?.product_type_id);
const shows = filedsets[0];
+ const [pickEditedInfo, setPickEditedInfo] = useState({}); // 传递联动的字段
+
// const [editable, setEditable] = useState(true);
const [formEditable, setFormEditable] = useState(true);
const [showSave, setShowSave] = useState(true);
@@ -39,6 +41,7 @@ const InfoForm = ({ onSubmit, onReset, onValuesChange, editablePerm, infoEditabl
const lgc_details_mapped = (editingProduct?.lgc_details || []).reduce((r, c) => ({ ...r, [c.lgc]: c }), {});
form.setFieldValue('lgc_details_mapped', lgc_details_mapped);
form.setFieldValue('quotation', editingProduct?.quotation);
+ setPickEditedInfo({ ...pickEditedInfo, product_title: editingProduct?.info?.product_title });
setFormEditable(infoEditable || priceEditable);
@@ -78,6 +81,10 @@ const InfoForm = ({ onSubmit, onReset, onValuesChange, editablePerm, infoEditabl
const onIValuesChange = (changedValues, allValues) => {
const dest = formValuesMapper(allValues);
// console.log('form onValuesChange', Object.keys(changedValues), changedValues);
+ if ('product_title' in changedValues) {
+ const editTitle = (changedValues.product_title);
+ setPickEditedInfo({ ...pickEditedInfo, product_title: editTitle });
+ }
if (typeof onValuesChange === 'function') {
onValuesChange(dest);
}
@@ -130,7 +137,7 @@ const InfoForm = ({ onSubmit, onReset, onValuesChange, editablePerm, infoEditabl
},
}),
]}>
-
+
diff --git a/src/views/products/Detail/ProductInfoLgc.jsx b/src/views/products/Detail/ProductInfoLgc.jsx
index 4fd4685..6beec47 100644
--- a/src/views/products/Detail/ProductInfoLgc.jsx
+++ b/src/views/products/Detail/ProductInfoLgc.jsx
@@ -6,7 +6,7 @@ import { useTranslation } from 'react-i18next';
import { useDefaultLgc } from '@/i18n/LanguageSwitcher';
import { cloneDeep, isEmpty, isNotEmpty } from '@/utils/commons';
-const ProductInfoLgc = ({ editable, formInstance, ...props }) => {
+const ProductInfoLgc = ({ editable, formInstance, pickEditedInfo, ...props }) => {
const { t } = useTranslation('products');
const { language: languageHT } = useDefaultLgc();
const HTLanguageSetsMapVal = useHTLanguageSetsMapVal();
@@ -15,6 +15,13 @@ const ProductInfoLgc = ({ editable, formInstance, ...props }) => {
const [activeKey, setActiveKey] = useState();
const [items, setItems] = useState([]);
+ useEffect(() => {
+ formInstance.setFieldValue(['lgc_details_mapped', '2', 'title'], pickEditedInfo.product_title);
+
+ return () => {};
+ }, [pickEditedInfo.product_title]);
+
+
useEffect(() => {
const existsLgc = (editingProduct?.lgc_details || []).map((ele, li) => ({
...ele,
diff --git a/src/views/products/Detail/ProductsTree.jsx b/src/views/products/Detail/ProductsTree.jsx
index c45b6e2..8ba536d 100644
--- a/src/views/products/Detail/ProductsTree.jsx
+++ b/src/views/products/Detail/ProductsTree.jsx
@@ -41,6 +41,7 @@ const getParentKey = (key, tree) => {
const ProductsTree = ({ onNodeSelect, ...props }) => {
const { t } = useTranslation();
const [agencyProducts, editingProduct, setEditingProduct] = useProductsStore((state) => [state.agencyProducts, state.editingProduct, state.setEditingProduct]);
+ const [activeAgency] = useProductsStore((state) => [state.activeAgency]);
const productsTypes = useProductsTypes();
const [treeData, setTreeData] = useState([]);
@@ -49,6 +50,11 @@ const ProductsTree = ({ onNodeSelect, ...props }) => {
const [expandedKeys, setExpandedKeys] = useState([]);
const [autoExpandParent, setAutoExpandParent] = useState(true);
+ useEffect(() => {
+ setExpandedKeys(productsTypes.map((item) => item.key)); // 全部展开
+ return () => {}
+ }, [productsTypes, activeAgency]);
+
useEffect(() => {
// 只显示有产品的类型;
// const title = text || r.lgc_details?.['2']?.title || r.lgc_details?.['1']?.title || '';
@@ -89,7 +95,7 @@ const ProductsTree = ({ onNodeSelect, ...props }) => {
setRawTreeData(_show);
setFlattenTreeData(flattenTreeFun(_show));
- setExpandedKeys(productsTypes.map((item) => item.key)); // 全部展开
+ // setExpandedKeys(productsTypes.map((item) => item.key)); // 全部展开
// setActiveKey(isEmpty(_show) ? [] : [_show[0].key]);
return () => {};
diff --git a/src/views/products/Print/AgencyContract_v0903.jsx b/src/views/products/Print/AgencyContract_v0903.jsx
new file mode 100644
index 0000000..11b7527
--- /dev/null
+++ b/src/views/products/Print/AgencyContract_v0903.jsx
@@ -0,0 +1,1147 @@
+import {
+ AlignmentType,
+ Document,
+ Header,
+ Footer,
+ HeadingLevel,
+ Paragraph,
+ TabStopType,
+ Table,
+ TableCell,
+ TableRow,
+ TextRun,
+ BorderStyle,
+ NumberFormat,
+ PageNumber,
+ WidthType,
+ LevelFormat,
+ Tab,
+ PositionalTab,
+ PositionalTabAlignment,
+ PositionalTabRelativeTo,
+ PositionalTabLeader,
+} from 'docx';
+import dayjs from 'dayjs';
+import { cloneDeep, flush, groupBy, isEmpty, isNotEmpty, sortBy, unique, uniqWith } from '@/utils/commons';
+
+// Shoulder Season 平季; peak season 旺季
+const isFullYearOrLonger = (year, startDate, endDate) => {
+ // Parse the dates
+ const start = dayjs(startDate, 'YYYY-MM-DD');
+ const end = dayjs(endDate, 'YYYY-MM-DD');
+
+ // Create the start and end dates for the year
+ const yearStart = dayjs(`${year}-01-01`, 'YYYY-MM-DD');
+ const yearEnd = dayjs(`${year}-12-31`, 'YYYY-MM-DD');
+
+ // Check if start is '01-01' and end is '12-31' and the year matches
+ const isFullYear = start.isSame(yearStart, 'day') && end.isSame(yearEnd, 'day');
+
+ // Check if the range is longer than a year
+ const isLongerThanYear = end.diff(start, 'year') >= 1;
+
+ return isFullYear || isLongerThanYear;
+};
+
+const shortDate = (date) => dayjs(date).format('MM.DD');
+
+/**
+ * 车辆人等配置
+ * 5座, 7座, 10座, 10以上
+ */
+const chunkCarSets = (numbers) => {
+ return numbers.reduce(
+ (acc, number) => {
+ if (number < 5) {
+ acc.lt5.push(number);
+ } else if (number < 7) {
+ acc.lt7.push(number);
+ } else if (number < 10) {
+ acc.lt7.push(number);
+ } else {
+ acc.gt10.push(number);
+ }
+ return acc;
+ },
+ { lt5: [], lt7: [], lt10: [], gt10: [] }
+ );
+};
+const uniqueBySub = (arr) =>
+ arr.filter((subArr1, _, self) => {
+ return !self.some((subArr2) => {
+ if (subArr1 === subArr2) return false; // don't compare a subarray with itself
+ const set1 = new Set(subArr1);
+ const set2 = new Set(subArr2);
+ // check if subArr1 is a subset of subArr2
+ return [...set1].every((value) => set2.has(value));
+ });
+ });
+const isFlatUnique = (bigArray) => {
+ let flattenedArray = bigArray.flat();
+ return flattenedArray.every((i) => {
+ let count = flattenedArray.filter((j) => j === i).length;
+ return count === 1;
+ });
+};
+const chunkBy = (use_year, dataList = [], by = []) => {
+ const dataRollSS = dataList.map((rowp, ii) => {
+ const quotation = rowp.quotation.map((quoteItem) => {
+ return {
+ ...quoteItem,
+ quote_season: isFullYearOrLonger(use_year, quoteItem.use_dates_start, quoteItem.use_dates_end) ? 'SS' : 'PS',
+ };
+ });
+ return { ...rowp, quotation, };
+ });
+ // console.log('\ndataRollSS', dataRollSS);
+ // console.log('\n\n', dataList[0].info.product_type_id, dataRollSS);
+
+ // 人等分组只取平季, 因为产品只一行
+ const allQuotesSS = dataRollSS.reduce((acc, rowp) => acc.concat(rowp.quotation.filter(q => q.quote_season === 'SS')), []);
+ const allQuotesPS = dataRollSS.reduce((acc, rowp) => acc.concat(rowp.quotation.filter(q => q.quote_season === 'PS')), []);
+ const allQuotesSSS = isEmpty(allQuotesSS) ? allQuotesPS : allQuotesSS;
+ // console.log('allQuotesSSS', allQuotesSS, '\n', allQuotesPS, '\n', allQuotesSSS);
+
+ // const groupSizeSS = (allQuotesSS).reduce((aq, cq) => aq.concat([[cq.group_size_min, cq.group_size_max]]), []);
+ const PGroupSizeSS = (allQuotesSSS).reduce((aq, cq) => {
+ aq[cq.WPI_SN] = aq[cq.WPI_SN] || [];
+ aq[cq.WPI_SN].push(cq.group_size_min);
+ aq[cq.WPI_SN] = unique(aq[cq.WPI_SN]);
+ return aq;
+ }, {});
+ // console.log('PGroupSizeSS', structuredClone(PGroupSizeSS));
+ const _SSMinSet = uniqWith(Object.values(PGroupSizeSS), (a, b) => a.join(',') === b.join(','));
+ // console.log('SSMinSet', _SSMinSet);
+ const uSSsizeSetArr = uniqueBySub(_SSMinSet);
+ // console.log('uSSsizeSetArr', uSSsizeSetArr);
+ for (const key in PGroupSizeSS) {
+ if (Object.prototype.hasOwnProperty.call(PGroupSizeSS, key)) {
+ const element = PGroupSizeSS[key];
+ const findSet = uSSsizeSetArr.find(minCut => element.every(v => minCut.includes(v)));
+ PGroupSizeSS[key] = findSet;
+ }
+ }
+ // console.log('PGroupSizeSS aaa', PGroupSizeSS);
+ const [SSsizeSets, PSsizeSets] = [uSSsizeSetArr, []].map((arr) => {
+ const _arr = structuredClone(arr);
+ const arrSets = _arr.map(keyMins => keyMins.reduce((acc, curr, idx, minsArr) => {
+ const _max = idx === minsArr.length - 1 ? Infinity : Number(minsArr[idx + 1])-1;
+ acc.push([Number(curr), _max]);
+ return acc;
+ }, []));
+ return arrSets;
+ });
+ // console.log('PGroupSizeSS fff', SSsizeSets);
+ const compactSizeSets = { SSsizeSetKey: uSSsizeSetArr.map((s) => s.join(',')).filter(isNotEmpty), sizeSets: SSsizeSets };
+ // console.log(compactSizeSets);
+ const chunkSS = structuredClone(dataRollSS).map(rowp => {
+ // console.log(rowp.info.id, rowp.info.product_title);
+
+ const pkey = (PGroupSizeSS[rowp.info.id] || []).join(',') || compactSizeSets.SSsizeSetKey[0]; // todo:
+ // console.log('pkey', pkey);
+
+ const thisRange = (PGroupSizeSS[rowp.info.id] || []).reduce((acc, curr, idx, minsArr) => {
+ const _max = idx === minsArr.length - 1 ? Infinity : Number(minsArr[idx + 1])-1;
+ acc.push([Number(curr), _max]);
+ return acc;
+ }, []);
+ const _quotation = rowp.quotation.map((quoteItem) => {
+ const ssSets = isEmpty(thisRange) ? SSsizeSets[0] : structuredClone(thisRange).reverse();
+ // if (isEmpty(ssSets)) {
+ // console.group('quotation item');
+ // console.log(rowp.info.id, rowp.info.product_title, rowp);
+ // console.log(ssSets);
+ // console.log([quoteItem.group_size_min, quoteItem.group_size_max]);
+ // console.groupEnd();
+ // }
+ // console.group('quotation item');
+ // console.log(ssSets);
+ // console.log([quoteItem.group_size_min, quoteItem.group_size_max]);
+ const matchRange = (ssSets).find((ss) => quoteItem.group_size_min >= ss[0] && quoteItem.group_size_max <= ss[1]);
+ const findEnd = matchRange || ssSets.find((ss) => quoteItem.group_size_max > ss[0] && quoteItem.group_size_max <= ss[1] && ss[1] !== Infinity);
+ const findStart = findEnd || ssSets.find((ss) => quoteItem.group_size_min >= ss[0]);
+ const finalRange = findStart;
+ // console.log('find mmm', matchRange, findEnd, findStart, finalRange);
+ // console.log('matchRange ', 'find', [quoteItem.group_size_min, quoteItem.group_size_max], 'matched', finalRange);
+ // console.groupEnd();
+ quoteItem.quote_size = finalRange.join('-');
+ return quoteItem;
+ });
+ const quote_chunk_flat = groupBy(_quotation, (quoteItem2) => by.map((key) => quoteItem2[key]).join('@'));
+ const quote_chunk = Object.keys(quote_chunk_flat).reduce((qc, ckey) => {
+ const ckeyArr = ckey.split('@');
+ if (isEmpty(qc[ckeyArr[0]])) {
+ qc[ckeyArr[0]] = ckeyArr[1] ? { [ckeyArr[1]]: quote_chunk_flat[ckey] } : quote_chunk_flat[ckey];
+ } else {
+ qc[ckeyArr[0]][ckeyArr[1]] = (qc[ckeyArr[0]][ckeyArr[1]] || []).concat(quote_chunk_flat[ckey]);
+ }
+ return qc;
+ }, {});
+ return {
+ ...rowp,
+ sizeSetsSS: pkey,
+ quotation: _quotation,
+ quote_chunk,
+ }
+ });
+ // console.log('quotation', chunkSS);
+ const allquotation = chunkSS.reduce((a, c) => a.concat(c.quotation), []);
+ // 取出两季相应的时效区间
+ const SSRange = unique((allquotation || []).filter((q) => q.quote_season === 'SS').map((qr) => `${qr.use_dates_start}~${qr.use_dates_end}`));
+ const PSRange = unique((allquotation || []).filter((q) => q.quote_season === 'PS').map((qr) => `${qr.use_dates_start}~${qr.use_dates_end}`));
+
+ return { chunk: chunkSS, dataSource: chunkSS, SSRange, PSRange, ...compactSizeSets };
+};
+
+const DOC_TITLE = '地接合同';
+const pageMargins = {
+ top: `15mm`,
+ bottom: `15mm`,
+ left: `10mm`,
+ right: `10mm`,
+};
+const tableBorderNone = {
+ top: { style: BorderStyle.NONE, size: 0, color: 'FFFFFF' },
+ bottom: { style: BorderStyle.NONE, size: 0, color: 'FFFFFF' },
+ left: { style: BorderStyle.NONE, size: 0, color: 'FFFFFF' },
+ right: { style: BorderStyle.NONE, size: 0, color: 'FFFFFF' },
+};
+const tableBorderOne = {
+ top: { style: BorderStyle.SINGLE, space: 0, size: 6, color: 'auto' },
+ bottom: { style: BorderStyle.SINGLE, space: 0, size: 6, color: 'auto' },
+ left: { style: BorderStyle.SINGLE, space: 0, size: 6, color: 'auto' },
+ right: { style: BorderStyle.SINGLE, space: 0, size: 6, color: 'auto' },
+};
+
+export default class AgencyContract {
+ create([headerParams, activeAgency, agencyProducts, agencyExtras]) {
+ const { use_year } = headerParams;
+ const h1 = `${activeAgency.travel_agency_name}${use_year}年${DOC_TITLE}`;
+ const yearStart = dayjs(`${use_year}-01-01`).format('YYYY.MM.DD');
+ const yearEnd = dayjs(`${use_year}-12-31`).format('YYYY.MM.DD');
+ // console.log(agencyExtras);
+ // console.log('*********************************************************************************************');
+
+ const document = new Document({
+ creator: 'China Highlights',
+ title: h1,
+ subject: '2025桂林海纳价格合同模板',
+ // description: '',
+ styles: {
+ paragraphStyles: [
+ {
+ id: 'Normal',
+ name: 'Normal',
+ quickFormat: true,
+ run: {
+ size: 22,
+ font: { name: '宋体' },
+ color: '000000',
+ },
+ paragraph: {
+ spacing: {
+ after: 10,
+ },
+ },
+ },
+ {
+ id: 'Title',
+ name: 'Title',
+ basedOn: 'Normal',
+ next: 'Normal',
+ quickFormat: true,
+ run: {
+ size: 44,
+ font: { name: '宋体' },
+ color: '000000',
+ },
+ paragraph: {
+ spacing: {
+ before: 200,
+ after: 200,
+ },
+ },
+ },
+ {
+ id: 'Heading1',
+ name: 'Heading 1',
+ basedOn: 'Normal',
+ next: 'Normal',
+ quickFormat: true,
+ run: {
+ size: 32,
+ font: { name: '宋体' },
+ color: '000000',
+ },
+ paragraph: {
+ spacing: {
+ before: 200,
+ after: 200,
+ },
+ },
+ },
+ {
+ id: 'Heading2',
+ name: 'Heading 2',
+ basedOn: 'Normal',
+ next: 'Normal',
+ quickFormat: true,
+ run: {
+ size: 28,
+ font: { name: '宋体' },
+ color: '000000',
+ },
+ paragraph: {
+ spacing: {
+ before: 120,
+ after: 120,
+ },
+ },
+ },
+ {
+ id: 'TableHeader',
+ name: 'Table Header',
+ basedOn: 'Normal',
+ next: 'Normal',
+ quickFormat: true,
+ run: {
+ size: 22,
+ font: { name: '宋体' },
+ color: '000000',
+ bold: true,
+ },
+ paragraph: {
+ spacing: {
+ before: 80,
+ after: 80,
+ },
+ },
+ },
+ // {
+ // id: "MySpectacularStyle",
+ // name: "My Spectacular Style",
+ // basedOn: "Heading1",
+ // next: "Heading1",
+ // quickFormat: true,
+ // run: {
+ // italics: true,
+ // color: "990000",
+ // },
+ // },
+ ],
+ },
+ numbering: {
+ config: [
+ { reference: 'products-type', levels: [{ level: 0, text: '%1、', format: LevelFormat.CHINESE_COUNTING }] },
+ { reference: 'terms', levels: [{ level: 0, text: '%1.', format: LevelFormat.DECIMAL }] },
+ ],
+ },
+ sections: [
+ {
+ properties: {
+ page: {
+ pageNumbers: {
+ start: 1,
+ formatType: NumberFormat.DECIMAL,
+ },
+ margin: pageMargins,
+ },
+ },
+ headers: {
+ default: new Header({
+ children: [
+ this.createPageHeaderText(`Email: xeniayou@hainatravel.com`, { italics: false }),
+ this.createPageHeaderText(`https://www.chinahighlights.com`, { italics: false }),
+ ],
+ }),
+ },
+ footers: {
+ default: new Footer({
+ children: [
+ new Paragraph({
+ alignment: AlignmentType.CENTER,
+ children: [
+ new TextRun({
+ children: ['第', PageNumber.CURRENT, '页'],
+ size: 20,
+ }),
+ new TextRun({
+ children: [', 共 ', PageNumber.TOTAL_PAGES, '页'],
+ size: 20,
+ }),
+ ],
+ }),
+ new Paragraph({
+ alignment: AlignmentType.RIGHT,
+ children: [
+ new TextRun({
+ text: `${new Date().toLocaleString()}系统生成`,
+ italics: true,
+ size: 20,
+ }),
+ ],
+ }),
+ ],
+ }),
+ },
+ children: [
+ this.createTitle(h1),
+ this.createSubHeading(`价格有效期: ${yearStart}-${yearEnd}`, { alignment: AlignmentType.CENTER }),
+
+ ...(isEmpty(agencyProducts['6'])
+ ? []
+ : [this.createSubHeading(`综费(元/人/天)`, { numbering: { reference: 'products-type', level: 0 } }), this.createTable_6(use_year, agencyProducts['6'])]),
+ ...(isEmpty(agencyProducts['B'])
+ ? []
+ : [this.createSubHeading(`超公里(元/人)`, { numbering: { reference: 'products-type', level: 0 } }), ...this.createTable_B(use_year, agencyProducts['B'])]),
+ ...(isEmpty(agencyProducts['J'])
+ ? []
+ : [this.createSubHeading(`车费(元/团)`, { numbering: { reference: 'products-type', level: 0 } }), ...this.createTable_JD(use_year, agencyProducts['J'])]),
+ ...(isEmpty(agencyProducts['Q'])
+ ? []
+ : [this.createSubHeading(`导游`, { numbering: { reference: 'products-type', level: 0 } }), this.createTable_Q(use_year, agencyProducts['Q'])]),
+ ...(isEmpty(agencyProducts['7'])
+ ? []
+ : [
+ this.createSubHeading(`景点(默认元/人,部分价格为元/团单独注明)`, { numbering: { reference: 'products-type', level: 0 } }),
+ this.createTable_7(use_year, agencyProducts['7'], agencyExtras),
+ ]),
+ ...(isEmpty(agencyProducts['R'])
+ ? []
+ : [
+ this.createSubHeading(`餐费(元/人/餐)`, { numbering: { reference: 'products-type', level: 0 } }),
+ ...this.createTable_R(use_year, agencyProducts['R'], agencyExtras),
+ ]),
+ ...(isEmpty(agencyProducts['D'])
+ ? []
+ : [
+ this.createSubHeading(`包价线路(元/团,部分价格为元/人单独注明)`, { numbering: { reference: 'products-type', level: 0 } }),
+ ...this.createTable_JD(use_year, agencyProducts['D']),
+ ]),
+ this.createSubHeading(`公司银行账户`, { numbering: { reference: 'products-type', level: 0 } }),
+ this.createInfo_Bank(),
+ this.createSubHeading(`联系资料`, { numbering: { reference: 'products-type', level: 0 } }),
+ this.createInfo_Contact(),
+ this.createSubHeading(`补充条款`, { numbering: { reference: 'products-type', level: 0 } }),
+ ...this.createInfo_Terms(),
+ ],
+ },
+ ],
+ });
+
+ return document;
+ }
+
+ /**
+ * 综费
+ */
+ createTable_6(use_year, dataList, style = {}) {
+ const { chunk, SSRange, sizeSets } = chunkBy(use_year, dataList, ['quote_season']);
+ // console.log('\n\n\n6', chunk, '\n',sizeSets);
+ return new Table({
+ borders: tableBorderNone,
+ width: {
+ size: 100,
+ type: WidthType.PERCENTAGE,
+ },
+ rows: [
+ new TableRow({
+ children: [this.createTableHeader('项目', 30), this.createTableHeader('人等', 20), this.createTableHeader([...SSRange], 50)],
+ }),
+ ...chunk.reduce((acc, row, ri) => acc.concat(this.createDetailRowSizeSS(sizeSets, row, ri)), []),
+
+ this.createTable_Memo(3),
+ ],
+ });
+ }
+ /**
+ * 超公里
+ */
+ createTable_B(use_year, dataList) {
+ // console.log('*********************************************************************************************');
+ const { chunk, sizeSets, SSRange, PSRange } = chunkBy(use_year, dataList, ['quote_size']);
+ const infoCol = (rowp) =>
+ new TableCell({
+ borders: tableBorderOne,
+ verticalAlign: AlignmentType.CENTER,
+ children: [
+ new Paragraph({
+ text: `${rowp?.info?.km}`,
+ alignment: AlignmentType.CENTER,
+ }),
+ ],
+ });
+ const tableS = sizeSets.reduce((acc, size) => {
+ const subTable = new Table({
+ borders: tableBorderNone,
+ width: {
+ size: 100,
+ type: WidthType.PERCENTAGE,
+ },
+ rows: [
+ new TableRow({
+ children: [
+ this.createTableHeader('超公里项目', 20),
+ this.createTableHeader('往返公里数', 20),
+ this.createTableHeader([...SSRange], 60, { columnSpan: size.length }),
+ ],
+ }),
+ new TableRow({
+ children: [
+ new TableCell({ borders: tableBorderOne, verticalAlign: AlignmentType.CENTER, children: [new Paragraph({ text: '' })] }),
+ new TableCell({ borders: tableBorderOne, verticalAlign: AlignmentType.CENTER, children: [new Paragraph({ text: '' })] }),
+ ...size.map((ss) => new TableCell({ borders: tableBorderOne, verticalAlign: AlignmentType.CENTER, children: [new Paragraph({
+ // text: `${ss[0]}`,
+ text: ss[1] === Infinity ? `${ss[0]}人以上` : `${unique(ss.filter((x) => x)).join('-')}人`,
+ alignment: AlignmentType.CENTER,
+ })] })),
+ ],
+ }),
+ ...chunk
+ .filter((p) => p.sizeSetsSS === size.map((mr) => mr[0]).join(','))
+ .reduce((acc, row, ri) => acc.concat(this.createDetailRowSize(size, row, ri, { infoCol, withSize: false, defaultUnit: '0' })), []),
+ // .reduce((a, c) => a.concat(c), []),
+
+ this.createTable_Memo(2 + size.length),
+ ],
+ });
+ acc.push(subTable);
+ acc.push(new Paragraph({ text: `` }));
+ return acc;
+ }, []);
+ return tableS;
+ }
+
+ /**
+ * 车费
+ * 包价线路
+ */
+ createTable_JD(use_year, dataList) {
+ const chunk_By = ['quote_size']; // dataList[0].info.product_type_id === 'J' ? ['quote_size'] : ['quote_season', 'quote_size'];
+ const showPSCol = false; // dataList[0].info.product_type_id === 'J' ? false : true;
+ const defaultUnit = '1'; // dataList[0].info.product_type_id === 'J' ? '' : '';
+ const { dataSource, sizeSets, SSRange, PSRange } = chunkBy(use_year, dataList, chunk_By);
+
+ const tableHeader = this.createTableHeader;
+ const tableS = sizeSets.reduce((rt, setItem) => {
+ const subTable = new Table({
+ borders: tableBorderNone,
+ width: {
+ size: 100,
+ type: WidthType.PERCENTAGE,
+ },
+ rows: [
+ new TableRow({
+ children: [
+ tableHeader('项目', 20),
+ tableHeader([...SSRange], 40, { columnSpan: setItem.length }),
+ showPSCol ? tableHeader(['旺季', ...PSRange], 40, { columnSpan: setItem.length }) : undefined,
+ ],
+ }),
+ new TableRow({
+ children: [
+ new TableCell({ borders: tableBorderOne, verticalAlign: AlignmentType.CENTER, children: [new Paragraph({ text: '' })] }),
+ ...setItem.map(
+ (ss) =>
+ new TableCell({
+ borders: tableBorderOne,
+ verticalAlign: AlignmentType.CENTER,
+ children: [
+ new Paragraph({
+ // text: `${ss[0]}`,
+ text: ss[1] === Infinity ? `${ss[0]}人以上` : `${unique(ss.filter((x) => x)).join('-')}人`,
+ alignment: AlignmentType.CENTER,
+ }),
+ ],
+ })
+ ),
+ ...(showPSCol
+ ? setItem.map(
+ (ss) =>
+ new TableCell({
+ borders: tableBorderOne,
+ verticalAlign: AlignmentType.CENTER,
+ children: [
+ new Paragraph({
+ // text: `${ss[0]}`,
+ text: ss[1] === Infinity ? `${ss[0]}人以上` : `${unique(ss.filter((x) => x)).join('-')}人`,
+ alignment: AlignmentType.CENTER,
+ }),
+ ],
+ })
+ )
+ : []),
+ ],
+ }),
+ ...dataSource
+ .filter((p) => p.sizeSetsSS === setItem.map((mr) => mr[0]).join(','))
+ .reduce((acc, row, ri) => acc.concat(this.createDetailRowSize(setItem, row, ri, { withSize: false, defaultUnit, withSeason: showPSCol })), []),
+ // .reduce((a, c) => a.concat(c), []),
+
+ this.createTable_Memo(1 + setItem.length * 2),
+ ],
+ });
+ rt.push(subTable);
+ rt.push(new Paragraph({ text: `` }));
+ return rt;
+ }, []);
+ return tableS;
+ }
+ /**
+ * 导游
+ */
+ createTable_Q(use_year, dataList) {
+ const { chunk, SSRange, PSRange } = chunkBy(use_year, dataList, ['quote_season']);
+
+ return new Table({
+ borders: tableBorderNone,
+ width: {
+ size: 100,
+ type: WidthType.PERCENTAGE,
+ },
+ rows: [
+ new TableRow({
+ children: [this.createTableHeader('项目', 30), this.createTableHeader(['平季(除去旺季以外的时间)', ...SSRange], 35), this.createTableHeader(['旺季', ...PSRange], 35)],
+ }),
+ ...chunk.map((row, ri) => this.createDetailRowSeason2(row, ri, { withSize: false })).reduce((a, c) => a.concat(c), []),
+
+ this.createTable_Memo(3),
+ ],
+ });
+ }
+ /**
+ * 景点
+ */
+ createTable_7(use_year, dataList, agencyExtras) {
+ const withExtras = dataList.map((row) => ({ ...row, extras: agencyExtras[row.info.id] || [] }));
+ const { chunk, sizeSets, SSRange, PSRange } = chunkBy(use_year, withExtras, ['quote_season']);
+ const extraCol = (rowp, i) => {
+ return new TableCell({
+ borders: tableBorderOne,
+ verticalAlign: AlignmentType.CENTER,
+ children: [
+ ...(rowp.extras || []).reduce((ac, extra) => {
+ const allSize = unique(extra.quotation.map((eq) => `${eq.group_size_min}-${eq.group_size_max}`));
+ const allDates = unique(extra.quotation.map((eq) => `${eq.use_dates_start}-${eq.use_dates_end}`));
+ // const compactBy = allSize.length > 1 ? 'size' : allDates.length > 1 ? 'dates' : 'all';
+ const compactBy = allSize.length < allDates.length ? 'size' : 'dates';
+ const compactQuotation = groupBy(
+ extra.quotation,
+ (ExtraQuoteItem) =>
+ `${ExtraQuoteItem.adult_cost}@${ExtraQuoteItem.unit_id}.` +
+ (compactBy === 'size' ? `[${ExtraQuoteItem.group_size_min}.${ExtraQuoteItem.group_size_max}]` : `${ExtraQuoteItem.use_dates_start},${ExtraQuoteItem.use_dates_end}`)
+ );
+ // console.log(compactQuotation);
+ const thisE = new Paragraph({
+ children: [new TextRun({ text: `${extra.info.product_title}`, bold: true })],
+ });
+ const thisP = Object.entries(compactQuotation).map(([key, [firstQ, ...others]]) => {
+ const date1 = shortDate(firstQ.use_dates_start);
+ const date2 = shortDate(firstQ.use_dates_end);
+ const othersDates = others.map((oq) => `${shortDate(oq.use_dates_start)}~${shortDate(oq.use_dates_end)}`).join(', ');
+ const otherStr = isEmpty(othersDates) ? '' : `, ${othersDates}`;
+ return new Paragraph({
+ children: [
+ // new TextRun({ text: `${extra.info.product_title} ${firstQ.unit_name}`, bold: true }),
+ new TextRun({
+ text:
+ `${firstQ.group_size_min}-${firstQ.group_size_max}人, ${firstQ.unit_name}, ${firstQ.adult_cost}` +
+ // + (`, ${firstQ.group_size_min}-${firstQ.group_size_max}人`)
+ (compactBy !== 'dates' ? `, ${date1}~${date2}${otherStr}` : ''),
+ }),
+ ],
+ });
+ });
+ return ac.concat([thisE, ...thisP]);
+ // return new Paragraph({ text: `${extra.info.product_title} ${extra.quotation?.[0]?.adult_cost || ''} ${extra.quotation?.[0]?.unit_name || ''}` });
+ }, []),
+ ],
+ });
+ };
+
+ return new Table({
+ borders: tableBorderNone,
+ width: {
+ size: 100,
+ type: WidthType.PERCENTAGE,
+ },
+ rows: [
+ new TableRow({
+ children: [
+ this.createTableHeader('景点', 25),
+ this.createTableHeader(['平季', ...SSRange], 25),
+ this.createTableHeader(['旺季', ...PSRange], 25),
+ this.createTableHeader('附加费用', 25),
+ ],
+ }),
+ ...chunk.reduce((acc, row, ri) => acc.concat(this.createDetailRowSeason2(row, ri, { withSize: true, defaultUnit: '0', extraCol })), []),
+ // ...chunk.map((row, ri) => this.createDetailRowSeason2(row, ri, { withSize: true, defaultUnit: '0', extraCol })).reduce((a, c) => a.concat(c), []),
+
+ this.createTable_Memo(1 + sizeSets.length * 2 + 1),
+ ],
+ });
+ }
+ /**
+ * 餐费
+ */
+ createTable_R(use_year, dataList, agencyExtras) {
+ const withExtras = dataList.map((row) => ({ ...row, extras: agencyExtras[row.info.id] || [] }));
+ const { chunk, sizeSets, SSRange, PSRange } = chunkBy(use_year, withExtras, ['quote_size']);
+ const extraCol = (rowp, i) =>
+ new TableCell({
+ borders: tableBorderOne,
+ verticalAlign: AlignmentType.CENTER,
+ children: [
+ ...(rowp.extras || []).map(
+ (extra) => new Paragraph({ text: `${extra.info.product_title} ${extra.quotation?.[0]?.adult_cost || ''} ${extra.quotation?.[0]?.unit_name || ''}` })
+ ),
+ // new Paragraph({ text: '' })
+ ],
+ });
+
+ const tableS = sizeSets.reduce((acc, size) => {
+ const thisChunk = chunk.filter((p) => p.sizeSetsSS === size.map((mr) => mr[0]).join(','));
+ const currentChunkExtras = uniqWith(thisChunk.map((p) => p.extras).flat(), (a, b) => a.info.id === b.info.id);
+ const mergedUniqueExtra = currentChunkExtras.map(
+ (extra) => new Paragraph({ text: `${extra.info.product_title} ${extra.quotation?.[0]?.adult_cost || ''} ${extra.quotation?.[0]?.unit_name || ''}` })
+ );
+
+ const subTable = new Table({
+ borders: tableBorderNone,
+ width: {
+ size: 100,
+ type: WidthType.PERCENTAGE,
+ },
+ rows: [
+ new TableRow({
+ children: [
+ this.createTableHeader('社会餐厅午餐/晚餐', 25),
+ this.createTableHeader([...SSRange, ...PSRange], 50, { columnSpan: size.length }),
+ this.createTableHeader('司陪餐补', 25),
+ ],
+ }),
+ new TableRow({
+ children: [
+ new TableCell({ borders: tableBorderOne, verticalAlign: AlignmentType.CENTER, children: [new Paragraph({ text: '' })] }),
+ ...size.map((ss) => new TableCell({ borders: tableBorderOne, verticalAlign: AlignmentType.CENTER, children: [new Paragraph({
+ // text: `${ss[0]}`,
+ text: ss[1] === Infinity ? `${ss[0]}人以上` : `${unique(ss.filter((x) => x)).join('-')}人`,
+ alignment: AlignmentType.CENTER,
+ })] })),
+ new TableCell({ borders: tableBorderOne, verticalAlign: AlignmentType.CENTER, rowSpan: thisChunk.length+1, children: mergedUniqueExtra }), // [new Paragraph({ text: `${thisChunk.length+1}` })]
+ // new TableCell({ borders: tableBorderOne, verticalAlign: AlignmentType.CENTER, children: [new Paragraph({ text: '' })] }),
+ ],
+ }),
+ ...thisChunk
+ .reduce((acc, row, ri) => acc.concat(this.createDetailRowSize(size, row, ri, { withSize: false, })), []),
+
+ this.createTable_Memo(1 + size.length + 1),
+ ],
+ });
+ acc.push(subTable);
+ acc.push(new Paragraph({ text: `` }));
+ return acc;
+ }, []);
+ return tableS;
+ }
+ /**
+ * 包价线路
+ * @deprecated
+ */
+ createTable_D(use_year, dataList) {}
+
+ createDetailRowSizeSS = (sizeSets, rowp, ii, { withSeason = false, withSize = true, infoCol = () => {}, extraCol = () => {} } = {}) => {
+ const thisSizeCol = rowp.sizeSetsSS.split(',').map((min, i, _arr) => [Number(min), _arr[i + 1] ? Number(_arr[i + 1]) - 1 : Infinity]);
+ const sizeLength = thisSizeCol.length;
+ const quote_chunk = (rowp.quote_chunk?.SS || []).reduce((acc, cur, i) => {
+ return { ...acc, [cur.quote_size]: cur.adult_cost };
+ }, {});
+
+ return thisSizeCol.map(
+ (sizeRow, ri) =>
+ new TableRow({
+ children: flush([
+ // new TableCell({
+ // borders: tableBorderOne,
+ // rowSpan: 3,
+ // verticalAlign: AlignmentType.CENTER,
+ // children: [new Paragraph(String(ii + 1))],
+ // }),
+ ...(ri === 0
+ ? [
+ new TableCell({
+ borders: tableBorderOne,
+ verticalAlign: AlignmentType.CENTER,
+ rowSpan: sizeLength,
+ children: [
+ new Paragraph({
+ text: `${rowp?.info?.product_title}`,
+ alignment: AlignmentType.LEFT,
+ }),
+ ],
+ }),
+ infoCol(rowp),
+ ]
+ : []),
+ new TableCell({
+ borders: tableBorderOne,
+ verticalAlign: AlignmentType.CENTER,
+ children: [
+ new Paragraph({
+ text: sizeRow[1] === Infinity ? `${sizeRow[0]}人以上` : `${unique(sizeRow.filter((x) => x)).join('-')}人`,
+ alignment: AlignmentType.CENTER,
+ }),
+ ],
+ }),
+ new TableCell({
+ borders: tableBorderOne,
+ verticalAlign: AlignmentType.CENTER,
+ children: [
+ new Paragraph({
+ text: `${quote_chunk?.[sizeRow.join('-')] || ''}`,
+ alignment: AlignmentType.CENTER,
+ }),
+ ],
+ }),
+ extraCol(rowp, ii),
+ ]),
+ })
+ );
+ };
+
+ createDetailRowSize(sizeSets, rowp, ii, { withSeason = false, withSize = true, infoCol = () => {}, extraCol = () => {}, defaultUnit = '0' } = {}) {
+ const sizeCol = sizeSets.map((ss) => ss.join('-'));
+
+ return [
+ new TableRow({
+ children: flush([
+ // new TableCell({
+ // borders: tableBorderOne,
+ // rowSpan: 3,
+ // verticalAlign: AlignmentType.CENTER,
+ // children: [new Paragraph(String(ii + 1))],
+ // }),
+ new TableCell({
+ borders: tableBorderOne,
+ verticalAlign: AlignmentType.CENTER,
+ children: [
+ new Paragraph({
+ text: `${rowp?.info?.product_title}`,
+ alignment: AlignmentType.LEFT,
+ }),
+ ],
+ }),
+ infoCol(rowp),
+ ...sizeCol.map(
+ (ss) =>
+ new TableCell({
+ borders: tableBorderOne,
+ width: { size: 2000, type: WidthType.DXA },
+ verticalAlign: AlignmentType.CENTER,
+ children: [
+ ...((withSeason ? rowp.quote_chunk?.['SS']?.[ss] : rowp.quote_chunk[ss]) || []).map(
+ (quoteItem, ii) =>
+ new Paragraph({
+ alignment: AlignmentType.CENTER,
+ text: isEmpty(quoteItem)
+ ? ''
+ : withSize && String(quoteItem.unit_id)!==defaultUnit
+ ? `${quoteItem.group_size_min}-${quoteItem.group_size_max}人,${quoteItem.unit_name}, ${quoteItem.adult_cost}`
+ : `${quoteItem.adult_cost}`,
+ })
+ ),
+ // new Paragraph({ text: '-'+ii })
+ ],
+ })
+ ),
+ ...(withSeason
+ ? sizeCol.map(
+ (ss) =>
+ new TableCell({
+ borders: tableBorderOne,
+ width: { size: 2000, type: WidthType.DXA },
+ verticalAlign: AlignmentType.CENTER,
+ children: [
+ ...(rowp.quote_chunk?.['PS']?.[ss] || []).map(
+ (quoteItem, ii) =>
+ new Paragraph({
+ alignment: AlignmentType.CENTER,
+ // text: `${quoteItem.adult_cost}, ${quoteItem.group_size_min}-${quoteItem.group_size_max}${quoteItem.unit_name}`,
+ text: withSize && String(quoteItem.unit_id)!==defaultUnit
+ ? `${quoteItem.group_size_min}-${quoteItem.group_size_max}人,${quoteItem.unit_name}, ${quoteItem.adult_cost}`
+ : `${quoteItem.adult_cost}`,
+ })
+ ),
+ ],
+ })
+ )
+ : []),
+ extraCol(rowp, ii),
+ ]),
+ }),
+ ];
+ }
+ createDetailRowSeason2(rowp, ii, { withSize = true, defaultUnit = '0', extraCol = () => {} } = {}) {
+
+ return [
+ new TableRow({
+ children: [
+ // new TableCell({
+ // borders: tableBorderOne,
+ // rowSpan: 3,
+ // verticalAlign: AlignmentType.CENTER,
+ // children: [new Paragraph(String(ii + 1))],
+ // }),
+ new TableCell({
+ borders: tableBorderOne,
+ verticalAlign: AlignmentType.CENTER,
+ children: [
+ new Paragraph({
+ text: `${rowp?.info?.product_title}`,
+ alignment: AlignmentType.LEFT,
+ }),
+ ],
+ }),
+ new TableCell({
+ borders: tableBorderOne,
+ width: { size: 2000, type: WidthType.DXA },
+ verticalAlign: AlignmentType.CENTER,
+ children: [
+ ...(rowp.quote_chunk['SS'] || []).map(
+ (quoteItem, ii) =>
+ new Paragraph({
+ alignment: AlignmentType.CENTER,
+ // text: `${quoteItem.adult_cost}, ${quoteItem.group_size_min}-${quoteItem.group_size_max}人,${quoteItem.unit_name}`,
+ text: (withSize && String(quoteItem.unit_id)!==defaultUnit ? `${quoteItem.group_size_min}-${quoteItem.group_size_max}人,${quoteItem.unit_name},` : '') + `${quoteItem.adult_cost}`,
+ })
+ ),
+ ],
+ }),
+ new TableCell({
+ borders: tableBorderOne,
+ width: { size: 2000, type: WidthType.DXA },
+ verticalAlign: AlignmentType.CENTER,
+ children: [
+ ...(rowp.quote_chunk['PS'] || []).map(
+ (quoteItem, ii) =>
+ new Paragraph({
+ alignment: AlignmentType.CENTER,
+ // text: `${quoteItem.adult_cost}, ${quoteItem.group_size_min}-${quoteItem.group_size_max}人,${quoteItem.unit_name}`,
+ text: (withSize && String(quoteItem.unit_id)!==defaultUnit ? `${quoteItem.group_size_min}-${quoteItem.group_size_max}人,${quoteItem.unit_name},` : '') + `${quoteItem.adult_cost}`,
+ })
+ ),
+ ],
+ }),
+ extraCol(rowp, ii),
+ ],
+ }),
+ ];
+ }
+
+ createTable_Memo(columnSpan) {
+ return new TableRow({
+ children: [
+ new TableCell({
+ borders: tableBorderOne,
+ // verticalAlign: AlignmentType.CENTER,
+ columnSpan,
+ children: [new Paragraph(`备注: `), new Paragraph(``)],
+ }),
+ ],
+ });
+ }
+
+ createInfo_Bank() {
+ const Col1 = (label, opt = {}) =>
+ new TableCell({
+ borders: tableBorderOne,
+ width: { size: 2000, type: WidthType.DXA },
+ // verticalAlign: AlignmentType.CENTER,
+ children: [new Paragraph(label)],
+ ...opt,
+ });
+ return new Table({
+ borders: tableBorderNone,
+ width: {
+ size: 100,
+ type: WidthType.PERCENTAGE,
+ },
+ rows: [
+ new TableRow({
+ children: [Col1('帐户:'), new TableCell({ borders: tableBorderOne, children: [new Paragraph(``)] })],
+ }),
+ new TableRow({
+ children: [Col1('银行:'), new TableCell({ borders: tableBorderOne, children: [new Paragraph(``)] })],
+ }),
+ new TableRow({
+ children: [Col1('帐号:'), new TableCell({ borders: tableBorderOne, children: [new Paragraph(``)] })],
+ }),
+ new TableRow({
+ children: [Col1('结账方式:'), new TableCell({ borders: tableBorderOne, children: [new Paragraph(``)] })],
+ }),
+ ],
+ });
+ }
+ createInfo_Contact() {
+ const Col1 = (label, opt = {}) =>
+ new TableCell({
+ borders: tableBorderOne,
+ width: { size: 2000, type: WidthType.DXA },
+ // verticalAlign: AlignmentType.CENTER,
+ children: [new Paragraph(label)],
+ ...opt,
+ });
+ return new Table({
+ borders: tableBorderNone,
+ width: {
+ size: 100,
+ type: WidthType.PERCENTAGE,
+ },
+ rows: [
+ new TableRow({
+ children: [this.createTableHeader('联系人', 25), this.createTableHeader('电话', 25), this.createTableHeader('微信', 25), this.createTableHeader('手机', 25)],
+ }),
+ new TableRow({
+ children: [Col1('经理:'), ...[null, null, null].map((col) => new TableCell({ borders: tableBorderOne, children: [new Paragraph(``)] }))],
+ }),
+ new TableRow({
+ children: [Col1('计调:'), ...[null, null, null].map((col) => new TableCell({ borders: tableBorderOne, children: [new Paragraph(``)] }))],
+ }),
+ new TableRow({
+ children: [Col1('财务(发票):'), ...[null, null, null].map((col) => new TableCell({ borders: tableBorderOne, children: [new Paragraph(``)] }))],
+ }),
+ ],
+ });
+ }
+ createInfo_Terms() {
+ const subHeader = (text) =>
+ new Paragraph({
+ alignment: AlignmentType.CENTER,
+ outlineLevel: 1,
+ spacing: { after: 200, before: 200 },
+ style: 'TableHeader',
+ children: [new TextRun({ text: `${text}`, bold: true, size: 28 })],
+ });
+ const numberingContent = ([abstract, ...content], instance) => [
+ new Paragraph({ text: abstract, indent: { firstLine: `2pc` } }),
+ ...content.map(
+ ([itemTitle, ...itemList]) =>
+ new Paragraph({
+ text: itemTitle,
+ numbering: { reference: 'terms', level: 0, instance },
+ children: itemList.map((li) => new TextRun({ text: li, break: 1 })),
+ })
+ ),
+ ];
+
+ return [
+ subHeader('中华游专利产品接待权标准'),
+ ...numberingContent(
+ [
+ '中华游是注重特色新产品开发的品牌,并希望通过开发新产品丰富中华游的网前线路,吸引更多的客户与中华游订购中国之旅。为了更好的鼓励各个地接社积极开发新产品、新线路,特制定中华游专利产品接待权标准,详情如下:',
+ ['新产品,新线路定义及专利期', '新产品,新线路非市场上现成的新产品,新体验,而是包含了独家设计或独家资源的产品和体验'],
+ ['中华游和地接社联合设计研发的新产品', '由中华游发起立意和产品框架', '地接社协助填充具体内容并落地', '专利期:6个月'],
+ ['地接社自主设计研发并落地(中华游或做细微调整)', '如:北京“民生探索”', '专利期:永久 (除非地接社已无法掌握产品或资源的独家性)'],
+ ],
+ 1
+ ),
+ subHeader('关于价格变更'),
+ ...numberingContent(
+ [
+ '中华游与各地接社签订年度地接协议后,将不认同中途涨价的要求。但考虑在实际合作中存在的不可控因素,为维护双方共同利益,两种价格变更情况处理方式如下',
+ [
+ '常规价格变更:',
+ '一般景区和酒店会提前3个月通知价格变更事宜,要求地接社及时用聊天工具或邮件形式通知中华游产品采购,并以收到相同形式确认回执为准,否则中华游将有权拒付额外增加的一切费用。额外增加费用的承担规则为已确认团队计划保持原价,新价格仅适用于确认回复日期起的新发送团队计划。',
+ ],
+ [
+ '临时价格变更:',
+ '一般属于政府行为或景区强制要求,如不立即交款则无法参观等紧急情况。因此种情况产生的额外费用要求第一时间通知中华游产品采购,并秉承维护双方共同利益与长期合作,共同协商友好解决方案。',
+ ],
+ ],
+ 2
+ ),
+ new Paragraph({
+ text: '签名盖章',
+ spacing: { before: 600, after: 200 },
+ children: [
+ new TextRun({ break: 2, children: ['甲方:', new Tab(), '乙方:桂林海纳国际旅行社有限公司'] }),
+ new TextRun({ break: 1, children: ['负责人签字盖章', new Tab(), '负责人签字盖章'] }),
+ new TextRun({ break: 3, children: ['联系人: ', new Tab(), '联系人:游佳佳'] }),
+ new TextRun({ break: 1, children: ['电话: ', new Tab(), '电话:13507831547'] }),
+ new TextRun({ break: 1, children: ['电子邮箱: ', new Tab(), '电子邮箱:xeniayou@hainatravel.com'] }),
+ new TextRun({ break: 1, children: [' 年 月 日', new Tab(), ' 年 月 日'] }),
+ ],
+ tabStops: [{ type: TabStopType.LEFT, position: 4800 }],
+ }),
+ // new Paragraph({
+ // tabStops: [{ type: TabStopType.RIGHT, position: 1000 }],
+ // children: [
+ // new TextRun({
+ // children: [
+ // '\t年',
+ // '\t\t月',
+ // '\t\t日',
+ // new PositionalTab({
+ // alignment: PositionalTabAlignment.CENTER,
+ // relativeTo: PositionalTabRelativeTo.MARGIN,
+ // leader: PositionalTabLeader.NONE,
+ // }),
+ // // new Tab(),
+ // '\t年',
+ // '\t\t月',
+ // '\t\t日',
+ // ],
+ // }),
+ // ],
+ // }),
+ ];
+ }
+ createTableHeader(text, w = null, opt = {}) {
+ const textP = typeof text === 'string' ? [text] : text;
+ return new TableCell({
+ borders: tableBorderOne,
+ width: { size: w || `8mm`, type: w ? WidthType.PERCENTAGE : WidthType.AUTO },
+ verticalAlign: AlignmentType.CENTER,
+ children: textP.map((t) => new Paragraph({ text: t, alignment: AlignmentType.CENTER, style: 'TableHeader' })),
+ ...opt,
+ });
+ }
+ createHeading(text) {
+ return new Paragraph({
+ text: text,
+ heading: HeadingLevel.HEADING_1,
+ // thematicBreak: true,
+ alignment: AlignmentType.CENTER,
+ });
+ }
+
+ createTitle(text) {
+ return new Paragraph({
+ text: text,
+ heading: HeadingLevel.TITLE,
+ // thematicBreak: true,
+ alignment: AlignmentType.CENTER,
+ });
+ }
+
+ createSubHeading(text, style = {}) {
+ return new Paragraph({
+ text: text,
+ heading: HeadingLevel.HEADING_1,
+ ...style,
+ });
+ }
+ createPageHeaderText(text, style = {}) {
+ return new Paragraph({
+ alignment: AlignmentType.RIGHT,
+ children: [
+ new TextRun({
+ text: text,
+ italics: true,
+ size: 20,
+ ...style,
+ }),
+ ],
+ });
+ }
+}
diff --git a/src/views/products/Print/AgencyContract.jsx b/src/views/products/Print/AgencyContract_v3.jsx
similarity index 72%
rename from src/views/products/Print/AgencyContract.jsx
rename to src/views/products/Print/AgencyContract_v3.jsx
index 3aaa855..3ce91a0 100644
--- a/src/views/products/Print/AgencyContract.jsx
+++ b/src/views/products/Print/AgencyContract_v3.jsx
@@ -22,7 +22,7 @@ import {
PositionalTabLeader,
} from 'docx';
import dayjs from 'dayjs';
-import { cloneDeep, groupBy, isEmpty, unique, uniqWith } from '@/utils/commons';
+import { cloneDeep, groupBy, isEmpty, isNotEmpty, sortBy, unique, uniqWith } from '@/utils/commons';
// Shoulder Season 平季; peak season 旺季
const isFullYearOrLonger = (year, startDate, endDate) => {
@@ -66,69 +66,131 @@ const chunkCarSets = (numbers) => {
{ lt5: [], lt7: [], lt10: [], gt10: [] }
);
};
+const uniqueBySub = (arr) =>
+ arr.filter((subArr1, _, self) => {
+ return !self.some((subArr2) => {
+ if (subArr1 === subArr2) return false; // don't compare a subarray with itself
+ const set1 = new Set(subArr1);
+ const set2 = new Set(subArr2);
+ // check if subArr1 is a subset of subArr2
+ return [...set1].every((value) => set2.has(value));
+ });
+ });
+const isFlatUnique = (bigArray) => {
+ let flattenedArray = bigArray.flat();
+ return flattenedArray.every((i) => {
+ let count = flattenedArray.filter((j) => j === i).length;
+ return count === 1;
+ });
+};
const chunkBy = (use_year, dataList = [], by = []) => {
- const groupSize = dataList.reduce((a, c) => a.concat((c.quotation || []).reduce((aq, cq) => aq.concat([[cq.group_size_min, cq.group_size_max]]), [])), []);
- const allSizeCut = groupBy(
- uniqWith(groupSize, (a, b) => a[0] === b[0] && a[1] === b[1]),
- (c) => c[0]
- );
- // 按max最大值 cut分组
- const sizeSets = Object.keys(allSizeCut).map((s1) => [Number(s1), Math.max(...allSizeCut[s1].map((c) => c[1]))]);
- const sizeSetsByMax = uniqWith(sizeSets, (a, b) => a[1] === b[1]);
- // // const sizeSetsByMax = [[1,4], [5,6], [7, 9], [10, Infinity]]; // test: 固定车辆座次
- // 按max最小值 cut分组
- // const sizeSets = Object.keys(allSizeCut).map((s1) => [Number(s1), Math.min(...allSizeCut[s1].map((c) => c[1]))]);
- // const sizeSetsByMax = uniqWith(sizeSets, (a, b) => a[1] === b[1]);
-
- const dataRoll = dataList.map((rowp, ii) => {
+ const dataRollSS = dataList.map((rowp, ii) => {
const quotation = rowp.quotation.map((quoteItem) => {
- const matchRange = cloneDeep(sizeSetsByMax)
- .reverse()
- .find((ss) => quoteItem.group_size_min >= ss[0] && quoteItem.group_size_max <= ss[1]);
- const inSet = matchRange;
- // const matchMax =
- // matchRange ||
- // cloneDeep(sizeSetsByMax)
- // // .reverse()
- // .find((ss) => quoteItem.group_size_max <= ss[1]);
- // const matchMin =
- // matchMax ||
- // cloneDeep(sizeSetsByMax)
- // // .reverse()
- // .find((ss) => quoteItem.group_size_min >= ss[0]);
- // const inSet = matchMin;
return {
...quoteItem,
quote_season: isFullYearOrLonger(use_year, quoteItem.use_dates_start, quoteItem.use_dates_end) ? 'SS' : 'PS',
- quote_size: inSet ? inSet.join('-') : '10-Infinity',
};
});
- return { ...rowp, quotation };
+ return { ...rowp, quotation, };
});
-
- const chunk = dataRoll.map((rowp) => {
- const quote_chunk = groupBy(rowp.quotation, (quoteItem) => by.map((key) => quoteItem[key]).join('@'));
- return { ...rowp, quote_chunk };
+ // console.log('\ndataRollSS', dataRollSS);
+ // console.log('\n\n', dataList[0].info.product_type_id, dataRollSS);
+
+ // 人等分组只取平季, 因为产品只一行
+ const allQuotesSS = dataRollSS.reduce((acc, rowp) => acc.concat(rowp.quotation.filter(q => q.quote_season === 'SS')), []);
+ const allQuotesPS = dataRollSS.reduce((acc, rowp) => acc.concat(rowp.quotation.filter(q => q.quote_season === 'PS')), []);
+ const allQuotesSSS = isEmpty(allQuotesSS) ? allQuotesPS : allQuotesSS;
+ // console.log('allQuotesSSS', allQuotesSS, '\n', allQuotesPS, '\n', allQuotesSSS);
+
+ // const groupSizeSS = (allQuotesSS).reduce((aq, cq) => aq.concat([[cq.group_size_min, cq.group_size_max]]), []);
+ const PGroupSizeSS = (allQuotesSSS).reduce((aq, cq) => {
+ aq[cq.WPI_SN] = aq[cq.WPI_SN] || [];
+ aq[cq.WPI_SN].push(cq.group_size_min);
+ aq[cq.WPI_SN] = unique(aq[cq.WPI_SN]);
+ return aq;
+ }, {});
+ // console.log('PGroupSizeSS', structuredClone(PGroupSizeSS));
+ const _SSMinSet = uniqWith(Object.values(PGroupSizeSS), (a, b) => a.join(',') === b.join(','));
+ // console.log('SSMinSet', _SSMinSet);
+ const uSSsizeSetArr = uniqueBySub(_SSMinSet);
+ // console.log('uSSsizeSetArr', uSSsizeSetArr);
+ for (const key in PGroupSizeSS) {
+ if (Object.prototype.hasOwnProperty.call(PGroupSizeSS, key)) {
+ const element = PGroupSizeSS[key];
+ const findSet = uSSsizeSetArr.find(minCut => element.every(v => minCut.includes(v)));
+ PGroupSizeSS[key] = findSet;
+ }
+ }
+ // console.log('PGroupSizeSS aaa', PGroupSizeSS);
+ const [SSsizeSets, PSsizeSets] = [uSSsizeSetArr, []].map((arr) => {
+ const _arr = structuredClone(arr);
+ const arrSets = _arr.map(keyMins => keyMins.reduce((acc, curr, idx, minsArr) => {
+ const _max = idx === minsArr.length - 1 ? Infinity : Number(minsArr[idx + 1])-1;
+ acc.push([Number(curr), _max]);
+ return acc;
+ }, []));
+ return arrSets;
});
- const dataSource = chunk.map((rowp, ri) => {
- const thisChunk = Object.keys(rowp.quote_chunk).reduce((qc, ckey) => {
+ // console.log('PGroupSizeSS fff', SSsizeSets);
+ const compactSizeSets = { SSsizeSetKey: uSSsizeSetArr.map((s) => s.join(',')).filter(isNotEmpty), sizeSets: SSsizeSets };
+ // console.log(compactSizeSets);
+ const chunkSS = structuredClone(dataRollSS).map(rowp => {
+ // console.log(rowp.info.id, rowp.info.product_title);
+
+ const pkey = (PGroupSizeSS[rowp.info.id] || []).join(',') || compactSizeSets.SSsizeSetKey[0]; // todo:
+ // console.log('pkey', pkey);
+
+ const thisRange = (PGroupSizeSS[rowp.info.id] || []).reduce((acc, curr, idx, minsArr) => {
+ const _max = idx === minsArr.length - 1 ? Infinity : Number(minsArr[idx + 1])-1;
+ acc.push([Number(curr), _max]);
+ return acc;
+ }, []);
+ const _quotation = rowp.quotation.map((quoteItem) => {
+ const ssSets = isEmpty(thisRange) ? SSsizeSets[0] : structuredClone(thisRange).reverse();
+ // if (isEmpty(ssSets)) {
+ // console.group('quotation item');
+ // console.log(rowp.info.id, rowp.info.product_title, rowp);
+ // console.log(ssSets);
+ // console.log([quoteItem.group_size_min, quoteItem.group_size_max]);
+ // console.groupEnd();
+ // }
+ // console.group('quotation item');
+ // console.log(ssSets);
+ // console.log([quoteItem.group_size_min, quoteItem.group_size_max]);
+ const matchRange = (ssSets).find((ss) => quoteItem.group_size_min >= ss[0] && quoteItem.group_size_max <= ss[1]);
+ const findEnd = matchRange || ssSets.find((ss) => quoteItem.group_size_max > ss[0] && quoteItem.group_size_max <= ss[1] && ss[1] !== Infinity);
+ const findStart = findEnd || ssSets.find((ss) => quoteItem.group_size_min >= ss[0]);
+ const finalRange = findStart;
+ // console.log('find mmm', matchRange, findEnd, findStart, finalRange);
+ // console.log('matchRange ', 'find', [quoteItem.group_size_min, quoteItem.group_size_max], 'matched', finalRange);
+ // console.groupEnd();
+ quoteItem.quote_size = finalRange.join('-');
+ return quoteItem;
+ });
+ const quote_chunk_flat = groupBy(_quotation, (quoteItem2) => by.map((key) => quoteItem2[key]).join('@'));
+ const quote_chunk = Object.keys(quote_chunk_flat).reduce((qc, ckey) => {
const ckeyArr = ckey.split('@');
if (isEmpty(qc[ckeyArr[0]])) {
- qc[ckeyArr[0]] = ckeyArr[1] ? { [ckeyArr[1]]: rowp.quote_chunk[ckey] } : rowp.quote_chunk[ckey];
+ qc[ckeyArr[0]] = ckeyArr[1] ? { [ckeyArr[1]]: quote_chunk_flat[ckey] } : quote_chunk_flat[ckey];
} else {
- qc[ckeyArr[0]][ckeyArr[1]] = (qc[ckeyArr[0]][ckeyArr[1]] || []).concat(rowp.quote_chunk[ckey]);
+ qc[ckeyArr[0]][ckeyArr[1]] = (qc[ckeyArr[0]][ckeyArr[1]] || []).concat(quote_chunk_flat[ckey]);
}
return qc;
}, {});
-
- return { ...rowp, quote_chunk: thisChunk };
+ return {
+ ...rowp,
+ sizeSetsSS: pkey,
+ quotation: _quotation,
+ quote_chunk,
+ }
});
- const allquotation = chunk.reduce((a, c) => a.concat(c.quotation), []);
+ // console.log('quotation', chunkSS);
+ const allquotation = chunkSS.reduce((a, c) => a.concat(c.quotation), []);
// 取出两季相应的时效区间
const SSRange = unique((allquotation || []).filter((q) => q.quote_season === 'SS').map((qr) => `${qr.use_dates_start}~${qr.use_dates_end}`));
const PSRange = unique((allquotation || []).filter((q) => q.quote_season === 'PS').map((qr) => `${qr.use_dates_start}~${qr.use_dates_end}`));
- // console.log('chunk', chunk, dataSource, sizeSets, sizeSetsByMax);
- return { chunk, dataSource, sizeSets: sizeSetsByMax, SSRange, PSRange };
+
+ return { chunk: chunkSS, dataSource: chunkSS, SSRange, PSRange, ...compactSizeSets };
};
const DOC_TITLE = '地接合同';
@@ -158,7 +220,7 @@ export default class AgencyContract {
const yearStart = dayjs(`${use_year}-01-01`).format('YYYY.MM.DD');
const yearEnd = dayjs(`${use_year}-12-31`).format('YYYY.MM.DD');
// console.log(agencyExtras);
- console.log('*********************************************************************************************');
+ // console.log('*********************************************************************************************');
const document = new Document({
creator: 'China Highlights',
@@ -331,23 +393,22 @@ export default class AgencyContract {
: [this.createSubHeading(`综费`, { numbering: { reference: 'products-type', level: 0 } }), this.createTable_6Q(use_year, agencyProducts['6'])]),
...(isEmpty(agencyProducts['B'])
? []
- : [this.createSubHeading(`超公里`, { numbering: { reference: 'products-type', level: 0 } }), this.createTable_B(use_year, agencyProducts['B'])]),
+ : [this.createSubHeading(`超公里`, { numbering: { reference: 'products-type', level: 0 } }), ...this.createTable_B(use_year, agencyProducts['B'])]),
...(isEmpty(agencyProducts['J'])
? []
- : [this.createSubHeading(`车费`, { numbering: { reference: 'products-type', level: 0 } }), this.createTable_JD(use_year, agencyProducts['J'])]),
+ : [this.createSubHeading(`车费`, { numbering: { reference: 'products-type', level: 0 } }), ...this.createTable_JD(use_year, agencyProducts['J'])]),
...(isEmpty(agencyProducts['Q'])
? []
: [this.createSubHeading(`导游`, { numbering: { reference: 'products-type', level: 0 } }), this.createTable_6Q(use_year, agencyProducts['Q'])]),
- // this.createTable_Q(use_year, agencyProducts['Q']),
...(isEmpty(agencyProducts['7'])
? []
: [this.createSubHeading(`景点`, { numbering: { reference: 'products-type', level: 0 } }), this.createTable_7(use_year, agencyProducts['7'], agencyExtras)]),
...(isEmpty(agencyProducts['R'])
? []
- : [this.createSubHeading(`餐费`, { numbering: { reference: 'products-type', level: 0 } }), this.createTable_R(use_year, agencyProducts['R'], agencyExtras)]),
+ : [this.createSubHeading(`餐费`, { numbering: { reference: 'products-type', level: 0 } }), ...this.createTable_R(use_year, agencyProducts['R'], agencyExtras)]),
...(isEmpty(agencyProducts['D'])
? []
- : [this.createSubHeading(`包价线路`, { numbering: { reference: 'products-type', level: 0 } }), this.createTable_JD(use_year, agencyProducts['D'])]),
+ : [this.createSubHeading(`包价线路`, { numbering: { reference: 'products-type', level: 0 } }), ...this.createTable_JD(use_year, agencyProducts['D'])]),
this.createSubHeading(`公司银行账户`, { numbering: { reference: 'products-type', level: 0 } }),
this.createInfo_Bank(),
this.createSubHeading(`联系资料`, { numbering: { reference: 'products-type', level: 0 } }),
@@ -389,7 +450,8 @@ export default class AgencyContract {
* 超公里
*/
createTable_B(use_year, dataList) {
- const { chunk: dataSource, sizeSets, SSRange, PSRange } = chunkBy(use_year, dataList, ['quote_size']);
+ // console.log('*********************************************************************************************');
+ const { chunk, sizeSets, SSRange, PSRange } = chunkBy(use_year, dataList, ['quote_size']);
const infoCol = (rowp) =>
new TableCell({
borders: tableBorderOne,
@@ -401,32 +463,41 @@ export default class AgencyContract {
}),
],
});
+ const tableS = sizeSets.reduce((acc, size) => {
+ const subTable = new Table({
+ borders: tableBorderNone,
+ width: {
+ size: 100,
+ type: WidthType.PERCENTAGE,
+ },
+ rows: [
+ new TableRow({
+ children: [
+ this.createTableHeader('超公里项目', 20),
+ this.createTableHeader('往返公里数', 20),
+ this.createTableHeader(['全年', ...SSRange, ...PSRange], 60, { columnSpan: size.length }),
+ ],
+ }),
+ new TableRow({
+ children: [
+ new TableCell({ borders: tableBorderOne, verticalAlign: AlignmentType.CENTER, children: [new Paragraph({ text: '' })] }),
+ new TableCell({ borders: tableBorderOne, verticalAlign: AlignmentType.CENTER, children: [new Paragraph({ text: '' })] }),
+ ...size.map((ss) => new TableCell({ borders: tableBorderOne, verticalAlign: AlignmentType.CENTER, children: [new Paragraph({ text: `${ss[0]}` })] })),
+ ],
+ }),
+ ...chunk
+ .filter((p) => p.sizeSetsSS === size.map((mr) => mr[0]).join(','))
+ .map((row, ri) => this.createDetailRowSize(size, row, ri, { infoCol }))
+ .reduce((a, c) => a.concat(c), []),
- return new Table({
- borders: tableBorderNone,
- width: {
- size: 100,
- type: WidthType.PERCENTAGE,
- },
- rows: [
- new TableRow({
- children: [
- this.createTableHeader('超公里项目', 20),
- this.createTableHeader('往返公里数', 20),
- this.createTableHeader(['全年', ...SSRange, ...PSRange], 60, { columnSpan: sizeSets.length }),
- ],
- }),
- new TableRow({
- children: [
- new TableCell({ borders: tableBorderOne, verticalAlign: AlignmentType.CENTER, children: [new Paragraph({ text: '' })] }),
- new TableCell({ borders: tableBorderOne, verticalAlign: AlignmentType.CENTER, children: [new Paragraph({ text: '' })] }),
- ...sizeSets.map((ss) => new TableCell({ borders: tableBorderOne, verticalAlign: AlignmentType.CENTER, children: [new Paragraph({ text: ss.join('-') })] })),
- ],
- }),
- ...dataSource.map((row, ri) => this.createDetailRowSize(sizeSets, row, ri, { infoCol })).reduce((a, c) => a.concat(c), []),
- this.createTable_Memo(2 + sizeSets.length),
- ],
- });
+ this.createTable_Memo(2 + size.length),
+ ],
+ });
+ acc.push(subTable);
+ acc.push(new Paragraph({ text: `` }));
+ return acc;
+ }, []);
+ return tableS;
}
/**
@@ -434,35 +505,42 @@ export default class AgencyContract {
* 包价线路
*/
createTable_JD(use_year, dataList) {
- const { chunk, dataSource, sizeSets, SSRange, PSRange } = chunkBy(use_year, dataList, ['quote_season', 'quote_size']);
- // console.log(chunk, dataSource, sizeSets);
-
- return new Table({
- borders: tableBorderNone,
- width: {
- size: 100,
- type: WidthType.PERCENTAGE,
- },
- rows: [
- new TableRow({
- children: [
- this.createTableHeader('项目', 20),
- this.createTableHeader(['平季', ...SSRange], 40, { columnSpan: sizeSets.length }),
- this.createTableHeader(['旺季', ...PSRange], 40, { columnSpan: sizeSets.length }),
- ],
- }),
- new TableRow({
- children: [
- new TableCell({ borders: tableBorderOne, verticalAlign: AlignmentType.CENTER, children: [new Paragraph({ text: '' })] }),
- ...sizeSets.map((ss) => new TableCell({ borders: tableBorderOne, verticalAlign: AlignmentType.CENTER, children: [new Paragraph({ text: ss.join('-') })] })),
- ...sizeSets.map((ss) => new TableCell({ borders: tableBorderOne, verticalAlign: AlignmentType.CENTER, children: [new Paragraph({ text: ss.join('-') })] })),
- ],
- }),
- ...dataSource.map((row, ri) => this.createDetailRowSize(sizeSets, row, ri, { withSeason: true })).reduce((a, c) => a.concat(c), []),
+ const { dataSource, sizeSets, SSRange, PSRange } = chunkBy(use_year, dataList, ['quote_season', 'quote_size']);
+
+ const tableHeader = this.createTableHeader;
+ const tableS = sizeSets.reduce((rt, setItem) => {
+ const subTable = new Table({
+ borders: tableBorderNone,
+ width: {
+ size: 100,
+ type: WidthType.PERCENTAGE,
+ },
+ rows: [
+ new TableRow({
+ children: [
+ tableHeader('项目', 20),
+ tableHeader(['平季', ...SSRange], 40, { columnSpan: setItem.length }),
+ tableHeader(['旺季', ...PSRange], 40, { columnSpan: setItem.length }),
+ ],
+ }),
+ new TableRow({
+ children: [
+ new TableCell({ borders: tableBorderOne, verticalAlign: AlignmentType.CENTER, children: [new Paragraph({ text: '' })] }),
+ ...setItem.map((ss) => new TableCell({ borders: tableBorderOne, verticalAlign: AlignmentType.CENTER, children: [new Paragraph({ text: `${ss[0]}` })] })),
+ ...setItem.map((ss) => new TableCell({ borders: tableBorderOne, verticalAlign: AlignmentType.CENTER, children: [new Paragraph({ text: `${ss[0]}` })] })),
+ ],
+ }),
+ ...dataSource.filter((p) => p.sizeSetsSS === setItem.map((mr) => mr[0]).join(','))
+ .map((row, ri) => this.createDetailRowSize(setItem, row, ri, { withSeason: true })).reduce((a, c) => a.concat(c), []),
- this.createTable_Memo(1 + sizeSets.length * 2),
- ],
- });
+ this.createTable_Memo(1 + setItem.length * 2),
+ ],
+ });
+ rt.push(subTable);
+ rt.push(new Paragraph({ text: `` }));
+ return rt;
+ }, []);
+ return tableS;
}
/**
* 导游
@@ -559,69 +637,46 @@ export default class AgencyContract {
],
});
- return new Table({
- borders: tableBorderNone,
- width: {
- size: 100,
- type: WidthType.PERCENTAGE,
- },
- rows: [
- new TableRow({
- children: [
- this.createTableHeader('社会餐厅午餐/晚餐', 25),
- this.createTableHeader(['价格', ...SSRange, ...PSRange], 50, { columnSpan: sizeSets.length }),
- this.createTableHeader('司陪餐补', 25),
- ],
- }),
- new TableRow({
- children: [
- new TableCell({ borders: tableBorderOne, verticalAlign: AlignmentType.CENTER, children: [new Paragraph({ text: '' })] }),
- ...sizeSets.map((ss) => new TableCell({ borders: tableBorderOne, verticalAlign: AlignmentType.CENTER, children: [new Paragraph({ text: ss.join('-') })] })),
- // new TableCell({ borders: tableBorderOne, verticalAlign: AlignmentType.CENTER, rowSpan: dataList.length+1, children: [new Paragraph({ text: '' })] }),
- new TableCell({ borders: tableBorderOne, verticalAlign: AlignmentType.CENTER, children: [new Paragraph({ text: '' })] }),
- ],
- }),
- ...chunk.map((row, ri) => this.createDetailRowSize(sizeSets, row, ri, { withSize: false, extraCol })).reduce((a, c) => a.concat(c), []),
- // ...dataSource.map((row, ri) => this.createDetailRowSize(sizeSets, row, ri, true)).reduce((a, c) => a.concat(c), []),
+ const tableS = sizeSets.reduce((acc, size) => {
+ const subTable = new Table({
+ borders: tableBorderNone,
+ width: {
+ size: 100,
+ type: WidthType.PERCENTAGE,
+ },
+ rows: [
+ new TableRow({
+ children: [
+ this.createTableHeader('社会餐厅午餐/晚餐', 25),
+ this.createTableHeader(['价格', ...SSRange, ...PSRange], 50, { columnSpan: size.length }),
+ this.createTableHeader('司陪餐补', 25),
+ ],
+ }),
+ new TableRow({
+ children: [
+ new TableCell({ borders: tableBorderOne, verticalAlign: AlignmentType.CENTER, children: [new Paragraph({ text: '' })] }),
+ ...size.map((ss) => new TableCell({ borders: tableBorderOne, verticalAlign: AlignmentType.CENTER, children: [new Paragraph({ text: `${ss[0]}` })] })),
+ // new TableCell({ borders: tableBorderOne, verticalAlign: AlignmentType.CENTER, rowSpan: dataList.length+1, children: [new Paragraph({ text: '' })] }),
+ new TableCell({ borders: tableBorderOne, verticalAlign: AlignmentType.CENTER, children: [new Paragraph({ text: '' })] }),
+ ],
+ }),
+ ...chunk.filter((p) => p.sizeSetsSS === size.map((mr) => mr[0]).join(','))
+ .map((row, ri) => this.createDetailRowSize(size, row, ri, { withSize: false, extraCol })).reduce((a, c) => a.concat(c), []),
- this.createTable_Memo(1 + sizeSets.length + 1),
- ],
- });
+ this.createTable_Memo(1 + size.length + 1),
+ ],
+ });
+ acc.push(subTable);
+ acc.push(new Paragraph({ text: `` }));
+ return acc;
+ }, []);
+ return tableS;
}
/**
* 包价线路
* @deprecated
*/
- createTable_D(use_year, dataList) {
- const { chunk, dataSource, sizeSets, SSRange, PSRange } = chunkBy(use_year, dataList, ['quote_season', 'quote_size']);
-
- return new Table({
- borders: tableBorderNone,
- width: {
- size: 100,
- type: WidthType.PERCENTAGE,
- },
- rows: [
- new TableRow({
- children: [
- this.createTableHeader('项目', 30),
- this.createTableHeader(['平季', ...SSRange], 35, { columnSpan: sizeSets.length }),
- this.createTableHeader(['旺季', ...PSRange], 35, { columnSpan: sizeSets.length }),
- ],
- }),
- new TableRow({
- children: [
- new TableCell({ borders: tableBorderOne, verticalAlign: AlignmentType.CENTER, children: [new Paragraph({ text: '' })] }),
- ...sizeSets.map((ss) => new TableCell({ borders: tableBorderOne, verticalAlign: AlignmentType.CENTER, children: [new Paragraph({ text: ss.join('-') })] })),
- ...sizeSets.map((ss) => new TableCell({ borders: tableBorderOne, verticalAlign: AlignmentType.CENTER, children: [new Paragraph({ text: ss.join('-') })] })),
- ],
- }),
- ...dataSource.map((row, ri) => this.createDetailRowSize(sizeSets, row, ri, { withSeason: true })).reduce((a, c) => a.concat(c), []),
-
- this.createTable_Memo(1 + sizeSets.length * 2),
- ],
- });
- }
+ createTable_D(use_year, dataList) {}
createDetailRowSize(sizeSets, rowp, ii, { withSeason = false, withSize = true, infoCol = () => {}, extraCol = () => {} } = {}) {
const sizeCol = sizeSets.map((ss) => ss.join('-'));