|
|
|
@ -4,9 +4,7 @@ import {
|
|
|
|
|
Header,
|
|
|
|
|
Footer,
|
|
|
|
|
HeadingLevel,
|
|
|
|
|
Packer,
|
|
|
|
|
Paragraph,
|
|
|
|
|
TabStopPosition,
|
|
|
|
|
TabStopType,
|
|
|
|
|
Table,
|
|
|
|
|
TableCell,
|
|
|
|
@ -16,7 +14,118 @@ import {
|
|
|
|
|
NumberFormat,
|
|
|
|
|
PageNumber,
|
|
|
|
|
WidthType,
|
|
|
|
|
LevelFormat,
|
|
|
|
|
Tab,
|
|
|
|
|
PositionalTab,
|
|
|
|
|
PositionalTabAlignment,
|
|
|
|
|
PositionalTabRelativeTo,
|
|
|
|
|
PositionalTabLeader,
|
|
|
|
|
} from 'docx';
|
|
|
|
|
import dayjs from 'dayjs';
|
|
|
|
|
import { cloneDeep, groupBy, isEmpty, 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 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]
|
|
|
|
|
);
|
|
|
|
|
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: 固定车辆座次
|
|
|
|
|
|
|
|
|
|
const dataRoll = 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 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;
|
|
|
|
|
const inSet = matchRange;
|
|
|
|
|
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 };
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const chunk = dataRoll.map((rowp) => {
|
|
|
|
|
const quote_chunk = groupBy(rowp.quotation, (quoteItem) => by.map((key) => quoteItem[key]).join('@'));
|
|
|
|
|
return { ...rowp, quote_chunk };
|
|
|
|
|
});
|
|
|
|
|
const dataSource = chunk.map((rowp, ri) => {
|
|
|
|
|
const thisChunk = Object.keys(rowp.quote_chunk).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];
|
|
|
|
|
} else {
|
|
|
|
|
qc[ckeyArr[0]][ckeyArr[1]] = (qc[ckeyArr[0]][ckeyArr[1]] || []).concat(rowp.quote_chunk[ckey]);
|
|
|
|
|
}
|
|
|
|
|
return qc;
|
|
|
|
|
}, {});
|
|
|
|
|
|
|
|
|
|
return { ...rowp, quote_chunk: thisChunk };
|
|
|
|
|
});
|
|
|
|
|
const allquotation = chunk.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, dataSource, sizeSets, sizeSetsByMax);
|
|
|
|
|
return { chunk, dataSource, sizeSets: sizeSetsByMax, SSRange, PSRange };
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const DOC_TITLE = '地接合同';
|
|
|
|
|
const pageMargins = {
|
|
|
|
|
top: `15mm`,
|
|
|
|
@ -38,10 +147,18 @@ const tableBorderOne = {
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export default class AgencyContract {
|
|
|
|
|
create([data]) {
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
const document = new Document({
|
|
|
|
|
creator: 'China Highlights',
|
|
|
|
|
title: DOC_TITLE,
|
|
|
|
|
title: h1,
|
|
|
|
|
subject: '2025桂林海纳价格合同模板',
|
|
|
|
|
// description: '',
|
|
|
|
|
styles: {
|
|
|
|
|
paragraphStyles: [
|
|
|
|
|
{
|
|
|
|
@ -49,13 +166,31 @@ export default class AgencyContract {
|
|
|
|
|
name: 'Normal',
|
|
|
|
|
quickFormat: true,
|
|
|
|
|
run: {
|
|
|
|
|
size: 20,
|
|
|
|
|
size: 22,
|
|
|
|
|
font: { name: '宋体' },
|
|
|
|
|
color: '000000',
|
|
|
|
|
},
|
|
|
|
|
paragraph: {
|
|
|
|
|
spacing: {
|
|
|
|
|
after: 0,
|
|
|
|
|
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,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
@ -72,7 +207,8 @@ export default class AgencyContract {
|
|
|
|
|
},
|
|
|
|
|
paragraph: {
|
|
|
|
|
spacing: {
|
|
|
|
|
after: 120,
|
|
|
|
|
before: 200,
|
|
|
|
|
after: 200,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
@ -83,17 +219,53 @@ export default class AgencyContract {
|
|
|
|
|
next: 'Normal',
|
|
|
|
|
quickFormat: true,
|
|
|
|
|
run: {
|
|
|
|
|
size: 24,
|
|
|
|
|
size: 28,
|
|
|
|
|
font: { name: '宋体' },
|
|
|
|
|
color: '000000',
|
|
|
|
|
},
|
|
|
|
|
paragraph: {
|
|
|
|
|
spacing: {
|
|
|
|
|
before: 120,
|
|
|
|
|
// after: 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: [
|
|
|
|
@ -109,7 +281,10 @@ export default class AgencyContract {
|
|
|
|
|
},
|
|
|
|
|
headers: {
|
|
|
|
|
default: new Header({
|
|
|
|
|
children: [this.createPageHeaderText(`${new Date().toLocaleString()}系统生成`)],
|
|
|
|
|
children: [
|
|
|
|
|
this.createPageHeaderText(`Email: xeniayou@hainatravel.com`, { italics: false }),
|
|
|
|
|
this.createPageHeaderText(`https://www.chinahighlights.com`, { italics: false }),
|
|
|
|
|
],
|
|
|
|
|
}),
|
|
|
|
|
},
|
|
|
|
|
footers: {
|
|
|
|
@ -137,17 +312,47 @@ export default class AgencyContract {
|
|
|
|
|
size: 20,
|
|
|
|
|
}),
|
|
|
|
|
],
|
|
|
|
|
})
|
|
|
|
|
}),
|
|
|
|
|
],
|
|
|
|
|
}),
|
|
|
|
|
},
|
|
|
|
|
children: [
|
|
|
|
|
new Paragraph({
|
|
|
|
|
text: DOC_TITLE,
|
|
|
|
|
heading: HeadingLevel.HEADING_1,
|
|
|
|
|
alignment: 'center',
|
|
|
|
|
}),
|
|
|
|
|
this.createSubHeading(`副标题`),
|
|
|
|
|
// new Paragraph({
|
|
|
|
|
// text: h1,
|
|
|
|
|
// heading: HeadingLevel.HEADING_1,
|
|
|
|
|
// alignment: 'center',
|
|
|
|
|
// }),
|
|
|
|
|
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_J(use_year, agencyProducts['J'])]),
|
|
|
|
|
...(isEmpty(agencyProducts['Q'])
|
|
|
|
|
? []
|
|
|
|
|
: [this.createSubHeading(`导游`, { numbering: { reference: 'products-type', level: 0 } }), this.createTable_6(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)]),
|
|
|
|
|
...(isEmpty(agencyProducts['D'])
|
|
|
|
|
? []
|
|
|
|
|
: [this.createSubHeading(`包价线路`, { numbering: { reference: 'products-type', level: 0 } }), this.createTable_J(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(),
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
@ -156,21 +361,584 @@ export default class AgencyContract {
|
|
|
|
|
return document;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 综费
|
|
|
|
|
*/
|
|
|
|
|
createTable_6(use_year, dataList, style = {}) {
|
|
|
|
|
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)).reduce((a, c) => a.concat(c), []),
|
|
|
|
|
|
|
|
|
|
this.createTable_Memo(3),
|
|
|
|
|
],
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* 超公里
|
|
|
|
|
*/
|
|
|
|
|
createTable_B(use_year, dataList) {
|
|
|
|
|
const { chunk: dataSource, 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,
|
|
|
|
|
}),
|
|
|
|
|
],
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
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),
|
|
|
|
|
],
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 车费
|
|
|
|
|
*/
|
|
|
|
|
createTable_J(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('项目', 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), []),
|
|
|
|
|
|
|
|
|
|
this.createTable_Memo(1 + sizeSets.length * 2),
|
|
|
|
|
],
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* 导游
|
|
|
|
|
* @ignore
|
|
|
|
|
* @deprecated
|
|
|
|
|
*/
|
|
|
|
|
createTable_Q(use_year, dataList) {}
|
|
|
|
|
/**
|
|
|
|
|
* 景点
|
|
|
|
|
*/
|
|
|
|
|
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.adult_cost}, ${firstQ.group_size_min}-${firstQ.group_size_max}人, ${firstQ.unit_name}` +
|
|
|
|
|
// + (`, ${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.map((row, ri) => this.createDetailRowSeason2(row, ri, { 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: '' })
|
|
|
|
|
],
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
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), []),
|
|
|
|
|
|
|
|
|
|
this.createTable_Memo(1 + sizeSets.length + 1),
|
|
|
|
|
],
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* 包价线路
|
|
|
|
|
* @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),
|
|
|
|
|
],
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
createDetailRowSize(sizeSets, rowp, ii, { withSeason = false, withSize = true, infoCol = () => {}, extraCol = () => {} } = {}) {
|
|
|
|
|
const sizeCol = sizeSets.map((ss) => ss.join('-'));
|
|
|
|
|
|
|
|
|
|
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,
|
|
|
|
|
}),
|
|
|
|
|
],
|
|
|
|
|
}),
|
|
|
|
|
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.LEFT,
|
|
|
|
|
text: isEmpty(quoteItem)
|
|
|
|
|
? ''
|
|
|
|
|
: withSize
|
|
|
|
|
? `${quoteItem.adult_cost}, ${quoteItem.group_size_min}-${quoteItem.group_size_max}人,${quoteItem.unit_name}`
|
|
|
|
|
: `${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.LEFT,
|
|
|
|
|
// text: `${quoteItem.adult_cost}, ${quoteItem.group_size_min}-${quoteItem.group_size_max}${quoteItem.unit_name}`,
|
|
|
|
|
text: withSize
|
|
|
|
|
? `${quoteItem.adult_cost}, ${quoteItem.group_size_min}-${quoteItem.group_size_max}人,${quoteItem.unit_name}`
|
|
|
|
|
: `${quoteItem.adult_cost}`,
|
|
|
|
|
})
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
})
|
|
|
|
|
)
|
|
|
|
|
: []),
|
|
|
|
|
extraCol(rowp, ii),
|
|
|
|
|
],
|
|
|
|
|
}),
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
createDetailRowSeason2(rowp, ii, { 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.LEFT,
|
|
|
|
|
text: `${quoteItem.adult_cost}, ${quoteItem.group_size_min}-${quoteItem.group_size_max}人,${quoteItem.unit_name}`,
|
|
|
|
|
})
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
}),
|
|
|
|
|
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.LEFT,
|
|
|
|
|
text: `${quoteItem.adult_cost}, ${quoteItem.group_size_min}-${quoteItem.group_size_max}人,${quoteItem.unit_name}`,
|
|
|
|
|
})
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
}),
|
|
|
|
|
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,
|
|
|
|
|
// thematicBreak: true,
|
|
|
|
|
alignment: AlignmentType.CENTER,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
createTitle(text) {
|
|
|
|
|
return new Paragraph({
|
|
|
|
|
text: text,
|
|
|
|
|
heading: HeadingLevel.TITLE,
|
|
|
|
|
// thematicBreak: true,
|
|
|
|
|
alignment: AlignmentType.CENTER,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
createSubHeading(text) {
|
|
|
|
|
createSubHeading(text, style = {}) {
|
|
|
|
|
return new Paragraph({
|
|
|
|
|
text: text,
|
|
|
|
|
heading: HeadingLevel.HEADING_2,
|
|
|
|
|
heading: HeadingLevel.HEADING_1,
|
|
|
|
|
...style,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
createPageHeaderText(text) {
|
|
|
|
|
createPageHeaderText(text, style = {}) {
|
|
|
|
|
return new Paragraph({
|
|
|
|
|
alignment: AlignmentType.RIGHT,
|
|
|
|
|
children: [
|
|
|
|
@ -178,6 +946,7 @@ export default class AgencyContract {
|
|
|
|
|
text: text,
|
|
|
|
|
italics: true,
|
|
|
|
|
size: 20,
|
|
|
|
|
...style,
|
|
|
|
|
}),
|
|
|
|
|
],
|
|
|
|
|
});
|
|
|
|
|