online-analysis-button 1.0.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 +380 -0
- package/dist/online-analysis-button.cjs.js +2 -0
- package/dist/online-analysis-button.cjs.js.map +1 -0
- package/dist/online-analysis-button.css +1 -0
- package/dist/online-analysis-button.es.js +2 -0
- package/dist/online-analysis-button.es.js.map +1 -0
- package/dist/online-analysis-button.umd.js +2 -0
- package/dist/online-analysis-button.umd.js.map +1 -0
- package/package.json +65 -0
package/README.md
ADDED
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
# Online Analysis Button
|
|
2
|
+
|
|
3
|
+
一个专门适配 Element UI `el-table` 的 Vue 2 组件,可以自动提取表格数据并进行透视分析。
|
|
4
|
+
|
|
5
|
+
## ✨ 特性
|
|
6
|
+
|
|
7
|
+
- 🚀 **一键分析**:点击按钮即可自动提取 Element UI el-table 中的数据
|
|
8
|
+
- 📊 **透视分析**:基于 PivotTable.js 的强大透视表功能
|
|
9
|
+
- 🎨 **美观界面**:现代化的 UI 设计,支持多种主题
|
|
10
|
+
- 📤 **数据导出**:支持导出为 Excel 和 HTML 格式
|
|
11
|
+
- 🔍 **数据过滤**:支持多种过滤条件
|
|
12
|
+
- 📱 **响应式设计**:完美适配各种屏幕尺寸
|
|
13
|
+
- 🎯 **灵活配置**:支持自定义按钮位置、样式和表格选择器
|
|
14
|
+
- 🖥️ **弹出式展示**:透视分析页面以模态框形式展示,不干扰原页面布局
|
|
15
|
+
|
|
16
|
+
## 📦 安装
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install online-analysis-button
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## 🚀 快速开始
|
|
23
|
+
|
|
24
|
+
### 方式一:全局注册
|
|
25
|
+
|
|
26
|
+
```javascript
|
|
27
|
+
import Vue from 'vue'
|
|
28
|
+
import OnlineAnalysisButton from 'online-analysis-button'
|
|
29
|
+
|
|
30
|
+
Vue.use(OnlineAnalysisButton)
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### 方式二:局部注册
|
|
34
|
+
|
|
35
|
+
```javascript
|
|
36
|
+
import { OnlineAnalysisButton } from 'online-analysis-button'
|
|
37
|
+
|
|
38
|
+
export default {
|
|
39
|
+
components: {
|
|
40
|
+
OnlineAnalysisButton
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## 📖 使用方法
|
|
46
|
+
|
|
47
|
+
### 基础用法
|
|
48
|
+
|
|
49
|
+
```html
|
|
50
|
+
<template>
|
|
51
|
+
<div>
|
|
52
|
+
<!-- 你的 Element UI 表格 -->
|
|
53
|
+
<el-table :data="tableData">
|
|
54
|
+
<el-table-column prop="name" label="姓名" />
|
|
55
|
+
<el-table-column prop="age" label="年龄" />
|
|
56
|
+
<el-table-column prop="city" label="城市" />
|
|
57
|
+
<el-table-column prop="sales" label="销售额" />
|
|
58
|
+
</el-table>
|
|
59
|
+
|
|
60
|
+
<!-- 分析按钮 -->
|
|
61
|
+
<OnlineAnalysisButton />
|
|
62
|
+
</div>
|
|
63
|
+
</template>
|
|
64
|
+
|
|
65
|
+
<script>
|
|
66
|
+
export default {
|
|
67
|
+
data() {
|
|
68
|
+
return {
|
|
69
|
+
tableData: [
|
|
70
|
+
{ name: '张三', age: 25, city: '北京', sales: 10000 },
|
|
71
|
+
{ name: '李四', age: 30, city: '上海', sales: 15000 },
|
|
72
|
+
{ name: '王五', age: 28, city: '广州', sales: 12000 }
|
|
73
|
+
]
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
</script>
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### 自定义配置
|
|
81
|
+
|
|
82
|
+
```html
|
|
83
|
+
<template>
|
|
84
|
+
<div>
|
|
85
|
+
<el-table id="my-table" :data="tableData">
|
|
86
|
+
<!-- 表格列 -->
|
|
87
|
+
</el-table>
|
|
88
|
+
|
|
89
|
+
<!-- 自定义按钮 -->
|
|
90
|
+
<OnlineAnalysisButton
|
|
91
|
+
position="top-right"
|
|
92
|
+
button-text="开始分析"
|
|
93
|
+
button-class="custom-btn"
|
|
94
|
+
table-selector="#my-table"
|
|
95
|
+
:auto-extract="true"
|
|
96
|
+
/>
|
|
97
|
+
</div>
|
|
98
|
+
</template>
|
|
99
|
+
|
|
100
|
+
<style>
|
|
101
|
+
.custom-btn {
|
|
102
|
+
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
|
|
103
|
+
}
|
|
104
|
+
</style>
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## 🎛️ Props
|
|
108
|
+
|
|
109
|
+
| 参数 | 类型 | 默认值 | 说明 |
|
|
110
|
+
|------|------|--------|------|
|
|
111
|
+
| `position` | String | `'bottom-right'` | 按钮位置:`'bottom-right'`, `'bottom-left'`, `'top-right'`, `'top-left'` |
|
|
112
|
+
| `buttonText` | String | `'📊 透视分析'` | 按钮显示文本 |
|
|
113
|
+
| `buttonClass` | String | `''` | 自定义按钮样式类名 |
|
|
114
|
+
| `tableSelector` | String | `'.el-table'` | Element UI 表格选择器,用于指定要分析的表格 |
|
|
115
|
+
| `autoExtract` | Boolean | `true` | 是否自动提取表格数据 |
|
|
116
|
+
|
|
117
|
+
## 🎯 方法
|
|
118
|
+
|
|
119
|
+
### setData(data)
|
|
120
|
+
|
|
121
|
+
手动设置要分析的数据。
|
|
122
|
+
|
|
123
|
+
```javascript
|
|
124
|
+
this.$refs.analysisButton.setData([
|
|
125
|
+
{ name: '张三', age: 25, city: '北京' },
|
|
126
|
+
{ name: '李四', age: 30, city: '上海' }
|
|
127
|
+
])
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### getData()
|
|
131
|
+
|
|
132
|
+
获取当前分析的数据。
|
|
133
|
+
|
|
134
|
+
```javascript
|
|
135
|
+
const data = this.$refs.analysisButton.getData()
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## 📊 功能说明
|
|
139
|
+
|
|
140
|
+
### 1. 数据提取
|
|
141
|
+
|
|
142
|
+
组件会自动查找页面中符合 `tableSelector` 的第一个 Element UI `el-table` 组件,并提取其中的数据。支持以下特性:
|
|
143
|
+
|
|
144
|
+
- 自动识别表头(`el-table__header-wrapper`)
|
|
145
|
+
- 自动提取数据行(`el-table__body-wrapper`)
|
|
146
|
+
- 智能数据类型转换(数字、字符串等)
|
|
147
|
+
- 支持多列表格
|
|
148
|
+
|
|
149
|
+
### 2. 透视分析
|
|
150
|
+
|
|
151
|
+
提供强大的透视表功能:
|
|
152
|
+
|
|
153
|
+
- **拖拽字段**:将字段拖拽到行、列、值区域
|
|
154
|
+
- **多种聚合方式**:计数、求和、平均值、最大值、最小值等
|
|
155
|
+
- **多种渲染器**:表格、热力图、柱状图、折线图等
|
|
156
|
+
- **数据过滤**:支持多种过滤条件
|
|
157
|
+
|
|
158
|
+
### 3. 数据导出
|
|
159
|
+
|
|
160
|
+
支持导出为多种格式:
|
|
161
|
+
|
|
162
|
+
- **Excel (.xlsx)**:透视表数据和原始数据
|
|
163
|
+
- **HTML (.html)**:带样式的 HTML 文件
|
|
164
|
+
|
|
165
|
+
### 4. 数据过滤
|
|
166
|
+
|
|
167
|
+
支持多种过滤操作:
|
|
168
|
+
|
|
169
|
+
- 等于、不等于
|
|
170
|
+
- 包含、不包含
|
|
171
|
+
- 大于、小于、大于等于、小于等于
|
|
172
|
+
- 包含于(多选)、不包含于(多选)
|
|
173
|
+
|
|
174
|
+
### 5. 弹出式展示
|
|
175
|
+
|
|
176
|
+
- 透视分析页面以模态框形式展示
|
|
177
|
+
- 不干扰原页面布局
|
|
178
|
+
- 支持全屏模式
|
|
179
|
+
- 点击遮罩层可关闭
|
|
180
|
+
|
|
181
|
+
## 🎨 样式定制
|
|
182
|
+
|
|
183
|
+
组件使用了 scoped CSS,不会影响你的页面样式。如果需要自定义样式,可以通过以下方式:
|
|
184
|
+
|
|
185
|
+
### 1. 使用 buttonClass 属性
|
|
186
|
+
|
|
187
|
+
```html
|
|
188
|
+
<OnlineAnalysisButton button-class="my-custom-button" />
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
```css
|
|
192
|
+
.my-custom-button {
|
|
193
|
+
background: your-custom-gradient;
|
|
194
|
+
/* 其他样式 */
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### 2. 全局样式覆盖
|
|
199
|
+
|
|
200
|
+
```css
|
|
201
|
+
/* 覆盖按钮样式 */
|
|
202
|
+
.online-analysis-button .analysis-button {
|
|
203
|
+
/* 你的样式 */
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/* 覆盖模态框样式 */
|
|
207
|
+
.modal-content {
|
|
208
|
+
/* 你的样式 */
|
|
209
|
+
}
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
## 🔧 依赖
|
|
213
|
+
|
|
214
|
+
- Vue 2.6.0+
|
|
215
|
+
- Element UI(用于 el-table)
|
|
216
|
+
- jQuery 3.7.1+
|
|
217
|
+
- jQuery UI 1.14.2+
|
|
218
|
+
- PivotTable.js 2.23.0+
|
|
219
|
+
- XLSX 0.18.5+
|
|
220
|
+
- Bootstrap 4.6.2+
|
|
221
|
+
- Vue Draggable 2.24.3+
|
|
222
|
+
|
|
223
|
+
## 📝 开发
|
|
224
|
+
|
|
225
|
+
### 安装依赖
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
npm install
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### 构建库
|
|
232
|
+
|
|
233
|
+
```bash
|
|
234
|
+
npm run build:lib
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### 预览
|
|
238
|
+
|
|
239
|
+
```bash
|
|
240
|
+
npm run preview
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
## 🚀 发布到 npm
|
|
244
|
+
|
|
245
|
+
### 1. 准备工作
|
|
246
|
+
|
|
247
|
+
确保你已经:
|
|
248
|
+
|
|
249
|
+
- [ ] 注册了 [npm](https://www.npmjs.com/) 账号
|
|
250
|
+
- [ ] 完善了 `package.json` 中的信息(作者、仓库等)
|
|
251
|
+
- [ ] 测试了构建产物
|
|
252
|
+
|
|
253
|
+
### 2. 登录 npm
|
|
254
|
+
|
|
255
|
+
```bash
|
|
256
|
+
npm login
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
### 3. 发布
|
|
260
|
+
|
|
261
|
+
```bash
|
|
262
|
+
npm publish
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
### 4. 更新版本
|
|
266
|
+
|
|
267
|
+
如果需要更新版本:
|
|
268
|
+
|
|
269
|
+
```bash
|
|
270
|
+
# 更新版本号(patch/minor/major)
|
|
271
|
+
npm version patch
|
|
272
|
+
|
|
273
|
+
# 重新构建
|
|
274
|
+
npm run build:lib
|
|
275
|
+
|
|
276
|
+
# 发布
|
|
277
|
+
npm publish
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
## 📄 License
|
|
281
|
+
|
|
282
|
+
MIT
|
|
283
|
+
|
|
284
|
+
## 🤝 贡献
|
|
285
|
+
|
|
286
|
+
欢迎提交 Issue 和 Pull Request!
|
|
287
|
+
|
|
288
|
+
## 📮 联系方式
|
|
289
|
+
|
|
290
|
+
如有问题或建议,请提交 Issue。
|
|
291
|
+
|
|
292
|
+
## 🙏 致谢
|
|
293
|
+
|
|
294
|
+
- [PivotTable.js](https://github.com/nicolaskruchten/pivottable) - 强大的透视表库
|
|
295
|
+
- [Element UI](https://element.eleme.io/) - 优秀的 Vue 2 UI 组件库
|
|
296
|
+
- [Vue.js](https://vuejs.org/) - 渐进式 JavaScript 框架
|
|
297
|
+
- [Vite](https://vitejs.dev/) - 下一代前端构建工具
|
|
298
|
+
|
|
299
|
+
## 📸 示例
|
|
300
|
+
|
|
301
|
+
### 完整示例
|
|
302
|
+
|
|
303
|
+
```html
|
|
304
|
+
<template>
|
|
305
|
+
<div>
|
|
306
|
+
<h1>销售数据分析</h1>
|
|
307
|
+
|
|
308
|
+
<el-table :data="salesData" border style="width: 100%">
|
|
309
|
+
<el-table-column prop="date" label="日期" width="180" />
|
|
310
|
+
<el-table-column prop="name" label="销售员" width="180" />
|
|
311
|
+
<el-table-column prop="product" label="产品" />
|
|
312
|
+
<el-table-column prop="quantity" label="数量" />
|
|
313
|
+
<el-table-column prop="price" label="单价" />
|
|
314
|
+
<el-table-column prop="total" label="总额" />
|
|
315
|
+
</el-table>
|
|
316
|
+
|
|
317
|
+
<!-- 分析按钮 -->
|
|
318
|
+
<OnlineAnalysisButton
|
|
319
|
+
position="bottom-right"
|
|
320
|
+
button-text="📊 数据透视分析"
|
|
321
|
+
/>
|
|
322
|
+
</div>
|
|
323
|
+
</template>
|
|
324
|
+
|
|
325
|
+
<script>
|
|
326
|
+
import { OnlineAnalysisButton } from 'online-analysis-button'
|
|
327
|
+
|
|
328
|
+
export default {
|
|
329
|
+
components: {
|
|
330
|
+
OnlineAnalysisButton
|
|
331
|
+
},
|
|
332
|
+
data() {
|
|
333
|
+
return {
|
|
334
|
+
salesData: [
|
|
335
|
+
{ date: '2024-01-01', name: '张三', product: '产品A', quantity: 10, price: 100, total: 1000 },
|
|
336
|
+
{ date: '2024-01-02', name: '李四', product: '产品B', quantity: 5, price: 200, total: 1000 },
|
|
337
|
+
{ date: '2024-01-03', name: '王五', product: '产品A', quantity: 8, price: 100, total: 800 },
|
|
338
|
+
{ date: '2024-01-04', name: '张三', product: '产品C', quantity: 3, price: 300, total: 900 },
|
|
339
|
+
{ date: '2024-01-05', name: '李四', product: '产品B', quantity: 7, price: 200, total: 1400 }
|
|
340
|
+
]
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
</script>
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
点击"📊 数据透视分析"按钮后,会弹出透视分析页面,你可以:
|
|
348
|
+
|
|
349
|
+
1. 拖拽字段到行、列、值区域
|
|
350
|
+
2. 选择不同的聚合方式
|
|
351
|
+
3. 应用数据过滤
|
|
352
|
+
4. 导出分析结果
|
|
353
|
+
|
|
354
|
+
## 💡 使用技巧
|
|
355
|
+
|
|
356
|
+
1. **数据准备**:确保 el-table 的数据格式正确,字段名清晰
|
|
357
|
+
2. **按钮位置**:根据页面布局选择合适的按钮位置
|
|
358
|
+
3. **自定义选择器**:如果页面有多个 el-table,使用 `tableSelector` 指定要分析的表格
|
|
359
|
+
4. **性能优化**:对于大数据量表格,建议先进行数据过滤再分析
|
|
360
|
+
|
|
361
|
+
## 🔍 常见问题
|
|
362
|
+
|
|
363
|
+
### Q: 为什么提取不到数据?
|
|
364
|
+
|
|
365
|
+
A: 请检查:
|
|
366
|
+
1. 页面中是否存在 Element UI 的 el-table 组件
|
|
367
|
+
2. tableSelector 是否正确
|
|
368
|
+
3. 表格是否有数据
|
|
369
|
+
|
|
370
|
+
### Q: 支持哪些 Element UI 版本?
|
|
371
|
+
|
|
372
|
+
A: 支持 Element UI 2.x 版本
|
|
373
|
+
|
|
374
|
+
### Q: 可以分析多个表格吗?
|
|
375
|
+
|
|
376
|
+
A: 目前默认分析第一个匹配的表格。如需分析其他表格,请使用 `tableSelector` 属性指定。
|
|
377
|
+
|
|
378
|
+
### Q: 如何自定义透视表的样式?
|
|
379
|
+
|
|
380
|
+
A: 可以通过 CSS 覆盖 `.pivot-output` 相关的样式类。
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const t=require("vue");function e(t){const e=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(t)for(const s in t)if("default"!==s){const a=Object.getOwnPropertyDescriptor(t,s);Object.defineProperty(e,s,a.get?a:{enumerable:!0,get:()=>t[s]})}return e.default=t,Object.freeze(e)}const s=e(require("xlsx"));function a(t,e,s,a,i,n,l,o){var r="function"==typeof t?t.options:t;return e&&(r.render=e,r.staticRenderFns=s,r._compiled=!0),n&&(r._scopeId="data-v-"+n),{exports:t,options:r}}const i=a(t.extend({name:"PivotTable",props:{data:{type:Array,default:()=>[]}},data:()=>({showPivotTable:!1,filters:[],showFilters:!1,pivotInitialized:!1,fileInput:null,isLoading:!1,errorMessage:"",isFullscreen:!1,showExportMenu:!1,sidePanelCollapsed:!1,filterSearchQuery:"",expandedFilters:new Set,displayedRows:50}),computed:{hasData(){return this.data.length>0},columns(){return this.hasData?Object.keys(this.data[0]):[]},filteredData(){return 0===this.filters.length?this.data:this.data.filter(t=>this.filters.every(e=>{const s=t[e.field],a=e.value,i=e.values;switch(e.operator){case"equals":return s==a;case"not_equals":return s!=a;case"contains":return String(s).toLowerCase().includes(String(a).toLowerCase());case"not_contains":return!String(s).toLowerCase().includes(String(a).toLowerCase());case"greater_than":return Number(s)>Number(a);case"less_than":return Number(s)<Number(a);case"greater_equal":return Number(s)>=Number(a);case"less_equal":return Number(s)<=Number(a);case"in":return!(i&&i.length>0)||i.includes(s);case"not_in":return!(i&&i.length>0)||!i.includes(s);default:return!0}}))},uniqueFieldValues(){const t={};return this.columns.forEach(e=>{const s=new Set(this.data.map(t=>t[e]));t[e]=Array.from(s).sort()}),t}},watch:{showPivotTable(t){t&&!this.pivotInitialized&&this.$nextTick(()=>{this.initializePivotTable()})},filteredData:{deep:!0,handler(t,e){this.showPivotTable&&this.pivotInitialized&&this.hasDataChanged(t,e)&&this.$nextTick(()=>{this.updatePivotTable()})}},data(){this.resetDisplayedRows()}},methods:{initializePivotTable(){const t=this.$refs.pivotOutput;if(t&&($(t).empty(),this.filteredData&&0!==this.filteredData.length))try{$(t).pivotUI(this.filteredData,{rows:[],cols:[],vals:[],aggregatorName:"Count",rendererName:"Table",renderers:$.extend($.pivotUtilities.renderers,$.pivotUtilities.c3_renderers,$.pivotUtilities.d3_renderers,$.pivotUtilities.export_renderers),hiddenAttributes:[],menuLimit:500,colsLimit:10,rowsLimit:10,unusedAttrsVertical:!0,autoSortUnusedAttrs:!1,onRefresh:t=>{}}),this.pivotInitialized=!0}catch(e){}},updatePivotTable(){const t=this.$refs.pivotOutput;t&&this.pivotInitialized&&$(t).pivotUI(this.filteredData,{rows:[],cols:[],vals:[],aggregatorName:"Count",rendererName:"Table",renderers:$.extend($.pivotUtilities.renderers,$.pivotUtilities.c3_renderers,$.pivotUtilities.d3_renderers,$.pivotUtilities.export_renderers),hiddenAttributes:[],menuLimit:500,colsLimit:10,rowsLimit:10,unusedAttrsVertical:!0,autoSortUnusedAttrs:!1},!0)},addFilter(){const t=this.filters.length;this.filters.push({field:this.columns[0],operator:"equals",value:""}),this.expandedFilters.add(t)},removeFilter(t){this.filters.splice(t,1)},clearFilters(){this.filters=[]},getOperatorLabel:t=>({equals:"等于",not_equals:"不等于",contains:"包含",not_contains:"不包含",greater_than:"大于",less_than:"小于",greater_equal:"大于等于",less_equal:"小于等于",in:"包含于",not_in:"不包含于"}[t]||t),toggleMultiSelectValue(t,e){t.values||this.$set(t,"values",[]);const s=t.values.indexOf(e);s>-1?t.values.splice(s,1):t.values.push(e),t.value="",this.$forceUpdate()},isMultiSelectValueSelected:(t,e)=>t.values&&t.values.includes(e),addCustomValue(t){if(!t.customValue||""===t.customValue.trim())return;t.values||this.$set(t,"values",[]);const e=t.customValue.trim();t.values.includes(e)||t.values.push(e),this.$set(t,"customValue",""),this.$forceUpdate()},handleFileUpload(t){const e=t.target,s=e.files?.[0];if(s){this.isLoading=!0,this.errorMessage="";try{const t=s.name.split(".").pop()?.toLowerCase();if("csv"===t)this.processCSV(s);else{if("xlsx"!==t&&"xls"!==t)throw new Error("不支持的文件格式。请上传 CSV 或 Excel 文件。");this.processExcel(s)}}catch(a){this.errorMessage=a instanceof Error?a.message:"文件处理失败"}finally{this.isLoading=!1}}},processCSV(t){const e=new FileReader;e.onload=t=>{try{const e=t.target?.result,s=this.parseCSV(e);this.$emit("data-loaded",s)}catch(e){this.errorMessage=e instanceof Error?e.message:"CSV 文件处理失败"}},e.onerror=()=>{this.errorMessage="CSV 文件读取失败"},e.readAsText(t)},parseCSV(t){const e=t.split("\n").filter(t=>t.trim());if(0===e.length)return[];const s=this.parseCSVLine(e[0]),a=[];for(let i=1;i<e.length;i++){const t=this.parseCSVLine(e[i]);if(t.length===s.length){const e={};s.forEach((s,a)=>{e[s]=t[a]}),a.push(e)}}return a},parseCSVLine(t){const e=[];let s="",a=!1;for(let i=0;i<t.length;i++){const n=t[i];'"'===n?a=!a:","!==n||a?s+=n:(e.push(s.trim()),s="")}return e.push(s.trim()),e},processExcel(t){const e=new FileReader;e.onload=t=>{try{const e=t.target?.result,a=s.read(e,{type:"binary"}),i=a.SheetNames[0],n=a.Sheets[i],l=s.utils.sheet_to_json(n,{header:1});if(0===l.length)throw new Error("Excel 文件为空");const o=l[0],r=l.slice(1).filter(t=>t.length>0&&t.some(t=>void 0!==t&&""!==t)).map(t=>{const e={};return o.forEach((s,a)=>{let i=t[a];"string"!=typeof i||isNaN(Number(i))||""===i.trim()||(i=Number(i)),e[s]=void 0!==i?i:""}),e});this.$emit("data-loaded",r)}catch(e){this.errorMessage=e instanceof Error?e.message:"Excel 文件处理失败"}},e.onerror=()=>{this.errorMessage="Excel 文件读取失败"},e.readAsBinaryString(t)},triggerFileInput(){const t=this.$refs.fileInput;t&&t.click()},hasDataChanged(t,e){if(!t||!e)return!0;if(t.length!==e.length)return!0;for(let s=0;s<t.length;s++){const a=Object.keys(t[s]),i=Object.keys(e[s]);if(a.length!==i.length)return!0;for(const n of a)if(t[s][n]!==e[s][n])return!0}return!1},toggleFullscreen(){this.isFullscreen=!this.isFullscreen,this.isFullscreen?(document.body.style.overflow="hidden",document.body.classList.add("fullscreen-mode")):(document.body.style.overflow="",document.body.classList.remove("fullscreen-mode"))},exportPivotTableToExcel(){try{const t=this.$refs.pivotOutput;if(!t)return void alert("透视表未初始化,无法导出");const e=t.querySelector("table.pvtTable");if(!e)return void alert("未找到透视表数据");const a=[];e.querySelectorAll("tr").forEach(t=>{const e=[];t.querySelectorAll("th, td").forEach(t=>{const s=parseInt(t.getAttribute("colspan")||"1"),a=t.textContent?.trim()||"";for(let i=0;i<s;i++)e.push(a)}),a.push(e)});const i=s.utils.book_new(),n=s.utils.aoa_to_sheet(a),l=a[0].map(()=>({wch:15}));n["!cols"]=l,s.utils.book_append_sheet(i,n,"透视表");const o=new Date,r=o.toISOString().slice(0,10).replace(/-/g,""),c=`透视表_${r}_${o.toTimeString().slice(0,8).replace(/:/g,"")}.xlsx`;s.writeFile(i,c)}catch(t){alert("导出透视表失败,请重试")}},exportRawDataToExcel(){try{if(!this.filteredData||0===this.filteredData.length)return void alert("没有数据可导出");const t=s.utils.book_new(),e=s.utils.json_to_sheet(this.filteredData),a=this.columns.map(()=>({wch:15}));e["!cols"]=a,s.utils.book_append_sheet(t,e,"数据");const i=new Date,n=i.toISOString().slice(0,10).replace(/-/g,""),l=`数据_${n}_${i.toTimeString().slice(0,8).replace(/:/g,"")}.xlsx`;s.writeFile(t,l)}catch(t){alert("导出数据失败,请重试")}},exportPivotTableToHTML(){try{const t=this.$refs.pivotOutput;if(!t)return void alert("透视表未初始化,无法导出");const e=t.querySelector("table.pvtTable");if(!e)return void alert("未找到透视表数据");const s=`\n<!DOCTYPE html>\n<html lang="zh-CN">\n<head>\n <meta charset="UTF-8">\n <meta name="viewport" content="width=device-width, initial-scale=1.0">\n <title>透视表导出</title>\n <style>\n * {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n }\n \n body {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;\n padding: 20px;\n background: #f8fafc;\n }\n \n .container {\n max-width: 100%;\n margin: 0 auto;\n background: white;\n padding: 20px;\n border-radius: 8px;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);\n }\n \n h1 {\n color: #334155;\n margin-bottom: 20px;\n font-size: 24px;\n }\n \n .export-info {\n color: #64748b;\n margin-bottom: 20px;\n font-size: 14px;\n }\n \n table {\n width: 100%;\n border-collapse: collapse;\n margin: 20px 0;\n font-size: 14px;\n }\n \n th, td {\n border: 1px solid #e2e8f0;\n padding: 12px;\n text-align: center;\n }\n \n th {\n background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);\n color: #334155;\n font-weight: 600;\n }\n \n tr:nth-child(even) {\n background: #f8fafc;\n }\n \n tr:hover {\n background: #e2e8f0;\n }\n \n .pvtTotal, .pvtGrandTotal {\n background: linear-gradient(135deg, #dbeafe 0%, #bfdbfe 100%) !important;\n font-weight: 700;\n color: #1e40af;\n }\n \n .pvtGrandTotal {\n background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%) !important;\n color: #92400e;\n }\n </style>\n</head>\n<body>\n <div class="container">\n <h1>数据透视表</h1>\n <div class="export-info">\n 导出时间: ${(new Date).toLocaleString("zh-CN")}<br>\n 数据行数: ${this.filteredData.length}<br>\n 字段数: ${this.columns.length}\n </div>\n ${e.outerHTML}\n </div>\n</body>\n</html>`,a=new Date,i=a.toISOString().slice(0,10).replace(/-/g,""),n=`透视表_${i}_${a.toTimeString().slice(0,8).replace(/:/g,"")}.html`,l=new Blob([s],{type:"text/html;charset=utf-8"}),o=URL.createObjectURL(l),r=document.createElement("a");r.href=o,r.download=n,document.body.appendChild(r),r.click(),document.body.removeChild(r),URL.revokeObjectURL(o)}catch(t){alert("导出透视表HTML失败,请重试")}},exportRawDataToHTML(){try{if(!this.filteredData||0===this.filteredData.length)return void alert("没有数据可导出");let t="<table>\n";t+="<thead>\n<tr>\n",this.columns.forEach(e=>{t+=`<th>${e}</th>\n`}),t+="</tr>\n</thead>\n",t+="<tbody>\n",this.filteredData.forEach(e=>{t+="<tr>\n",this.columns.forEach(s=>{t+=`<td>${void 0!==e[s]?e[s]:""}</td>\n`}),t+="</tr>\n"}),t+="</tbody>\n</table>";const e=`\n<!DOCTYPE html>\n<html lang="zh-CN">\n<head>\n <meta charset="UTF-8">\n <meta name="viewport" content="width=device-width, initial-scale=1.0">\n <title>数据导出</title>\n <style>\n * {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n }\n \n body {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;\n padding: 20px;\n background: #f8fafc;\n }\n \n .container {\n max-width: 100%;\n margin: 0 auto;\n background: white;\n padding: 20px;\n border-radius: 8px;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);\n }\n \n h1 {\n color: #334155;\n margin-bottom: 20px;\n font-size: 24px;\n }\n \n .export-info {\n color: #64748b;\n margin-bottom: 20px;\n font-size: 14px;\n }\n \n table {\n width: 100%;\n border-collapse: collapse;\n margin: 20px 0;\n font-size: 14px;\n }\n \n th, td {\n border: 1px solid #e2e8f0;\n padding: 12px;\n text-align: left;\n }\n \n th {\n background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);\n color: #334155;\n font-weight: 600;\n position: sticky;\n top: 0;\n }\n \n tr:nth-child(even) {\n background: #f8fafc;\n }\n \n tr:hover {\n background: #e2e8f0;\n }\n </style>\n</head>\n<body>\n <div class="container">\n <h1>原始数据</h1>\n <div class="export-info">\n 导出时间: ${(new Date).toLocaleString("zh-CN")}<br>\n 数据行数: ${this.filteredData.length}<br>\n 字段数: ${this.columns.length}\n </div>\n ${t}\n </div>\n</body>\n</html>`,s=new Date,a=s.toISOString().slice(0,10).replace(/-/g,""),i=`数据_${a}_${s.toTimeString().slice(0,8).replace(/:/g,"")}.html`,n=new Blob([e],{type:"text/html;charset=utf-8"}),l=URL.createObjectURL(n),o=document.createElement("a");o.href=l,o.download=i,document.body.appendChild(o),o.click(),document.body.removeChild(o),URL.revokeObjectURL(l)}catch(t){alert("导出数据HTML失败,请重试")}},toggleSidePanel(){this.sidePanelCollapsed=!this.sidePanelCollapsed},toggleFilterCollapse(t){this.expandedFilters.has(t)?this.expandedFilters.delete(t):this.expandedFilters.add(t)},isFilterExpanded(t){return this.expandedFilters.has(t)},getFilteredUniqueValues(t){const e=this.uniqueFieldValues[t]||[];return this.filterSearchQuery?e.filter(t=>String(t).toLowerCase().includes(this.filterSearchQuery.toLowerCase())):e},clearFilterSearch(){this.filterSearchQuery=""},loadMoreData(){this.displayedRows+=50},resetDisplayedRows(){this.displayedRows=50}}}),function(){var t=this,e=t._self._c;return t._self._setupProxy,e("div",{staticClass:"pivot-table"},[t.hasData?e("div",{staticClass:"data-container"},[e("input",{ref:"fileInput",staticStyle:{display:"none"},attrs:{type:"file",accept:".csv,.xlsx,.xls"},on:{change:t.handleFileUpload}}),e("div",{staticClass:"toolbar"},[e("div",{staticClass:"toolbar-left"},[e("div",{staticClass:"view-toggle"},[e("button",{class:["toggle-btn",{active:!t.showPivotTable}],on:{click:function(e){t.showPivotTable=!1}}},[e("svg",{attrs:{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"2"}},[e("path",{attrs:{d:"M3 3h18v18H3zM3 9h18M3 15h18M9 3v18M15 3v18"}})]),t._v(" 原始数据 ")]),e("button",{class:["toggle-btn",{active:t.showPivotTable}],on:{click:function(e){t.showPivotTable=!0}}},[e("svg",{attrs:{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"2"}},[e("rect",{attrs:{x:"3",y:"3",width:"18",height:"18",rx:"2"}}),e("path",{attrs:{d:"M3 9h18M3 15h18M9 3v18"}})]),t._v(" 透视分析 ")])])]),e("div",{staticClass:"toolbar-right"},[e("div",{staticClass:"data-stats"},[e("div",{staticClass:"stat-item"},[e("span",{staticClass:"stat-label"},[t._v("总行数")]),e("span",{staticClass:"stat-value"},[t._v(t._s(t.data.length.toLocaleString()))])]),e("div",{staticClass:"stat-item"},[e("span",{staticClass:"stat-label"},[t._v("字段数")]),e("span",{staticClass:"stat-value"},[t._v(t._s(t.columns.length))])]),t.filters.length>0?e("div",{staticClass:"stat-item highlighted"},[e("span",{staticClass:"stat-label"},[t._v("过滤后")]),e("span",{staticClass:"stat-value"},[t._v(t._s(t.filteredData.length.toLocaleString()))])]):t._e()]),e("div",{staticClass:"toolbar-actions"},[e("div",{staticClass:"export-dropdown"},[e("button",{staticClass:"export-btn",attrs:{title:t.showPivotTable?"导出透视表":"导出原始数据"},on:{click:function(e){t.showExportMenu=!t.showExportMenu}}},[e("svg",{attrs:{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"2"}},[e("path",{attrs:{d:"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"}}),e("polyline",{attrs:{points:"7 10 12 15 17 10"}}),e("line",{attrs:{x1:"12",y1:"15",x2:"12",y2:"3"}})]),t._v(" "+t._s(t.showPivotTable?"导出透视表":"导出数据")+" "),e("svg",{attrs:{width:"12",height:"12",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"2"}},[e("polyline",{attrs:{points:"6 9 12 15 18 9"}})])]),t.showExportMenu?e("div",{staticClass:"export-menu"},[e("button",{staticClass:"export-menu-item",on:{click:function(e){t.showPivotTable?t.exportPivotTableToExcel():t.exportRawDataToExcel(),t.showExportMenu=!1}}},[e("svg",{attrs:{width:"14",height:"14",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"2"}},[e("path",{attrs:{d:"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"}}),e("polyline",{attrs:{points:"14 2 14 8 20 8"}}),e("line",{attrs:{x1:"16",y1:"13",x2:"8",y2:"13"}}),e("line",{attrs:{x1:"16",y1:"17",x2:"8",y2:"17"}}),e("polyline",{attrs:{points:"10 9 9 9 8 9"}})]),t._v(" 导出为 Excel (.xlsx) ")]),e("button",{staticClass:"export-menu-item",on:{click:function(e){t.showPivotTable?t.exportPivotTableToHTML():t.exportRawDataToHTML(),t.showExportMenu=!1}}},[e("svg",{attrs:{width:"14",height:"14",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"2"}},[e("path",{attrs:{d:"M12 2L2 7l10 5 10-5-10-5z"}}),e("path",{attrs:{d:"M2 17l10 5 10-5"}}),e("path",{attrs:{d:"M2 12l10 5 10-5"}})]),t._v(" 导出为 HTML (.html) ")])]):t._e()]),e("button",{staticClass:"fullscreen-btn",attrs:{title:t.isFullscreen?"退出全屏":"全屏显示"},on:{click:t.toggleFullscreen}},[t.isFullscreen?e("svg",{attrs:{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"2"}},[e("path",{attrs:{d:"M8 3v3a2 2 0 0 1-2 2H3m18 0h-3a2 2 0 0 1-2-2V3m0 18v-3a2 2 0 0 1 2-2h3M3 16h3a2 2 0 0 1 2 2v3"}})]):e("svg",{attrs:{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"2"}},[e("path",{attrs:{d:"M8 3H5a2 2 0 0 0-2 2v3m18 0V5a2 2 0 0 0-2-2h-3m0 18h3a2 2 0 0 0 2-2v-3M3 16v3a2 2 0 0 0 2 2h3"}})]),t._v(" "+t._s(t.isFullscreen?"退出全屏":"全屏")+" ")])])])]),e("div",{staticClass:"main-content"},[t.showPivotTable?e("div",{staticClass:"side-panel",class:{collapsed:t.sidePanelCollapsed}},[e("button",{staticClass:"panel-collapse-btn",attrs:{title:t.sidePanelCollapsed?"展开过滤面板":"折叠过滤面板"},on:{click:t.toggleSidePanel}},[e("svg",{class:{rotated:t.sidePanelCollapsed},attrs:{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"2"}},[e("polyline",{attrs:{points:"9 18 15 12 9 6"}})])]),e("div",{directives:[{name:"show",rawName:"v-show",value:!t.sidePanelCollapsed,expression:"!sidePanelCollapsed"}],staticClass:"panel-section"},[e("div",{staticClass:"panel-header"},[e("h3",{staticClass:"panel-title"},[t._v("数据过滤")]),e("button",{staticClass:"icon-btn",attrs:{title:"添加过滤"},on:{click:t.addFilter}},[e("svg",{attrs:{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"2"}},[e("line",{attrs:{x1:"12",y1:"5",x2:"12",y2:"19"}}),e("line",{attrs:{x1:"5",y1:"12",x2:"19",y2:"12"}})])])]),0===t.filters.length?e("div",{staticClass:"empty-filters"},[e("p",[t._v("暂无过滤条件")]),e("button",{staticClass:"text-btn",on:{click:t.addFilter}},[t._v("添加过滤")])]):e("div",{staticClass:"filters-list"},[t._l(t.filters,function(s,a){return e("div",{key:a,staticClass:"filter-card"},[e("div",{staticClass:"filter-header"},[e("button",{staticClass:"collapse-btn",attrs:{title:t.isFilterExpanded(a)?"收起":"展开"},on:{click:function(e){return t.toggleFilterCollapse(a)}}},[e("svg",{class:{rotated:t.isFilterExpanded(a)},attrs:{width:"14",height:"14",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"2"}},[e("polyline",{attrs:{points:"6 9 12 15 18 9"}})])]),e("select",{directives:[{name:"model",rawName:"v-model",value:s.field,expression:"filter.field"}],staticClass:"filter-field-select",on:{change:function(e){var a=Array.prototype.filter.call(e.target.options,function(t){return t.selected}).map(function(t){return"_value"in t?t._value:t.value});t.$set(s,"field",e.target.multiple?a:a[0])}}},t._l(t.columns,function(s){return e("option",{key:s,domProps:{value:s}},[t._v(t._s(s))])}),0),e("button",{staticClass:"icon-btn small",attrs:{title:"删除"},on:{click:function(e){return t.removeFilter(a)}}},[e("svg",{attrs:{width:"14",height:"14",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"2"}},[e("line",{attrs:{x1:"18",y1:"6",x2:"6",y2:"18"}}),e("line",{attrs:{x1:"6",y1:"6",x2:"18",y2:"18"}})])])]),e("div",{directives:[{name:"show",rawName:"v-show",value:t.isFilterExpanded(a),expression:"isFilterExpanded(index)"}],staticClass:"filter-body"},[e("select",{directives:[{name:"model",rawName:"v-model",value:s.operator,expression:"filter.operator"}],staticClass:"filter-operator-select",on:{change:function(e){var a=Array.prototype.filter.call(e.target.options,function(t){return t.selected}).map(function(t){return"_value"in t?t._value:t.value});t.$set(s,"operator",e.target.multiple?a:a[0])}}},[e("option",{attrs:{value:"equals"}},[t._v("等于")]),e("option",{attrs:{value:"not_equals"}},[t._v("不等于")]),e("option",{attrs:{value:"contains"}},[t._v("包含")]),e("option",{attrs:{value:"not_contains"}},[t._v("不包含")]),e("option",{attrs:{value:"greater_than"}},[t._v("大于")]),e("option",{attrs:{value:"less_than"}},[t._v("小于")]),e("option",{attrs:{value:"greater_equal"}},[t._v("大于等于")]),e("option",{attrs:{value:"less_equal"}},[t._v("小于等于")]),e("option",{attrs:{value:"in"}},[t._v("包含于(多选)")]),e("option",{attrs:{value:"not_in"}},[t._v("不包含于(多选)")])]),"in"!==s.operator&&"not_in"!==s.operator?e("div",{staticClass:"filter-value-wrapper"},[e("select",{directives:[{name:"model",rawName:"v-model",value:s.value,expression:"filter.value"}],staticClass:"filter-value-select",on:{change:function(e){var a=Array.prototype.filter.call(e.target.options,function(t){return t.selected}).map(function(t){return"_value"in t?t._value:t.value});t.$set(s,"value",e.target.multiple?a:a[0])}}},[e("option",{attrs:{value:""}},[t._v("选择或输入值")]),t._l(t.uniqueFieldValues[s.field],function(s){return e("option",{key:s,domProps:{value:s}},[t._v(t._s(s))])})],2),e("input",{directives:[{name:"model",rawName:"v-model",value:s.value,expression:"filter.value"}],staticClass:"filter-value-input",attrs:{type:"text",placeholder:"或手动输入"},domProps:{value:s.value},on:{input:function(e){e.target.composing||t.$set(s,"value",e.target.value)}}})]):e("div",{staticClass:"filter-multi-select"},[e("div",{staticClass:"multi-select-header"},[e("span",{staticClass:"selected-count"},[t._v("已选 "+t._s(s.values?s.values.length:0)+" 项")]),s.values&&s.values.length>0?e("button",{staticClass:"clear-selection-btn",on:{click:function(t){s.values=[]}}},[t._v(" 清空 ")]):t._e()]),e("div",{staticClass:"multi-select-search"},[e("input",{directives:[{name:"model",rawName:"v-model",value:t.filterSearchQuery,expression:"filterSearchQuery"}],staticClass:"search-input",attrs:{type:"text",placeholder:"搜索值..."},domProps:{value:t.filterSearchQuery},on:{input:function(e){e.target.composing||(t.filterSearchQuery=e.target.value)}}}),t.filterSearchQuery?e("button",{staticClass:"clear-search-btn",attrs:{title:"清除搜索"},on:{click:t.clearFilterSearch}},[e("svg",{attrs:{width:"14",height:"14",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"2"}},[e("line",{attrs:{x1:"18",y1:"6",x2:"6",y2:"18"}}),e("line",{attrs:{x1:"6",y1:"6",x2:"18",y2:"18"}})])]):t._e()]),e("div",{staticClass:"multi-select-list"},[t._l(t.getFilteredUniqueValues(s.field),function(a){return e("label",{key:a,class:["multi-select-item",{selected:t.isMultiSelectValueSelected(s,a)}]},[e("input",{attrs:{type:"checkbox"},domProps:{checked:t.isMultiSelectValueSelected(s,a)},on:{change:function(e){return t.toggleMultiSelectValue(s,a)}}}),e("span",[t._v(t._s(a))])])}),0===t.getFilteredUniqueValues(s.field).length?e("div",{staticClass:"no-results"},[t._v(" 没有找到匹配的值 ")]):t._e()],2),e("div",{staticClass:"multi-select-add"},[e("input",{directives:[{name:"model",rawName:"v-model",value:s.customValue,expression:"filter.customValue"}],staticClass:"filter-custom-input",attrs:{type:"text",placeholder:"输入自定义值"},domProps:{value:s.customValue},on:{keyup:function(e){return!e.type.indexOf("key")&&t._k(e.keyCode,"enter",13,e.key,"Enter")?null:t.addCustomValue(s)},input:function(e){e.target.composing||t.$set(s,"customValue",e.target.value)}}}),e("button",{staticClass:"add-value-btn",on:{click:function(e){return t.addCustomValue(s)}}},[t._v(" 添加 ")])])])])])}),t.filters.length>0?e("button",{staticClass:"clear-filters-btn",on:{click:t.clearFilters}},[t._v(" 清除所有过滤 ")]):t._e()],2)])]):t._e(),e("div",{staticClass:"content-area"},[e("div",{directives:[{name:"show",rawName:"v-show",value:!t.showPivotTable,expression:"!showPivotTable"}],staticClass:"data-view"},[e("div",{staticClass:"data-table-wrapper"},[e("table",{staticClass:"modern-table"},[e("thead",[e("tr",t._l(t.columns,function(s){return e("th",{key:s,staticClass:"table-header"},[e("div",{staticClass:"header-content"},[e("span",[t._v(t._s(s))])])])}),0)]),e("tbody",t._l(t.data.slice(0,t.displayedRows),function(s,a){return e("tr",{key:a,staticClass:"table-row"},t._l(t.columns,function(a){return e("td",{key:a,staticClass:"table-cell"},[t._v(" "+t._s(s[a])+" ")])}),0)}),0)])]),t.data.length>t.displayedRows?e("div",{staticClass:"table-footer"},[e("div",{staticClass:"table-footer-content"},[e("span",{staticClass:"table-info"},[t._v("显示 "+t._s(t.displayedRows)+" 行,共 "+t._s(t.data.length.toLocaleString())+" 行数据")]),e("button",{staticClass:"load-more-btn",on:{click:t.loadMoreData}},[e("svg",{attrs:{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"2"}},[e("polyline",{attrs:{points:"6 9 12 15 18 9"}})]),t._v(" 加载更多 ")])])]):t.data.length>0?e("div",{staticClass:"table-footer"},[e("span",{staticClass:"table-info"},[t._v("已显示全部 "+t._s(t.data.length.toLocaleString())+" 行数据")])]):t._e()]),e("div",{directives:[{name:"show",rawName:"v-show",value:t.showPivotTable,expression:"showPivotTable"}],staticClass:"pivot-view"},[e("div",{staticClass:"pivot-wrapper"},[e("div",{ref:"pivotOutput",staticClass:"pivot-output"})])])])])]):e("div",{staticClass:"empty-state"},[e("div",{staticClass:"empty-state-content"},[e("div",{staticClass:"empty-icon"},[e("svg",{attrs:{width:"120",height:"120",viewBox:"0 0 24 24",fill:"none",xmlns:"http://www.w3.org/2000/svg"}},[e("path",{attrs:{d:"M3 3V21H21",stroke:"#E2E8F0","stroke-width":"2","stroke-linecap":"round","stroke-linejoin":"round"}}),e("path",{attrs:{d:"M19 9L14 14L10 10L7 13",stroke:"#CBD5E1","stroke-width":"2","stroke-linecap":"round","stroke-linejoin":"round"}}),e("path",{attrs:{d:"M19 9V13H15",stroke:"#CBD5E1","stroke-width":"2","stroke-linecap":"round","stroke-linejoin":"round"}})])]),e("h2",{staticClass:"empty-title"},[t._v("暂无数据")]),e("p",{staticClass:"empty-description"},[t._v("请先导入数据文件或加载示例数据开始分析")])])])])},[],0,0,"33ade542").exports;const n=a(t.extend({name:"OnlineAnalysisButton",components:{PivotTable:i},data:()=>({showModal:!1,tableData:[],buttonPosition:"bottom-right"}),props:{position:{type:String,default:"bottom-right"},buttonText:{type:String,default:"📊 透视分析"},buttonClass:{type:String,default:""},tableSelector:{type:String,default:".el-table"},autoExtract:{type:Boolean,default:!0}},mounted(){this.buttonPosition=this.position},methods:{openAnalysis(){this.autoExtract&&this.extractTableData(),this.showModal=!0},closeAnalysis(){this.showModal=!1},extractTableData(){try{const t=document.querySelectorAll(this.tableSelector);if(0===t.length)return void(this.tableData=[]);const e=t[0],s=this.parseElTable(e);this.tableData=s}catch(t){this.tableData=[]}},parseElTable(t){const e=[];try{const s=[],a=t.querySelectorAll(".el-table__header-wrapper thead tr th .cell");if(0===a.length)return[];a.forEach(t=>{const e=t.textContent?.trim()||"";e&&s.push(e)});t.querySelectorAll(".el-table__body-wrapper tbody tr").forEach(t=>{const a=t.querySelectorAll("td .cell");if(0===a.length)return;const i={};a.forEach((t,e)=>{if(e<s.length){const a=s[e];let n=t.textContent?.trim()||"";""===n||isNaN(Number(n))||(n=Number(n)),i[a]=n}}),Object.keys(i).length>0&&e.push(i)})}catch(s){}return e},setData(t){this.tableData=t},getData(){return this.tableData}}}),function(){var t=this,e=t._self._c;return t._self._setupProxy,e("div",{staticClass:"online-analysis-button"},[e("button",{class:["analysis-button",t.buttonPosition,t.buttonClass],attrs:{title:"点击进行透视分析"},on:{click:t.openAnalysis}},[t._v(" "+t._s(t.buttonText)+" ")]),e("transition",{attrs:{name:"modal"}},[t.showModal?e("div",{staticClass:"modal-overlay",on:{click:function(e){return e.target!==e.currentTarget?null:t.closeAnalysis.apply(null,arguments)}}},[e("div",{staticClass:"modal-content"},[e("div",{staticClass:"modal-header"},[e("h2",{staticClass:"modal-title"},[t._v("📊 数据透视分析")]),e("button",{staticClass:"close-button",attrs:{title:"关闭"},on:{click:t.closeAnalysis}},[e("svg",{attrs:{width:"24",height:"24",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":"2"}},[e("line",{attrs:{x1:"18",y1:"6",x2:"6",y2:"18"}}),e("line",{attrs:{x1:"6",y1:"6",x2:"18",y2:"18"}})])])]),e("div",{staticClass:"modal-body"},[e("PivotTable",{attrs:{data:t.tableData}})],1)])]):t._e()])],1)},[],0,0,"7e7b1fe0").exports,l=function(t){l.installed||(l.installed=!0,t.component("OnlineAnalysisButton",n),t.component("PivotTable",i))};"undefined"!=typeof window&&window.Vue&&l(window.Vue);const o={install:l,OnlineAnalysisButton:n,PivotTable:i};exports.OnlineAnalysisButton=n,exports.PivotTable=i,exports.default=o;
|
|
2
|
+
//# sourceMappingURL=online-analysis-button.cjs.js.map
|