cnf
2025-05-15 5f0b94e9c252e507b4c09badf923796151be0d03
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
<template>
  <view class="container">
    <view v-if="loading">加载中...</view>
    <view v-if="error" class="error">无法加载文件</view>
    <view v-if="data" class="table-container">
      <view class="table">
        <view class="row" v-for="(row, rowIndex) in data" :key="rowIndex">
          <view
            class="cell"
            v-for="(cell, cellIndex) in row"
            :key="cellIndex"
            :rowspan="getMergeSpan(rowIndex, cellIndex, 'row')"
            :colspan="getMergeSpan(rowIndex, cellIndex, 'col')"
          >
            {{ cell }}
          </view>
        </view>
      </view>
    </view>
  </view>
</template>
 
<script>
import * as XLSX from 'xlsx';
 
export default {
  data() {
    return {
      loading: false,
      error: false,
      data: null, // 用于存储解析后的 Excel 数据
      merges: [] // 用于存储合并单元格信息
    };
  },
  onLoad() {
    this.loadExcelFile();
  },
  methods: {
    async loadExcelFile() {
      this.loading = true;
      this.error = false;
      this.data = null;
 
      try {
        // 从本地存储中读取 Base64 数据
        const base64Data = uni.getStorageSync('excelBase64Data');
        const arrayBuffer = this.base64ToArrayBuffer(base64Data);
 
        const workbook = XLSX.read(arrayBuffer, { type: 'buffer' });
        const firstSheetName = workbook.SheetNames[0];
        const worksheet = workbook.Sheets[firstSheetName];
 
        // 初始化合并单元格信息
        this.initMerge(worksheet);
 
        // 将工作表转换为 JSON 格式
        const jsonData = XLSX.utils.sheet_to_json(worksheet, { header: 1 });
 
        // 动态计算最大列数
        const maxColumns = Math.max(...jsonData.map(row => row.length));
 
        // 为每行填充空单元格
        const normalizedData = jsonData.map(row => {
          while (row.length < maxColumns) {
            row.push(""); // 填充空单元格
          }
          return row;
        });
 
        this.data = normalizedData;
        console.log('Normalized Data:', this.data);
        console.log('Merges:', this.merges);
      } catch (error) {
        console.error('Failed to load Excel file:', error);
        this.error = true;
      } finally {
        this.loading = false;
      }
    },
    base64ToArrayBuffer(base64) {
      const binaryString = atob(base64);
      const len = binaryString.length;
      const bytes = new Uint8Array(len);
      for (let i = 0; i < len; i++) {
        bytes[i] = binaryString.charCodeAt(i);
      }
      return bytes.buffer;
    },
    initMerge(worksheet) {
      const merges = worksheet['!merges'];
      if (!merges) return;
 
      this.merges = merges.map(merge => [
        merge.s.r, merge.s.c, merge.e.r, merge.e.c
      ]);
    },
    getMergeSpan(rowIndex, cellIndex, type) {
      for (const merge of this.merges) {
        const [startRow, startCol, endRow, endCol] = merge;
 
        // 检查当前单元格是否在合并范围内
        if (
          rowIndex >= startRow &&
          rowIndex <= endRow &&
          cellIndex >= startCol &&
          cellIndex <= endCol
        ) {
          // 如果是起始单元格,返回合并的行/列跨度
          if (rowIndex === startRow && cellIndex === startCol) {
            return type === 'row'
              ? endRow - startRow + 1
              : endCol - startCol + 1;
          } else {
            // 如果不是起始单元格,返回 0,表示该单元格被合并
            return 0;
          }
        }
      }
      return 1; // 默认情况下,每个单元格占用一行一列
    }
  }
};
</script>
 
<style scoped>
.container {
  padding: 20px;
}
 
.table-container {
  overflow-x: auto; /* 添加横向滚动条 */
  overflow-y: auto; /* 添加纵向滚动条 */
  max-width: 100%; /* 限制表格宽度 */
  max-height: 1000px; /* 限制表格高度 */
  border: 1px solid #ccc;
}
 
.table {
  display: table;
  table-layout: fixed; /* 固定表格布局 */
  border-collapse: collapse;
  width: 100%; /* 确保表格宽度占满容器 */
}
 
.row {
  display: table-row;
}
 
.cell {
  display: table-cell;
  padding: 8px;
  border: 1px solid #ccc;
  text-overflow: ellipsis; /* 超出部分显示省略号 */
  white-space: nowrap; /* 防止内容换行 */
  overflow: hidden; /* 隐藏超出内容 */
  width: 100px; /* 固定单元格宽度 */
}
 
.error {
  color: red;
}
</style>