@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.
Files changed (95) hide show
  1. package/README.md +28 -10
  2. package/dist/ExcelBindingWizard-DiaxvWpQ.cjs +1 -0
  3. package/dist/ExcelBindingWizard-RLJIXKKG.js +816 -0
  4. package/dist/{ReportPreview-DRBAUkxj.js → ReportPreview-B5ZNEasW.js} +23 -22
  5. package/dist/ReportPreview-DRtVPUYo.cjs +6 -0
  6. package/dist/RuleEditor-N4qnMZ-Z.cjs +1 -0
  7. package/dist/RuleEditor-ynnUEK0s.js +1575 -0
  8. package/dist/TemplateReviewPanel-C_Lmzis6.cjs +1 -0
  9. package/dist/TemplateReviewPanel-Cn32OY4_.js +173 -0
  10. package/dist/{_plugin-vue_export-helper-DPbiz14D.js → _plugin-vue_export-helper-8SL1F89S.js} +2 -2
  11. package/dist/analytics.cjs +1 -1
  12. package/dist/analytics.d.cts +188 -5
  13. package/dist/analytics.d.ts +188 -5
  14. package/dist/analytics.js +68 -202
  15. package/dist/{assets-B9qJku3V.js → assets-DDsfEi8R.js} +3 -3
  16. package/dist/{assets-RZan7EyL.cjs → assets-ahTRUXRk.cjs} +1 -1
  17. package/dist/binding-preview-B5834rml.cjs +2 -0
  18. package/dist/binding-preview-ChXjN5L5.js +649 -0
  19. package/dist/{capabilities-joSutDF8.js → capabilities-Cm9hZ3uV.js} +5 -5
  20. package/dist/{capabilities-xGTpnPjJ.cjs → capabilities-DYzWL7KS.cjs} +1 -1
  21. package/dist/dataset-BkRmwgeJ.cjs +1 -0
  22. package/dist/dataset-H5pFuQGU.js +121 -0
  23. package/dist/defaults-DXhiM1ZD.js +10 -0
  24. package/dist/defaults-xhmcLLrf.cjs +1 -0
  25. package/dist/designer.cjs +2 -1
  26. package/dist/designer.d.cts +1391 -6
  27. package/dist/designer.d.ts +1391 -6
  28. package/dist/designer.js +2636 -673
  29. package/dist/grid-geometry-BNptEcMm.js +65 -0
  30. package/dist/grid-geometry-CZ_cYB6O.cjs +1 -0
  31. package/dist/import-template-CNMLJSQw.js +23030 -0
  32. package/dist/import-template-CpxunKVp.cjs +29 -0
  33. package/dist/index.cjs +7 -7
  34. package/dist/index.d.cts +202 -3
  35. package/dist/index.d.ts +202 -3
  36. package/dist/index.js +554 -535
  37. package/dist/matrix-CNPDJxED.js +745 -0
  38. package/dist/matrix-Div9Ilh3.cjs +1 -0
  39. package/dist/pdf.cjs +46 -46
  40. package/dist/pdf.d.cts +2 -0
  41. package/dist/pdf.d.ts +2 -0
  42. package/dist/pdf.js +17 -16
  43. package/dist/{plugin-BurDDMcd.js → plugin-BWwIgZXV.js} +1 -1
  44. package/dist/{plugin-DSFu51Ua.cjs → plugin-Dg-J1Rbm.cjs} +1 -1
  45. package/dist/progress-7OSZbFok.js +39 -0
  46. package/dist/progress-BnLiS5eH.cjs +1 -0
  47. package/dist/render-plan-7xpGrCEl.cjs +1 -0
  48. package/dist/render-plan-Ck6koX9L.js +13 -0
  49. package/dist/server/node.d.cts +62 -0
  50. package/dist/server/node.d.ts +62 -0
  51. package/dist/server-node.cjs +1 -1
  52. package/dist/server-node.js +373 -145
  53. package/dist/server.cjs +1 -1
  54. package/dist/server.d.cts +311 -0
  55. package/dist/server.d.ts +311 -0
  56. package/dist/server.js +590 -186
  57. package/dist/{style-Dv5o_x6b.js → style-CQ1PK8ZB.js} +5 -5
  58. package/dist/style-UgIJSA1F.cjs +1 -0
  59. package/dist/style.css +1 -1
  60. package/dist/template-registry-CHMYZ7SD.cjs +1 -0
  61. package/dist/template-registry-R61AMCr0.js +433 -0
  62. package/dist/template-review-hvWWQFsi.js +1027 -0
  63. package/dist/template-review-jEcOfmGr.cjs +1 -0
  64. package/dist/textwrap-CWHyzkBH.cjs +4 -0
  65. package/dist/{textwrap-DOl04hCQ.js → textwrap-DE1kgcJB.js} +1 -1
  66. package/dist/{validate-DfHPD8wX.cjs → validate-BDiMqkJC.cjs} +1 -1
  67. package/dist/{validate-S6CgIm5d.js → validate-DWPF7icl.js} +13 -13
  68. package/dist/vue/async.d.cts +186 -0
  69. package/dist/vue/async.d.ts +186 -0
  70. package/dist/vue/index.d.cts +271 -3
  71. package/dist/vue/index.d.ts +271 -3
  72. package/dist/vue-async.cjs +1 -1
  73. package/dist/vue-async.js +3 -3
  74. package/dist/vue.cjs +1 -1
  75. package/dist/vue.js +4 -4
  76. package/dist/worker.cjs +1 -1
  77. package/dist/worker.d.cts +2 -0
  78. package/dist/worker.d.ts +2 -0
  79. package/dist/worker.js +1 -1
  80. package/dist/xlsx.cjs +2 -30
  81. package/dist/xlsx.d.cts +268 -0
  82. package/dist/xlsx.d.ts +268 -0
  83. package/dist/xlsx.js +220 -23440
  84. package/package.json +1 -1
  85. package/dist/ReportPreview-DjGeWHY-.cjs +0 -6
  86. package/dist/progress-DD964VAB.js +0 -102
  87. package/dist/progress-KvhwXZ1Q.cjs +0 -1
  88. package/dist/render-plan-CckPEQyf.cjs +0 -1
  89. package/dist/render-plan-uzZYYSy1.js +0 -19
  90. package/dist/report-source-BXHNy_AD.js +0 -755
  91. package/dist/report-source-CCAvFE3t.cjs +0 -1
  92. package/dist/style-CpwiOPyB.cjs +0 -1
  93. package/dist/template-registry-DWExx0gU.cjs +0 -1
  94. package/dist/template-registry-NpOakidD.js +0 -354
  95. 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
+ };