From 9e6a2445044ef16df982dc45a61abf6d8653b373 Mon Sep 17 00:00:00 2001 From: Lei OT Date: Mon, 18 Aug 2025 15:20:15 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=BA=A7=E5=93=81=E7=AE=A1=E7=90=86:?= =?UTF-8?q?=20=E5=AF=BC=E5=87=BA=E5=90=88=E5=90=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/useProductsQuotationFormat.js | 40 +- src/views/products/Detail/Header.jsx | 7 +- src/views/products/Print/AgencyContract.jsx | 1423 +++++++------------ src/views/products/Print/AgencyPreview.jsx | 35 +- 4 files changed, 556 insertions(+), 949 deletions(-) diff --git a/src/hooks/useProductsQuotationFormat.js b/src/hooks/useProductsQuotationFormat.js index 7f395e0..9896c2e 100644 --- a/src/hooks/useProductsQuotationFormat.js +++ b/src/hooks/useProductsQuotationFormat.js @@ -2,7 +2,7 @@ import { flush, groupBy, isEmpty, isNotEmpty, pick, unique, uniqWith } from '@/u import dayjs from 'dayjs'; import { formatGroupSize } from './useProductsSets'; // Shoulder Season 平季; peak season 旺季 -const isFullYearOrLonger = (year, startDate, endDate) => { +export const isFullYearOrLonger = (year, startDate, endDate) => { // Parse the dates const start = dayjs(startDate, 'YYYY-MM-DD'); const end = dayjs(endDate, 'YYYY-MM-DD'); @@ -74,6 +74,7 @@ export const chunkBy = (use_year, dataList = [], by = []) => { return aq; }, {}); + // 补全产品旺季的人等分组 (当旺季和平季的人等不完全一致时) for (const WPI in PGroupSizeSS) { if (Object.prototype.hasOwnProperty.call(PGroupSizeSS, WPI)) { const element = PGroupSizeSS[WPI]; @@ -168,11 +169,12 @@ export const chunkBy = (use_year, dataList = [], by = []) => { const rowsByDate = groupBy(_sizeRows, qi => `${qi.use_dates_start}~${qi.use_dates_end}`); const _rowsFromDate = Object.keys(rowsByDate).reduce((accDate, dateKeys) => { const _dateRows = rowsByDate[dateKeys]; + const rowKey = _dateRows.map(e => e.id).join(','); const keepCol = pick(_dateRows[0], ['WPI_SN', 'WPP_VEI_SN', 'currency', 'unit_id', 'unit_name', 'use_dates_start', 'use_dates_end', 'weekdays', 'quote_season']); const _colFromDateRow = _dateRows.reduce((accCols, rowp) => { // const _colRow = pick(rowp, ['currency', 'unit_id', 'unit_name', 'use_dates_start', 'use_dates_end', 'weekdays', 'child_cost', 'adult_cost']); return { ...accCols, [rowp.quote_col_key]: rowp }; - }, {...keepCol, originRows: _dateRows }); + }, {...keepCol, originRows: _dateRows, rowKey }); accDate.push(_colFromDateRow); return accDate; }, []); @@ -211,7 +213,7 @@ export const chunkBy = (use_year, dataList = [], by = []) => { * 按人等拆分表格 * @use D J B R 8 */ -const splitTable_SizeSets = (chunkData) => { +export const splitTable_SizeSets = (chunkData) => { const { SSRange, PSRange, SSsizeSetKey, SSsizeSetsMap, chunk } = chunkData; const bySizeSetKey = groupBy(chunk, 'sizeSetsSS'); // next: city // agencyProducts.J. @@ -241,7 +243,7 @@ const splitTable_SizeSets = (chunkData) => { * 按季度分列 [平季, 旺季] * @use Q 7 6 */ -const splitTable_Season = (chunkData) => { +export const splitTable_Season = (chunkData) => { const { SSRange, PSRange, SSsizeSetKey, SSsizeSetsMap, chunk } = chunkData; // console.log(chunkData); const tablesQuote = chunk.map((pitem) => { @@ -256,6 +258,7 @@ const splitTable_Season = (chunkData) => { const valRow = pick(valRows[0], ['adult_cost', 'child_cost', 'currency', 'unit_id', 'unit_name', 'group_size_min', 'group_size_max']); // valRow.dates = valRows.map((v) => pick(v, ['id', 'use_dates_end', 'use_dates_start'])); valRow.rows = valRows; + valRow.rowKey = valRows.map(v => v.id).join(','); accv.push(valRow); return accv; }, []); @@ -263,22 +266,24 @@ const splitTable_Season = (chunkData) => { return { ...accp, [_s]: valUnderSeason }; }, {}); // console.log('---- rowSeason', rowSeason); - return { info: pitem.info, ...rowSeason }; + return { info: pitem.info, ...rowSeason, rowKey: pitem.info.id }; }); // console.log('---- tablesQuote', tablesQuote); return tablesQuote; }; -export const splitTable_D = (use_year, dataSource) => { +export const splitTable_D = (use_year, dataSource, retTableOnly = true) => { const chunked = chunkBy(use_year, dataSource); // console.log(chunked); - return addCityRow4Split(splitTable_SizeSets(chunked)); + const tables = addCityRow4Split(splitTable_SizeSets(chunked)); + return retTableOnly ? tables : { ...chunked, tables }; }; -export const splitTable_J = (use_year, dataSource) => { +export const splitTable_J = (use_year, dataSource, retTableOnly = true) => { const chunked = chunkBy(use_year, dataSource); // console.log(chunked); - return addCityRow4Split(splitTable_SizeSets(chunked)); + const tables = addCityRow4Split(splitTable_SizeSets(chunked)); + return retTableOnly ? tables : { ...chunked, tables }; }; export const splitTable_Q = (use_year, dataSource) => { @@ -291,10 +296,11 @@ export const splitTable_7 = (use_year, dataSource) => { return addCityRow4Season(splitTable_Season(chunked)); }; -export const splitTable_R = (use_year, dataSource) => { +export const splitTable_R = (use_year, dataSource, retTableOnly = true) => { const chunked = chunkBy(use_year, dataSource); // console.log(chunked); - return addCityRow4Split(splitTable_SizeSets(chunked)); + const tables = addCityRow4Split(splitTable_SizeSets(chunked)); + return retTableOnly ? tables : { ...chunked, tables }; }; export const splitTable_8 = (use_year, dataSource) => { @@ -303,22 +309,24 @@ export const splitTable_8 = (use_year, dataSource) => { return addCityRow4Split(splitTable_SizeSets(chunked)); }; -export const splitTable_6 = (use_year, dataSource) => { +export const splitTable_6 = (use_year, dataSource, retTableOnly = true) => { const chunked = chunkBy(use_year, dataSource, ['quote_season']); - return (splitTable_Season(chunked)); + const tables = splitTable_Season(chunked); + return retTableOnly ? tables : { ...chunked, tables }; }; -export const splitTable_B = (use_year, dataSource) => { +export const splitTable_B = (use_year, dataSource, retTableOnly = true) => { const chunked = chunkBy(use_year, dataSource); // console.log(chunked); - return addCityRow4Split(splitTable_SizeSets(chunked)); + const tables = addCityRow4Split(splitTable_SizeSets(chunked)); + return retTableOnly ? tables : { ...chunked, tables }; }; export const addCityRow4Season = (table) => { const byCity = groupBy(table, (ele) => `${ele.info.city_id}@${ele.info.city_name}`); const withCityRow = Object.keys(byCity).reduce((acc, cityIdName) => { const [cityId, cityName] = cityIdName.split('@'); - acc.push({ info: { product_title: cityName, isCityRow: true,}, use_dates_end: '', use_dates_start: '', quote_season: 'SS', rowSpan: 1 }); + acc.push({ info: { product_title: cityName, isCityRow: true,}, use_dates_end: '', use_dates_start: '', quote_season: 'SS', rowSpan: 1, rowKey: `c_${cityId}` }); return acc.concat(byCity[cityIdName]); }, []); return withCityRow; diff --git a/src/views/products/Detail/Header.jsx b/src/views/products/Detail/Header.jsx index faba56f..04c3f12 100644 --- a/src/views/products/Detail/Header.jsx +++ b/src/views/products/Detail/Header.jsx @@ -172,20 +172,23 @@ const Header = ({ refresh, ...props }) => { // await refresh(); const agencyExtras = await getAgencyAllExtrasAction(switchParams); const remarks = await getRemarkList() + const remarksMappedByType = remarks.reduce((r, v) => ({...r, [v.product_type_id]: v}), {}); const documentCreator = new AgencyContract(); const doc = documentCreator.create([ switchParams, activeAgency, agencyProducts, agencyExtras, - remarks + // remarks, + remarksMappedByType, ]); const _d = dayjs().format("YYYYMMDD_HH.mm.ss.SSS"); // Date.now().toString(32) + const _state = pickAuditState.value ? pickAuditState.label : ''; Packer.toBlob(doc).then((blob) => { saveAs( blob, - `${activeAgency.travel_agency_name}${pickYear}年地接合同-${_d}.docx` + `${activeAgency.travel_agency_name}${pickYear}年地接合同-${_state}-${_d}.docx` ); }); }; diff --git a/src/views/products/Print/AgencyContract.jsx b/src/views/products/Print/AgencyContract.jsx index aeeede0..47acadf 100644 --- a/src/views/products/Print/AgencyContract.jsx +++ b/src/views/products/Print/AgencyContract.jsx @@ -1,4 +1,4 @@ -import { flush, groupBy, isEmpty, isNotEmpty, unique, uniqWith } from '@/utils/commons' +import { isEmpty } from '@/utils/commons' import dayjs from 'dayjs' import { AlignmentType, @@ -19,193 +19,8 @@ import { TextRun, WidthType, } from 'docx' - -// 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 } - }) - - // 人等分组只取平季, 因为产品只一行 - 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 - - 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]) - aq[cq.WPI_SN] = aq[cq.WPI_SN].slice().sort((a,b) => a-b) - return aq - }, {}) - - const maxGroupSize = Math.max(...allQuotesSSS.map((q) => q.group_size_max)) - const maxSet = maxGroupSize === 1000 ? Infinity : maxGroupSize - - const _SSMinSet = uniqWith(Object.values(PGroupSizeSS), (a, b) => a.join(',') === b.join(',')) - // const uSSsizeSetArr = (_SSMinSet) - const uSSsizeSetArr = uniqueBySub(_SSMinSet) - - // * 若不重叠分组, 则上面不要 uniqueBySub - 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 - } - } - - 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 ? maxSet : Number(minsArr[idx + 1]) - 1 - acc.push([Number(curr), _max]) - return acc - }, []), - ) - return arrSets - }) - - const compactSizeSets = { - SSsizeSetKey: uSSsizeSetArr.map((s) => s.join(',')).filter(isNotEmpty), - sizeSets: SSsizeSets, - } - - const chunkSS = structuredClone(dataRollSS).map((rowp) => { - const pkey = (PGroupSizeSS[rowp.info.id] || []).join(',') || compactSizeSets.SSsizeSetKey[0] // todo: - - const thisRange = (PGroupSizeSS[rowp.info.id] || []).reduce((acc, curr, idx, minsArr) => { - const _max = idx === minsArr.length - 1 ? maxSet : 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() - - 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 || ssSets[0] - - 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, - } - }) - - 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, - } -} +import { splitTable_6, splitTable_7, splitTable_B, splitTable_D, splitTable_J, splitTable_Q, splitTable_R } from '@/hooks/useProductsQuotationFormat'; +import { formatGroupSize } from '@/hooks/useProductsSets' const DOC_TITLE = '地接合同' const pageMargins = { @@ -227,11 +42,30 @@ const tableBorderOne = { left: { style: BorderStyle.SINGLE, space: 0, size: 6, color: 'auto' }, right: { style: BorderStyle.SINGLE, space: 0, size: 6, color: 'auto' }, } +const tableBorderInner = { + top: { style: BorderStyle.NONE, space: 0, size: 6, color: 'auto' }, + bottom: { style: BorderStyle.INSET, space: 0, size: 6, color: 'auto' }, + left: { style: BorderStyle.NONE, space: 0, size: 6, color: 'auto' }, + right: { style: BorderStyle.INSET, space: 0, size: 6, color: 'auto' }, +} +const tableBorderInnerB = { + top: { style: BorderStyle.NONE, space: 0, size: 6, color: 'auto' }, + bottom: { style: BorderStyle.INSET, space: 0, size: 6, color: 'auto' }, + left: { style: BorderStyle.NONE, space: 0, size: 6, color: 'auto' }, + right: { style: BorderStyle.NONE, space: 0, size: 6, color: 'auto' }, +} +const tableBorderInnerR = { + top: { style: BorderStyle.NONE, space: 0, size: 6, color: 'auto' }, + bottom: { style: BorderStyle.NONE, space: 0, size: 6, color: 'auto' }, + left: { style: BorderStyle.NONE, space: 0, size: 6, color: 'auto' }, + right: { style: BorderStyle.INSET, space: 0, size: 6, color: 'auto' }, +} /** - * v1120 + * @version + * @date 2025-08-20 */ export default class AgencyContract { - #remarkList = [] + #remarkList = {} create([headerParams, activeAgency, agencyProducts, agencyExtras, remarks]) { this.#remarkList = remarks const { use_year } = headerParams @@ -482,10 +316,11 @@ export default class AgencyContract { * 综费 */ createTable_6(use_year, dataList, style = {}) { - const { chunk, SSRange, sizeSets } = chunkBy(use_year, dataList, ['quote_season']) + const { tables, SSRange } = splitTable_6(use_year, dataList, false); - //当前表格的备注信息 - const [remarkItem] = this.#remarkList.filter((i) => i.product_type_id == '6') + const table2Rows = tables.reduce((acc, {info, SS}) => { + return acc.concat(SS.map((v, i) => ({...v, info, rowSpan: i===0 ? SS.length : 0}))); + }, []); return new Table({ borders: tableBorderNone, @@ -498,37 +333,64 @@ export default class AgencyContract { children: [ this.createTableHeader('项目', 30), this.createTableHeader('人等', 20), - this.createTableHeader([...SSRange], 50), + this.createTableHeader([...SSRange], 50) ], }), - ...chunk.reduce((acc, row, ri) => { - return acc.concat(this.createDetailRowSizeSS(sizeSets, row, ri)) - }, []), + ...table2Rows.map( + (row, ri) => + new TableRow({ + children: [ + ...(ri === 0 + ? [ + new TableCell({ + borders: tableBorderOne, + verticalAlign: AlignmentType.CENTER, + rowSpan: row.rowSpan, + children: [ + new Paragraph({ + text: `${row?.info?.product_title}`, + alignment: AlignmentType.LEFT, + }), + ], + }), + ] + : []), + new TableCell({ + borders: tableBorderOne, + verticalAlign: AlignmentType.CENTER, + children: [ + new Paragraph({ + text: formatGroupSize(row.group_size_min, row.group_size_max, true), + alignment: AlignmentType.CENTER, + }), + ], + }), + new TableCell({ + borders: tableBorderOne, + verticalAlign: AlignmentType.CENTER, + children: [ + new Paragraph({ + text: `${row.adult_cost ?? ''}`, + alignment: AlignmentType.CENTER, + }), + ], + }), + ], + }) + ), - this.createTable_Memo(3, remarkItem.Memo.split(`\n`)), + this.createTable_Memo(3, this.#remarkList['6'].Memo.split(`\n`)), ], - }) + }); } /** * 超公里 */ createTable_B(use_year, dataList) { // console.log('*********************************************************************************************'); - const { chunk, sizeSets, SSRange, PSRange } = chunkBy(use_year, dataList, ['quote_size']) - //当前表格的备注信息 - const [remarkItem] = this.#remarkList.filter((i) => i.product_type_id == 'B') - 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 { tables, SSRange } = splitTable_B(use_year, dataList, false); + + const tableS = tables.reduce((acc, { cols, data }) => { const subTable = new Table({ borders: tableBorderNone, width: { @@ -541,7 +403,7 @@ export default class AgencyContract { this.createTableHeader('超公里项目', 20), this.createTableHeader('往返公里数', 20), this.createTableHeader([...SSRange], 60, { - columnSpan: size.length, + columnSpan: cols.length, }), ], }), @@ -557,14 +419,14 @@ export default class AgencyContract { verticalAlign: AlignmentType.CENTER, children: [new Paragraph({ text: '' })], }), - ...size.map( + ...cols.map( (ss) => new TableCell({ borders: tableBorderOne, verticalAlign: AlignmentType.CENTER, children: [ new Paragraph({ - text: ss[1] === Infinity ? `${ss[0]}人以上` : `${unique(ss.filter((x) => x)).join('-')}人`, + text: formatGroupSize(...ss, true), alignment: AlignmentType.CENTER, }), ], @@ -572,25 +434,39 @@ export default class AgencyContract { ), ], }), - ...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', + ...data.map((row, ri) => new TableRow({ + children: [ + row.info?.isCityRow ? this.createTableHeader(row.info?.product_title || '', 20) : new TableCell({ + borders: tableBorderOne, + verticalAlign: AlignmentType.CENTER, + children: [new Paragraph({ text: row.info?.product_title || '' })], + }), + new TableCell({ + borders: tableBorderOne, + verticalAlign: AlignmentType.CENTER, + children: [new Paragraph({ text: `${row.info?.km || '0'}`, alignment: AlignmentType.CENTER, })], + }), + ...cols.map( + (ss) => + new TableCell({ + borders: tableBorderOne, + verticalAlign: AlignmentType.CENTER, + children: [ + new Paragraph({ + text: `${row?.[formatGroupSize(...ss)]?.adult_cost ?? ''}`, + alignment: AlignmentType.CENTER, + }), + ], }), - ), - [], - ), + ), + ], + })), - this.createTable_Memo(2 + size.length, remarkItem.Memo.split(`\n`)), + this.createTable_Memo(2 + cols.length, this.#remarkList['B'].Memo.split(`\n`)), ], }) - acc.push(subTable) - acc.push(new Paragraph({ text: `` })) + acc.push(subTable); + acc.push(new Paragraph({ text: `` })) // 多表格之间分隔一行 return acc }, []) return tableS @@ -600,16 +476,11 @@ export default class AgencyContract { * 车费 */ createTable_J(use_year, dataList) { - const chunk_By = ['quote_size'] - const showPSCol = false - const defaultUnit = '1' - const { dataSource, sizeSets, SSRange, PSRange } = chunkBy(use_year, dataList, chunk_By) + const { tables, SSRange, PSRange, } = splitTable_J(use_year, dataList, false); + // const defaultUnit = '1' const showRangeCol = PSRange.length > 0; - //当前表格的备注信息 - const [remarkItem] = this.#remarkList.filter((i) => i.product_type_id == 'J') - const tableHeader = this.createTableHeader - const tableS = sizeSets.reduce((rt, setItem) => { + const tableS = tables.reduce((acc, { cols, data }) => { const subTable = new Table({ borders: tableBorderNone, width: { @@ -619,14 +490,9 @@ export default class AgencyContract { rows: [ new TableRow({ children: [ - tableHeader('项目', 15), - ...(showRangeCol ? [tableHeader('', 15)] : []), - tableHeader([...SSRange], 30, { columnSpan: setItem.length + 1 }), - showPSCol - ? tableHeader(['旺季', ...PSRange], 40, { - columnSpan: setItem.length, - }) - : undefined, + this.createTableHeader('项目', 20), + ...(showRangeCol ? [this.createTableHeader('', 15)] : []), + this.createTableHeader([...SSRange], 65, { columnSpan: cols.length }), ], }), //人数区间行 @@ -642,58 +508,78 @@ export default class AgencyContract { verticalAlign: AlignmentType.CENTER, children: [new Paragraph({ text: '时段', alignment: 'center' })], })]: []), - ...setItem.map((ss) => { + ...cols.map((ss) => { return new TableCell({ borders: tableBorderOne, verticalAlign: AlignmentType.CENTER, width: { size: 2000, type: WidthType.DXA }, children: [ new Paragraph({ - text: ss[1] === Infinity ? `${ss[0]}人以上` : `${unique(ss.filter((x) => x)).join('-')}人`, + text: formatGroupSize(...ss, true), alignment: AlignmentType.CENTER, }), ], }); }), - ...(showPSCol - ? setItem.map( + ], + }), + //动态生成数据行 + ...data.map( + (row, ri) => + new TableRow({ + children: [ + ...(row.rowSpan > 0 + ? [ + row.info?.isCityRow + ? this.createTableHeader(row.info?.product_title || '', 20) + : new TableCell({ + borders: tableBorderOne, + verticalAlign: AlignmentType.CENTER, + children: [new Paragraph({ text: row.info?.product_title || '' })], + rowSpan: row.rowSpan, + }), + ] + : []), + ...(showRangeCol + ? [ + new TableCell({ + borders: tableBorderOne, + verticalAlign: AlignmentType.CENTER, + children: [ + ...(row.quote_season === 'SS' + ? row.rowSpan > 1 + ? ['平季', '(除特殊时段外)'].map((str) => new Paragraph({ text: str, alignment: AlignmentType.LEFT })) + : [new Paragraph({ text: '' })] + : ['特殊时段', `${row.use_dates_start.replace(`${use_year}-`, '')}~${row.use_dates_end.replace(`${use_year}-`, '')}`].map( + (str) => new Paragraph({ text: str, alignment: AlignmentType.LEFT }) + )), + ], + }), + ] + : []), + ...cols.map( (ss) => new TableCell({ borders: tableBorderOne, - width: { size: 2000, type: WidthType.DXA }, verticalAlign: AlignmentType.CENTER, - columnSpan: sizeSets.length + 1, children: [ new Paragraph({ - text: ss[1] === Infinity ? `${ss[0]}人以上` : `${unique(ss.filter((x) => x)).join('-')}人`, + text: `${row?.[formatGroupSize(...ss)]?.adult_cost ?? ''}`, alignment: AlignmentType.CENTER, }), ], }) - ) - : []), - ], - }), - //动态生成数据行 - ...dataSource - .filter((p) => p.sizeSetsSS === setItem.map((mr) => mr[0]).join(',')) - .reduce((acc, row, ri) => { - return acc.concat( - this.createDetailRowSize_J(setItem, row, ri, { - withSize: false, - defaultUnit, - withSeason: showPSCol, - showRangeCol, - }) - ); - }, []), + ), + ], + }) + ), //备注行 - this.createTable_Memo(1 + setItem.length * 2, remarkItem.Memo.split(`\n`)), + this.createTable_Memo(1 + cols.length + (showRangeCol ? 1 : 0), this.#remarkList['J'].Memo.split(`\n`)), ], }); - rt.push(subTable) - rt.push(new Paragraph({ text: `` })) - return rt + acc.push(subTable) + acc.push(new Paragraph({ text: `` })) + return acc }, []) return tableS } @@ -702,17 +588,14 @@ export default class AgencyContract { * 包价线路 */ createTable_D(use_year, dataList) { - const chunk_By = ['quote_size'] - const showPSCol = false - const defaultUnit = '1' - const { dataSource, sizeSets, SSRange, PSRange } = chunkBy(use_year, dataList, chunk_By) - const showRangeCol = PSRange.length > 0; + const { tables, SSRange, PSRange } = splitTable_D(use_year, dataList, false); + + // console.log('DDDD', tables, SSRange, PSRange); + // const defaultUnit = '1' + const showRangeCol = PSRange.length > 0; // 显示时段列 // console.log(sizeSets, dataSource) - //当前表格的备注信息 - const [remarkItem] = this.#remarkList.filter((i) => i.product_type_id == 'D') - const tableHeader = this.createTableHeader - const tableS = sizeSets.reduce((rt, setItem) => { + const tableS = tables.reduce((acc, { cols, data }) => { const subTable = new Table({ borders: tableBorderNone, width: { @@ -722,14 +605,9 @@ export default class AgencyContract { rows: [ new TableRow({ children: [ - tableHeader('项目', 20), - ...(showRangeCol ? [tableHeader('', 15)] : []), - tableHeader([...SSRange], 40, { columnSpan: setItem.length }), - showPSCol - ? tableHeader(['旺季', ...PSRange], 40, { - columnSpan: setItem.length, - }) - : undefined, + this.createTableHeader('项目', 20), + ...(showRangeCol ? [this.createTableHeader('', 15)] : []), + this.createTableHeader([...SSRange], 65, { columnSpan: cols.length }), ], }), new TableRow({ @@ -739,64 +617,87 @@ export default class AgencyContract { verticalAlign: AlignmentType.CENTER, children: [new Paragraph({ text: '' })], }), - ...(showRangeCol ? [new TableCell({ - borders: tableBorderOne, - verticalAlign: AlignmentType.CENTER, - children: [new Paragraph({ text: '时段', alignment: 'center' })], - })]: []), - ...setItem.map( + ...(showRangeCol + ? [ + new TableCell({ + borders: tableBorderOne, + verticalAlign: AlignmentType.CENTER, + children: [new Paragraph({ text: '时段', alignment: 'center' })], + }), + ] + : []), + ...cols.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('-')}人`, + text: formatGroupSize(...ss, true), alignment: AlignmentType.CENTER, }), ], - }), + }) ), - ...(showPSCol - ? setItem.map( + ], + }), + ...data.map( + (row, ri) => + new TableRow({ + children: [ + ...(row.rowSpan > 0 + ? [ + row.info?.isCityRow + ? this.createTableHeader(row.info?.product_title || '', 20) + : new TableCell({ + borders: tableBorderOne, + verticalAlign: AlignmentType.CENTER, + children: [new Paragraph({ text: row.info?.product_title || '' })], + rowSpan: row.rowSpan, + }), + ] + : []), + ...(showRangeCol + ? [ + new TableCell({ + borders: tableBorderOne, + verticalAlign: AlignmentType.CENTER, + children: [ + ...(row.quote_season === 'SS' + ? row.rowSpan > 1 + ? ['平季', '(除特殊时段外)'].map((str) => new Paragraph({ text: str, alignment: AlignmentType.LEFT })) + : [new Paragraph({ text: '' })] + : ['特殊时段', `${row.use_dates_start.replace(`${use_year}-`, '')}~${row.use_dates_end.replace(`${use_year}-`, '')}`].map( + (str) => new Paragraph({ text: str, alignment: AlignmentType.LEFT }) + )), + ], + }), + ] + : []), + ...cols.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('-')}人`, + text: `${row?.[formatGroupSize(...ss)]?.adult_cost ?? ''}`, alignment: AlignmentType.CENTER, }), ], - }), - ) - : []), - ], - }), - ...dataSource - .filter((p) => p.sizeSetsSS === setItem.map((mr) => mr[0]).join(',')) - .reduce( - (acc, row, ri) => - acc.concat( - this.createDetailRowSize_J(setItem, row, ri, { - withSize: false, - defaultUnit, - withSeason: showPSCol, - showRangeCol, - }), - ), - [], - ), + }) + ), + ], + }) + ), + //备注行 - this.createTable_Memo(1 + setItem.length * 2, remarkItem.Memo.split(`\n`)), + this.createTable_Memo(1 + cols.length + (showRangeCol ? 1 : 0), this.#remarkList['D'].Memo.split(`\n`)), ], - }) - rt.push(subTable) - rt.push(new Paragraph({ text: `` })) - return rt + }); + acc.push(subTable) + acc.push(new Paragraph({ text: `` })) + return acc }, []) return tableS } @@ -804,9 +705,8 @@ export default class AgencyContract { * 导游 */ createTable_Q(use_year, dataList) { - const { chunk, SSRange, PSRange } = chunkBy(use_year, dataList, ['quote_season']) - //当前表格的备注信息 - const [remarkItem] = this.#remarkList.filter((i) => i.product_type_id == 'Q') + const tables = splitTable_Q(use_year, dataList, false); + // console.log('QQQ', tables); return new Table({ borders: tableBorderNone, @@ -817,87 +717,130 @@ export default class AgencyContract { rows: [ new TableRow({ children: [ - this.createTableHeader('项目', 30), - this.createTableHeader(['平季(除去旺季以外)'], 35), - this.createTableHeader(['旺季'], 35), + this.createTableHeader('项目', 40), + this.createTableHeader(['平季(除去旺季以外)'], 30), + this.createTableHeader(['旺季'], 30) ], }), - ...chunk - .map((row, ri) => this.createDetailRowSeason2(row, ri, { withSize: false })) - .reduce((a, c) => a.concat(c), []), + ...tables.map( + (row, ri) => + new TableRow({ + children: [ + row.info?.isCityRow + ? this.createTableHeader(row.info?.product_title || '', 40) + : new TableCell({ + borders: tableBorderOne, + verticalAlign: AlignmentType.CENTER, + children: [new Paragraph({ text: row.info?.product_title || '' })], + }), + new TableCell({ + borders: tableBorderOne, + verticalAlign: AlignmentType.CENTER, + children: + (row?.SS || []).length <= 1 + ? [new Paragraph({ text: `${row?.SS?.[0]?.adult_cost ?? ''}`, alignment: AlignmentType.CENTER })] + : [ + new Table({ + borders: tableBorderNone, + width: { + size: 100, + type: WidthType.PERCENTAGE, + }, + rows: (row?.SS || []).map( + (quoteItem, ii, _arr) => + new TableRow({ + borders: tableBorderInner, + children: [ + new TableCell({ + borders: ii !== _arr.length - 1 ? tableBorderInner : tableBorderInnerR, + width: { size: 1200, type: WidthType.DXA }, + verticalAlign: AlignmentType.CENTER, + children: [ + new Paragraph({ + text: `${formatGroupSize(quoteItem.group_size_min, quoteItem.group_size_max, true)}`, + alignment: AlignmentType.LEFT, + }), + ], + }), + new TableCell({ + borders: ii !== _arr.length - 1 ? tableBorderInner : tableBorderInnerR, + verticalAlign: AlignmentType.CENTER, + children: [ + new Paragraph({ + text: `${quoteItem.unit_name}`, + alignment: AlignmentType.LEFT, + }), + ], + }), + new TableCell({ + borders: ii !== _arr.length - 1 ? tableBorderInnerB : tableBorderNone, + verticalAlign: AlignmentType.CENTER, + children: [ + new Paragraph({ + text: `${quoteItem.adult_cost}`, + alignment: AlignmentType.LEFT, + }), + ], + }), + ], + }) + ), + }), + ], + }), + new TableCell({ + borders: tableBorderOne, + verticalAlign: AlignmentType.CENTER, + children: + (row?.PS || []).length === 0 + ? [new Paragraph({ text: '', alignment: AlignmentType.CENTER })] + : [ + new Table({ + borders: tableBorderNone, + width: { + size: 100, + type: WidthType.PERCENTAGE, + }, + rows: (row?.PS || []).map( + (quoteItem, ii, _arr) => + new TableRow({ + borders: tableBorderInner, + children: [ + new TableCell({ + borders: ii !== _arr.length - 1 ? tableBorderInner : tableBorderInnerR, + width: { size: 2400, type: WidthType.DXA }, + verticalAlign: AlignmentType.CENTER, + children: quoteItem.rows.map(d => new Paragraph({ alignment: AlignmentType.LEFT, text: `${d.use_dates_start.replace(`${use_year}-`, '')}~${d.use_dates_end.replace(`${use_year}-`, '')}` })), + }), + new TableCell({ + borders: ii !== _arr.length - 1 ? tableBorderInnerB : tableBorderNone, + verticalAlign: AlignmentType.CENTER, + children: [ + new Paragraph({ + text: `${quoteItem.adult_cost}`, + alignment: AlignmentType.LEFT, + }), + ], + }), + ], + }) + ), + }), + ], + }), + ], + }) + ), - this.createTable_Memo(3, remarkItem.Memo.split(`\n`)), + this.createTable_Memo(3, this.#remarkList['Q'].Memo.split(`\n`)), ], - }) + }); } /** * 景点 */ 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 [remarkItem] = this.#remarkList.filter((i) => i.product_type_id == '7') - - 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}`), - ) - - const thisE = new Paragraph({ - children: [ - new TextRun({ - text: `${extra.info.product_title}-${extra.info.product_type_name}`, - 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}` - // const sizeStr = - // [0, 1].includes(firstQ.group_size_min) && firstQ.group_size_max === 1000 - // ? '不分人等,' - // : `${firstQ.group_size_min}-${firstQ.group_size_max}人,` - // return new Paragraph({ - // children: [ - // new TextRun({ - // text: - // `${sizeStr} ${firstQ.unit_name}, ${firstQ.adult_cost}` + - // (compactBy !== 'dates' ? `, ${date1}~${date2}${otherStr}` : ''), - // }), - // ], - // }) - // }) - - // return ac.concat([thisE, ...thisP]) - return ac.concat([thisE]) - }, []), - ], - }) - } + const tables = splitTable_7(use_year, dataList, false); return new Table({ borders: tableBorderNone, @@ -914,62 +857,151 @@ export default class AgencyContract { this.createTableHeader('附加费用', 25), ], }), - ...chunk.reduce( - (acc, row, ri) => - acc.concat( - this.createDetailRowSeason2(row, ri, { - withSize: true, - defaultUnit: '0', - extraCol, - }), - ), - [], + ...tables.map( + (row, ri) => + new TableRow({ + children: [ + row.info?.isCityRow + ? this.createTableHeader(row.info?.product_title || '', 25) + : new TableCell({ + borders: tableBorderOne, + verticalAlign: AlignmentType.CENTER, + children: [new Paragraph({ text: row.info?.product_title || '' })], + }), + new TableCell({ + borders: tableBorderOne, + verticalAlign: AlignmentType.CENTER, + children: + (row?.SS || []).length === 0 + ? [new Paragraph({ text: '', alignment: AlignmentType.CENTER })] + : (row?.SS || []).length === 1 && row?.SS?.[0]?.unit_id === '0' + ? [new Paragraph({ text: `${row?.SS?.[0]?.adult_cost ?? ''}`, alignment: AlignmentType.CENTER })] + : [ + new Table({ + borders: tableBorderNone, + width: { + size: 100, + type: WidthType.PERCENTAGE, + }, + rows: (row?.SS || []).map( + (quoteItem, ii, _arr) => + new TableRow({ + borders: tableBorderInner, + children: [ + new TableCell({ + borders: ii !== _arr.length - 1 ? tableBorderInner : tableBorderInnerR, + width: { size: 1600, type: WidthType.DXA }, + verticalAlign: AlignmentType.CENTER, + children: [ + new Paragraph({ + text: `${formatGroupSize(quoteItem.group_size_min, quoteItem.group_size_max, true)}`, + alignment: AlignmentType.LEFT, + }), + ], + }), + new TableCell({ + borders: ii !== _arr.length - 1 ? tableBorderInner : tableBorderInnerR, + width: { size: 1200, type: WidthType.DXA }, + verticalAlign: AlignmentType.CENTER, + children: [ + new Paragraph({ + text: `${quoteItem.unit_name}`, + alignment: AlignmentType.LEFT, + }), + ], + }), + new TableCell({ + borders: ii !== _arr.length - 1 ? tableBorderInnerB : tableBorderNone, + width: { size: 1200, type: WidthType.DXA }, + verticalAlign: AlignmentType.CENTER, + children: [ + new Paragraph({ + text: `${quoteItem.adult_cost}`, + alignment: AlignmentType.LEFT, + }), + ], + }), + ], + }) + ), + }), + ], + }), + new TableCell({ + borders: tableBorderOne, + verticalAlign: AlignmentType.CENTER, + children: + (row?.PS || []).length === 0 + ? [new Paragraph({ text: '', alignment: AlignmentType.CENTER })] + : [ + new Table({ + borders: tableBorderNone, + width: { + size: 100, + type: WidthType.PERCENTAGE, + }, + rows: (row?.PS || []).map( + (quoteItem, ii, _arr) => + new TableRow({ + borders: tableBorderInner, + children: [ + new TableCell({ + borders: ii !== _arr.length - 1 ? tableBorderInner : tableBorderInnerR, + width: { size: 2000, type: WidthType.DXA }, + verticalAlign: AlignmentType.CENTER, + children: quoteItem.rows.map( + (d) => + new Paragraph({ + alignment: AlignmentType.LEFT, + text: `${d.use_dates_start.replace(`${use_year}-`, '')}~${d.use_dates_end.replace(`${use_year}-`, '')}`, + }) + ), + }), + new TableCell({ + borders: ii !== _arr.length - 1 ? tableBorderInnerB : tableBorderNone, + verticalAlign: AlignmentType.CENTER, + children: [ + new Paragraph({ + text: `${quoteItem.adult_cost}`, + alignment: AlignmentType.LEFT, + }), + ], + }), + ], + }) + ), + }), + ], + }), + new TableCell({ + borders: tableBorderOne, + verticalAlign: AlignmentType.LEFT, + children: (agencyExtras[row.info?.id] || []).map(extra => new Paragraph({ + children: [ + new TextRun({ + text: `${extra.info.product_title}-${extra.info.product_type_name}`, + bold: true, + }), + ], + })), + }), + ], + }) ), + //备注行 - this.createTable_Memo(1 + sizeSets.length * 2 + 1, remarkItem.Memo.split(`\n`)), + this.createTable_Memo(1 + 2 + 1, this.#remarkList['7'].Memo.split(`\n`)), ], - }) + }); } /** * 餐费 */ 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 [remarkItem] = this.#remarkList.filter((i) => i.product_type_id == 'R') - 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 { tables, SSRange, PSRange } = splitTable_R(use_year, dataList, false); + // console.log('RRRRRR', tables); + const tableS = tables.reduce((acc, { cols, data }) => { const subTable = new Table({ borders: tableBorderNone, width: { @@ -981,7 +1013,7 @@ export default class AgencyContract { children: [ this.createTableHeader('社会餐厅午餐/晚餐', 25), this.createTableHeader([...SSRange, ...PSRange], 50, { - columnSpan: size.length, + columnSpan: cols.length, }), this.createTableHeader('司陪餐补(元/团/餐)', 25), ], @@ -993,14 +1025,14 @@ export default class AgencyContract { verticalAlign: AlignmentType.CENTER, children: [new Paragraph({ text: '' })], }), - ...size.map( + ...cols.map( (ss) => new TableCell({ borders: tableBorderOne, verticalAlign: AlignmentType.CENTER, children: [ new Paragraph({ - text: ss[1] === Infinity ? `${ss[0]}人以上` : `${unique(ss.filter((x) => x)).join('-')}人`, + text: formatGroupSize(...ss, true), alignment: AlignmentType.CENTER, }), ], @@ -1008,7 +1040,7 @@ export default class AgencyContract { ), new TableCell({ borders: tableBorderOne, - rowSpan: thisChunk.length + 1, + rowSpan: data.length + 1, children: [ new Paragraph({ alignment: AlignmentType.CENTER, @@ -1018,483 +1050,38 @@ export default class AgencyContract { }), ], }), - ...thisChunk.reduce( - (acc, row, ri) => acc.concat(this.createDetailRowSize(size, row, ri, { withSize: false })), - [], - ), - - this.createTable_Memo(1 + size.length + 1, remarkItem.Memo.split(`\n`)), - ], - }) - acc.push(subTable) - acc.push(new Paragraph({ text: `` })) - return acc - }, []) - return tableS - } - - 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 } - }, {}) - - const data = thisSizeCol.map((sizeRow, ri) => { - return new TableRow({ - children: flush([ - ...(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, + ...data.map((row, ri) => new TableRow({ children: [ - new Paragraph({ - text: `${quote_chunk?.[sizeRow.join('-')] || ''}`, - alignment: AlignmentType.CENTER, - }), - ], - }), - extraCol(rowp, ii), - ]), - }) - }) - return data - } - - createDetailRowSize_J( - sizeSets, - rowp, - ii, - { withSeason = false, withSize = true, showRangeCol=true, infoCol = () => {}, extraCol = () => {}, defaultUnit = '0' } = {}, - ) { - const sizeCol = sizeSets.map((ss) => ss.join('-')) - - const ranges = rowp['quotation'].map((i) => - Object.assign(i, { - range: ((quote_season) => { - const range = `${dayjs(i.use_dates_start).format('M-D').replace(/-/gi, '.')}-${dayjs(i.use_dates_end) - .format('M-D') - .replace(/-/gi, '.')}` - if (quote_season == 'SS') return `平季(除特殊时段以外)` - else return `特殊时段(${range})` - })(i.quote_season), - }), - ) - - //每个项目(产品)有多少个行(不同的时间段) - const product_rows = [...new Map(ranges.map((item) => [item.range, item])).values()] - - const rows = product_rows.reduce((acc, i) => { - const row = [] - sizeCol.forEach((j) => { - const target = rowp['quotation'] - .filter( - (item) => - item.use_dates_start == i.use_dates_start && - item.use_dates_end == i.use_dates_end && - item.quote_size == j, - ) - .pop() - if (target) row.push(target) - else row.push(``) - }) - - return Object.assign(acc, { [i.range]: row }) - }, {}) - - return [ - ...Object.entries(rows).map(([rangeStr, arr], index) => { - return new TableRow({ - children: flush([ - //合并相同项目的第一列 - ...(index == 0 - ? [ - new TableCell({ - rowSpan: index == 0 ? Object.values(rows).length : 0, - borders: tableBorderOne, - verticalAlign: AlignmentType.CENTER, - children: [ - new Paragraph({ - text: index == 0 ? `${rowp?.info?.product_title}` : '', - alignment: AlignmentType.LEFT, - }), - ], - }), - ] - : []), - ...(showRangeCol ? [new TableCell({ - borders: tableBorderOne, - verticalAlign: AlignmentType.CENTER, - children: [ - new Paragraph({ - text: Object.values(rows).length > 1 ? rangeStr : '', - alignment: AlignmentType.CENTER, - }), - ], - })] : []), - infoCol(rowp), - ...arr.map((quoteItem) => { - return new TableCell({ + row.info?.isCityRow ? this.createTableHeader(row.info?.product_title || '', 25) : new TableCell({ borders: tableBorderOne, - width: { size: 2000, type: WidthType.DXA }, verticalAlign: AlignmentType.CENTER, - children: [ - 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}`, - }), - ], - }) - }), - ...(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), - ]), - }) - }), - ] - } - - createDetailRowSize_D( - sizeSets, - rowp, - ii, - { withSeason = false, withSize = true, infoCol = () => {}, extraCol = () => {}, defaultUnit = '0' } = {}, - ) { - const sizeCol = sizeSets.map((ss) => ss.join('-')) - - const ranges = rowp['quotation'].map((i) => - Object.assign(i, { - range: ((quote_season) => { - const range = `${dayjs(i.use_dates_start).format('M-D').replace(/-/gi, '.')}-${dayjs(i.use_dates_end) - .format('M-D') - .replace(/-/gi, '.')}` - if (quote_season == 'SS') return `平季(除特殊时段以外)` - else return `特殊时段(${range})` - })(i.quote_season), - }), - ) - - //每个项目(产品)有多少个行(不同的时间段) - const product_rows = [...new Map(ranges.map((item) => [item.range, item])).values()] - - //默认时间 全年 - const firstDayOfYear = dayjs().startOf('year').format('YYYY-MM-DD') - const lastDayOfYear = dayjs().endOf('year').format('YYYY-MM-DD') - - return [ - new TableRow({ - children: flush([ - new TableCell({ - borders: tableBorderOne, - verticalAlign: AlignmentType.CENTER, - children: [ - new Paragraph({ - text: `${rowp?.info?.product_title}`, - alignment: AlignmentType.LEFT, + children: [new Paragraph({ text: row.info?.product_title || '' })], }), - ], - }), - infoCol(rowp), - ...sizeCol.map((ss) => { - const subItems = (withSeason ? rowp.quote_chunk?.['SS']?.[ss] : rowp.quote_chunk[ss]) || [] - return new TableCell({ - borders: tableBorderOne, - width: { size: 2000, type: WidthType.DXA }, - verticalAlign: AlignmentType.CENTER, - children: [ - ...subItems.reduce((acc, quoteItem, index) => { - const start = dayjs(quoteItem.use_dates_start).format('M-D').replace('-', '.') - const end = dayjs(quoteItem.use_dates_end).format('M-D').replace('-', '.') - const year = dayjs(quoteItem.use_dates_start).year() - return acc.concat( - ...[ - 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}`, - }), - ...( !isFullYearOrLonger(year, quoteItem.use_dates_start, quoteItem.use_dates_end) - ? [ - new Paragraph({ - alignment: AlignmentType.CENTER, - text: `(${start}-${end})`, - }), - ] - : []), - ], - ) - }, []), - ], - }) - }), - ...(withSeason - ? sizeCol.map( + ...cols.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: - 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), - ]), - }), - ] - } - - 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, - verticalAlign: AlignmentType.CENTER, - children: [ - new Paragraph({ - text: `${rowp?.info?.product_title}`, - alignment: AlignmentType.LEFT, - }), - ], - }), - infoCol(rowp), - ...sizeCol.map((ss) => { - return 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}`, - }), - ), - ], - }) - }), - ...(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}`, - }), - ), + new Paragraph({ + text: `${row?.[formatGroupSize(...ss)]?.adult_cost ?? ''}`, + alignment: AlignmentType.CENTER, + }), ], }), - ) - : []), - extraCol(rowp, ii), - ]), - }), - ] - } - - createDetailRowSeason2(rowp, ii, { withSize = true, defaultUnit = '0', extraCol = () => {} } = {}) { - // console.log(rowp); - return [ - new TableRow({ - children: [ - //标题列 - new TableCell({ - borders: tableBorderOne, - verticalAlign: AlignmentType.CENTER, - children: [ - new Paragraph({ - text: `${rowp?.info?.product_title}`, - alignment: AlignmentType.LEFT, - }), - ], - }), - //SS - new TableCell({ - borders: tableBorderOne, - width: { size: 2000, type: WidthType.DXA }, - verticalAlign: AlignmentType.CENTER, - children: [ - ...(rowp.quote_chunk['SS'] || []).map( - (quoteItem, ii, _arr) => - new Paragraph({ - alignment: AlignmentType.CENTER, - text: - (withSize && (String(quoteItem.unit_id) !== defaultUnit || _arr.length > 1) - ? `${quoteItem.group_size_min}-${quoteItem.group_size_max}人,${quoteItem.unit_name},` - : '') + `${quoteItem.adult_cost}`, - }), ), ], - }), - //PS - new TableCell({ - borders: tableBorderOne, - width: { size: 2000, type: WidthType.DXA }, - verticalAlign: AlignmentType.CENTER, - children: [ - //一个立即执行函数 - ...(() => { - //存储价格的数组 - const helper = [] - //PS 是所有旺季的数据 - const PS = rowp.quote_chunk['PS'] || [] - //第一次迭代获取所有价格和时间区间的数组 - const AllDatas = PS.reduce((acc, quoteItem, ii) => { - //价格文本 - const text = - (withSize && String(quoteItem.unit_id) === defaultUnit - ? `${quoteItem.group_size_min}-${quoteItem.group_size_max}人,${quoteItem.unit_name},` - : '') + `${quoteItem.adult_cost}` - - //计算开始日期和结束日期 - const start = dayjs(quoteItem.use_dates_start).format('M-D').replace('-', '.') - const end = dayjs(quoteItem.use_dates_end).format('M-D').replace('-', '.') - //添加到数组的元素 - // const group = { ...quoteItem, text, range:start_year == end_year ? `${start}-${end}; ` : `${start_year}.${start}-${end_year}.${end}; ` } - const group = { ...quoteItem, text, range: `${start}-${end}; ` } - acc.push(group) - return acc - }, []) - - //第二次迭代对重复价格的元素进行时间区间字符串拼接 - const data = AllDatas.reduce((acc, obj) => { - const { text } = obj - //判断数组中是否已经有当前价格的元素 - if (acc.some((i) => i.text == text)) { - acc = acc.map((j) => { - //如果数组中已存在当前价格的元素,合并他们的时间区间字符串 - if (j.text == text) return { text, range: j.range + obj.range } - else return j - }) - } else acc.push(obj) - - return acc - }, []) - - for (let index = 0; index < data.length; index++) { - const element = data[index] - //添加价格 - helper.push( - new Paragraph({ - alignment: AlignmentType.CENTER, - text: element.text, - }), - ) - //添加时间 - helper.push( - new Paragraph({ - alignment: AlignmentType.CENTER, - text: `(${element.range})`, - }), - ) - } + })), - return helper - })(), - ], - }), - extraCol(rowp, ii), + this.createTable_Memo(1 + cols.length + 1, this.#remarkList['R'].Memo.split(`\n`)), ], - }), - ] + }) + acc.push(subTable) + acc.push(new Paragraph({ text: `` })) + return acc + }, []) + + return tableS } createTable_Memo(columnSpan, remarkContent = []) { diff --git a/src/views/products/Print/AgencyPreview.jsx b/src/views/products/Print/AgencyPreview.jsx index 74ad1ea..993e75c 100644 --- a/src/views/products/Print/AgencyPreview.jsx +++ b/src/views/products/Print/AgencyPreview.jsx @@ -57,10 +57,11 @@ const AgencyPreview = ({ params, ...props }) => { if (!('6' in agencyProducts)) { return null; } - const tablesQuote = splitTable_6(use_year, agencyProducts['6']); - const table2Rows = tablesQuote.reduce((acc, {info, SS}) => { + const {tables, SSRange} = splitTable_6(use_year, agencyProducts['6'], false); + const table2Rows = tables.reduce((acc, {info, SS}) => { return acc.concat(SS.map((v, i) => ({...v, info, rowSpan: i===0 ? SS.length : 0}))); }, []); + // console.log('tablesQuote', tablesQuote) // console.log('table2Rows', table2Rows) return ( <> @@ -68,7 +69,8 @@ const AgencyPreview = ({ params, ...props }) => { bordered striped sticky={{ offsetHeader: -24 }} - key={'ti'} + key={'ti6'} + rowKey={'rowKey'} dataSource={table2Rows} size={'small'} pagination={false} @@ -92,7 +94,7 @@ const AgencyPreview = ({ params, ...props }) => { render: (_, r) =>
{formatGroupSize(r.group_size_min, r.group_size_max, true)}
, }, { - title: '-', + title: <>{SSRange.map(v =>
{v}
)}, dataIndex: 'SS', key: 'SS', width: '9rem', @@ -121,7 +123,8 @@ const AgencyPreview = ({ params, ...props }) => { bordered striped sticky={{ offsetHeader: -24 }} - key={ti} + key={colsKey} + rowKey={'rowKey'} rowClassName={cityRowHighlights} columns={[ { @@ -190,6 +193,7 @@ const AgencyPreview = ({ params, ...props }) => { return null; } const tablesQuote = splitTable_J(use_year, agencyProducts.J); + // console.log(tablesQuote) return ( <> {tablesQuote.map(({ cols, colsKey, data }, ti) => ( @@ -197,7 +201,8 @@ const AgencyPreview = ({ params, ...props }) => { bordered striped sticky={{ offsetHeader: -24 }} - key={ti} + key={colsKey} + rowKey={'rowKey'} rowClassName={cityRowHighlights} columns={[ { @@ -218,11 +223,11 @@ const AgencyPreview = ({ params, ...props }) => { fixed: 'left', render: (_, { quote_season, use_dates_start, use_dates_end, rowSpan }) => quote_season === 'SS' ? (rowSpan > 1 ? ( -
+
平季
(除特殊时段外)
) : '') : ( -
+
特殊时段
{use_dates_start.replace(`${use_year}-`, '')}~{use_dates_end.replace(`${use_year}-`, '')} @@ -230,8 +235,6 @@ const AgencyPreview = ({ params, ...props }) => {
), }, - // { title: '时段', dataIndex: 'dateText', key: 'dateText', width: '9rem', render: (_, { quote_season, use_dates_start, use_dates_end}) => quote_season === 'SS' ? (
平季
(除特殊时段外)
) : (
特殊时段
{use_dates_start.replace(`${use_year}-`, '')}~{use_dates_end.replace(`${use_year}-`, '')}
)}, - // `特殊时段\n${use_dates_start.replace(`${use_year}-`, '')}~${use_dates_end.replace(`${use_year}-`, '')}` }, ...cols.map((col) => ({ title: formatGroupSize(...col), // dataIndex: [formatGroupSize(...col), 'adult_cost'], @@ -259,6 +262,7 @@ const AgencyPreview = ({ params, ...props }) => { return null; } const tablesQuote = splitTable_D(use_year, agencyProducts.D); + // console.log(tablesQuote) return ( <> {tablesQuote.map(({ cols, colsKey, data }, ti) => ( @@ -266,7 +270,8 @@ const AgencyPreview = ({ params, ...props }) => { bordered striped sticky={{ offsetHeader: -24 }} - key={ti} + key={colsKey} + rowKey={'rowKey'} rowClassName={cityRowHighlights} columns={[ { @@ -334,6 +339,7 @@ const AgencyPreview = ({ params, ...props }) => { striped sticky={{ offsetHeader: -24 }} key={'ti'} + rowKey={'rowKey'} dataSource={tablesQuote} size={'small'} pagination={false} @@ -483,6 +489,7 @@ const AgencyPreview = ({ params, ...props }) => { striped sticky={{ offsetHeader: -24 }} key={'ti'} + rowKey={'rowKey'} dataSource={tablesQuote} size={'small'} pagination={false} @@ -592,7 +599,8 @@ const AgencyPreview = ({ params, ...props }) => { bordered striped sticky={{ offsetHeader: -24 }} - key={ti} + key={colsKey} + rowKey={'rowKey'} rowClassName={cityRowHighlights} columns={[ { @@ -664,7 +672,8 @@ const AgencyPreview = ({ params, ...props }) => { bordered striped sticky={{ offsetHeader: -24 }} - key={ti} + key={colsKey} + rowKey={'rowKey'} rowClassName={cityRowHighlights} columns={[ {