@scenetechnology/cj_element_table 0.0.1

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 (61) hide show
  1. package/.browserslistrc +4 -0
  2. package/.env.base +11 -0
  3. package/.env.dev +23 -0
  4. package/.env.gitee +23 -0
  5. package/.env.pro +24 -0
  6. package/.env.test +23 -0
  7. package/.eslintrc.js +18 -0
  8. package/README.md +24 -0
  9. package/babel.config.js +6 -0
  10. package/dist/cj_element_table.common.js +66535 -0
  11. package/dist/cj_element_table.common.js.map +1 -0
  12. package/dist/cj_element_table.css +1 -0
  13. package/dist/cj_element_table.umd.js +66554 -0
  14. package/dist/cj_element_table.umd.js.map +1 -0
  15. package/dist/cj_element_table.umd.min.js +61 -0
  16. package/dist/cj_element_table.umd.min.js.map +1 -0
  17. package/dist/demo.html +1 -0
  18. package/package.json +42 -0
  19. package/packages/components/SaveViewDialog.vue +109 -0
  20. package/packages/components/exportExcel.js +305 -0
  21. package/packages/components/exportTable.vue +361 -0
  22. package/packages/components/historyDialog.vue +100 -0
  23. package/packages/components/index.vue +1235 -0
  24. package/packages/components/tablesetting.vue +344 -0
  25. package/packages/components/tuo-drag.vue +197 -0
  26. package/packages/components/viewEdit.vue +239 -0
  27. package/packages/index.js +13 -0
  28. package/public/favicon.ico +0 -0
  29. package/public/index.html +17 -0
  30. package/src/App.vue +59 -0
  31. package/src/api/All.ts +104 -0
  32. package/src/assets/images/TablehederTool.png +0 -0
  33. package/src/assets/images/addIcon.png +0 -0
  34. package/src/assets/images/blue_lock.png +0 -0
  35. package/src/assets/images/changeIcon.png +0 -0
  36. package/src/assets/images/downImg.png +0 -0
  37. package/src/assets/images/kong_icon.png +0 -0
  38. package/src/assets/images/lbIcon.png +0 -0
  39. package/src/assets/images/lookImg.png +0 -0
  40. package/src/assets/images/model_title_icon.png +0 -0
  41. package/src/assets/images/pgIcon.png +0 -0
  42. package/src/assets/images/pzIcon.png +0 -0
  43. package/src/assets/images/tuozhui_icon.png +0 -0
  44. package/src/assets/images/view_save_icon.png +0 -0
  45. package/src/assets/images/view_setting_icon.png +0 -0
  46. package/src/assets/images/yaIcon.png +0 -0
  47. package/src/assets/logo.png +0 -0
  48. package/src/components/Dialog/index.ts +3 -0
  49. package/src/components/Dialog/src/Dialog.vue +72 -0
  50. package/src/components/HelloWorld.vue +60 -0
  51. package/src/components/Upload/index.vue +287 -0
  52. package/src/config/axios/config.ts +122 -0
  53. package/src/config/axios/index.ts +48 -0
  54. package/src/config/axios/service.ts +118 -0
  55. package/src/main.ts +13 -0
  56. package/src/router/index.ts +16 -0
  57. package/src/shims-vue.d.ts +6 -0
  58. package/tsconfig.json +41 -0
  59. package/types/global.d.ts +39 -0
  60. package/types/vite-env.d.ts +0 -0
  61. package/vue.config.js +24 -0
@@ -0,0 +1,1235 @@
1
+ <template>
2
+ <div class="table-component">
3
+ <!-- 筛选区域 -->
4
+ <div class="filter-area" v-if="hasSearchColumns">
5
+ <el-row :gutter="20">
6
+ <template v-if="!isExpanded">
7
+ <!-- 收起状态:显示前N-1个搜索条件 -->
8
+ <el-col :span="colSpan" v-for="(col, index) in visibleSearchColumns" :key="index">
9
+ <el-form-item :label="col.label" :label-width="col.labelsWidth || 120">
10
+ <!-- 默认输入框 -->
11
+ <el-input
12
+ v-if="!col.searchType || col.searchType === 'input'"
13
+ v-model="searchForm[col.prop]"
14
+ :placeholder="`请输入${col.label}`"
15
+ clearable
16
+ />
17
+ <!-- 下拉选择 -->
18
+ <el-select
19
+ v-else-if="col.searchType === 'select'"
20
+ v-model="searchForm[col.prop]"
21
+ multiple
22
+ collapse-tags
23
+ collapse-tags-tooltip
24
+ :placeholder="`请选择${col.label}`"
25
+ clearable
26
+ >
27
+ <el-option
28
+ v-for="opt in col.options"
29
+ :key="opt.value"
30
+ :label="opt.label"
31
+ :value="opt.value"
32
+ />
33
+ </el-select>
34
+ <!-- 日期选择 -->
35
+ <el-date-picker
36
+ v-else-if="col.searchType === 'date'"
37
+ style="width: 100%"
38
+ v-model="searchForm[col.prop]"
39
+ type="date"
40
+ value-format="YYYY-MM-DD"
41
+ :placeholder="`请选择${col.label}`"
42
+ clearable
43
+ />
44
+ <el-date-picker
45
+ v-else-if="col.searchType === 'dateYear'"
46
+ style="width: 100%"
47
+ v-model="searchForm[col.prop]"
48
+ type="year"
49
+ :placeholder="`请选择${col.label}`"
50
+ value-format="YYYY"
51
+ clearable
52
+ />
53
+ <el-date-picker
54
+ v-else-if="col.searchType === 'dateMonth'"
55
+ value-format="YYYY-MM"
56
+ style="width: 100%"
57
+ v-model="searchForm[col.prop]"
58
+ type="month"
59
+ :placeholder="`请选择${col.label}`"
60
+ clearable
61
+ />
62
+ <el-date-picker
63
+ v-else-if="col.searchType === 'datePicker'"
64
+ style="width: 100%"
65
+ v-model="searchForm[col.prop]"
66
+ type="datetimerange"
67
+ value-format="YYYY-MM-DD HH:mm:ss"
68
+ range-separator="~"
69
+ start-placeholder="开始时间"
70
+ end-placeholder="结束时间"
71
+ />
72
+ </el-form-item>
73
+ </el-col>
74
+
75
+ <!-- 收起状态的操作按钮 -->
76
+ <el-col :span="colSpan" :offset="computedOffsetTop">
77
+ <div class="filter-buttons">
78
+ <el-button
79
+ @click="toggleSearchArea"
80
+ v-if="seaColumnsLength > 24 / colSpan - 1"
81
+ class="el-icon--right"
82
+ :icon="ArrowDownBold"
83
+ >展开全部条件</el-button
84
+ >
85
+ <el-button type="primary" @click="handleSearch">查询</el-button>
86
+ <el-button @click="handleReset">重置</el-button>
87
+ </div>
88
+ </el-col>
89
+ </template>
90
+
91
+ <template v-else>
92
+ <!-- 展开状态:第一行显示cols-per-row个搜索条件 -->
93
+ <el-col :span="colSpan" v-for="(col, index) in firstRowColumns" :key="index">
94
+ <el-form-item :label="col.label" :label-width="col.labelWidth || 120">
95
+ <!-- 默认输入框 -->
96
+ <el-input
97
+ v-if="!col.searchType || col.searchType === 'input'"
98
+ v-model="searchForm[col.prop]"
99
+ :placeholder="`请输入${col.label}`"
100
+ clearable
101
+ />
102
+ <!-- 下拉选择 -->
103
+ <el-select
104
+ v-else-if="col.searchType === 'select'"
105
+ multiple
106
+ collapse-tags
107
+ collapse-tags-tooltip
108
+ v-model="searchForm[col.prop]"
109
+ :placeholder="`请选择${col.label}`"
110
+ clearable
111
+ >
112
+ <el-option
113
+ v-for="opt in col.options"
114
+ :key="opt.value"
115
+ :label="opt.label"
116
+ :value="opt.value"
117
+ />
118
+ </el-select>
119
+ <!-- 日期选择 -->
120
+ <el-date-picker
121
+ v-else-if="col.searchType === 'dateMonth'"
122
+ style="width: 100%"
123
+ v-model="searchForm[col.prop]"
124
+ type="month"
125
+ :placeholder="`请选择${col.label}`"
126
+ value-format="YYYY-MM"
127
+ clearable
128
+ />
129
+ <el-date-picker
130
+ v-else-if="col.searchType === 'dateYear'"
131
+ style="width: 100%"
132
+ v-model="searchForm[col.prop]"
133
+ type="year"
134
+ :placeholder="`请选择${col.label}`"
135
+ value-format="YYYY"
136
+ clearable
137
+ />
138
+ <el-date-picker
139
+ v-else-if="col.searchType === 'date'"
140
+ style="width: 100%"
141
+ v-model="searchForm[col.prop]"
142
+ type="date"
143
+ value-format="YYYY-MM-DD"
144
+ :placeholder="`请选择${col.label}`"
145
+ clearable
146
+ />
147
+ <el-date-picker
148
+ v-else-if="col.searchType === 'datePicker'"
149
+ style="width: 100%"
150
+ v-model="searchForm[col.prop]"
151
+ type="datetimerange"
152
+ value-format="YYYY-MM-DD HH:mm:ss"
153
+ range-separator="~"
154
+ start-placeholder="开始时间"
155
+ end-placeholder="结束时间"
156
+ />
157
+ </el-form-item>
158
+ </el-col>
159
+
160
+ <!-- 展开状态:剩余搜索条件 -->
161
+ <template v-if="remainingColumns.length > 0">
162
+ <el-col
163
+ :span="colSpan"
164
+ v-for="(col, index) in remainingColumns"
165
+ :key="`remaining-${index}`"
166
+ >
167
+ <el-form-item :label="col.label" :label-width="col.labelWidth || 120">
168
+ <!-- 默认输入框 -->
169
+ <el-input
170
+ v-if="!col.searchType || col.searchType === 'input'"
171
+ v-model="searchForm[col.prop]"
172
+ :placeholder="`请输入${col.label}`"
173
+ clearable
174
+ />
175
+ <!-- 下拉选择 -->
176
+ <el-select
177
+ v-else-if="col.searchType === 'select'"
178
+ multiple
179
+ collapse-tags
180
+ collapse-tags-tooltip
181
+ v-model="searchForm[col.prop]"
182
+ :placeholder="`请选择${col.label}`"
183
+ clearable
184
+ >
185
+ <el-option
186
+ v-for="opt in col.options"
187
+ :key="opt.value"
188
+ :label="opt.label"
189
+ :value="opt.value"
190
+ />
191
+ </el-select>
192
+ <!-- 日期选择 -->
193
+ <el-date-picker
194
+ v-else-if="col.searchType === 'dateMonth'"
195
+ style="width: 100%"
196
+ v-model="searchForm[col.prop]"
197
+ type="month"
198
+ :placeholder="`请选择${col.label}`"
199
+ value-format="YYYY-MM"
200
+ clearable
201
+ />
202
+ <el-date-picker
203
+ v-else-if="col.searchType === 'dateYear'"
204
+ style="width: 100%"
205
+ v-model="searchForm[col.prop]"
206
+ type="year"
207
+ :placeholder="`请选择${col.label}`"
208
+ value-format="YYYY"
209
+ clearable
210
+ />
211
+ <el-date-picker
212
+ v-else-if="col.searchType === 'date'"
213
+ v-model="searchForm[col.prop]"
214
+ type="date"
215
+ value-format="YYYY-MM-DD"
216
+ :placeholder="`请选择${col.label}`"
217
+ style="width: 100%"
218
+ clearable
219
+ />
220
+ <el-date-picker
221
+ v-else-if="col.searchType === 'datePicker'"
222
+ style="width: 100%"
223
+ v-model="searchForm[col.prop]"
224
+ type="datetimerange"
225
+ value-format="YYYY-MM-DD HH:mm:ss"
226
+ range-separator="~"
227
+ start-placeholder="开始时间"
228
+ end-placeholder="结束时间"
229
+ />
230
+ </el-form-item>
231
+ </el-col>
232
+ </template>
233
+
234
+ <!-- 收起按钮始终展示在第二行最右侧 -->
235
+ <el-col :span="colSpan" :offset="computedOffset">
236
+ <div class="filter-buttons">
237
+ <el-button @click="toggleSearchArea" class="el-icon--right" :icon="ArrowUpBold"
238
+ >收起全部条件</el-button
239
+ >
240
+ <el-button type="primary" @click="handleSearch">查询</el-button>
241
+ <el-button @click="handleReset">重置</el-button>
242
+ </div>
243
+ </el-col>
244
+ </template>
245
+ </el-row>
246
+ </div>
247
+ <!-- 操作栏 -->
248
+ <div
249
+ class="operation-bar"
250
+ v-if="
251
+ showInputButtons || showOutputButtons || showTableSettingButtons || showViewSettingButtons
252
+ "
253
+ >
254
+ <div class="operation-left">
255
+ <slot name="operation"></slot>
256
+ <Upload
257
+ v-show="false"
258
+ :showButton="false"
259
+ :targetId="route_path + 'input'"
260
+ :uploadUrl="inputUrl"
261
+ :showFileList="false"
262
+ @change="handleSearch"
263
+ :name="inputName"
264
+ />
265
+ <el-dropdown v-if="showInputButtons">
266
+ <el-button type="primary" plain style="margin-left: 10px"
267
+ >导入<el-icon class="el-icon--right"><arrow-down /></el-icon>
268
+ </el-button>
269
+
270
+ <template #dropdown>
271
+ <el-dropdown-menu>
272
+ <el-dropdown-item @click="importOperation('input')">选择导入文件</el-dropdown-item>
273
+ <el-dropdown-item @click="importOperation('down')">下载导入模板</el-dropdown-item>
274
+ <!-- <el-dropdown-item @click="importOperation('history')">导入记录</el-dropdown-item> -->
275
+ </el-dropdown-menu>
276
+ </template>
277
+ </el-dropdown>
278
+ <el-dropdown v-if="showOutputButtons">
279
+ <el-button type="primary" plain style="margin-left: 10px"
280
+ >导出<el-icon class="el-icon--right"><arrow-down /></el-icon>
281
+ </el-button>
282
+ <template #dropdown>
283
+ <el-dropdown-menu>
284
+ <el-dropdown-item @click="exportExcel('all')">导出全部数据</el-dropdown-item>
285
+ <el-dropdown-item @click="exportExcel('current')">导出当前页</el-dropdown-item>
286
+ <el-dropdown-item @click="exportExcel('select')">导出选中数据</el-dropdown-item>
287
+ <el-dropdown-item @click="exportExcel('custom')">自定义导出</el-dropdown-item>
288
+ </el-dropdown-menu>
289
+ </template>
290
+ </el-dropdown>
291
+ </div>
292
+ <div class="tool-bar-right">
293
+ <ElButton v-if="showTableSettingButtons" type="primary" plain @click="clickSetting" ghost
294
+ >列表设置</ElButton
295
+ >
296
+ <ElDropdown v-if="showViewSettingButtons" trigger="click" style="margin-left: 10px">
297
+ <ElButton type="primary" plain style="width: 150px" ghost>
298
+ <p>
299
+ 列表视图
300
+ <span style="margin: 0 8px">({{ viewList.length }})</span>
301
+ </p>
302
+ <el-icon>
303
+ <ArrowDownBold />
304
+ </el-icon>
305
+ </ElButton>
306
+ <template #dropdown>
307
+ <ElDropdownMenu>
308
+ <div style="padding: 0px 10px">
309
+ <ElInput
310
+ v-model="filterViewValue"
311
+ clearable
312
+ @input="filterViewList"
313
+ @enter="filterViewList"
314
+ placeholder="请输入视图名称"
315
+ />
316
+ </div>
317
+ <div style="padding: 7px 16px; margin-top: 7px; font-size: 14px">视图</div>
318
+ <div style="max-height: 100px; overflow-y: auto">
319
+ <ElDropdownItem
320
+ v-for="(item, index) in viewList"
321
+ :key="item.id"
322
+ @click="clickItem(item)"
323
+ >
324
+ <div class="dropdownItem_content">
325
+ <div class="textTitle">{{ item.name }}</div>
326
+ <div class="textTitle2">{{ item.type == 2 ? '个人' : '公共' }}</div>
327
+ </div>
328
+ </ElDropdownItem>
329
+ </div>
330
+ <ElDropdownItem
331
+ style="box-shadow: 0px -6px 6px -6px rgba(147, 147, 147, 0.24)"
332
+ @click="clickItem('viewSave')"
333
+ >
334
+ <div style="display: flex; align-items: center">
335
+ <img
336
+ :src="viewSaveIcon"
337
+ style="width: 15px; height: 15px; vertical-align: middle"
338
+ />
339
+ <span
340
+ style="
341
+ color: #333333;
342
+ font-weight: 400;
343
+ font-size: 14px;
344
+ vertical-align: middle;
345
+ margin-left: 5px;
346
+ "
347
+ >保存当前视图</span
348
+ >
349
+ </div>
350
+ </ElDropdownItem>
351
+ <ElDropdownItem @click="clickItem('viewSetting')">
352
+ <div style="display: flex; align-items: center">
353
+ <img
354
+ :src="viewSettingIcon"
355
+ style="width: 15px; height: 15px; vertical-align: middle"
356
+ />
357
+ <span
358
+ style="
359
+ color: #333333;
360
+ font-weight: 400;
361
+ font-size: 14px;
362
+ vertical-align: middle;
363
+ margin-left: 5px;
364
+ "
365
+ >视图管理</span
366
+ >
367
+ </div>
368
+ </ElDropdownItem>
369
+ </ElDropdownMenu>
370
+ </template>
371
+ </ElDropdown>
372
+ </div>
373
+ </div>
374
+ <!-- 表格 -->
375
+ <el-table
376
+ ref="tableRef"
377
+ :data="tableData.rows"
378
+ :border="true"
379
+ stripe
380
+ style="width: 100%"
381
+ :max-height="maxHeight"
382
+ @selection-change="handleSelectionChange"
383
+ :header-cell-style="headerCellStyle"
384
+ @sort-change="handleSortChange"
385
+ :default-sort="defaultSort"
386
+ >
387
+ <el-table-column v-if="showIndex" type="index" width="55" label="序号" align="center" />
388
+ <el-table-column
389
+ v-if="showSelection"
390
+ type="selection"
391
+ width="55"
392
+ align="center"
393
+ :selectable="(row) => row[selecTableDisabledField.key] != selecTableDisabledField.value"
394
+ />
395
+ <template v-for="col in useColumns" :key="col.prop">
396
+ <!-- 使用插槽的列 -->
397
+ <template v-if="col.slot">
398
+ <el-table-column :prop="col.prop" :label="col.label" align="center" min-width="100">
399
+ <template #default="scope">
400
+ <slot :name="col.prop" :row="scope.row"></slot>
401
+ </template>
402
+ </el-table-column>
403
+ </template>
404
+ <!-- 普通列 -->
405
+ <el-table-column
406
+ v-else
407
+ :column-key="col.id"
408
+ :width="col.width"
409
+ :prop="col.prop"
410
+ :fixed="col.freeze"
411
+ show-overflow-tooltip
412
+ popper-class="table-tooltip"
413
+ :label="col.label"
414
+ align="center"
415
+ min-width="100"
416
+ :sortable="col.options ? false : 'custom'"
417
+ >
418
+ <template #header>
419
+ <el-popover
420
+ v-if="col.options"
421
+ placement="bottom"
422
+ :width="200"
423
+ trigger="click"
424
+ v-model:visible="col.headerFilter"
425
+ >
426
+ <template #reference>
427
+ <span class="headerfilter">{{ col.label }}<img :src="TablehederTool" /></span>
428
+ </template>
429
+ <tuo-drag
430
+ v-if="col.options"
431
+ @stopDrag="
432
+ (res) => {
433
+ change_headersort(res, col)
434
+ }
435
+ "
436
+ :checkAllGroupObj="useColumns"
437
+ :initialSortColumns="getLabel(col.options)"
438
+ ></tuo-drag>
439
+ </el-popover>
440
+ <span v-else>{{ col.label }}</span>
441
+ </template>
442
+ <template v-if="col.options && !col.searchKey" #default="scope">
443
+ <span :style="`color:${getOptionColor(scope.row[col.prop], col.options)}`">{{
444
+ getOptionLabel(scope.row[col.prop], col.options)
445
+ }}</span>
446
+ </template>
447
+ </el-table-column>
448
+ </template>
449
+ <slot name="columns"></slot>
450
+ </el-table>
451
+
452
+ <!-- 分页 -->
453
+ <div class="pagination-container">
454
+ <el-pagination
455
+ :current-page="query.page"
456
+ :page-size="query.rows"
457
+ :page-sizes="pageSizes"
458
+ :total="query.total"
459
+ @size-change="handleSizeChange"
460
+ @current-change="handleCurrentChange"
461
+ background
462
+ layout="total, sizes, prev, pager, next,jumper"
463
+ />
464
+ </div>
465
+ </div>
466
+ <tablesetting
467
+ v-model="dialogVisible"
468
+ :columns-list="columnsList"
469
+ :columnSetting="columnSetting"
470
+ @updateTable="init"
471
+ />
472
+ <SaveViewDialog
473
+ v-model="saveViewStatus"
474
+ :title="formModel_title"
475
+ :max-length="fieldData.length"
476
+ @save="saveView"
477
+ />
478
+ <viewEdit
479
+ v-model="viewEditVisible"
480
+ :viewList="viewList"
481
+ @update="getViewList"
482
+ @confirm="handleViewEditConfirm"
483
+ @cancel="handleViewEditCancel"
484
+ />
485
+ <exportTable
486
+ ref="exportTableRef"
487
+ v-model="exportStatus"
488
+ :columns-list="columnsList"
489
+ :tableData="tableDataExport"
490
+ :columnSetting="columnSetting"
491
+ :exportXlsxName="XlsxName"
492
+ ></exportTable>
493
+ <historyDialog v-model="inputHistory"></historyDialog>
494
+ </template>
495
+
496
+ <script setup lang="ts">
497
+ import {
498
+ ElTable,
499
+ ElPagination,
500
+ ElButton,
501
+ ElDropdown,
502
+ ElDropdownMenu,
503
+ ElDropdownItem,
504
+ ElInput,
505
+ ElIcon,
506
+ ElMessage,
507
+ ElDatePicker
508
+ } from 'element-plus'
509
+ import Upload from '@/components/Upload/index.vue'
510
+ import { ref, computed, watch, onMounted, defineExpose, nextTick } from 'vue'
511
+ import viewSaveIcon from '@/assets/images/view_save_icon.png'
512
+ import TablehederTool from '@/assets/images/TablehederTool.png'
513
+ import viewSettingIcon from '@/assets/images/view_setting_icon.png'
514
+ import tablesetting from './tablesetting.vue'
515
+ import viewEdit from './viewEdit.vue'
516
+ import SaveViewDialog from './SaveViewDialog.vue'
517
+ import exportTable from './exportTable.vue'
518
+ import { UserQuery_update, UserQuery_save, UserQuery_index } from '@/api/All.ts'
519
+ import { useRoute, useRouter } from 'vue-router'
520
+ import tuoDrag from './tuo-drag.vue'
521
+ import { config } from '@/config/axios/config'
522
+ import { template } from 'lodash-es'
523
+ import historyDialog from './historyDialog.vue'
524
+ import { ArrowDownBold, ArrowUpBold } from '@element-plus/icons-vue'
525
+ let route_path = ''
526
+ const route = useRoute()
527
+ if(route&&route.name)
528
+ {
529
+ route_path = route.name
530
+ }
531
+ const router = useRouter()
532
+ const viewEditVisible = ref(false)
533
+ const tableRef = ref()
534
+ const selection = ref([])
535
+ const handleViewEditConfirm = () => {
536
+ // 处理确认逻辑
537
+ }
538
+
539
+ const props = defineProps({
540
+ tableData: {
541
+ //表格数据
542
+ type: Object,
543
+ required: true,
544
+ default: () => ({
545
+ rows: [],
546
+ total: 0
547
+ })
548
+ },
549
+ columns: {
550
+ //表格列配置
551
+ type: Array,
552
+ required: true,
553
+ default: () => []
554
+ },
555
+ exportUrl: {
556
+ //导出表格数据接口
557
+ type: String
558
+ },
559
+ templateUrl: {
560
+ //下载表格模板接口
561
+ type: String
562
+ },
563
+ templateInProject: {
564
+ type: Boolean,
565
+ default: false
566
+ },
567
+ inputUrl: {
568
+ //导入表格数据接口
569
+ type: String
570
+ },
571
+ inputName: {
572
+ type: String
573
+ },
574
+ exportXlsxName: {
575
+ //导出表格名称 默认为路由名称
576
+ type: String
577
+ },
578
+ showSelection: {
579
+ //是否显示表格多选框
580
+ type: Boolean,
581
+ default: true
582
+ },
583
+ showIndex: {
584
+ //是否显示表格序号
585
+ type: Boolean,
586
+ default: true
587
+ },
588
+ showInputButtons: {
589
+ //是否显示导入按钮
590
+ type: Boolean,
591
+ default: true
592
+ },
593
+ showOutputButtons: {
594
+ //是否显示导出按钮
595
+ type: Boolean,
596
+ default: true
597
+ },
598
+ showTableSettingButtons: {
599
+ //是否显示列表设置按钮
600
+ type: Boolean,
601
+ default: true
602
+ },
603
+ showViewSettingButtons: {
604
+ //是否显示视图设置按钮
605
+ type: Boolean,
606
+ default: true
607
+ },
608
+ maxHeight: {
609
+ //表格最大高度
610
+ default: '55vh'
611
+ },
612
+ selecTableDisabledField: {
613
+ //表格多选框禁用条件 key:字段名 value:字段值
614
+ type: Object,
615
+ default: () => ({ key: '', value: '' })
616
+ },
617
+ initialQuery: {
618
+ //初始化查询条件
619
+ type: Object,
620
+ default: () => ({})
621
+ },
622
+ pageSizes: {
623
+ //分页大小选项
624
+ type: Array,
625
+ default: () => [10, 20, 30, 50]
626
+ },
627
+ // 新增配置项:每行的列数
628
+ colsPerRow: {
629
+ type: Number,
630
+ default: 4,
631
+ validator: (value: number) => {
632
+ // 确保值是24的约数
633
+ return 24 % value === 0 && value > 0 && value <= 24
634
+ }
635
+ },
636
+ // 新增表头单元格样式
637
+ headerCellStyle: {
638
+ type: Object,
639
+ default: () => ({
640
+ background: '#f5f7fa',
641
+ color: '#606266',
642
+ fontWeight: 'bold'
643
+ })
644
+ }
645
+ })
646
+ const viewList = ref([])
647
+ const columnSetting = ref()
648
+ const exportStatus = ref(false)
649
+ const useColumns = ref([])
650
+ const saveViewStatus = ref(false)
651
+ const formModel_title = ref('')
652
+ const filterViewValue = ref('')
653
+ const viewListP = ref([])
654
+ const viewlistStatus = ref(false)
655
+ const inputHistory = ref(false)
656
+ const tableDataExport = ref([])
657
+ const exportTableRef = ref()
658
+ let currentRoutePath = ''
659
+ if(router && router.currentRoute){
660
+ currentRoutePath = router.currentRoute._value.meta.title
661
+ }
662
+
663
+
664
+ const XlsxName = ref(props.exportXlsxName ?? currentRoutePath)
665
+ // const XlsxName = '测试'
666
+ const taglist = ref({
667
+ view: route_path + '-view', // 视图
668
+ table: route_path + '-table' //表格设置
669
+ })
670
+ const emit = defineEmits(['search', 'selection-change'])
671
+
672
+ // 查询参数
673
+ const query = ref({
674
+ page: 1,
675
+ rows: 10,
676
+ total: 0,
677
+ ...props.initialQuery
678
+ })
679
+ const dialogVisible = ref(false)
680
+ const columnsList = ref([])
681
+
682
+ onMounted(() => {
683
+ emit('search', { ...query.value, ...searchForm.value })
684
+ init()
685
+ })
686
+
687
+ const init = () => {
688
+ if (props.showTableSettingButtons) {
689
+ getTableList()
690
+ } else {
691
+ useColumns.value = props.columns //没有使用表格设置的直接展示所有的字段
692
+ }
693
+ if (props.showViewSettingButtons) {
694
+ getViewList()
695
+ }
696
+ }
697
+
698
+ const getViewList = () => {
699
+ UserQuery_index({ tag: taglist.value.view }).then((res) => {
700
+ viewList.value = res.data
701
+ viewListP.value = JSON.parse(JSON.stringify(res.data))
702
+ })
703
+ }
704
+ const getTableList = () => {
705
+ // UserQuery_index({ tag: taglist.value.table }).then((res) => {
706
+ // if (res.data.length == 0) {
707
+ // useColumns.value = props.columns //没有使用表格设置的直接展示所有的字段
708
+ // } else {
709
+ // columnSetting.value = res.data[0]
710
+ // useColumns.value = []
711
+ // columnSetting.value.content = JSON.parse(columnSetting.value.content)
712
+ // columnSetting.value.content.checkColumnData.forEach((item, index) => {
713
+ // props.columns.forEach((item2, index2) => {
714
+ // if (item == item2.label) {
715
+ // useColumns.value.push(item2)
716
+ // }
717
+ // })
718
+ // })
719
+ // for (let i = 0; i < columnSetting.value.content.freeze; i++) {
720
+ // useColumns.value[i].freeze = true
721
+ // }
722
+ // }
723
+ // })
724
+ }
725
+ const clickSetting = () => {
726
+ columnsList.value = props.columns
727
+ // console.log(columnsList.value, 111)
728
+ dialogVisible.value = true
729
+ }
730
+ const filterViewList = () => {
731
+ viewList.value = viewListP.value.filter((item, index) => {
732
+ console.log(item.name, filterViewValue.value)
733
+ if (item.name.indexOf(filterViewValue.value) != -1) {
734
+ return item
735
+ }
736
+ })
737
+ console.log(viewList.value)
738
+ }
739
+
740
+ // 筛选表单数据
741
+ const searchForm = ref({})
742
+ const isExpanded = ref(false)
743
+ // 在script setup中添加
744
+ const defaultSort = ref({ sort: '', order: '' })
745
+
746
+ // 监听defaultSort的变化
747
+
748
+ // 处理排序变化
749
+ const handleSortChange = (sort) => {
750
+ console.log(sort)
751
+ defaultSort.value.sort = sort.column.property
752
+ defaultSort.value.order = sort.column.order
753
+ nextTick().then(() => {
754
+ handleSearch()
755
+ })
756
+ }
757
+ const viewForm = ref({
758
+ name: '',
759
+ tag: taglist.value.view,
760
+ // user_id: JSON.parse(window.sessionStorage.getItem('user')).id,
761
+ user_id: '666',
762
+ type: 2,
763
+ content: ''
764
+ })
765
+ const subloading = ref(false)
766
+ const fieldData = {
767
+ length: 50
768
+ }
769
+ const getLabel = (options) => {
770
+ let arr = []
771
+ options.map((item) => {
772
+ arr.push(item.label)
773
+ })
774
+ return arr
775
+ }
776
+ const change_headersort = (res, col) => {
777
+ console.log(res, col.options)
778
+ let arr = []
779
+ res.map((item) => {
780
+ col.options.map((cont) => {
781
+ if (cont.label === item) {
782
+ console.log(cont)
783
+ arr.push(cont.value)
784
+ }
785
+ })
786
+ })
787
+ searchForm.value.sortOrder = arr.join()
788
+ searchForm.value.sort = col.prop
789
+ handleSearch()
790
+ }
791
+ const saveView = async (val) => {
792
+ viewForm.value.name = val.name
793
+ viewForm.value.type = val.type
794
+ if (!viewForm.value.name) {
795
+ ElMessage.error('请输入视图名称')
796
+ return
797
+ }
798
+ subloading.value = true
799
+ try {
800
+ const api = viewForm.value.id ? UserQuery_update : UserQuery_save
801
+ let content = {
802
+ query: query.value,
803
+ tag: taglist.value.view,
804
+ filterForm: { ...searchForm.value },
805
+ defaultSort: defaultSort.value
806
+ }
807
+ console.log(content)
808
+ viewForm.value.content = JSON.stringify(content)
809
+ console.log(viewForm.value)
810
+ await api(viewForm.value)
811
+ ElMessage.success('保存成功')
812
+ closeModel()
813
+ init()
814
+ } catch (error) {
815
+ console.error(error)
816
+ } finally {
817
+ subloading.value = false
818
+ }
819
+ }
820
+ const clickItem = (item) => {
821
+ if (item === 'viewSave') {
822
+ // 处理保存视图
823
+ saveViewStatus.value = true
824
+ return
825
+ } else if (item == 'viewSetting') {
826
+ viewEditVisible.value = true
827
+ } else if (item.id) {
828
+ //应用视图
829
+ // 处理点击视图
830
+ let content = JSON.parse(item.content)
831
+ query.value = { ...query.value, ...content.query }
832
+ searchForm.value = content.filterForm
833
+ defaultSort.value = content.defaultSort
834
+ nextTick(() => {
835
+ tableRef.value.sort(defaultSort.value.sort, defaultSort.value.order)
836
+ })
837
+ emit('search', { ...query.value, ...searchForm.value })
838
+ }
839
+ }
840
+ const closeModel = () => {
841
+ saveViewStatus.value = false
842
+ viewForm.value = {
843
+ name: '',
844
+ type: 2,
845
+ tag: taglist.value.view,
846
+ // user_id: JSON.parse(window.sessionStorage.getItem('user')).id
847
+ user_id: '666'
848
+ }
849
+ }
850
+ const importOperation = async (type) => {
851
+ if (type === 'input') {
852
+ const input = document.getElementById(route_path + 'input')
853
+ input.click()
854
+ } else if (type === 'down') {
855
+ let downsrc = `${config.simpUrl}${props.templateUrl}`
856
+ if (props.templateInProject) {
857
+ downsrc = props.templateUrl
858
+ }
859
+ const a = document.createElement('a')
860
+ a.download = ''
861
+ a.href = downsrc
862
+ a.click()
863
+ } else if (type === 'history') {
864
+ inputHistory.value = true
865
+ }
866
+ }
867
+ const input_success = (val) => {
868
+ if (val) {
869
+ ElMessage.success('导入成功')
870
+ handleSearch()
871
+ }
872
+ }
873
+ const exportExcel = async (type) => {
874
+ if (type === 'custom') {
875
+ columnsList.value = props.columns
876
+ let table_data_arr = []
877
+ props.exportUrl({ page: 1, rows: 10000 }).then((res) => {
878
+ tableDataExport.value = formate_tabledata(res.data.rows)
879
+ table_data_arr[0] = formate_tabledata(res.data.rows)
880
+ exportStatus.value = true
881
+ })
882
+ table_data_arr[1] = formate_tabledata(props.tableData.rows)
883
+ table_data_arr[2] = formate_tabledata(selection.value)
884
+ exportTableRef.value.updatesortColumns(table_data_arr, type)
885
+ return
886
+ }
887
+ if (type === 'all') {
888
+ await props.exportUrl({ page: 1, rows: 10000 }).then((res) => {
889
+ tableDataExport.value = formate_tabledata(res.data.rows)
890
+ })
891
+ } else if (type === 'current') {
892
+ tableDataExport.value = formate_tabledata(props.tableData.rows)
893
+ } else if (type === 'select') {
894
+ console.log(selection.value, 111)
895
+ if (selection.value.length > 0) {
896
+ tableDataExport.value = formate_tabledata(selection.value)
897
+ } else {
898
+ ElMessage.error('请先选择数据')
899
+ return
900
+ }
901
+ }
902
+ nextTick().then(() => {
903
+ exportTableRef.value.updatesortColumns(useColumns.value)
904
+ exportTableRef.value.handleSubmit()
905
+ })
906
+ }
907
+ // 获取需要显示搜索框的列
908
+ const searchColumns = computed(() => props.columns.filter((col) => col.search))
909
+ const hasSearchColumns = computed(() => searchColumns.value.length > 0)
910
+
911
+ // 每个列的span值
912
+ const colSpan = computed(() => 24 / props.colsPerRow)
913
+
914
+ // 展开状态下第一行显示的列
915
+ const firstRowColumns = computed(() => {
916
+ return searchColumns.value.slice(0, props.colsPerRow)
917
+ })
918
+
919
+ // 展开状态下剩余的列
920
+ const remainingColumns = computed(() => {
921
+ return searchColumns.value.slice(props.colsPerRow)
922
+ })
923
+
924
+ // 根据展开状态显示的搜索列 (收起状态下显示的列数)
925
+ const visibleSearchColumns = computed(() => {
926
+ return searchColumns.value.slice(0, props.colsPerRow - 1)
927
+ })
928
+ const seaColumnsLength = computed(() => {
929
+ const column = props.columns.filter((column) => column.search === true)
930
+ return column.length
931
+ })
932
+ // 计算操作按钮的偏移量
933
+ const computedOffset = computed(() => {
934
+ // 如果第一行列数少于colsPerRow,则不需要偏移
935
+ if (firstRowColumns.value.length < props.colsPerRow) return 0
936
+
937
+ const remainingCount = remainingColumns.value.length
938
+ // 如果没有剩余列,说明恰好占满了第一行,按钮应该展示在第二行开头
939
+ //if (remainingCount === 0) return colSpan.value * (props.colsPerRow - 1) // 偏移到最右侧
940
+
941
+ // 计算最后一行已经占用的格子数
942
+ const usedColumns = remainingCount % props.colsPerRow
943
+
944
+ // 如果最后一行已经满了,不需要偏移
945
+ if (usedColumns === 0) {
946
+ return colSpan.value * (props.colsPerRow - 1)
947
+ // if (remainingCount === 0) {
948
+ // return colSpan.value * (props.colsPerRow - 1)
949
+ // }else{
950
+ // return 0
951
+ // }
952
+ }
953
+
954
+
955
+
956
+
957
+ // 否则计算需要偏移的格子数,使按钮位于最右侧
958
+ return (props.colsPerRow - usedColumns - 1) * colSpan.value
959
+ })
960
+ const computedOffsetTop = computed(() => {
961
+ const column = props.columns.filter((column) => column.search === true)
962
+ if (column.length + 1 < 24 / colSpan.value) {
963
+ return (24 / colSpan.value - column.length - 1) * colSpan.value
964
+ }
965
+ })
966
+ // 切换筛选区域展开/收起
967
+ const toggleSearchArea = () => {
968
+ isExpanded.value = !isExpanded.value
969
+ }
970
+
971
+ // 处理查询
972
+ const handleSearch = () => {
973
+ query.value.page = 1 // 重置页码
974
+ for (let key in searchForm.value) {
975
+ if (searchForm.value[key] === '') {
976
+ delete searchForm.value[key]
977
+ }
978
+ }
979
+ const column = props.columns.filter((column) => column.search === true)
980
+ searchForm.value = transformKeys(column, searchForm.value)
981
+
982
+ // 处理搜索条件
983
+ for (const key in searchForm.value) {
984
+ if (searchForm.value[key] === '') {
985
+ continue // 跳过空值
986
+ }
987
+
988
+ // 找到对应的列配置
989
+ }
990
+ emit('search', { ...query.value, ...searchForm.value })
991
+ }
992
+ const transformKeys = (configArray, dataObj) => {
993
+ const result = { ...dataObj } // 避免直接修改原对象
994
+
995
+ configArray.forEach((item) => {
996
+ const propValue = result[item.prop]
997
+
998
+ // 1. 替换键名(如果有 searchKey)
999
+ if (item.searchKey && propValue !== undefined) {
1000
+ result[item.searchKey] = propValue // 复制值到新 key
1001
+ // delete result[item.prop] // 删除旧 key
1002
+ }
1003
+
1004
+ // 2. 处理数组拆分(如果有 dataType 且值是数组)
1005
+ if (item.dataType && Array.isArray(propValue)) {
1006
+ const [startValue, endValue] = propValue
1007
+
1008
+ // 如果有 dataName,则使用 dataName + "_start/end"
1009
+ if (item.dataName) {
1010
+ result[`${item.dataName}_start`] = startValue
1011
+ result[`${item.dataName}_end`] = endValue
1012
+ }
1013
+ // 否则直接使用 "start" 和 "end"
1014
+ else {
1015
+ result.start = startValue
1016
+ result.end = endValue
1017
+ }
1018
+
1019
+ // 如果原键名未被 searchKey 替换,则删除原数组
1020
+ if (!item.searchKey) {
1021
+ // delete result[item.prop]
1022
+ }
1023
+ }
1024
+ })
1025
+
1026
+ return result
1027
+ }
1028
+ // 处理重置
1029
+ const handleReset = () => {
1030
+ searchForm.value = {}
1031
+ query.value.page = 1
1032
+ emit('search', { ...query.value })
1033
+ }
1034
+
1035
+ // 处理每页条数变化
1036
+ const handleSizeChange = (val: number) => {
1037
+ query.value.rows = val
1038
+ query.value.page = 1
1039
+ emit('search', { ...query.value, ...searchForm.value })
1040
+ }
1041
+
1042
+ // 处理页码变化
1043
+ const handleCurrentChange = (val: number) => {
1044
+ query.value.page = val
1045
+ emit('search', { ...query.value, ...searchForm.value })
1046
+ }
1047
+
1048
+ const getOptionColor = (value: any, options: any[]) => {
1049
+ const option = options.find((opt) => opt.value == value)
1050
+ return option ? option.color : ''
1051
+ }
1052
+ // 获取选项标签
1053
+ const getOptionLabel = (value: any, options: any[]) => {
1054
+ const option = options.find((opt) => opt.value == value)
1055
+ return option ? option.label : ''
1056
+ }
1057
+
1058
+ // 处理表格选择变化
1059
+ const handleSelectionChange = (selectrows: any[]) => {
1060
+ selection.value = selectrows
1061
+ selection.value = selection.value.concat([])
1062
+ const selectedIds = selectrows.map((row) => row.id)
1063
+ emit('selection-change', { ids: selectedIds, rows: selectrows })
1064
+ }
1065
+ const formate_tabledata = (tableData) => {
1066
+ tableData = JSON.parse(JSON.stringify(tableData))
1067
+ if (tableData?.length > 0) {
1068
+ tableData.map((item) => {
1069
+ for (let key in item) {
1070
+ props.columns.map((col) => {
1071
+ if (key == col.prop && col.options) {
1072
+ col.options.map((label) => {
1073
+ if (item[key] == label.value) item[key] = label.label
1074
+ })
1075
+ }
1076
+ })
1077
+ }
1078
+ })
1079
+ }
1080
+ return tableData
1081
+ }
1082
+ // 监听tableData的变化
1083
+ watch(
1084
+ () => defaultSort.value,
1085
+ (newVal) => {
1086
+ searchForm.value.sort = newVal.sort
1087
+ searchForm.value.sortOrder = newVal.order == 'descending' ? 'desc' : 'asc'
1088
+ },
1089
+ { deep: true }
1090
+ )
1091
+ watch(
1092
+ () => useColumns.value,
1093
+ (newVal) => {
1094
+ console.log(useColumns.value)
1095
+ },
1096
+ { deep: true }
1097
+ )
1098
+ watch(
1099
+ () => props.tableData,
1100
+ (newVal) => {
1101
+ if (newVal.hasOwnProperty('total')) {
1102
+ query.value.total = newVal.total
1103
+ }
1104
+ // formate_tabledata(props.tableData)
1105
+ },
1106
+ { immediate: true }
1107
+ )
1108
+
1109
+ // 监听props.initialQuery的变化
1110
+ watch(
1111
+ () => props.initialQuery,
1112
+ (newVal) => {
1113
+ if (newVal) {
1114
+ query.value = { ...query.value, ...newVal }
1115
+ }
1116
+ },
1117
+ { deep: true }
1118
+ )
1119
+
1120
+ // 暴露方法给父组件
1121
+ defineExpose({
1122
+ handleSearch,
1123
+ handleReset
1124
+ })
1125
+ </script>
1126
+
1127
+ <style scoped lang="less">
1128
+ .table-component {
1129
+ // padding: 20px;
1130
+ }
1131
+ .el-table {
1132
+ transform: scale(1) !important;
1133
+ transform-origin: 0 0 !important;
1134
+ overflow: visible !important;
1135
+ }
1136
+ .filter-area {
1137
+ margin-bottom: 20px;
1138
+ /deep/ .el-form-item--default .el-form-item__label {
1139
+ line-height: 15px;
1140
+ text-align: right;
1141
+ align-items: center;
1142
+ font-size: 12px;
1143
+ }
1144
+ }
1145
+
1146
+ .operation-bar {
1147
+ margin-bottom: 20px;
1148
+ display: flex;
1149
+ justify-content: space-between;
1150
+ align-items: center;
1151
+ }
1152
+
1153
+ :global(.table-tooltip) {
1154
+ transform: translateY(-50%) !important;
1155
+ }
1156
+
1157
+ .operation-left {
1158
+ display: flex;
1159
+ align-items: center;
1160
+ }
1161
+
1162
+ .operation-right {
1163
+ display: flex;
1164
+ gap: 10px;
1165
+ }
1166
+
1167
+ .filter-buttons {
1168
+ display: flex;
1169
+ gap: 8px;
1170
+ align-items: center;
1171
+ height: 100%;
1172
+ justify-content: flex-end;
1173
+ margin-top: -10px;
1174
+ }
1175
+
1176
+ .filter-buttons-expanded {
1177
+ margin-top: 20px;
1178
+ text-align: right;
1179
+ }
1180
+
1181
+ .text-right {
1182
+ text-align: right;
1183
+ }
1184
+
1185
+ .pagination-container {
1186
+ margin-top: 20px;
1187
+ display: flex;
1188
+ justify-content: center;
1189
+ }
1190
+
1191
+ :deep(.el-form-item__content) {
1192
+ width: calc(100% - 120px);
1193
+ }
1194
+
1195
+ .dropdownItem_content {
1196
+ display: flex;
1197
+ align-items: center;
1198
+ justify-content: space-between;
1199
+ .textTitle {
1200
+ width: 110px;
1201
+ overflow: hidden;
1202
+ text-overflow: ellipsis;
1203
+ white-space: nowrap;
1204
+ margin-right: 5px;
1205
+ font-size: 12px;
1206
+ }
1207
+ .textTitle2 {
1208
+ font-weight: 400;
1209
+ font-size: 12px;
1210
+ color: #666666;
1211
+ }
1212
+ }
1213
+ .headerfilter {
1214
+ cursor: pointer;
1215
+ img {
1216
+ display: inline-block;
1217
+ position: relative;
1218
+ top: -2px;
1219
+ margin-left: 2px;
1220
+ }
1221
+ i {
1222
+ position: relative;
1223
+ top: 3px;
1224
+ margin-left: 2px;
1225
+ }
1226
+ }
1227
+ // 设置输入框placeholder的字体大小
1228
+ // input::placeholder {
1229
+ // font-size: 14px;
1230
+ // }
1231
+ /deep/ .el-input__inner::placeholder,
1232
+ .el-select__placeholder {
1233
+ font-size: 12px;
1234
+ }
1235
+ </style>