159159 </div >
160160 <div v-else-if =" rowType==='data'" style =" margin-top :6px ;color :#909399 ;font-size :11px ;line-height :1.6 " >
161161 绑定数据集后按<b >每条数据自动扩展一行</b >。单元格可写 <code >${字段名}</code >、<code >${数据集.字段}</code >、<code >${rowIndex}</code >(行号)或 <code >=公式</code >。
162+ <el-checkbox v-model =" rowZebra" size =" small" @change =" updateRowZebra" style =" margin-top :4px " >斑马纹(预览隔行浅灰底)</el-checkbox >
162163 </div >
163164 <div v-else-if =" rowType==='footer'" style =" margin-top :6px ;color :#909399 ;font-size :11px ;line-height :1.6 " >
164165 渲染 1 次(数据行下方)。绑定数据集后支持聚合:<code >${金额:SUM}</code >、<code >${字段:AVG}</code >、MIN / MAX / COUNT。
@@ -397,6 +398,8 @@ const cellValue = ref(''), rowType = ref('data')
397398const rowTypes = ref <string []>([]) // 每行类型: title/header/data/footer
398399const rowDatasets = ref <Record <number , string >>({}) // 行号 → 数据集id
399400const rowDataset = ref (' ' ) // 当前选中行绑定的数据集
401+ const rowZebras = ref <Record <number , boolean >>({}) // 行号 → 斑马纹开关
402+ const rowZebra = ref (false ) // 当前选中行的斑马纹
400403const showPreview = ref (false ), pageSettingsVisible = ref (false )
401404const formulaHelpVisible = ref (false )
402405const previewHtml = ref (' ' ), previewParams = ref <any []>([])
@@ -413,7 +416,7 @@ const canUndo = computed(() => undoStack.value.length > 0)
413416const canRedo = computed (() => redoStack .value .length > 0 )
414417
415418function snapState() {
416- return JSON .stringify ({ cells: cells .value , rows: rowHeights .value , types: rowTypes .value .slice (), datasets: { ... rowDatasets .value }, cols: colWidths .value , maxR: maxRows .value , maxC: maxCols .value })
419+ return JSON .stringify ({ cells: cells .value , rows: rowHeights .value , types: rowTypes .value .slice (), datasets: { ... rowDatasets .value }, zebras: { ... rowZebras . value }, cols: colWidths .value , maxR: maxRows .value , maxC: maxCols .value })
417420}
418421
419422function pushHistory() {
@@ -441,6 +444,7 @@ function restoreState(snap: string) {
441444 rowHeights .value = s .rows || []
442445 rowTypes .value = s .types || []
443446 rowDatasets .value = s .datasets || {}
447+ rowZebras .value = s .zebras || {}
444448 colWidths .value = s .cols || []
445449 maxRows .value = s .maxR || 10
446450 maxCols .value = s .maxC || 6
@@ -630,6 +634,8 @@ function loadLayoutJson() {
630634 rowTypes .value = layout .rows ?.map ((r : any )=> r .type || ' header' ) || []
631635 rowDatasets .value = {}
632636 layout .rows ?.forEach ((r : any , i : number ) => { if (r .dataset ) rowDatasets .value [i ] = r .dataset })
637+ rowZebras .value = {}
638+ layout .rows ?.forEach ((r : any , i : number ) => { if (r .zebra === true ) rowZebras .value [i ] = true })
633639 colWidths .value = layout .cols ?.map ((c : any )=> c .width || 100 ) || []
634640 pageSize .value = layout .page ?.size || ' A4' ; pageOrientation .value = layout .page ?.orientation || ' portrait'
635641 if (layout .page ?.margin ) Object .assign (pageMargin , layout .page .margin )
@@ -683,6 +689,7 @@ function onCellMouseDown(_e:MouseEvent, r:number, c:number) {
683689 cellValue .value = cell ?.value || ' '
684690 rowType .value = rowTypes .value [r ] || (rowHeights .value [r ]=== ' data' ? ' data' : ' header' )
685691 rowDataset .value = rowDatasets .value [r ] || ' '
692+ rowZebra .value = !! rowZebras .value [r ]
686693 boldActive .value = cell ?.style ?.bold || false
687694 italicActive .value = cell ?.style ?.italic || false
688695 selFontSize .value = cell ?.style ?.fontSize || 12
@@ -762,6 +769,11 @@ function updateRowDataset() {
762769 if (rowDataset .value ) rowDatasets .value [selR .value ] = rowDataset .value
763770 else delete rowDatasets .value [selR .value ]
764771}
772+ function updateRowZebra() {
773+ if (selR .value < 0 ) return
774+ if (rowZebra .value ) rowZebras .value [selR .value ] = true
775+ else delete rowZebras .value [selR .value ]
776+ }
765777
766778function applyStyle(prop : string , val ? : any ) {
767779 pushHistory ()
@@ -834,13 +846,19 @@ function insertRow(dir: number) {
834846 cells .value = newCells
835847 rowHeights .value .splice (r , 0 , 25 )
836848 rowTypes .value .splice (r , 0 , ' header' )
837- // 数据集绑定按新行号重映射
849+ // 数据集绑定/斑马纹按新行号重映射
838850 const newDs: Record <number , string > = {}
839851 for (const [k, v] of Object .entries (rowDatasets .value )) {
840852 const idx = Number (k )
841853 newDs [idx >= r ? idx + 1 : idx ] = v
842854 }
843855 rowDatasets .value = newDs
856+ const newZb: Record <number , boolean > = {}
857+ for (const [k, v] of Object .entries (rowZebras .value )) {
858+ const idx = Number (k )
859+ newZb [idx >= r ? idx + 1 : idx ] = v
860+ }
861+ rowZebras .value = newZb
844862 maxRows .value ++
845863 if (dir > 0 ) selR .value ++
846864}
@@ -859,14 +877,21 @@ function deleteRow() {
859877 cells .value = newCells
860878 rowHeights .value .splice (r , 1 )
861879 rowTypes .value .splice (r , 1 )
862- // 数据集绑定按新行号重映射
880+ // 数据集绑定/斑马纹按新行号重映射
863881 const newDs: Record <number , string > = {}
864882 for (const [k, v] of Object .entries (rowDatasets .value )) {
865883 const idx = Number (k )
866884 if (idx > r ) newDs [idx - 1 ] = v
867885 else if (idx < r ) newDs [idx ] = v
868886 }
869887 rowDatasets .value = newDs
888+ const newZb: Record <number , boolean > = {}
889+ for (const [k, v] of Object .entries (rowZebras .value )) {
890+ const idx = Number (k )
891+ if (idx > r ) newZb [idx - 1 ] = v
892+ else if (idx < r ) newZb [idx ] = v
893+ }
894+ rowZebras .value = newZb
870895 maxRows .value --
871896 selR .value = Math .min (selR .value , maxRows .value - 1 )
872897}
@@ -912,7 +937,8 @@ function saveLayoutJson() {
912937 height:typeof rowHeights .value [r ]=== ' string' ? 25 : (rowHeights .value [r ]|| 25 ),
913938 type:rowTypes .value [r ] || (rowHeights .value [r ]=== ' data' ? ' data' : ' header' ),
914939 dataset:rowDatasets .value [r ] || ' ' ,
915- expand:(rowTypes .value [r ]=== ' data' && rowDatasets .value [r ]) ? ' auto' : ' '
940+ expand:(rowTypes .value [r ]=== ' data' && rowDatasets .value [r ]) ? ' auto' : ' ' ,
941+ zebra:rowZebras .value [r ] === true
916942 })
917943 const cols= []; for (let c= 0 ;c < maxCols .value ;c ++ ) cols .push ({width:colWidths .value [c ]|| 100 })
918944 const cellArr= Object .entries (cells .value ).map (([k ,v ]: any )=> ({r:Number (k .split (' ,' )[0 ]),c:Number (k .split (' ,' )[1 ]),... v }))
0 commit comments