@agile-team/mach-report 2.8.3 → 2.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -10
- package/dist/ExcelBindingWizard-DiaxvWpQ.cjs +1 -0
- package/dist/ExcelBindingWizard-RLJIXKKG.js +816 -0
- package/dist/{ReportPreview-DRBAUkxj.js → ReportPreview-B5ZNEasW.js} +23 -22
- package/dist/ReportPreview-DRtVPUYo.cjs +6 -0
- package/dist/RuleEditor-N4qnMZ-Z.cjs +1 -0
- package/dist/RuleEditor-ynnUEK0s.js +1575 -0
- package/dist/TemplateReviewPanel-C_Lmzis6.cjs +1 -0
- package/dist/TemplateReviewPanel-Cn32OY4_.js +173 -0
- package/dist/{_plugin-vue_export-helper-DPbiz14D.js → _plugin-vue_export-helper-8SL1F89S.js} +2 -2
- package/dist/analytics.cjs +1 -1
- package/dist/analytics.d.cts +188 -5
- package/dist/analytics.d.ts +188 -5
- package/dist/analytics.js +68 -202
- package/dist/{assets-B9qJku3V.js → assets-DDsfEi8R.js} +3 -3
- package/dist/{assets-RZan7EyL.cjs → assets-ahTRUXRk.cjs} +1 -1
- package/dist/binding-preview-B5834rml.cjs +2 -0
- package/dist/binding-preview-ChXjN5L5.js +649 -0
- package/dist/{capabilities-joSutDF8.js → capabilities-Cm9hZ3uV.js} +5 -5
- package/dist/{capabilities-xGTpnPjJ.cjs → capabilities-DYzWL7KS.cjs} +1 -1
- package/dist/dataset-BkRmwgeJ.cjs +1 -0
- package/dist/dataset-H5pFuQGU.js +121 -0
- package/dist/defaults-DXhiM1ZD.js +10 -0
- package/dist/defaults-xhmcLLrf.cjs +1 -0
- package/dist/designer.cjs +2 -1
- package/dist/designer.d.cts +1391 -6
- package/dist/designer.d.ts +1391 -6
- package/dist/designer.js +2636 -673
- package/dist/grid-geometry-BNptEcMm.js +65 -0
- package/dist/grid-geometry-CZ_cYB6O.cjs +1 -0
- package/dist/import-template-CNMLJSQw.js +23030 -0
- package/dist/import-template-CpxunKVp.cjs +29 -0
- package/dist/index.cjs +7 -7
- package/dist/index.d.cts +202 -3
- package/dist/index.d.ts +202 -3
- package/dist/index.js +554 -535
- package/dist/matrix-CNPDJxED.js +745 -0
- package/dist/matrix-Div9Ilh3.cjs +1 -0
- package/dist/pdf.cjs +46 -46
- package/dist/pdf.d.cts +2 -0
- package/dist/pdf.d.ts +2 -0
- package/dist/pdf.js +17 -16
- package/dist/{plugin-BurDDMcd.js → plugin-BWwIgZXV.js} +1 -1
- package/dist/{plugin-DSFu51Ua.cjs → plugin-Dg-J1Rbm.cjs} +1 -1
- package/dist/progress-7OSZbFok.js +39 -0
- package/dist/progress-BnLiS5eH.cjs +1 -0
- package/dist/render-plan-7xpGrCEl.cjs +1 -0
- package/dist/render-plan-Ck6koX9L.js +13 -0
- package/dist/server/node.d.cts +62 -0
- package/dist/server/node.d.ts +62 -0
- package/dist/server-node.cjs +1 -1
- package/dist/server-node.js +373 -145
- package/dist/server.cjs +1 -1
- package/dist/server.d.cts +311 -0
- package/dist/server.d.ts +311 -0
- package/dist/server.js +590 -186
- package/dist/{style-Dv5o_x6b.js → style-CQ1PK8ZB.js} +5 -5
- package/dist/style-UgIJSA1F.cjs +1 -0
- package/dist/style.css +1 -1
- package/dist/template-registry-CHMYZ7SD.cjs +1 -0
- package/dist/template-registry-R61AMCr0.js +433 -0
- package/dist/template-review-hvWWQFsi.js +1027 -0
- package/dist/template-review-jEcOfmGr.cjs +1 -0
- package/dist/textwrap-CWHyzkBH.cjs +4 -0
- package/dist/{textwrap-DOl04hCQ.js → textwrap-DE1kgcJB.js} +1 -1
- package/dist/{validate-DfHPD8wX.cjs → validate-BDiMqkJC.cjs} +1 -1
- package/dist/{validate-S6CgIm5d.js → validate-DWPF7icl.js} +13 -13
- package/dist/vue/async.d.cts +186 -0
- package/dist/vue/async.d.ts +186 -0
- package/dist/vue/index.d.cts +271 -3
- package/dist/vue/index.d.ts +271 -3
- package/dist/vue-async.cjs +1 -1
- package/dist/vue-async.js +3 -3
- package/dist/vue.cjs +1 -1
- package/dist/vue.js +4 -4
- package/dist/worker.cjs +1 -1
- package/dist/worker.d.cts +2 -0
- package/dist/worker.d.ts +2 -0
- package/dist/worker.js +1 -1
- package/dist/xlsx.cjs +2 -30
- package/dist/xlsx.d.cts +268 -0
- package/dist/xlsx.d.ts +268 -0
- package/dist/xlsx.js +220 -23440
- package/package.json +1 -1
- package/dist/ReportPreview-DjGeWHY-.cjs +0 -6
- package/dist/progress-DD964VAB.js +0 -102
- package/dist/progress-KvhwXZ1Q.cjs +0 -1
- package/dist/render-plan-CckPEQyf.cjs +0 -1
- package/dist/render-plan-uzZYYSy1.js +0 -19
- package/dist/report-source-BXHNy_AD.js +0 -755
- package/dist/report-source-CCAvFE3t.cjs +0 -1
- package/dist/style-CpwiOPyB.cjs +0 -1
- package/dist/template-registry-DWExx0gU.cjs +0 -1
- package/dist/template-registry-NpOakidD.js +0 -354
- package/dist/textwrap-CnGsEum6.cjs +0 -4
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";const F=require("./dataset-BkRmwgeJ.cjs"),S=require("./template-registry-CHMYZ7SD.cjs"),A=require("./grid-geometry-CZ_cYB6O.cjs");function x(e){let t="";for(let o=e;o>0;o=Math.floor((o-1)/26))t=String.fromCharCode(65+(o-1)%26)+t;return t}function v(e){return`${x(e.left)}${e.top}:${x(e.right)}${e.bottom}`}function O(e){let t=0;for(const o of e.toUpperCase())t=t*26+o.charCodeAt(0)-64;return t}function u(e){if(typeof e!="string")throw new Error("Excel 范围应为 A1:B20 格式的字符串");const t=/^\$?([A-Z]{1,3})\$?([1-9]\d{0,6})(?::\$?([A-Z]{1,3})\$?([1-9]\d{0,6}))?$/i.exec(e.trim());if(!t)throw new Error(`Excel 范围无效:${e}`);const o={left:O(t[1]),top:Number(t[2]),right:O(t[3]??t[1]),bottom:Number(t[4]??t[2])};if(o.right<o.left||o.bottom<o.top||o.right>16384||o.bottom>1048576)throw new Error(`Excel 范围超出边界或顺序无效:${e}`);return o}function _(e,t){if(t!==void 0)return u(t);const o=e.model.rows??[];if(!o.length)return{top:1,left:1,bottom:1,right:1};const n={top:1/0,left:1/0,bottom:1,right:1};for(const r of o)n.top=Math.min(n.top,r.number),n.bottom=Math.max(n.bottom,r.number),n.left=Math.min(n.left,r.min||1),n.right=Math.max(n.right,r.max||1);return n}function W(e,t,o){const n=e.bottom-e.top+1,r=e.right-e.left+1;if(n>t.limits.maxRows||r>t.limits.maxColumns||n*r>o)throw new Error(`Excel 范围 ${v(e)} 超过导入行、列或单元格上限;请用 sheets/range 缩小范围`);return n*r}function Y(e,t){return e.top<=t.bottom&&e.bottom>=t.top&&e.left<=t.right&&e.right>=t.left}function q(e,t){const o=[];for(const n of e.model.merges){const r=u(n);if(Y(t,r)){if(r.left<t.left||r.right>t.right||r.top<t.top||r.bottom>t.bottom)throw new Error(`${e.name}: 范围 ${v(t)} 截断合并单元格 ${n},请包含完整合并区域`);o.push(r)}}return o}function Z(e,t){const o=new Map;for(const r of t)o.set(r.top,Math.max(o.get(r.top)??r.top,r.bottom));const n=[];for(let r=e.top;r<=e.bottom;){let s=o.get(r)??r;for(let i=r;i<=s;i++)s=Math.max(s,o.get(i)??i);n.push({top:r,bottom:s}),r=s+1}return n}function z(e,t,o,n){const r=[];let s,i=0;for(const a of e){const l=a.bottom-a.top+1;if(l>200)throw new Error("合并单元格跨越超过 200 行,无法安全分段;请先缩小或拆分该合并区域");let c=0;for(let d=a.top;d<=a.bottom;d++)c+=n(d);if(c>o&&Number.isFinite(o))throw new Error("合并区域或单行高度超过标准纸张可用高度;请使用 wide 或调整原模板行高");const m=s?a.bottom-s.top+1:l;s&&(m>t||i+c>o)&&(r.push(s),s=void 0,i=0),s?s.bottom=a.bottom:s={...a},i+=c}return s&&r.push(s),r}function U(e){const t=new Map,o=new Set;for(const n of e){t.set(`${n.top}:${n.left}`,n);for(let r=n.top;r<=n.bottom;r++)for(let s=n.left;s<=n.right;s++)(r!==n.top||s!==n.left)&&o.add(`${r}:${s}`)}return{masters:t,covered:o}}function $(e){return JSON.parse(JSON.stringify(e))}function V(e,t){const o=e.template.pages.slice(t.pageStart,t.pageStart+t.pageCount),n=o[0];if(!n)throw new Error(`工作表 ${t.name} 没有可绑定页面`);const r=new Map;let s=[];for(const i of o)for(const a of i.components){if(a.kind==="list"||!a.grid||a.meta?.xlsxSheet!==t.name)continue;const l=u(String(a.meta.xlsxRange)),c=a.grid;s=c.colWidthsMm??[],c.cells.forEach((m,d)=>r.set(l.top+d,{cells:$(m),height:c.rowHeightsMm?.[d]??6}))}if(!s.length||!r.size)throw new Error(`工作表 ${t.name} 缺少导入几何元数据`);return{rows:r,widths:[...s],page:n,range:u(t.range)}}function C(e,t,o){const n=[],r=[];for(let s=t;s<=o;s++){const i=e.rows.get(s);if(!i)throw new Error(`导入模板缺少第 ${s} 行`);for(const a of i.cells)if(a&&s+(a.rowSpan??1)-1>o)throw new Error(`第 ${s} 行合并区域跨越绑定边界,请调整 header/detail 范围`);n.push($(i.cells)),r.push(i.height)}return{cells:n,rowHeightsMm:r,colWidthsMm:e.widths,paddingMm:.25}}function Q(e,t){const o=u(e.header),n=e.detail?u(e.detail):{...t.range,top:o.bottom+1};for(const r of[o,n])if(r.left!==t.range.left||r.right!==t.range.right||r.top<t.range.top||r.bottom>t.range.bottom||r.top>r.bottom)throw new Error("绑定区域必须位于导入选区内并覆盖其完整列宽");if(n.top!==o.bottom+1)throw new Error("detail 应紧接 header,避免静态内容被隐式删除");if(e.columns.length!==t.widths.length)throw new Error("columns 应逐列映射整个选区;不能自动猜测业务字段");return X(t,[o.top,o.bottom+1,n.bottom+1]),{header:o,detail:n}}function X(e,t){for(const[o,n]of e.rows)for(const r of n.cells){const s=o+(r?.rowSpan??1);if(t.some(i=>o<i&&s>i))throw new Error(`第 ${o} 行合并区域跨越绑定边界,请调整 header/detail 范围`)}}function ee(e,t){const o=[];for(const n of A.resolveGridLayout(e,t.reduce((r,s)=>r+s,0),100).cells)for(let r=n.ci;r<Math.min(t.length,n.ci+(n.cell.colSpan??1));r++)o[r]=n.cell;return o}function te(e,t,o,n){if(t)return t;const r=e?.numberFormat;if(!r||r==="General")return;const s=/^(#,##)?0(?:\.(0+))?(%)?$/.exec(r);if(s){const i=s[2]?.length??0;if(i<=100)return s[3]?{kind:"percent",digits:i}:{kind:"number",digits:i,...s[1]?{thousands:!0}:{}}}n.push(`${o}: Excel 数字格式 ${r} 未自动套用到动态数据,请在 columns 中显式声明 format`)}function oe(e,t,o,n,r){const s=ee(t,n),i=A.resolveGridLayout(o,n.reduce((m,d)=>m+d,0),20).cells;if(i.some(({cell:m})=>(m.colSpan??1)!==1||(m.rowSpan??1)!==1))throw new Error("动态明细样例行不能包含合并格;合并表头可以保留");const a=new Map(i.map(m=>[m.ci,m.cell])),l=new Set,c=e.columns.map((m,d)=>{const f=typeof m=="string"?{field:m}:m;if(!f||typeof f.field!="string"||!f.field.trim()||l.has(f.field))throw new Error(`columns[${d}] 需要唯一的非空 field`);l.add(f.field);const g=s[d]?.text??f.field,h=a.get(d),w=e.inferSampleFormats===!1?f.format:te(h,f.format,f.field,r);return{...f,...w?{format:w}:{},header:f.header??g,widthMm:n[d],style:{...h?.style,...f.style},...f.semanticRole&&!f.align?{align:"auto"}:{},...f.editable===void 0&&h?.editable===!1?{editable:!1}:{}}});return re(e,s,c),c}function re(e,t,o){const n=new Map;e.columns.forEach((r,s)=>{const i=t[s];if(!i||typeof r=="string")return;const a=n.get(i)??{style:{}};if(r.header!==void 0){if(a.text!==void 0&&a.text!==r.header)throw new Error("同一合并表头不能配置不同 header");a.text=r.header}ne(a.style,{...r.headerAlign?{align:r.headerAlign}:{},...r.headerStyle}),n.set(i,a)});for(const[r,s]of n)s.text!==void 0&&Object.assign(r,{text:s.text,rawText:s.text,value:s.text}),r.style={...r.style,...s.style},t.forEach((i,a)=>{i===r&&(s.text!==void 0&&(o[a].header=s.text),s.style.align!==void 0&&(o[a].headerAlign=s.style.align))})}function ne(e,t){for(const o of Object.keys(t))if(t[o]!==void 0){if(e[o]!==void 0&&e[o]!==t[o])throw new Error(`同一合并表头不能配置不同 ${o}`);Object.assign(e,{[o]:t[o]})}}function se(e,t){const o=e.page,n=t.rowHeightsMm.reduce((r,s)=>r+s,0);return{...o,heightMm:Math.max(o.heightMm,n+(o.marginTopMm??0)+(o.marginBottomMm??0)),components:[{kind:"rect",leftMm:o.marginLeftMm??0,topMm:o.marginTopMm??0,widthMm:e.widths.reduce((r,s)=>r+s,0),heightMm:n,grid:t}]}}function ae(e,t,o,n){const r=V(e,t),{header:s,detail:i}=Q(o,r),a=C(r,r.range.top,s.bottom),l=C(r,i.top,i.top),c={...r.page,components:[]},m={kind:"list",id:`bound:${t.name}`,dataset:o.dataset??"detail",title:t.name,leftMm:c.marginLeftMm??0,topMm:c.marginTopMm??0,widthMm:r.widths.reduce((d,f)=>d+f,0),layout:c.layout??"page",headerGrid:a,columns:oe(o,a,l,r.widths,n),rowHeightMm:l.rowHeightsMm[0],headerEveryPage:!0,align:"auto",paddingMm:.25,...o.rowKey?{rowKey:o.rowKey}:{},...o.revisionField?{revisionField:o.revisionField}:{},...o.sourceTokenField?{sourceTokenField:o.sourceTokenField}:{},...o.groupBy?{groupBy:o.groupBy}:{},...o.grandTotal===void 0?{}:{grandTotal:o.grandTotal}};return c.components.push(m),i.bottom===r.range.bottom?[c]:(n.push(`${t.name}: 明细区域后的静态内容保留为后续独立页面,不推断动态页脚定位`),[c,se(r,C(r,i.bottom+1,r.range.bottom))])}function j(e,t){const o=S.validateReportTemplate(e.template);if(!o.ok)throw new Error(`导入模板无效:${o.errors[0]?.message}`);if(!t.length)throw new Error("至少需要一个 Excel 业务绑定");const n=new Map;for(const l of t){if(!e.sheets.some(c=>c.name===l.sheet)||n.has(l.sheet))throw new Error(`绑定工作表不存在或重复:${l.sheet}`);n.set(l.sheet,l)}const r=[...e.warnings],s=e.sheets.flatMap(l=>{const c=n.get(l.name);return c?ae(e,l,c,r):$(e.template.pages.slice(l.pageStart,l.pageStart+l.pageCount))}),i={...$(e.template),pages:s},a=S.validateReportTemplate(i);if(!a.ok)throw new Error(`业务模板无效:${a.errors[0]?.path} ${a.errors[0]?.message}`);return{template:i,warnings:r}}function ie(e,t){return ce(e,t)}function ce(e,t){const o=e.sheets.find(l=>l.name===t.sheet);if(!o)return[];const n=u(t.regions.header),r=u(t.regions.detail),s=[n.top,n.bottom+1,r.bottom+1],i=[],a=new Set;for(const l of e.template.pages.slice(o.pageStart,o.pageStart+o.pageCount))for(const c of l.components){if(c.kind==="list"||!c.grid||c.meta?.xlsxSheet!==t.sheet)continue;const m=u(String(c.meta.xlsxRange));c.grid.cells.forEach((d,f)=>{const g=m.top+f;for(const h of d){const w=s.some(b=>g<b&&g+(h?.rowSpan??1)>b),E=g===r.top&&((h?.rowSpan??1)>1||(h?.colSpan??1)>1);if(!w&&!E)continue;const y=w?"$.recipe.regions":"$.recipe.regions.detail";a.has(y)||(a.add(y),i.push({path:y,code:"region",message:w?`第 ${g} 行合并区域跨越绑定边界,请选择完整合并区域`:"动态明细原型行不能包含合并格"}))}})}return i}function G(e){return JSON.parse(JSON.stringify(e))}function M(e){return e instanceof Error?e.message:String(e)}function p(e,t,o,n){e.push({path:t,code:o,message:n})}function K(e,t){return{fields:e.fields,...t?{rowKey:t}:{}}}function le(e,t){const o=new Set;for(const[n,r]of e.entries()){const s=`$.datasets[${n}]`;if(!r||typeof r.id!="string"||!r.id.trim()||o.has(r.id)){p(t,s,"schema","数据集标识应非空且唯一");continue}o.add(r.id);try{F.validateDatasetRows([],K(r,r.rowKey));for(const[i,a]of r.fields.entries())a.digits!==void 0&&(!Number.isInteger(a.digits)||a.digits<0||a.digits>100)&&p(t,`${s}.fields[${i}].digits`,"schema","显示精度应为 0–100 的整数")}catch(i){p(t,s,"schema",M(i))}}}function fe(e,t,o){const n=e.sheets.find(a=>a.name===t.sheet);if(!n){p(o,"$.recipe.sheet","source","指定的工作表不存在");return}let r;try{r=u(n.range)}catch(a){p(o,"$.source.sheets","source",M(a));return}const s=new Map;for(const a of["title","header","detail","footer"]){const l=t.regions?.[a];if(!(!l&&(a==="title"||a==="footer")))try{const c=u(l??"");if(c.left!==r.left||c.right!==r.right||c.top<r.top||c.bottom>r.bottom)throw new Error("区域必须覆盖选区完整列宽,并位于原始工作表内");s.set(a,c)}catch(c){p(o,`$.recipe.regions.${a}`,"region",M(c))}}const i=[...s.values()];i.length&&(i[0].top!==r.top||i[i.length-1].bottom!==r.bottom)&&p(o,"$.recipe.regions","region","标题、表头、明细、页脚应完整覆盖来源,不能隐式删除静态内容");for(let a=1;a<i.length;a++)i[a].top!==i[a-1].bottom+1&&p(o,"$.recipe.regions","region","各区域应顺序相邻且不重叠")}function me(e,t,o,n){if(!Array.isArray(e.fields)||e.fields.length!==o)return p(n,"$.recipe.fields","mapping","每个物理 Excel 列必须显式绑定一个业务字段"),0;const r=new Set(t.fields.map(a=>a.field)),s=new Set;let i=0;e.fields.forEach((a,l)=>{typeof a!="string"||!r.has(a)?p(n,`$.recipe.fields[${l}]`,"mapping","请选择契约中已声明的字段"):s.has(a)?p(n,`$.recipe.fields[${l}]`,"mapping","同一业务字段不能重复绑定物理列"):(i++,s.add(a))});try{if(!e.rowKey)throw new Error("请明确选择稳定业务主键,不能使用展示行号");const a=K(t,e.rowKey),l=F.validateDatasetRows(t.samples??[],a,{path:`$.datasets.${t.id}.samples`,maxRows:100,maxCells:2e5,maxIssues:30});for(const c of l.issues)p(n,c.path,c.code==="row-key"?"row-key":"schema",c.message)}catch(a){p(n,"$.recipe.rowKey","row-key",M(a))}return i}function D(e,t){const o=[];return!t||t.version!=="1.0"?[{path:"$.recipe.version",code:"schema",message:"不支持的 Excel 绑定配置版本"}]:(fe(e,t,o),o.length||o.push(...ie(e,t)),o)}function L(e,t,o){const n=[];if(!t||t.version!=="1.0")return{ok:!1,issues:[{path:"$.recipe.version",code:"schema",message:"不支持的 Excel 绑定配置版本"}],mapped:0,total:0};le(o,n);const r=e.sheets.find(a=>a.name===t.sheet)?.columnCount??0,s=o.find(a=>a.id===t.dataset);let i=0;return s?n.some(a=>a.code==="schema")||(i=me(t,s,r,n)):p(n,"$.recipe.dataset","schema","请明确选择宿主提供的数据集契约"),{ok:n.length===0,issues:n,mapped:i,total:r}}function J(e,t,o){const n=L(e,t,o);if(!t||t.version!=="1.0")return n;const r=[...D(e,t),...n.issues];return{...n,ok:r.length===0,issues:r}}function ge(e){const t=e.semanticRole??(e.type==="number"||e.type==="decimal"?"measure":e.type==="date"?"date":"text");return{field:e.field,semanticRole:t,editable:!1,...e.type==="number"&&e.digits!==void 0?{format:{kind:"number",digits:e.digits}}:{},...e.type==="date"?{format:{kind:"date",pattern:"YYYY-MM-DD"}}:{}}}function he(e,t,o,n){const r=J(e,t,o);if(!r.ok)throw new Error(r.issues.map(m=>`${m.path}: ${m.message}`).join(`
|
|
2
|
+
`));const s=e.sheets.find(m=>m.name===t.sheet),i={...e,sheets:[{...s,pageStart:0}],template:{...e.template,pages:e.template.pages.slice(s.pageStart,s.pageStart+s.pageCount)}},a=new Map(o.find(m=>m.id===t.dataset).fields.map(m=>[m.field,m])),l={sheet:t.sheet,dataset:t.dataset,header:t.regions.header,detail:t.regions.detail,rowKey:t.rowKey,inferSampleFormats:!1,columns:t.fields.map(m=>ge(a.get(m)))},c=j(i,[l]);return{document:S.defineReportTemplate({...n,template:c.template}),recipe:G(t),warnings:c.warnings}}function de(e){return e===null||typeof e=="string"||typeof e=="boolean"||typeof e=="number"&&Number.isFinite(e)}function H(e,t=0){if(de(e))return;if(!e||typeof e!="object"||t>16)throw new Error("绑定会话元数据只允许有限深度的普通 JSON 值");const o=Object.getPrototypeOf(e);if(Array.isArray(e)?o!==Array.prototype:o!==Object.prototype&&o!==null)throw new Error("绑定会话不能包含特殊对象原型");if(Object.getOwnPropertySymbols(e).length)throw new Error("绑定会话不能包含 Symbol");if(Array.isArray(e)&&Object.keys(e).length!==e.length)throw new Error("绑定会话数组不能包含空位或额外属性");for(const[n,r]of Object.entries(Object.getOwnPropertyDescriptors(e)))if(!(Array.isArray(e)&&n==="length")){if(["__proto__","prototype","constructor"].includes(n)||r.get||r.set||!r.enumerable)throw new Error("绑定会话包含不安全元数据");H(r.value,t+1)}}function ue(e,t){if(e?.version!=="1.0"||!Array.isArray(e.fields)||e.fields.length>16384||e.fields.some(o=>typeof o!="string"))throw new Error("Excel 绑定配置无效");if(typeof e.dataset!="string"||typeof e.rowKey!="string"||!e.regions||typeof t?.id!="string"||typeof t.name!="string")throw new Error("Excel 绑定参数或标识无效");for(const o of Object.values(e.regions))o!==""&&u(o)}function pe(e){for(const t of e.sheets)if(u(t.range),typeof t.name!="string"||![t.index,t.rowCount,t.columnCount,t.pageCount].every(o=>Number.isInteger(o)&&o>0)||!Number.isInteger(t.pageStart)||t.pageStart<0||t.pageStart+t.pageCount>e.template.pages.length)throw new Error("Excel 绑定工作表几何元数据无效")}function we(e,t,o){if(H({sheets:e.sheets,warnings:e.warnings,recipe:t,identity:o}),!Array.isArray(e.sheets)||!e.sheets.length||e.sheets.length>32||!Array.isArray(e.warnings)||e.warnings.some(n=>typeof n!="string"))throw new Error("Excel 绑定来源元数据无效");if(ue(t,o),!e.sheets.some(n=>n.name===t.sheet))throw new Error("Excel 绑定工作表不存在");pe(e)}function P(e,t,o){return we(e,t,o),S.parseReportTemplate({schemaVersion:"1.0",id:o.id,name:o.name,template:e.template}),G({version:"1.0",source:e,recipe:t,identity:o})}function ye(e){if(typeof e=="string"&&e.length>1e7)throw new Error("Excel 绑定会话超过 1000 万字符上限");const t=typeof e=="string"?JSON.parse(e):e;if(!t||t.version!=="1.0"||t.recipe?.version!=="1.0"||!Array.isArray(t.source?.sheets))throw new Error("Excel 绑定会话结构或版本无效");return P(t.source,t.recipe,t.identity)}function Ee(e,t,o,n){const r=e.sheets.find(l=>l.name===t);if(!r)throw new Error("工作表不存在");const s=u(r.range),i=Math.min(o,n),a=Math.max(o,n);if(!Number.isInteger(i)||!Number.isInteger(a)||i<s.top||a>s.bottom)throw new Error("选中行超出来源区域");return v({...s,top:i,bottom:a})}function I(e,t,o){const n=e??t;if(!Number.isInteger(n)||n<1||n>o)throw new Error(`预览窗口大小应为 1–${o} 的整数`);return n}function T(e,t,o){const n=e??t;if(!Number.isInteger(n))throw new Error("预览起点应为整数");return Math.max(t,Math.min(o,n))}function be(e,t,o={}){const n=e.sheets.find(f=>f.name===t);if(!n)throw new Error("指定的工作表不存在");const r=u(n.range),s=T(o.row,r.top,r.bottom),i=T(o.column,r.left,r.right),a=Math.min(r.bottom,s+I(o.rows,24,100)-1),l=Math.min(r.right,i+I(o.columns,12,32)-1),c=Array.from({length:a-s+1},(f,g)=>({row:s+g,cells:[]})),m=new Set;for(const f of e.template.pages.slice(n.pageStart,n.pageStart+n.pageCount))for(const g of f.components){if(g.kind==="list"||!g.grid||g.meta?.xlsxSheet!==t)continue;const h=u(String(g.meta.xlsxRange));if(h.bottom<s||h.top>a)continue;const w=A.resolveGridLayout(g.grid,g.widthMm,g.heightMm);for(const E of w.cells)d(E.cell,h.top+E.ri,h.left+E.ci)}for(const f of c){for(let g=i;g<=l;g++)m.has(`${f.row}:${g}`)||f.cells.push({address:`${x(g)}${f.row}`,row:f.row,column:g,text:"",rowSpan:1,colSpan:1,continued:!1});f.cells.sort((g,h)=>g.column-h.column)}return{top:s,bottom:a,left:i,right:l,source:r,rows:c,columns:Array.from({length:l-i+1},(f,g)=>({column:i+g,name:x(i+g)}))};function d(f,g,h){const w=g+(f.rowSpan??1)-1,E=h+(f.colSpan??1)-1;if(w<s||g>a||E<i||h>l)return;const y=Math.max(s,g),b=Math.max(i,h),B=Math.min(a,w)-y+1,N=Math.min(l,E)-b+1;c[y-s].cells.push({address:`${x(h)}${g}`,row:y,column:b,text:f.text??f.rawText??String(f.value??""),rowSpan:B,colSpan:N,continued:y!==g||b!==h,style:f.style});for(let R=y;R<y+B;R++)for(let k=b;k<b+N;k++)m.add(`${R}:${k}`)}}exports.bindExcelTemplate=j;exports.checkedRange=W;exports.columnName=x;exports.createExcelBindingDocument=he;exports.createExcelBindingSession=P;exports.excelBindingRowRange=Ee;exports.getExcelSheetWindow=be;exports.mergeLookup=U;exports.mergeRowGroups=Z;exports.parseExcelBindingSession=ye;exports.parseImportRange=u;exports.rangeName=v;exports.rowSegments=z;exports.selectedMerges=q;exports.selectedRange=_;exports.validateExcelBindingFields=L;exports.validateExcelBindingRecipe=J;exports.validateExcelBindingRegions=D;
|
|
@@ -0,0 +1,649 @@
|
|
|
1
|
+
import { v as j } from "./dataset-H5pFuQGU.js";
|
|
2
|
+
import { v as N, d as D, p as H } from "./template-registry-R61AMCr0.js";
|
|
3
|
+
import { r as C } from "./grid-geometry-BNptEcMm.js";
|
|
4
|
+
function $(t) {
|
|
5
|
+
let e = "";
|
|
6
|
+
for (let o = t; o > 0; o = Math.floor((o - 1) / 26)) e = String.fromCharCode(65 + (o - 1) % 26) + e;
|
|
7
|
+
return e;
|
|
8
|
+
}
|
|
9
|
+
function A(t) {
|
|
10
|
+
return `${$(t.left)}${t.top}:${$(t.right)}${t.bottom}`;
|
|
11
|
+
}
|
|
12
|
+
function I(t) {
|
|
13
|
+
let e = 0;
|
|
14
|
+
for (const o of t.toUpperCase()) e = e * 26 + o.charCodeAt(0) - 64;
|
|
15
|
+
return e;
|
|
16
|
+
}
|
|
17
|
+
function u(t) {
|
|
18
|
+
if (typeof t != "string") throw new Error("Excel 范围应为 A1:B20 格式的字符串");
|
|
19
|
+
const e = /^\$?([A-Z]{1,3})\$?([1-9]\d{0,6})(?::\$?([A-Z]{1,3})\$?([1-9]\d{0,6}))?$/i.exec(t.trim());
|
|
20
|
+
if (!e) throw new Error(`Excel 范围无效:${t}`);
|
|
21
|
+
const o = { left: I(e[1]), top: Number(e[2]), right: I(e[3] ?? e[1]), bottom: Number(e[4] ?? e[2]) };
|
|
22
|
+
if (o.right < o.left || o.bottom < o.top || o.right > 16384 || o.bottom > 1048576)
|
|
23
|
+
throw new Error(`Excel 范围超出边界或顺序无效:${t}`);
|
|
24
|
+
return o;
|
|
25
|
+
}
|
|
26
|
+
function dt(t, e) {
|
|
27
|
+
if (e !== void 0) return u(e);
|
|
28
|
+
const o = t.model.rows ?? [];
|
|
29
|
+
if (!o.length) return { top: 1, left: 1, bottom: 1, right: 1 };
|
|
30
|
+
const n = { top: 1 / 0, left: 1 / 0, bottom: 1, right: 1 };
|
|
31
|
+
for (const r of o)
|
|
32
|
+
n.top = Math.min(n.top, r.number), n.bottom = Math.max(n.bottom, r.number), n.left = Math.min(n.left, r.min || 1), n.right = Math.max(n.right, r.max || 1);
|
|
33
|
+
return n;
|
|
34
|
+
}
|
|
35
|
+
function wt(t, e, o) {
|
|
36
|
+
const n = t.bottom - t.top + 1, r = t.right - t.left + 1;
|
|
37
|
+
if (n > e.limits.maxRows || r > e.limits.maxColumns || n * r > o)
|
|
38
|
+
throw new Error(`Excel 范围 ${A(t)} 超过导入行、列或单元格上限;请用 sheets/range 缩小范围`);
|
|
39
|
+
return n * r;
|
|
40
|
+
}
|
|
41
|
+
function P(t, e) {
|
|
42
|
+
return t.top <= e.bottom && t.bottom >= e.top && t.left <= e.right && t.right >= e.left;
|
|
43
|
+
}
|
|
44
|
+
function yt(t, e) {
|
|
45
|
+
const o = [];
|
|
46
|
+
for (const n of t.model.merges) {
|
|
47
|
+
const r = u(n);
|
|
48
|
+
if (P(e, r)) {
|
|
49
|
+
if (r.left < e.left || r.right > e.right || r.top < e.top || r.bottom > e.bottom)
|
|
50
|
+
throw new Error(`${t.name}: 范围 ${A(e)} 截断合并单元格 ${n},请包含完整合并区域`);
|
|
51
|
+
o.push(r);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return o;
|
|
55
|
+
}
|
|
56
|
+
function bt(t, e) {
|
|
57
|
+
const o = /* @__PURE__ */ new Map();
|
|
58
|
+
for (const r of e) o.set(r.top, Math.max(o.get(r.top) ?? r.top, r.bottom));
|
|
59
|
+
const n = [];
|
|
60
|
+
for (let r = t.top; r <= t.bottom; ) {
|
|
61
|
+
let s = o.get(r) ?? r;
|
|
62
|
+
for (let i = r; i <= s; i++) s = Math.max(s, o.get(i) ?? i);
|
|
63
|
+
n.push({ top: r, bottom: s }), r = s + 1;
|
|
64
|
+
}
|
|
65
|
+
return n;
|
|
66
|
+
}
|
|
67
|
+
function Et(t, e, o, n) {
|
|
68
|
+
const r = [];
|
|
69
|
+
let s, i = 0;
|
|
70
|
+
for (const a of t) {
|
|
71
|
+
const l = a.bottom - a.top + 1;
|
|
72
|
+
if (l > 200) throw new Error("合并单元格跨越超过 200 行,无法安全分段;请先缩小或拆分该合并区域");
|
|
73
|
+
let c = 0;
|
|
74
|
+
for (let p = a.top; p <= a.bottom; p++) c += n(p);
|
|
75
|
+
if (c > o && Number.isFinite(o)) throw new Error("合并区域或单行高度超过标准纸张可用高度;请使用 wide 或调整原模板行高");
|
|
76
|
+
const m = s ? a.bottom - s.top + 1 : l;
|
|
77
|
+
s && (m > e || i + c > o) && (r.push(s), s = void 0, i = 0), s ? s.bottom = a.bottom : s = { ...a }, i += c;
|
|
78
|
+
}
|
|
79
|
+
return s && r.push(s), r;
|
|
80
|
+
}
|
|
81
|
+
function $t(t) {
|
|
82
|
+
const e = /* @__PURE__ */ new Map(), o = /* @__PURE__ */ new Set();
|
|
83
|
+
for (const n of t) {
|
|
84
|
+
e.set(`${n.top}:${n.left}`, n);
|
|
85
|
+
for (let r = n.top; r <= n.bottom; r++)
|
|
86
|
+
for (let s = n.left; s <= n.right; s++)
|
|
87
|
+
(r !== n.top || s !== n.left) && o.add(`${r}:${s}`);
|
|
88
|
+
}
|
|
89
|
+
return { masters: e, covered: o };
|
|
90
|
+
}
|
|
91
|
+
function x(t) {
|
|
92
|
+
return JSON.parse(JSON.stringify(t));
|
|
93
|
+
}
|
|
94
|
+
function _(t, e) {
|
|
95
|
+
const o = t.template.pages.slice(e.pageStart, e.pageStart + e.pageCount), n = o[0];
|
|
96
|
+
if (!n) throw new Error(`工作表 ${e.name} 没有可绑定页面`);
|
|
97
|
+
const r = /* @__PURE__ */ new Map();
|
|
98
|
+
let s = [];
|
|
99
|
+
for (const i of o)
|
|
100
|
+
for (const a of i.components) {
|
|
101
|
+
if (a.kind === "list" || !a.grid || a.meta?.xlsxSheet !== e.name) continue;
|
|
102
|
+
const l = u(String(a.meta.xlsxRange)), c = a.grid;
|
|
103
|
+
s = c.colWidthsMm ?? [], c.cells.forEach((m, p) => r.set(l.top + p, { cells: x(m), height: c.rowHeightsMm?.[p] ?? 6 }));
|
|
104
|
+
}
|
|
105
|
+
if (!s.length || !r.size) throw new Error(`工作表 ${e.name} 缺少导入几何元数据`);
|
|
106
|
+
return { rows: r, widths: [...s], page: n, range: u(e.range) };
|
|
107
|
+
}
|
|
108
|
+
function k(t, e, o) {
|
|
109
|
+
const n = [], r = [];
|
|
110
|
+
for (let s = e; s <= o; s++) {
|
|
111
|
+
const i = t.rows.get(s);
|
|
112
|
+
if (!i) throw new Error(`导入模板缺少第 ${s} 行`);
|
|
113
|
+
for (const a of i.cells)
|
|
114
|
+
if (a && s + (a.rowSpan ?? 1) - 1 > o) throw new Error(`第 ${s} 行合并区域跨越绑定边界,请调整 header/detail 范围`);
|
|
115
|
+
n.push(x(i.cells)), r.push(i.height);
|
|
116
|
+
}
|
|
117
|
+
return { cells: n, rowHeightsMm: r, colWidthsMm: t.widths, paddingMm: 0.25 };
|
|
118
|
+
}
|
|
119
|
+
function G(t, e) {
|
|
120
|
+
const o = u(t.header), n = t.detail ? u(t.detail) : { ...e.range, top: o.bottom + 1 };
|
|
121
|
+
for (const r of [o, n])
|
|
122
|
+
if (r.left !== e.range.left || r.right !== e.range.right || r.top < e.range.top || r.bottom > e.range.bottom || r.top > r.bottom) throw new Error("绑定区域必须位于导入选区内并覆盖其完整列宽");
|
|
123
|
+
if (n.top !== o.bottom + 1) throw new Error("detail 应紧接 header,避免静态内容被隐式删除");
|
|
124
|
+
if (t.columns.length !== e.widths.length) throw new Error("columns 应逐列映射整个选区;不能自动猜测业务字段");
|
|
125
|
+
return L(e, [o.top, o.bottom + 1, n.bottom + 1]), { header: o, detail: n };
|
|
126
|
+
}
|
|
127
|
+
function L(t, e) {
|
|
128
|
+
for (const [o, n] of t.rows) for (const r of n.cells) {
|
|
129
|
+
const s = o + (r?.rowSpan ?? 1);
|
|
130
|
+
if (e.some((i) => o < i && s > i)) throw new Error(`第 ${o} 行合并区域跨越绑定边界,请调整 header/detail 范围`);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
function Y(t, e) {
|
|
134
|
+
const o = [];
|
|
135
|
+
for (const n of C(t, e.reduce((r, s) => r + s, 0), 100).cells)
|
|
136
|
+
for (let r = n.ci; r < Math.min(e.length, n.ci + (n.cell.colSpan ?? 1)); r++) o[r] = n.cell;
|
|
137
|
+
return o;
|
|
138
|
+
}
|
|
139
|
+
function W(t, e, o, n) {
|
|
140
|
+
if (e) return e;
|
|
141
|
+
const r = t?.numberFormat;
|
|
142
|
+
if (!r || r === "General") return;
|
|
143
|
+
const s = /^(#,##)?0(?:\.(0+))?(%)?$/.exec(r);
|
|
144
|
+
if (s) {
|
|
145
|
+
const i = s[2]?.length ?? 0;
|
|
146
|
+
if (i <= 100) return s[3] ? { kind: "percent", digits: i } : { kind: "number", digits: i, ...s[1] ? { thousands: !0 } : {} };
|
|
147
|
+
}
|
|
148
|
+
n.push(`${o}: Excel 数字格式 ${r} 未自动套用到动态数据,请在 columns 中显式声明 format`);
|
|
149
|
+
}
|
|
150
|
+
function Z(t, e, o, n, r) {
|
|
151
|
+
const s = Y(e, n), i = C(o, n.reduce((m, p) => m + p, 0), 20).cells;
|
|
152
|
+
if (i.some(({ cell: m }) => (m.colSpan ?? 1) !== 1 || (m.rowSpan ?? 1) !== 1)) throw new Error("动态明细样例行不能包含合并格;合并表头可以保留");
|
|
153
|
+
const a = new Map(i.map((m) => [m.ci, m.cell])), l = /* @__PURE__ */ new Set(), c = t.columns.map((m, p) => {
|
|
154
|
+
const f = typeof m == "string" ? { field: m } : m;
|
|
155
|
+
if (!f || typeof f.field != "string" || !f.field.trim() || l.has(f.field)) throw new Error(`columns[${p}] 需要唯一的非空 field`);
|
|
156
|
+
l.add(f.field);
|
|
157
|
+
const g = s[p]?.text ?? f.field, h = a.get(p), w = t.inferSampleFormats === !1 ? f.format : W(h, f.format, f.field, r);
|
|
158
|
+
return { ...f, ...w ? { format: w } : {}, header: f.header ?? g, widthMm: n[p], style: { ...h?.style, ...f.style }, ...f.semanticRole && !f.align ? { align: "auto" } : {}, ...f.editable === void 0 && h?.editable === !1 ? { editable: !1 } : {} };
|
|
159
|
+
});
|
|
160
|
+
return z(t, s, c), c;
|
|
161
|
+
}
|
|
162
|
+
function z(t, e, o) {
|
|
163
|
+
const n = /* @__PURE__ */ new Map();
|
|
164
|
+
t.columns.forEach((r, s) => {
|
|
165
|
+
const i = e[s];
|
|
166
|
+
if (!i || typeof r == "string") return;
|
|
167
|
+
const a = n.get(i) ?? { style: {} };
|
|
168
|
+
if (r.header !== void 0) {
|
|
169
|
+
if (a.text !== void 0 && a.text !== r.header) throw new Error("同一合并表头不能配置不同 header");
|
|
170
|
+
a.text = r.header;
|
|
171
|
+
}
|
|
172
|
+
U(a.style, { ...r.headerAlign ? { align: r.headerAlign } : {}, ...r.headerStyle }), n.set(i, a);
|
|
173
|
+
});
|
|
174
|
+
for (const [r, s] of n)
|
|
175
|
+
s.text !== void 0 && Object.assign(r, { text: s.text, rawText: s.text, value: s.text }), r.style = { ...r.style, ...s.style }, e.forEach((i, a) => {
|
|
176
|
+
i === r && (s.text !== void 0 && (o[a].header = s.text), s.style.align !== void 0 && (o[a].headerAlign = s.style.align));
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
function U(t, e) {
|
|
180
|
+
for (const o of Object.keys(e))
|
|
181
|
+
if (e[o] !== void 0) {
|
|
182
|
+
if (t[o] !== void 0 && t[o] !== e[o]) throw new Error(`同一合并表头不能配置不同 ${o}`);
|
|
183
|
+
Object.assign(t, { [o]: e[o] });
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
function V(t, e) {
|
|
187
|
+
const o = t.page, n = e.rowHeightsMm.reduce((r, s) => r + s, 0);
|
|
188
|
+
return { ...o, heightMm: Math.max(o.heightMm, n + (o.marginTopMm ?? 0) + (o.marginBottomMm ?? 0)), components: [{ kind: "rect", leftMm: o.marginLeftMm ?? 0, topMm: o.marginTopMm ?? 0, widthMm: t.widths.reduce((r, s) => r + s, 0), heightMm: n, grid: e }] };
|
|
189
|
+
}
|
|
190
|
+
function q(t, e, o, n) {
|
|
191
|
+
const r = _(t, e), { header: s, detail: i } = G(o, r), a = k(r, r.range.top, s.bottom), l = k(r, i.top, i.top), c = { ...r.page, components: [] }, m = {
|
|
192
|
+
kind: "list",
|
|
193
|
+
id: `bound:${e.name}`,
|
|
194
|
+
dataset: o.dataset ?? "detail",
|
|
195
|
+
title: e.name,
|
|
196
|
+
leftMm: c.marginLeftMm ?? 0,
|
|
197
|
+
topMm: c.marginTopMm ?? 0,
|
|
198
|
+
widthMm: r.widths.reduce((p, f) => p + f, 0),
|
|
199
|
+
layout: c.layout ?? "page",
|
|
200
|
+
headerGrid: a,
|
|
201
|
+
columns: Z(o, a, l, r.widths, n),
|
|
202
|
+
rowHeightMm: l.rowHeightsMm[0],
|
|
203
|
+
headerEveryPage: !0,
|
|
204
|
+
align: "auto",
|
|
205
|
+
paddingMm: 0.25,
|
|
206
|
+
...o.rowKey ? { rowKey: o.rowKey } : {},
|
|
207
|
+
...o.revisionField ? { revisionField: o.revisionField } : {},
|
|
208
|
+
...o.sourceTokenField ? { sourceTokenField: o.sourceTokenField } : {},
|
|
209
|
+
...o.groupBy ? { groupBy: o.groupBy } : {},
|
|
210
|
+
...o.grandTotal === void 0 ? {} : { grandTotal: o.grandTotal }
|
|
211
|
+
};
|
|
212
|
+
return c.components.push(m), i.bottom === r.range.bottom ? [c] : (n.push(`${e.name}: 明细区域后的静态内容保留为后续独立页面,不推断动态页脚定位`), [c, V(r, k(r, i.bottom + 1, r.range.bottom))]);
|
|
213
|
+
}
|
|
214
|
+
function Q(t, e) {
|
|
215
|
+
const o = N(t.template);
|
|
216
|
+
if (!o.ok) throw new Error(`导入模板无效:${o.errors[0]?.message}`);
|
|
217
|
+
if (!e.length) throw new Error("至少需要一个 Excel 业务绑定");
|
|
218
|
+
const n = /* @__PURE__ */ new Map();
|
|
219
|
+
for (const l of e) {
|
|
220
|
+
if (!t.sheets.some((c) => c.name === l.sheet) || n.has(l.sheet)) throw new Error(`绑定工作表不存在或重复:${l.sheet}`);
|
|
221
|
+
n.set(l.sheet, l);
|
|
222
|
+
}
|
|
223
|
+
const r = [...t.warnings], s = t.sheets.flatMap((l) => {
|
|
224
|
+
const c = n.get(l.name);
|
|
225
|
+
return c ? q(t, l, c, r) : x(t.template.pages.slice(l.pageStart, l.pageStart + l.pageCount));
|
|
226
|
+
}), i = { ...x(t.template), pages: s }, a = N(i);
|
|
227
|
+
if (!a.ok) throw new Error(`业务模板无效:${a.errors[0]?.path} ${a.errors[0]?.message}`);
|
|
228
|
+
return { template: i, warnings: r };
|
|
229
|
+
}
|
|
230
|
+
function X(t, e) {
|
|
231
|
+
return tt(t, e);
|
|
232
|
+
}
|
|
233
|
+
function tt(t, e) {
|
|
234
|
+
const o = t.sheets.find((l) => l.name === e.sheet);
|
|
235
|
+
if (!o) return [];
|
|
236
|
+
const n = u(e.regions.header), r = u(e.regions.detail), s = [n.top, n.bottom + 1, r.bottom + 1], i = [], a = /* @__PURE__ */ new Set();
|
|
237
|
+
for (const l of t.template.pages.slice(
|
|
238
|
+
o.pageStart,
|
|
239
|
+
o.pageStart + o.pageCount
|
|
240
|
+
))
|
|
241
|
+
for (const c of l.components) {
|
|
242
|
+
if (c.kind === "list" || !c.grid || c.meta?.xlsxSheet !== e.sheet)
|
|
243
|
+
continue;
|
|
244
|
+
const m = u(String(c.meta.xlsxRange));
|
|
245
|
+
c.grid.cells.forEach((p, f) => {
|
|
246
|
+
const g = m.top + f;
|
|
247
|
+
for (const h of p) {
|
|
248
|
+
const w = s.some(
|
|
249
|
+
(E) => g < E && g + (h?.rowSpan ?? 1) > E
|
|
250
|
+
), b = g === r.top && ((h?.rowSpan ?? 1) > 1 || (h?.colSpan ?? 1) > 1);
|
|
251
|
+
if (!w && !b) continue;
|
|
252
|
+
const y = w ? "$.recipe.regions" : "$.recipe.regions.detail";
|
|
253
|
+
a.has(y) || (a.add(y), i.push({
|
|
254
|
+
path: y,
|
|
255
|
+
code: "region",
|
|
256
|
+
message: w ? `第 ${g} 行合并区域跨越绑定边界,请选择完整合并区域` : "动态明细原型行不能包含合并格"
|
|
257
|
+
}));
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
return i;
|
|
262
|
+
}
|
|
263
|
+
function F(t) {
|
|
264
|
+
return JSON.parse(JSON.stringify(t));
|
|
265
|
+
}
|
|
266
|
+
function S(t) {
|
|
267
|
+
return t instanceof Error ? t.message : String(t);
|
|
268
|
+
}
|
|
269
|
+
function d(t, e, o, n) {
|
|
270
|
+
t.push({ path: e, code: o, message: n });
|
|
271
|
+
}
|
|
272
|
+
function K(t, e) {
|
|
273
|
+
return { fields: t.fields, ...e ? { rowKey: e } : {} };
|
|
274
|
+
}
|
|
275
|
+
function et(t, e) {
|
|
276
|
+
const o = /* @__PURE__ */ new Set();
|
|
277
|
+
for (const [n, r] of t.entries()) {
|
|
278
|
+
const s = `$.datasets[${n}]`;
|
|
279
|
+
if (!r || typeof r.id != "string" || !r.id.trim() || o.has(r.id)) {
|
|
280
|
+
d(e, s, "schema", "数据集标识应非空且唯一");
|
|
281
|
+
continue;
|
|
282
|
+
}
|
|
283
|
+
o.add(r.id);
|
|
284
|
+
try {
|
|
285
|
+
j([], K(r, r.rowKey));
|
|
286
|
+
for (const [i, a] of r.fields.entries())
|
|
287
|
+
a.digits !== void 0 && (!Number.isInteger(a.digits) || a.digits < 0 || a.digits > 100) && d(
|
|
288
|
+
e,
|
|
289
|
+
`${s}.fields[${i}].digits`,
|
|
290
|
+
"schema",
|
|
291
|
+
"显示精度应为 0–100 的整数"
|
|
292
|
+
);
|
|
293
|
+
} catch (i) {
|
|
294
|
+
d(e, s, "schema", S(i));
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
function ot(t, e, o) {
|
|
299
|
+
const n = t.sheets.find((a) => a.name === e.sheet);
|
|
300
|
+
if (!n) {
|
|
301
|
+
d(o, "$.recipe.sheet", "source", "指定的工作表不存在");
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
let r;
|
|
305
|
+
try {
|
|
306
|
+
r = u(n.range);
|
|
307
|
+
} catch (a) {
|
|
308
|
+
d(o, "$.source.sheets", "source", S(a));
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
const s = /* @__PURE__ */ new Map();
|
|
312
|
+
for (const a of ["title", "header", "detail", "footer"]) {
|
|
313
|
+
const l = e.regions?.[a];
|
|
314
|
+
if (!(!l && (a === "title" || a === "footer")))
|
|
315
|
+
try {
|
|
316
|
+
const c = u(l ?? "");
|
|
317
|
+
if (c.left !== r.left || c.right !== r.right || c.top < r.top || c.bottom > r.bottom)
|
|
318
|
+
throw new Error("区域必须覆盖选区完整列宽,并位于原始工作表内");
|
|
319
|
+
s.set(a, c);
|
|
320
|
+
} catch (c) {
|
|
321
|
+
d(o, `$.recipe.regions.${a}`, "region", S(c));
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
const i = [...s.values()];
|
|
325
|
+
i.length && (i[0].top !== r.top || i[i.length - 1].bottom !== r.bottom) && d(
|
|
326
|
+
o,
|
|
327
|
+
"$.recipe.regions",
|
|
328
|
+
"region",
|
|
329
|
+
"标题、表头、明细、页脚应完整覆盖来源,不能隐式删除静态内容"
|
|
330
|
+
);
|
|
331
|
+
for (let a = 1; a < i.length; a++)
|
|
332
|
+
i[a].top !== i[a - 1].bottom + 1 && d(o, "$.recipe.regions", "region", "各区域应顺序相邻且不重叠");
|
|
333
|
+
}
|
|
334
|
+
function rt(t, e, o, n) {
|
|
335
|
+
if (!Array.isArray(t.fields) || t.fields.length !== o)
|
|
336
|
+
return d(
|
|
337
|
+
n,
|
|
338
|
+
"$.recipe.fields",
|
|
339
|
+
"mapping",
|
|
340
|
+
"每个物理 Excel 列必须显式绑定一个业务字段"
|
|
341
|
+
), 0;
|
|
342
|
+
const r = new Set(e.fields.map((a) => a.field)), s = /* @__PURE__ */ new Set();
|
|
343
|
+
let i = 0;
|
|
344
|
+
t.fields.forEach((a, l) => {
|
|
345
|
+
typeof a != "string" || !r.has(a) ? d(
|
|
346
|
+
n,
|
|
347
|
+
`$.recipe.fields[${l}]`,
|
|
348
|
+
"mapping",
|
|
349
|
+
"请选择契约中已声明的字段"
|
|
350
|
+
) : s.has(a) ? d(
|
|
351
|
+
n,
|
|
352
|
+
`$.recipe.fields[${l}]`,
|
|
353
|
+
"mapping",
|
|
354
|
+
"同一业务字段不能重复绑定物理列"
|
|
355
|
+
) : (i++, s.add(a));
|
|
356
|
+
});
|
|
357
|
+
try {
|
|
358
|
+
if (!t.rowKey)
|
|
359
|
+
throw new Error("请明确选择稳定业务主键,不能使用展示行号");
|
|
360
|
+
const a = K(e, t.rowKey), l = j(e.samples ?? [], a, {
|
|
361
|
+
path: `$.datasets.${e.id}.samples`,
|
|
362
|
+
maxRows: 100,
|
|
363
|
+
maxCells: 2e5,
|
|
364
|
+
maxIssues: 30
|
|
365
|
+
});
|
|
366
|
+
for (const c of l.issues)
|
|
367
|
+
d(
|
|
368
|
+
n,
|
|
369
|
+
c.path,
|
|
370
|
+
c.code === "row-key" ? "row-key" : "schema",
|
|
371
|
+
c.message
|
|
372
|
+
);
|
|
373
|
+
} catch (a) {
|
|
374
|
+
d(n, "$.recipe.rowKey", "row-key", S(a));
|
|
375
|
+
}
|
|
376
|
+
return i;
|
|
377
|
+
}
|
|
378
|
+
function nt(t, e) {
|
|
379
|
+
const o = [];
|
|
380
|
+
return !e || e.version !== "1.0" ? [
|
|
381
|
+
{
|
|
382
|
+
path: "$.recipe.version",
|
|
383
|
+
code: "schema",
|
|
384
|
+
message: "不支持的 Excel 绑定配置版本"
|
|
385
|
+
}
|
|
386
|
+
] : (ot(t, e, o), o.length || o.push(...X(t, e)), o);
|
|
387
|
+
}
|
|
388
|
+
function st(t, e, o) {
|
|
389
|
+
const n = [];
|
|
390
|
+
if (!e || e.version !== "1.0")
|
|
391
|
+
return {
|
|
392
|
+
ok: !1,
|
|
393
|
+
issues: [
|
|
394
|
+
{
|
|
395
|
+
path: "$.recipe.version",
|
|
396
|
+
code: "schema",
|
|
397
|
+
message: "不支持的 Excel 绑定配置版本"
|
|
398
|
+
}
|
|
399
|
+
],
|
|
400
|
+
mapped: 0,
|
|
401
|
+
total: 0
|
|
402
|
+
};
|
|
403
|
+
et(o, n);
|
|
404
|
+
const r = t.sheets.find((a) => a.name === e.sheet)?.columnCount ?? 0, s = o.find((a) => a.id === e.dataset);
|
|
405
|
+
let i = 0;
|
|
406
|
+
return s ? n.some((a) => a.code === "schema") || (i = rt(e, s, r, n)) : d(
|
|
407
|
+
n,
|
|
408
|
+
"$.recipe.dataset",
|
|
409
|
+
"schema",
|
|
410
|
+
"请明确选择宿主提供的数据集契约"
|
|
411
|
+
), { ok: n.length === 0, issues: n, mapped: i, total: r };
|
|
412
|
+
}
|
|
413
|
+
function at(t, e, o) {
|
|
414
|
+
const n = st(t, e, o);
|
|
415
|
+
if (!e || e.version !== "1.0") return n;
|
|
416
|
+
const r = [
|
|
417
|
+
...nt(t, e),
|
|
418
|
+
...n.issues
|
|
419
|
+
];
|
|
420
|
+
return { ...n, ok: r.length === 0, issues: r };
|
|
421
|
+
}
|
|
422
|
+
function it(t) {
|
|
423
|
+
const e = t.semanticRole ?? (t.type === "number" || t.type === "decimal" ? "measure" : t.type === "date" ? "date" : "text");
|
|
424
|
+
return {
|
|
425
|
+
field: t.field,
|
|
426
|
+
semanticRole: e,
|
|
427
|
+
editable: !1,
|
|
428
|
+
...t.type === "number" && t.digits !== void 0 ? { format: { kind: "number", digits: t.digits } } : {},
|
|
429
|
+
...t.type === "date" ? { format: { kind: "date", pattern: "YYYY-MM-DD" } } : {}
|
|
430
|
+
};
|
|
431
|
+
}
|
|
432
|
+
function xt(t, e, o, n) {
|
|
433
|
+
const r = at(t, e, o);
|
|
434
|
+
if (!r.ok)
|
|
435
|
+
throw new Error(
|
|
436
|
+
r.issues.map((m) => `${m.path}: ${m.message}`).join(`
|
|
437
|
+
`)
|
|
438
|
+
);
|
|
439
|
+
const s = t.sheets.find((m) => m.name === e.sheet), i = {
|
|
440
|
+
...t,
|
|
441
|
+
sheets: [{ ...s, pageStart: 0 }],
|
|
442
|
+
template: {
|
|
443
|
+
...t.template,
|
|
444
|
+
pages: t.template.pages.slice(
|
|
445
|
+
s.pageStart,
|
|
446
|
+
s.pageStart + s.pageCount
|
|
447
|
+
)
|
|
448
|
+
}
|
|
449
|
+
}, a = new Map(
|
|
450
|
+
o.find((m) => m.id === e.dataset).fields.map((m) => [m.field, m])
|
|
451
|
+
), l = {
|
|
452
|
+
sheet: e.sheet,
|
|
453
|
+
dataset: e.dataset,
|
|
454
|
+
header: e.regions.header,
|
|
455
|
+
detail: e.regions.detail,
|
|
456
|
+
rowKey: e.rowKey,
|
|
457
|
+
inferSampleFormats: !1,
|
|
458
|
+
columns: e.fields.map((m) => it(a.get(m)))
|
|
459
|
+
}, c = Q(i, [l]);
|
|
460
|
+
return {
|
|
461
|
+
document: D({ ...n, template: c.template }),
|
|
462
|
+
recipe: F(e),
|
|
463
|
+
warnings: c.warnings
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
function ct(t) {
|
|
467
|
+
return t === null || typeof t == "string" || typeof t == "boolean" || typeof t == "number" && Number.isFinite(t);
|
|
468
|
+
}
|
|
469
|
+
function J(t, e = 0) {
|
|
470
|
+
if (ct(t)) return;
|
|
471
|
+
if (!t || typeof t != "object" || e > 16)
|
|
472
|
+
throw new Error("绑定会话元数据只允许有限深度的普通 JSON 值");
|
|
473
|
+
const o = Object.getPrototypeOf(t);
|
|
474
|
+
if (Array.isArray(t) ? o !== Array.prototype : o !== Object.prototype && o !== null)
|
|
475
|
+
throw new Error("绑定会话不能包含特殊对象原型");
|
|
476
|
+
if (Object.getOwnPropertySymbols(t).length)
|
|
477
|
+
throw new Error("绑定会话不能包含 Symbol");
|
|
478
|
+
if (Array.isArray(t) && Object.keys(t).length !== t.length)
|
|
479
|
+
throw new Error("绑定会话数组不能包含空位或额外属性");
|
|
480
|
+
for (const [n, r] of Object.entries(
|
|
481
|
+
Object.getOwnPropertyDescriptors(t)
|
|
482
|
+
))
|
|
483
|
+
if (!(Array.isArray(t) && n === "length")) {
|
|
484
|
+
if (["__proto__", "prototype", "constructor"].includes(n) || r.get || r.set || !r.enumerable)
|
|
485
|
+
throw new Error("绑定会话包含不安全元数据");
|
|
486
|
+
J(r.value, e + 1);
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
function lt(t, e) {
|
|
490
|
+
if (t?.version !== "1.0" || !Array.isArray(t.fields) || t.fields.length > 16384 || t.fields.some((o) => typeof o != "string"))
|
|
491
|
+
throw new Error("Excel 绑定配置无效");
|
|
492
|
+
if (typeof t.dataset != "string" || typeof t.rowKey != "string" || !t.regions || typeof e?.id != "string" || typeof e.name != "string")
|
|
493
|
+
throw new Error("Excel 绑定参数或标识无效");
|
|
494
|
+
for (const o of Object.values(t.regions))
|
|
495
|
+
o !== "" && u(o);
|
|
496
|
+
}
|
|
497
|
+
function ft(t) {
|
|
498
|
+
for (const e of t.sheets)
|
|
499
|
+
if (u(e.range), typeof e.name != "string" || ![e.index, e.rowCount, e.columnCount, e.pageCount].every(
|
|
500
|
+
(o) => Number.isInteger(o) && o > 0
|
|
501
|
+
) || !Number.isInteger(e.pageStart) || e.pageStart < 0 || e.pageStart + e.pageCount > t.template.pages.length)
|
|
502
|
+
throw new Error("Excel 绑定工作表几何元数据无效");
|
|
503
|
+
}
|
|
504
|
+
function mt(t, e, o) {
|
|
505
|
+
if (J({
|
|
506
|
+
sheets: t.sheets,
|
|
507
|
+
warnings: t.warnings,
|
|
508
|
+
recipe: e,
|
|
509
|
+
identity: o
|
|
510
|
+
}), !Array.isArray(t.sheets) || !t.sheets.length || t.sheets.length > 32 || !Array.isArray(t.warnings) || t.warnings.some((n) => typeof n != "string"))
|
|
511
|
+
throw new Error("Excel 绑定来源元数据无效");
|
|
512
|
+
if (lt(e, o), !t.sheets.some((n) => n.name === e.sheet))
|
|
513
|
+
throw new Error("Excel 绑定工作表不存在");
|
|
514
|
+
ft(t);
|
|
515
|
+
}
|
|
516
|
+
function gt(t, e, o) {
|
|
517
|
+
return mt(t, e, o), H({
|
|
518
|
+
schemaVersion: "1.0",
|
|
519
|
+
id: o.id,
|
|
520
|
+
name: o.name,
|
|
521
|
+
template: t.template
|
|
522
|
+
}), F({ version: "1.0", source: t, recipe: e, identity: o });
|
|
523
|
+
}
|
|
524
|
+
function St(t) {
|
|
525
|
+
if (typeof t == "string" && t.length > 1e7)
|
|
526
|
+
throw new Error("Excel 绑定会话超过 1000 万字符上限");
|
|
527
|
+
const e = typeof t == "string" ? JSON.parse(t) : t;
|
|
528
|
+
if (!e || e.version !== "1.0" || e.recipe?.version !== "1.0" || !Array.isArray(e.source?.sheets))
|
|
529
|
+
throw new Error("Excel 绑定会话结构或版本无效");
|
|
530
|
+
return gt(
|
|
531
|
+
e.source,
|
|
532
|
+
e.recipe,
|
|
533
|
+
e.identity
|
|
534
|
+
);
|
|
535
|
+
}
|
|
536
|
+
function Mt(t, e, o, n) {
|
|
537
|
+
const r = t.sheets.find((l) => l.name === e);
|
|
538
|
+
if (!r) throw new Error("工作表不存在");
|
|
539
|
+
const s = u(r.range), i = Math.min(o, n), a = Math.max(o, n);
|
|
540
|
+
if (!Number.isInteger(i) || !Number.isInteger(a) || i < s.top || a > s.bottom)
|
|
541
|
+
throw new Error("选中行超出来源区域");
|
|
542
|
+
return A({ ...s, top: i, bottom: a });
|
|
543
|
+
}
|
|
544
|
+
function T(t, e, o) {
|
|
545
|
+
const n = t ?? e;
|
|
546
|
+
if (!Number.isInteger(n) || n < 1 || n > o)
|
|
547
|
+
throw new Error(`预览窗口大小应为 1–${o} 的整数`);
|
|
548
|
+
return n;
|
|
549
|
+
}
|
|
550
|
+
function B(t, e, o) {
|
|
551
|
+
const n = t ?? e;
|
|
552
|
+
if (!Number.isInteger(n)) throw new Error("预览起点应为整数");
|
|
553
|
+
return Math.max(e, Math.min(o, n));
|
|
554
|
+
}
|
|
555
|
+
function vt(t, e, o = {}) {
|
|
556
|
+
const n = t.sheets.find((f) => f.name === e);
|
|
557
|
+
if (!n) throw new Error("指定的工作表不存在");
|
|
558
|
+
const r = u(n.range), s = B(o.row, r.top, r.bottom), i = B(o.column, r.left, r.right), a = Math.min(
|
|
559
|
+
r.bottom,
|
|
560
|
+
s + T(o.rows, 24, 100) - 1
|
|
561
|
+
), l = Math.min(
|
|
562
|
+
r.right,
|
|
563
|
+
i + T(o.columns, 12, 32) - 1
|
|
564
|
+
), c = Array.from({ length: a - s + 1 }, (f, g) => ({
|
|
565
|
+
row: s + g,
|
|
566
|
+
cells: []
|
|
567
|
+
})), m = /* @__PURE__ */ new Set();
|
|
568
|
+
for (const f of t.template.pages.slice(
|
|
569
|
+
n.pageStart,
|
|
570
|
+
n.pageStart + n.pageCount
|
|
571
|
+
))
|
|
572
|
+
for (const g of f.components) {
|
|
573
|
+
if (g.kind === "list" || !g.grid || g.meta?.xlsxSheet !== e)
|
|
574
|
+
continue;
|
|
575
|
+
const h = u(String(g.meta.xlsxRange));
|
|
576
|
+
if (h.bottom < s || h.top > a) continue;
|
|
577
|
+
const w = C(
|
|
578
|
+
g.grid,
|
|
579
|
+
g.widthMm,
|
|
580
|
+
g.heightMm
|
|
581
|
+
);
|
|
582
|
+
for (const b of w.cells)
|
|
583
|
+
p(b.cell, h.top + b.ri, h.left + b.ci);
|
|
584
|
+
}
|
|
585
|
+
for (const f of c) {
|
|
586
|
+
for (let g = i; g <= l; g++)
|
|
587
|
+
m.has(`${f.row}:${g}`) || f.cells.push({
|
|
588
|
+
address: `${$(g)}${f.row}`,
|
|
589
|
+
row: f.row,
|
|
590
|
+
column: g,
|
|
591
|
+
text: "",
|
|
592
|
+
rowSpan: 1,
|
|
593
|
+
colSpan: 1,
|
|
594
|
+
continued: !1
|
|
595
|
+
});
|
|
596
|
+
f.cells.sort((g, h) => g.column - h.column);
|
|
597
|
+
}
|
|
598
|
+
return {
|
|
599
|
+
top: s,
|
|
600
|
+
bottom: a,
|
|
601
|
+
left: i,
|
|
602
|
+
right: l,
|
|
603
|
+
source: r,
|
|
604
|
+
rows: c,
|
|
605
|
+
columns: Array.from({ length: l - i + 1 }, (f, g) => ({
|
|
606
|
+
column: i + g,
|
|
607
|
+
name: $(i + g)
|
|
608
|
+
}))
|
|
609
|
+
};
|
|
610
|
+
function p(f, g, h) {
|
|
611
|
+
const w = g + (f.rowSpan ?? 1) - 1, b = h + (f.colSpan ?? 1) - 1;
|
|
612
|
+
if (w < s || g > a || b < i || h > l)
|
|
613
|
+
return;
|
|
614
|
+
const y = Math.max(s, g), E = Math.max(i, h), R = Math.min(a, w) - y + 1, O = Math.min(l, b) - E + 1;
|
|
615
|
+
c[y - s].cells.push({
|
|
616
|
+
address: `${$(h)}${g}`,
|
|
617
|
+
row: y,
|
|
618
|
+
column: E,
|
|
619
|
+
text: f.text ?? f.rawText ?? String(f.value ?? ""),
|
|
620
|
+
rowSpan: R,
|
|
621
|
+
colSpan: O,
|
|
622
|
+
continued: y !== g || E !== h,
|
|
623
|
+
style: f.style
|
|
624
|
+
});
|
|
625
|
+
for (let M = y; M < y + R; M++)
|
|
626
|
+
for (let v = E; v < E + O; v++)
|
|
627
|
+
m.add(`${M}:${v}`);
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
export {
|
|
631
|
+
gt as a,
|
|
632
|
+
Q as b,
|
|
633
|
+
xt as c,
|
|
634
|
+
at as d,
|
|
635
|
+
Mt as e,
|
|
636
|
+
nt as f,
|
|
637
|
+
vt as g,
|
|
638
|
+
u as h,
|
|
639
|
+
$ as i,
|
|
640
|
+
wt as j,
|
|
641
|
+
yt as k,
|
|
642
|
+
Et as l,
|
|
643
|
+
bt as m,
|
|
644
|
+
$t as n,
|
|
645
|
+
St as p,
|
|
646
|
+
A as r,
|
|
647
|
+
dt as s,
|
|
648
|
+
st as v
|
|
649
|
+
};
|