sh-view 2.8.12 → 2.8.15
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/package.json +3 -2
- package/packages/components/sh-calendar/index.vue +1 -1
- package/packages/components/sh-date/index.vue +2 -2
- package/packages/components/sh-table/css/index.scss +13 -10
- package/packages/components/sh-table/grid.vue +26 -45
- package/packages/components/sh-table/js/props.js +7 -1
- package/packages/components/sh-table/js/useTable.js +74 -20
- package/packages/components/sh-table/table.vue +12 -18
- package/packages/components/sh-tabs/index.vue +6 -3
- package/packages/components/sh-tree/css/index.scss +1 -1
- package/packages/components/sh-tree/index.vue +1 -1
- package/packages/vxeTable/css/index.scss +0 -3
- package/packages/vxeTable/index.js +14 -2
- package/packages/vxeTable/plugins/export.js +36 -23
- package/packages/vxeTable/render/cell/vxe-render-tree.vue +1 -1
- package/packages/vxeTable/render/globalRenders.jsx +1 -1
- package/packages/vxeTable/render/mixin/cell-hooks.js +13 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sh-view",
|
|
3
|
-
"version": "2.8.
|
|
3
|
+
"version": "2.8.15",
|
|
4
4
|
"description": "基于vxe-table二次封装,更包含Alert,Badge,Card,CodeEditor,Col,Corner,CountTo,Drawer,Empty,Form,Header,Icon,List,Loading,Modal,Noticebar,Poptip,Progress,PullRefresh,Query,Result,Row,Split,Grid,Table,Tabs,Tag,Toolbar,Tree,Upload,WaterFall,WaterMark等丰富组件库",
|
|
5
5
|
"main": "packages/index.js",
|
|
6
6
|
"typings": "types/index.d.ts",
|
|
@@ -37,9 +37,10 @@
|
|
|
37
37
|
"vue": "^3.3.4",
|
|
38
38
|
"vue-masonry": "^0.16.0",
|
|
39
39
|
"vue-router": "^4.2.4",
|
|
40
|
-
"vxe-table": "^4.5.
|
|
40
|
+
"vxe-table": "^4.5.21",
|
|
41
41
|
"vxe-table-plugin-export-pdf": "^4.0.1",
|
|
42
42
|
"vxe-table-plugin-export-xlsx": "^4.0.1",
|
|
43
|
+
"vxe-table-plugin-menus": "^4.0.0",
|
|
43
44
|
"xe-clipboard": "^1.10.2"
|
|
44
45
|
},
|
|
45
46
|
"devDependencies": {
|
|
@@ -109,7 +109,7 @@ export default defineComponent({
|
|
|
109
109
|
|
|
110
110
|
const pulldownValue = ref(false)
|
|
111
111
|
const inputValue = ref(props.modelValue)
|
|
112
|
-
const rangeValue = ref(props.modelValue
|
|
112
|
+
const rangeValue = ref(Array.isArray(props.modelValue) ? props.modelValue : [])
|
|
113
113
|
|
|
114
114
|
const inputConfig = computed(() => {
|
|
115
115
|
let defaultProps = {}
|
|
@@ -217,7 +217,7 @@ export default defineComponent({
|
|
|
217
217
|
watch(
|
|
218
218
|
() => props.modelValue,
|
|
219
219
|
(value, oldValue) => {
|
|
220
|
-
if (props.range) {
|
|
220
|
+
if (props.range && Array.isArray(value)) {
|
|
221
221
|
rangeValue.value = value
|
|
222
222
|
} else {
|
|
223
223
|
inputValue.value = value
|
|
@@ -49,23 +49,26 @@
|
|
|
49
49
|
margin-right: 10px;
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
|
-
.sh-table-toolbar
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
.sh-table-toolbar{
|
|
53
|
+
& > .vxe-toolbar{
|
|
54
|
+
padding: 0.6em;
|
|
55
|
+
.vxe-button{
|
|
56
|
+
& + .vxe-custom--wrapper{
|
|
57
|
+
margin-left: 0.8em;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
.vxe-custom--wrapper{
|
|
61
|
+
margin-left: 0;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
55
64
|
.sh-table-toolbar-item{
|
|
56
65
|
display: inline-block;
|
|
57
66
|
vertical-align: baseline;
|
|
58
|
-
|
|
59
|
-
margin: 5px;
|
|
67
|
+
margin: 0 0.8em;
|
|
60
68
|
& + .sh-table-toolbar-item{
|
|
61
69
|
margin-left: 0;
|
|
62
70
|
}
|
|
63
71
|
}
|
|
64
|
-
.sh-table-toolbar-left{
|
|
65
|
-
flex: 1;
|
|
66
|
-
}
|
|
67
|
-
.sh-table-toolbar-right{
|
|
68
|
-
}
|
|
69
72
|
}
|
|
70
73
|
// 关键词搜索高亮样式
|
|
71
74
|
.sh-keyword-lighten{
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="sh-vxe-table" :class="{ 'sh-table-ghost': tableGlobalConfig.ghost }" :style="{ height: wrapHeight }">
|
|
3
3
|
<vxe-grid
|
|
4
|
-
:id="id"
|
|
5
4
|
ref="tableRef"
|
|
6
5
|
:key="renderKey"
|
|
7
6
|
:class="{ 'is--hasfooter': showFooter }"
|
|
@@ -36,38 +35,34 @@
|
|
|
36
35
|
</sh-query>
|
|
37
36
|
</slot>
|
|
38
37
|
</template>
|
|
39
|
-
<template #toolbar>
|
|
40
|
-
<div class="sh-table-toolbar
|
|
41
|
-
<
|
|
42
|
-
<
|
|
43
|
-
<
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
<
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
<
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
<
|
|
58
|
-
<
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
<div class="sh-table-toolbar-item">
|
|
38
|
+
<template v-if="isToolbarSlot" #toolbar>
|
|
39
|
+
<div class="sh-table-toolbar">
|
|
40
|
+
<vxe-toolbar ref="toolbarRef" v-bind="tableToolbarConfig">
|
|
41
|
+
<template #buttons>
|
|
42
|
+
<div v-if="tableGlobalConfig.title" class="sh-table-toolbar-item">
|
|
43
|
+
<h3 class="tableName">{{ tableGlobalConfig.tableName }}</h3>
|
|
44
|
+
</div>
|
|
45
|
+
<!--ps:全表搜索不支持反转-->
|
|
46
|
+
<div v-if="tableGlobalConfig.globalFilter" class="sh-table-toolbar-item">
|
|
47
|
+
<vxe-input v-model="tableFilterText" v-bind="tableFilterConfig" @blur="handleTableFilter" @clear="handleTableFilter" @search-click="handleTableFilter" />
|
|
48
|
+
<span v-if="tableFilterData">
|
|
49
|
+
共搜索到 <strong>{{ tableFilterData.length }}</strong> 条数据
|
|
50
|
+
</span>
|
|
51
|
+
</div>
|
|
52
|
+
<div v-if="slots.toolbarLeft" class="sh-table-toolbar-item">
|
|
53
|
+
<slot name="toolbarLeft"></slot>
|
|
54
|
+
</div>
|
|
55
|
+
</template>
|
|
56
|
+
<template #tools>
|
|
57
|
+
<div v-if="slots.toolbarRight" class="sh-table-toolbar-item">
|
|
58
|
+
<slot name="toolbarRight"></slot>
|
|
59
|
+
</div>
|
|
60
|
+
<div class="sh-table-toolbar-item" v-for="(tool, toolIndex) in tableTools" :key="toolIndex">
|
|
62
61
|
<vxe-button v-ripple :size="size" v-bind="tool" @click="handleTableTool(tool)"></vxe-button>
|
|
63
62
|
</div>
|
|
63
|
+
<div v-if="tableMoneyConfig.enabled" @click.stop class="sh-table-toolbar-item">单位:<sh-select v-model="tableMoneyUnit" v-bind="tableMoneyConfig" /></div>
|
|
64
64
|
</template>
|
|
65
|
-
|
|
66
|
-
<div v-if="tableGlobalConfig.zoom" class="sh-table-toolbar-item">
|
|
67
|
-
<vxe-button v-if="!tableIsFullscreen" v-ripple :size="size" icon="vxe-icon-zoom-out" @click="handleTableZoomBtn(true)">全屏</vxe-button>
|
|
68
|
-
<vxe-button v-else v-ripple :size="size" icon="vxe-icon-zoom-in" @click="handleTableZoomBtn(false)">退出全屏</vxe-button>
|
|
69
|
-
</div>
|
|
70
|
-
</div>
|
|
65
|
+
</vxe-toolbar>
|
|
71
66
|
</div>
|
|
72
67
|
</template>
|
|
73
68
|
<template #pagerLeft>
|
|
@@ -135,22 +130,8 @@ export default defineComponent({
|
|
|
135
130
|
|
|
136
131
|
const useTableHooks = useTable(props, context, proxy, true)
|
|
137
132
|
|
|
138
|
-
const tableIsFullscreen = ref(false) // 表格是否全屏显示状态
|
|
139
|
-
|
|
140
|
-
// 表格切换全屏缩放按钮
|
|
141
|
-
const handleTableZoomBtn = val => {
|
|
142
|
-
tableIsFullscreen.value = val
|
|
143
|
-
if (val) {
|
|
144
|
-
useTableHooks.tableRef.value.zoom()
|
|
145
|
-
} else {
|
|
146
|
-
useTableHooks.tableRef.value.revert()
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
133
|
return {
|
|
151
|
-
...useTableHooks
|
|
152
|
-
tableIsFullscreen,
|
|
153
|
-
handleTableZoomBtn
|
|
134
|
+
...useTableHooks
|
|
154
135
|
}
|
|
155
136
|
}
|
|
156
137
|
})
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export default {
|
|
2
2
|
id: {
|
|
3
3
|
type: String,
|
|
4
|
-
default: '
|
|
4
|
+
default: ''
|
|
5
5
|
},
|
|
6
6
|
dataSourse: {
|
|
7
7
|
type: Array,
|
|
@@ -270,6 +270,12 @@ export default {
|
|
|
270
270
|
return {}
|
|
271
271
|
}
|
|
272
272
|
},
|
|
273
|
+
menuConfig: {
|
|
274
|
+
type: Object,
|
|
275
|
+
default() {
|
|
276
|
+
return {}
|
|
277
|
+
}
|
|
278
|
+
},
|
|
273
279
|
footerCalculate: {
|
|
274
280
|
type: Object,
|
|
275
281
|
default() {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { computed, onMounted, reactive, ref, watch } from 'vue'
|
|
1
|
+
import { computed, onMounted, reactive, ref, watch, nextTick } from 'vue'
|
|
2
2
|
import { columnDefaultFilterMethod, tableFooterCompute, getTransfarFields } from './tableMethods'
|
|
3
3
|
|
|
4
4
|
// 记录自定义参数,传给vxe要过滤掉
|
|
@@ -41,12 +41,34 @@ const exportAndPrintDefault = {
|
|
|
41
41
|
useStyle: false,
|
|
42
42
|
columnFilterMethod: columnDefaultFilterMethod
|
|
43
43
|
}
|
|
44
|
+
const menuConfigDefault = {
|
|
45
|
+
header: {
|
|
46
|
+
options: [
|
|
47
|
+
[
|
|
48
|
+
{ code: 'HIDDEN_COLUMN', name: '隐藏' },
|
|
49
|
+
{ code: 'RESET_COLUMN', name: '取消隐藏' },
|
|
50
|
+
{ code: 'FIXED_LEFT_COLUMN', name: '固定到左侧' },
|
|
51
|
+
{ code: 'FIXED_RIGHT_COLUMN', name: '固定到右侧' },
|
|
52
|
+
{ code: 'CLEAR_FIXED_COLUMN', name: '取消固定' }
|
|
53
|
+
]
|
|
54
|
+
]
|
|
55
|
+
},
|
|
56
|
+
body: {
|
|
57
|
+
options: [
|
|
58
|
+
[
|
|
59
|
+
{ code: 'SORT_ASC', name: '升序', prefixIcon: 'fa fa-sort-alpha-desc' },
|
|
60
|
+
{ code: 'SORT_DESC', name: '倒序', prefixIcon: 'fa fa-sort-alpha-desc' },
|
|
61
|
+
{ code: 'CLEAR_SORT', name: '清除排序' }
|
|
62
|
+
]
|
|
63
|
+
]
|
|
64
|
+
}
|
|
65
|
+
}
|
|
44
66
|
const toolsList = [
|
|
45
|
-
{ status: 'primary', code: 'addRow',
|
|
46
|
-
{ status: 'danger', code: 'deleteRow',
|
|
47
|
-
{ status: 'primary', code: 'import', icon: 'vxe-icon-upload',
|
|
48
|
-
{ status: 'success', code: 'export', icon: 'vxe-icon-download',
|
|
49
|
-
{ status: 'warning', code: 'print', icon: 'vxe-icon-print',
|
|
67
|
+
{ status: 'primary', code: 'addRow', icon: 'vxe-icon-square-plus', title: '新增行', circle: true },
|
|
68
|
+
{ status: 'danger', code: 'deleteRow', icon: 'vxe-icon-square-minus', title: '删除行', circle: true },
|
|
69
|
+
{ status: 'primary', code: 'import', icon: 'vxe-icon-upload', title: '导入', circle: true },
|
|
70
|
+
{ status: 'success', code: 'export', icon: 'vxe-icon-download', title: '导出', circle: true },
|
|
71
|
+
{ status: 'warning', code: 'print', icon: 'vxe-icon-print', title: '打印', circle: true }
|
|
50
72
|
]
|
|
51
73
|
// 表头默认值
|
|
52
74
|
const columnObjDefault = { minWidth: 120, sortable: true, filter: true }
|
|
@@ -58,10 +80,11 @@ const columnsMapDefault = {
|
|
|
58
80
|
}
|
|
59
81
|
|
|
60
82
|
export default function (props, context, proxy, isGrid) {
|
|
61
|
-
const { $vUtils, $vTableSetup, $vxePluginNames } = proxy
|
|
83
|
+
const { $vUtils, $vTableSetup, $vxePluginNames, $route } = proxy
|
|
62
84
|
const { emit, slots } = context
|
|
63
85
|
|
|
64
86
|
const tableRef = ref()
|
|
87
|
+
const toolbarRef = ref()
|
|
65
88
|
const renderKey = ref(1) // 渲染key值
|
|
66
89
|
const selectedRowKeys = ref([]) // table选中keys
|
|
67
90
|
const selectionRows = ref([]) // table选中records
|
|
@@ -166,13 +189,17 @@ export default function (props, context, proxy, isGrid) {
|
|
|
166
189
|
tableVmConfig.value
|
|
167
190
|
)
|
|
168
191
|
})
|
|
192
|
+
const tableToolbarConfig = computed(() => {
|
|
193
|
+
return Object.assign({ perfect: true, zoom: tableGlobalConfig.value.zoom, custom: tableGlobalConfig.value.custom }, props.toolbarConfig, tableVmConfig.value)
|
|
194
|
+
})
|
|
195
|
+
const tableMenuConfig = computed(() => Object.assign({ enabled: false }, menuConfigDefault, props.menuConfig))
|
|
169
196
|
const tableFilterConfig = computed(() => Object.assign({ clearable: true, type: 'search', placeholder: '全局关键字搜索' }, tableVmConfig.value))
|
|
170
197
|
const tableSlots = computed(() => {
|
|
171
198
|
let disSlots = ['top', 'head', 'foot', 'form', 'toolbar', 'formLeft', 'formRight', 'toolbarLeft', 'toolbarRight', 'pagerLeft', 'pagerRight']
|
|
172
199
|
return Object.keys(slots).filter(key => !disSlots.includes(key))
|
|
173
200
|
})
|
|
174
201
|
const tableBindConfig = computed(() => {
|
|
175
|
-
let defaultProps = { footerMethod: tableFooterMethod, footerSpanMethod: tableFooterSpanMethod }
|
|
202
|
+
let defaultProps = { id: `sh-table-${$route.fullPath}`, footerMethod: tableFooterMethod, footerSpanMethod: tableFooterSpanMethod }
|
|
176
203
|
let tableProps = $vUtils.omit(props, (val, key) => omitProps.includes(key) || $vUtils.isNone(val))
|
|
177
204
|
let shProps = {
|
|
178
205
|
data: tableViewData.value,
|
|
@@ -186,8 +213,10 @@ export default function (props, context, proxy, isGrid) {
|
|
|
186
213
|
exportConfig: tableExportConfig.value,
|
|
187
214
|
printConfig: tablePrintConfig.value,
|
|
188
215
|
moneyConfig: tableMoneyConfig.value,
|
|
189
|
-
moneyUnit: tableMoneyUnit.value
|
|
216
|
+
moneyUnit: tableMoneyUnit.value,
|
|
217
|
+
menuConfig: tableMenuConfig.value
|
|
190
218
|
}
|
|
219
|
+
if (tableMenuConfig.value.enabled) shProps.menuConfig = tableMenuConfig.value
|
|
191
220
|
return Object.assign(defaultProps, tableProps, shProps)
|
|
192
221
|
})
|
|
193
222
|
const importBindConfig = reactive({
|
|
@@ -197,6 +226,15 @@ export default function (props, context, proxy, isGrid) {
|
|
|
197
226
|
importConfig: props.importConfig,
|
|
198
227
|
importRules: tableEditRules.value
|
|
199
228
|
})
|
|
229
|
+
const isToolbarSlot = computed(() => {
|
|
230
|
+
const globalFg = tableGlobalConfig.value
|
|
231
|
+
const toolbarFg = tableToolbarConfig.value
|
|
232
|
+
const toolsFg = tableTools.value
|
|
233
|
+
const globalTool = globalFg.title || globalFg.globalFilter
|
|
234
|
+
const toolbarTool = toolbarFg.import || toolbarFg.export || toolbarFg.print || toolbarFg.refresh || toolbarFg.custom
|
|
235
|
+
const slotsTool = slots.toolbar || slots.toolbarLeft || slots.toolbarRight
|
|
236
|
+
return globalTool || toolbarTool || slotsTool || toolsFg.length > 0
|
|
237
|
+
})
|
|
200
238
|
|
|
201
239
|
// 获取选中数据
|
|
202
240
|
const getSelectionData = () => {
|
|
@@ -206,7 +244,8 @@ export default function (props, context, proxy, isGrid) {
|
|
|
206
244
|
// visible为true获取视图数据
|
|
207
245
|
const getFullData = params => {
|
|
208
246
|
const { visible = false, deleteXid = false } = params || {}
|
|
209
|
-
let
|
|
247
|
+
let fullData = tableRef.value.internalData.afterFullData
|
|
248
|
+
let data = $vUtils.clone(fullData, true)
|
|
210
249
|
const columns = tableRef.value.getColumns()
|
|
211
250
|
let rnameColumns = columns.filter(col => col.rname)
|
|
212
251
|
rnameColumns.forEach(col => {
|
|
@@ -479,6 +518,7 @@ export default function (props, context, proxy, isGrid) {
|
|
|
479
518
|
handleTablePrintBtn()
|
|
480
519
|
break
|
|
481
520
|
}
|
|
521
|
+
emit('toolbar-btn-click', code)
|
|
482
522
|
}
|
|
483
523
|
// 表格导出按钮
|
|
484
524
|
const handleTableExportBtn = options => {
|
|
@@ -498,6 +538,17 @@ export default function (props, context, proxy, isGrid) {
|
|
|
498
538
|
}
|
|
499
539
|
return tableRef.value.openPrint(options)
|
|
500
540
|
}
|
|
541
|
+
// 关联toolbar
|
|
542
|
+
const connectToolbar = () => {
|
|
543
|
+
nextTick(() => {
|
|
544
|
+
// 将表格和工具栏进行关联
|
|
545
|
+
const $table = tableRef.value
|
|
546
|
+
const $toolbar = toolbarRef.value
|
|
547
|
+
if ($table && $toolbar) {
|
|
548
|
+
$table.connect($toolbar)
|
|
549
|
+
}
|
|
550
|
+
})
|
|
551
|
+
}
|
|
501
552
|
|
|
502
553
|
// 自定义操作列点击事件
|
|
503
554
|
const handleGoptionClick = async (btnObj, dataObj) => {
|
|
@@ -554,9 +605,7 @@ export default function (props, context, proxy, isGrid) {
|
|
|
554
605
|
value => {
|
|
555
606
|
initTableColumns()
|
|
556
607
|
},
|
|
557
|
-
{
|
|
558
|
-
deep: true
|
|
559
|
-
}
|
|
608
|
+
{ deep: true }
|
|
560
609
|
)
|
|
561
610
|
watch(
|
|
562
611
|
() => props.dataSourse,
|
|
@@ -564,24 +613,27 @@ export default function (props, context, proxy, isGrid) {
|
|
|
564
613
|
updateSelection([])
|
|
565
614
|
updateExpended()
|
|
566
615
|
},
|
|
567
|
-
{
|
|
568
|
-
immediate: true
|
|
569
|
-
}
|
|
616
|
+
{ immediate: true }
|
|
570
617
|
)
|
|
571
618
|
watch(
|
|
572
619
|
() => props.editRules,
|
|
573
620
|
value => {
|
|
574
621
|
initEditRules(value)
|
|
575
622
|
},
|
|
576
|
-
{
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
623
|
+
{ deep: true, immediate: true }
|
|
624
|
+
)
|
|
625
|
+
watch(
|
|
626
|
+
() => isToolbarSlot.value,
|
|
627
|
+
() => {
|
|
628
|
+
connectToolbar()
|
|
629
|
+
},
|
|
630
|
+
{ deep: true, immediate: true }
|
|
580
631
|
)
|
|
581
632
|
|
|
582
633
|
return {
|
|
583
634
|
slots,
|
|
584
635
|
tableRef,
|
|
636
|
+
toolbarRef,
|
|
585
637
|
renderKey,
|
|
586
638
|
wrapHeight,
|
|
587
639
|
tableGlobalConfig,
|
|
@@ -590,11 +642,13 @@ export default function (props, context, proxy, isGrid) {
|
|
|
590
642
|
tableColumnObjConfig,
|
|
591
643
|
tablePagerConfig,
|
|
592
644
|
tableQueryConfig,
|
|
645
|
+
tableToolbarConfig,
|
|
593
646
|
tableFilterText,
|
|
594
647
|
tableFilterConfig,
|
|
595
648
|
tableFilterData,
|
|
596
649
|
tableTools,
|
|
597
650
|
tableSlots,
|
|
651
|
+
isToolbarSlot,
|
|
598
652
|
selectionRows,
|
|
599
653
|
tableBindConfig,
|
|
600
654
|
importBindConfig,
|
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
</div>
|
|
12
12
|
<div v-if="isToolbarSlot" ref="toolbarSlotRef" v-resize="handleResize" class="sh-table-toolbar">
|
|
13
13
|
<slot name="toolbar">
|
|
14
|
-
<
|
|
15
|
-
<
|
|
14
|
+
<vxe-toolbar ref="toolbarRef" v-bind="tableToolbarConfig">
|
|
15
|
+
<template #buttons>
|
|
16
16
|
<div v-if="tableGlobalConfig.title" class="sh-table-toolbar-item">
|
|
17
17
|
<h3 class="tableName">{{ tableGlobalConfig.tableName }}</h3>
|
|
18
18
|
</div>
|
|
@@ -26,24 +26,21 @@
|
|
|
26
26
|
<div v-if="slots.toolbarLeft" class="sh-table-toolbar-item">
|
|
27
27
|
<slot name="toolbarLeft"></slot>
|
|
28
28
|
</div>
|
|
29
|
-
</
|
|
30
|
-
<
|
|
29
|
+
</template>
|
|
30
|
+
<template #tools>
|
|
31
31
|
<div v-if="slots.toolbarRight" class="sh-table-toolbar-item">
|
|
32
32
|
<slot name="toolbarRight"></slot>
|
|
33
33
|
</div>
|
|
34
|
-
<
|
|
35
|
-
<
|
|
36
|
-
|
|
37
|
-
</div>
|
|
38
|
-
</template>
|
|
34
|
+
<div class="sh-table-toolbar-item" v-for="(tool, toolIndex) in tableTools" :key="toolIndex">
|
|
35
|
+
<vxe-button v-ripple :size="size" v-bind="tool" @click="handleTableTool(tool)"></vxe-button>
|
|
36
|
+
</div>
|
|
39
37
|
<div v-if="tableMoneyConfig.enabled" @click.stop class="sh-table-toolbar-item">单位:<sh-select v-model="tableMoneyUnit" v-bind="tableMoneyConfig" /></div>
|
|
40
|
-
</
|
|
41
|
-
</
|
|
38
|
+
</template>
|
|
39
|
+
</vxe-toolbar>
|
|
42
40
|
</slot>
|
|
43
41
|
</div>
|
|
44
42
|
<div v-if="isHeadSlot" ref="headSlotRef" v-resize="handleResize" class="sh-table-head"><slot name="head"></slot></div>
|
|
45
43
|
<vxe-table
|
|
46
|
-
:id="id"
|
|
47
44
|
ref="tableRef"
|
|
48
45
|
:key="renderKey"
|
|
49
46
|
:class="{ 'is--hasfooter': showFooter }"
|
|
@@ -93,7 +90,7 @@
|
|
|
93
90
|
</template>
|
|
94
91
|
|
|
95
92
|
<script>
|
|
96
|
-
import { computed, defineComponent, getCurrentInstance,
|
|
93
|
+
import { computed, defineComponent, getCurrentInstance, ref, watch, nextTick } from 'vue'
|
|
97
94
|
import './css/index.scss'
|
|
98
95
|
|
|
99
96
|
import props from './js/props'
|
|
@@ -125,6 +122,7 @@ export default defineComponent({
|
|
|
125
122
|
'page-change',
|
|
126
123
|
'toolbar-button-click',
|
|
127
124
|
'toolbar-tool-click',
|
|
125
|
+
'toolbar-btn-click',
|
|
128
126
|
|
|
129
127
|
'form-submit',
|
|
130
128
|
'form-reset',
|
|
@@ -145,16 +143,13 @@ export default defineComponent({
|
|
|
145
143
|
const footSlotRef = ref()
|
|
146
144
|
const pagerSlotRef = ref()
|
|
147
145
|
const bottomSlotRef = ref()
|
|
146
|
+
|
|
148
147
|
const tableHeight = ref(props.height)
|
|
149
148
|
|
|
150
149
|
const useTableHooks = useTable(props, context, proxy)
|
|
151
150
|
|
|
152
151
|
const isTopSlot = computed(() => Boolean(slots.top))
|
|
153
152
|
const isFormSlot = computed(() => useTableHooks.tableGlobalConfig.value.search || Boolean(slots.form))
|
|
154
|
-
const isToolbarSlot = computed(() => {
|
|
155
|
-
const { title, globalFilter } = useTableHooks.tableGlobalConfig.value
|
|
156
|
-
return title || globalFilter || slots.toolbar || slots.toolbarLeft || slots.toolbarRight || useTableHooks.tableTools.value.length
|
|
157
|
-
})
|
|
158
153
|
const isHeadSlot = computed(() => Boolean(slots.head))
|
|
159
154
|
const isFootSlot = computed(() => Boolean(slots.foot))
|
|
160
155
|
const isPagerSlot = computed(() => useTableHooks.tablePagerConfig.value.enabled)
|
|
@@ -184,7 +179,6 @@ export default defineComponent({
|
|
|
184
179
|
tableHeight,
|
|
185
180
|
isTopSlot,
|
|
186
181
|
isFormSlot,
|
|
187
|
-
isToolbarSlot,
|
|
188
182
|
isHeadSlot,
|
|
189
183
|
isFootSlot,
|
|
190
184
|
isPagerSlot,
|
|
@@ -9,10 +9,10 @@
|
|
|
9
9
|
<div ref="navScrollRef" class="sh-tabs-nav-scroll" @DOMMouseScroll="handleScroll" @mousewheel="handleScroll">
|
|
10
10
|
<div ref="navRef" v-resize="handleResize" class="sh-tabs-nav-inner" :style="navStyle">
|
|
11
11
|
<template v-for="(tab, tabIndex) in tabList" :key="tabIndex">
|
|
12
|
-
<div v-
|
|
12
|
+
<div v-bind="getTabItemBind(tab, tabIndex)" @click="handleChange(tab)">
|
|
13
13
|
<slot name="tabItem" v-bind="{ ...tab, isActive: tab[labelKey] === activeKey }">
|
|
14
14
|
<div v-if="tab.icon" class="sh-tab-icon"><sh-icon :type="tab.icon"></sh-icon></div>
|
|
15
|
-
<div class="sh-tab-label">{{ tab[labelField] }}</div>
|
|
15
|
+
<div v-if="tab[labelField]" class="sh-tab-label">{{ tab[labelField] }}</div>
|
|
16
16
|
<div v-if="getTabIsClosable(tab)" class="sh-tab-close" @click.stop="handleClose(tab)"><sh-icon type="ios-close"></sh-icon></div>
|
|
17
17
|
</slot>
|
|
18
18
|
</div>
|
|
@@ -445,7 +445,10 @@ export default defineComponent({
|
|
|
445
445
|
.sh-tab-icon {
|
|
446
446
|
display: inline-flex;
|
|
447
447
|
align-items: center;
|
|
448
|
-
padding: 0 0.
|
|
448
|
+
padding: 0 0.5em;
|
|
449
|
+
& + .sh-tab-label {
|
|
450
|
+
padding-left: 0;
|
|
451
|
+
}
|
|
449
452
|
}
|
|
450
453
|
.sh-tab-label {
|
|
451
454
|
flex: 1;
|
|
@@ -94,7 +94,7 @@ export default defineComponent({
|
|
|
94
94
|
return ''
|
|
95
95
|
})
|
|
96
96
|
const selectConfigIn = computed(() => {
|
|
97
|
-
return Object.assign({ transfer: true
|
|
97
|
+
return Object.assign({ transfer: true }, props.globalConfig?.selectConfig, checkConfig.value)
|
|
98
98
|
})
|
|
99
99
|
const selectInputConfigIn = computed(() => {
|
|
100
100
|
return Object.assign({ clearable: true, controls: false, transfer: false, suffixIcon: 'vxe-icon-caret-down', placeholder: props.placeholder }, props.globalConfig?.inputConfig)
|
|
@@ -2,7 +2,9 @@ import VXETable from 'vxe-table'
|
|
|
2
2
|
import './css/index.scss'
|
|
3
3
|
import VXETablePluginExportXLSX from './plugins/export'
|
|
4
4
|
import VXETablePluginExportPDF from 'vxe-table-plugin-export-pdf'
|
|
5
|
+
import VXETablePluginMenus from 'vxe-table-plugin-menus'
|
|
5
6
|
import { jsPDF } from 'jspdf'
|
|
7
|
+
import ExcelJS from 'exceljs'
|
|
6
8
|
import XEClipboard from 'xe-clipboard'
|
|
7
9
|
import ShValidators from 'sh-tools/packages/utils/validate'
|
|
8
10
|
import { utils } from 'sh-tools'
|
|
@@ -143,6 +145,11 @@ let vxeOptions = {
|
|
|
143
145
|
autoHidden: false,
|
|
144
146
|
enabled: true
|
|
145
147
|
},
|
|
148
|
+
toolbar: {
|
|
149
|
+
custom: {
|
|
150
|
+
immediate: false
|
|
151
|
+
}
|
|
152
|
+
},
|
|
146
153
|
form: {},
|
|
147
154
|
modal: {
|
|
148
155
|
lockView: true,
|
|
@@ -190,7 +197,10 @@ let vxePdfOptions = {
|
|
|
190
197
|
jsPDF,
|
|
191
198
|
fonts: [{ fontName: 'SourceHanSansNormal' }]
|
|
192
199
|
}
|
|
193
|
-
let vxeXlsxOptions = {
|
|
200
|
+
let vxeXlsxOptions = {
|
|
201
|
+
ExcelJS
|
|
202
|
+
}
|
|
203
|
+
let vxeMenuOptions = {}
|
|
194
204
|
Object.keys(ShValidators).forEach(key => {
|
|
195
205
|
VXETable.validators.add(key, {
|
|
196
206
|
itemValidatorMethod({ itemValue }) {
|
|
@@ -207,13 +217,15 @@ VXETable.renderer.mixin(extraRenders)
|
|
|
207
217
|
VXETable.renderer.mixin(filterRenders)
|
|
208
218
|
|
|
209
219
|
const index = {
|
|
210
|
-
install(Vue, { vxeOption
|
|
220
|
+
install(Vue, { vxeOption, vxePdfOption, vxeXlsxOption, vxeMenuOption }) {
|
|
211
221
|
let setupOption = utils.merge(vxeOptions, vxeOption)
|
|
212
222
|
let xlsxSetUpOption = utils.merge(vxeXlsxOptions, vxeXlsxOption)
|
|
213
223
|
let pdfSetUpOption = utils.merge(vxePdfOptions, vxePdfOption)
|
|
224
|
+
let menuSetUpOption = utils.merge(vxeMenuOptions, vxeMenuOption)
|
|
214
225
|
VXETable.setup(setupOption)
|
|
215
226
|
VXETable.use(VXETablePluginExportXLSX, xlsxSetUpOption)
|
|
216
227
|
VXETable.use(VXETablePluginExportPDF, pdfSetUpOption)
|
|
228
|
+
VXETable.use(VXETablePluginMenus, menuSetUpOption)
|
|
217
229
|
Vue.use(VXETable)
|
|
218
230
|
Vue.config.globalProperties.$vTable = VXETable
|
|
219
231
|
Vue.config.globalProperties.$vTableSetup = setupOption
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import XEUtils from 'xe-utils'
|
|
2
|
-
import ExcelJS from 'exceljs'
|
|
3
2
|
|
|
4
|
-
let
|
|
3
|
+
let globalVxetable = null
|
|
4
|
+
let globalExcelJS = null
|
|
5
5
|
|
|
6
6
|
const defaultHeaderBackgroundColor = '80c1ff'
|
|
7
|
-
const defaultCellFontColor = '
|
|
7
|
+
const defaultCellFontColor = '333333'
|
|
8
8
|
const defaultCellBorderStyle = 'thin'
|
|
9
9
|
const defaultCellBorderColor = 'e7f1ff'
|
|
10
10
|
|
|
@@ -96,12 +96,15 @@ function getDefaultBorderStyle() {
|
|
|
96
96
|
|
|
97
97
|
function exportXLSX(params) {
|
|
98
98
|
const msgKey = 'xlsx'
|
|
99
|
-
const { modal, t } =
|
|
99
|
+
const { modal, t } = globalVxetable
|
|
100
100
|
const { $table, options, columns, colgroups, datas } = params
|
|
101
101
|
const { props, reactData } = $table
|
|
102
|
+
const { computeColumnOpts } = $table.getComputeMaps()
|
|
102
103
|
const { headerAlign: allHeaderAlign, align: allAlign, footerAlign: allFooterAlign } = props
|
|
103
104
|
const { rowHeight } = reactData
|
|
104
105
|
const { message, sheetName, isHeader, isFooter, isMerge, isColgroup, original, useStyle, sheetMethod } = options
|
|
106
|
+
const columnOpts = computeColumnOpts.value
|
|
107
|
+
const _isCustomColumn = options._isCustomColumn
|
|
105
108
|
const showMsg = message !== false
|
|
106
109
|
const mergeCells = $table.getMergeCells()
|
|
107
110
|
const colList = []
|
|
@@ -110,10 +113,8 @@ function exportXLSX(params) {
|
|
|
110
113
|
const sheetMerges = []
|
|
111
114
|
let beforeRowCount = 0
|
|
112
115
|
let headerRowCount = 0
|
|
113
|
-
const colHead = {}
|
|
114
116
|
columns.forEach(column => {
|
|
115
|
-
const { id,
|
|
116
|
-
colHead[id] = headerExportMethod ? headerExportMethod({ column, $table }) : original ? field : column.getTitle()
|
|
117
|
+
const { id, renderWidth } = column
|
|
117
118
|
sheetCols.push({
|
|
118
119
|
key: id,
|
|
119
120
|
width: XEUtils.ceil(renderWidth / 8, 1)
|
|
@@ -129,10 +130,11 @@ function exportXLSX(params) {
|
|
|
129
130
|
groupHead[column.id] = null
|
|
130
131
|
})
|
|
131
132
|
cols.forEach(column => {
|
|
132
|
-
const { _colSpan, _rowSpan
|
|
133
|
+
const { _colSpan, _rowSpan } = column
|
|
133
134
|
const validColumn = getValidColumn(column)
|
|
134
135
|
const columnIndex = columns.indexOf(validColumn)
|
|
135
|
-
|
|
136
|
+
const headExportMethod = column.headerExportMethod || columnOpts.headerExportMethod
|
|
137
|
+
groupHead[validColumn.id] = headExportMethod ? headExportMethod({ column, options, $table }) : original ? validColumn.field : column.getTitle()
|
|
136
138
|
if (_colSpan > 1 || _rowSpan > 1) {
|
|
137
139
|
sheetMerges.push({
|
|
138
140
|
s: { r: rIndex, c: columnIndex },
|
|
@@ -143,13 +145,19 @@ function exportXLSX(params) {
|
|
|
143
145
|
colList.push(groupHead)
|
|
144
146
|
})
|
|
145
147
|
} else {
|
|
148
|
+
const colHead = {}
|
|
149
|
+
columns.forEach(column => {
|
|
150
|
+
const { id, field } = column
|
|
151
|
+
const headExportMethod = column.headerExportMethod || columnOpts.headerExportMethod
|
|
152
|
+
colHead[id] = headExportMethod ? headExportMethod({ column, options, $table }) : original ? field : column.getTitle()
|
|
153
|
+
})
|
|
146
154
|
colList.push(colHead)
|
|
147
155
|
}
|
|
148
156
|
headerRowCount = colList.length
|
|
149
157
|
beforeRowCount += headerRowCount
|
|
150
158
|
}
|
|
151
159
|
// 处理合并
|
|
152
|
-
if (isMerge) {
|
|
160
|
+
if (isMerge && !_isCustomColumn) {
|
|
153
161
|
mergeCells.forEach(mergeItem => {
|
|
154
162
|
const { row: mergeRowIndex, rowspan: mergeRowspan, col: mergeColIndex, colspan: mergeColspan } = mergeItem
|
|
155
163
|
sheetMerges.push({
|
|
@@ -172,7 +180,7 @@ function exportXLSX(params) {
|
|
|
172
180
|
const footers = getFooterData(options, footerData)
|
|
173
181
|
const mergeFooterItems = $table.getMergeFooterItems()
|
|
174
182
|
// 处理合并
|
|
175
|
-
if (isMerge) {
|
|
183
|
+
if (isMerge && !_isCustomColumn) {
|
|
176
184
|
mergeFooterItems.forEach(mergeItem => {
|
|
177
185
|
const { row: mergeRowIndex, rowspan: mergeRowspan, col: mergeColIndex, colspan: mergeColspan } = mergeItem
|
|
178
186
|
sheetMerges.push({
|
|
@@ -190,7 +198,7 @@ function exportXLSX(params) {
|
|
|
190
198
|
})
|
|
191
199
|
}
|
|
192
200
|
const exportMethod = () => {
|
|
193
|
-
const workbook = new ExcelJS.Workbook()
|
|
201
|
+
const workbook = new (globalExcelJS || window.ExcelJS).Workbook()
|
|
194
202
|
const sheet = workbook.addWorksheet(sheetName, { views: [{ state: 'frozen', xSplit: 0, ySplit: headerRowCount }] })
|
|
195
203
|
workbook.creator = 'vxe-table'
|
|
196
204
|
sheet.columns = sheetCols
|
|
@@ -271,7 +279,8 @@ function exportXLSX(params) {
|
|
|
271
279
|
})
|
|
272
280
|
})
|
|
273
281
|
}
|
|
274
|
-
|
|
282
|
+
// 自定义处理
|
|
283
|
+
if (sheetMethod) {
|
|
275
284
|
sheetMethod({ options: options, workbook, worksheet: sheet, columns, colgroups, datas, $table })
|
|
276
285
|
}
|
|
277
286
|
sheetMerges.forEach(({ s, e }) => {
|
|
@@ -296,7 +305,7 @@ function exportXLSX(params) {
|
|
|
296
305
|
}
|
|
297
306
|
|
|
298
307
|
function downloadFile(params, blob, options) {
|
|
299
|
-
const { modal, t } =
|
|
308
|
+
const { modal, t } = globalVxetable
|
|
300
309
|
const { message, filename, type } = options
|
|
301
310
|
const showMsg = message !== false
|
|
302
311
|
if (window.Blob) {
|
|
@@ -323,7 +332,7 @@ function checkImportData(tableFields, fields) {
|
|
|
323
332
|
}
|
|
324
333
|
|
|
325
334
|
function importError(params) {
|
|
326
|
-
const { modal, t } =
|
|
335
|
+
const { modal, t } = globalVxetable
|
|
327
336
|
const { $table, options } = params
|
|
328
337
|
const { internalData } = $table
|
|
329
338
|
const { _importReject } = internalData
|
|
@@ -337,7 +346,7 @@ function importError(params) {
|
|
|
337
346
|
}
|
|
338
347
|
|
|
339
348
|
function importXLSX(params) {
|
|
340
|
-
const { modal, t } =
|
|
349
|
+
const { modal, t } = globalVxetable
|
|
341
350
|
const { $table, columns, options, file } = params
|
|
342
351
|
const { internalData } = $table
|
|
343
352
|
const { _importResolve } = internalData
|
|
@@ -354,7 +363,7 @@ function importXLSX(params) {
|
|
|
354
363
|
tableFields.push(field)
|
|
355
364
|
}
|
|
356
365
|
})
|
|
357
|
-
const workbook = new ExcelJS.Workbook()
|
|
366
|
+
const workbook = new (globalExcelJS || window.ExcelJS).Workbook()
|
|
358
367
|
const readerTarget = evnt.target
|
|
359
368
|
if (readerTarget) {
|
|
360
369
|
workbook.xlsx.load(readerTarget.result).then(wb => {
|
|
@@ -421,22 +430,26 @@ function handleExportEvent(params) {
|
|
|
421
430
|
}
|
|
422
431
|
|
|
423
432
|
/**
|
|
424
|
-
* 基于 vxe-table
|
|
433
|
+
* 基于 vxe-table 表格的扩展插件,支持导出 xlsx 格式
|
|
425
434
|
*/
|
|
426
435
|
export const VXETablePluginExportXLSX = {
|
|
427
|
-
install(
|
|
428
|
-
|
|
436
|
+
install(vxetable, options) {
|
|
437
|
+
// 检查版本
|
|
438
|
+
if (!/^(4)\./.test(vxetable.version)) {
|
|
439
|
+
console.error('[vxe-table-plugin-export-pdf] Version vxe-table 4.x is required')
|
|
440
|
+
}
|
|
429
441
|
|
|
430
|
-
|
|
442
|
+
globalVxetable = vxetable
|
|
443
|
+
globalExcelJS = options ? options.ExcelJS : null
|
|
431
444
|
|
|
432
|
-
|
|
445
|
+
vxetable.config({
|
|
433
446
|
export: {
|
|
434
447
|
types: {
|
|
435
448
|
xlsx: 0
|
|
436
449
|
}
|
|
437
450
|
}
|
|
438
451
|
})
|
|
439
|
-
interceptor.mixin({
|
|
452
|
+
vxetable.interceptor.mixin({
|
|
440
453
|
'event.import': handleImportEvent,
|
|
441
454
|
'event.export': handleExportEvent
|
|
442
455
|
})
|
|
@@ -43,7 +43,7 @@ let defaultProps = {
|
|
|
43
43
|
$vTextArea: { placeholder: '请输入', rows: 2, transfer: true, resize: 'none', showWordCount: true },
|
|
44
44
|
$vSelect: { placeholder: '请选择', filterable: true, transfer: true, showType: 'text', tagColor: 'default', split: ',', options: [] },
|
|
45
45
|
$vTree: { placeholder: '请选择', transfer: true, split: ',', nodeKey: 'id', labelField: 'label' },
|
|
46
|
-
$vTime: { type: 'date', placeholder: '请选择时间', transfer: true, editable: false, prefixType: 'text', suffixType: 'text' },
|
|
46
|
+
$vTime: { type: 'date', placeholder: '请选择时间', transfer: true, editable: false, prefixType: 'text', suffixType: 'text', separator: '至' },
|
|
47
47
|
$vProgress: { strokeWidth: 20, strokeColor: ['#108ee9', '#87d068'], textInside: true, min: 0, max: 100, digits: 2 },
|
|
48
48
|
$vSwitch: { placeholder: '请选择', openLabel: '是', openValue: '1', closeLabel: '否', closeValue: '0' },
|
|
49
49
|
$vMoney: { type: 'number', placeholder: '请输入', transfer: true, commafy: true, digits: 2, moneyUnit: 1, min: 0, max: 1000000000000 },
|
|
@@ -27,6 +27,7 @@ export default function (props, context, proxy) {
|
|
|
27
27
|
// 初始化数据
|
|
28
28
|
const initData = () => {
|
|
29
29
|
let keyValue = $vUtils.get(props.rdata, props.rkey)
|
|
30
|
+
if (keyValue && $vUtils.isEqual(keyValue, renderValue.value)) return
|
|
30
31
|
formatValueFun(keyValue)
|
|
31
32
|
}
|
|
32
33
|
|
|
@@ -98,10 +99,18 @@ export default function (props, context, proxy) {
|
|
|
98
99
|
renderText.value = footerText
|
|
99
100
|
return
|
|
100
101
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
102
|
+
const { rvalue, rtext } = $vUtils.formatRender(value, props.rkey, props.rdata, props.rname, props.rprops, proxy, editable)
|
|
103
|
+
if (['$vMoney'].includes(props.rname)) {
|
|
104
|
+
renderValue.value = rtext
|
|
105
|
+
} else {
|
|
106
|
+
renderValue.value = rvalue
|
|
107
|
+
}
|
|
108
|
+
if (props.rname === '$vTime' && props.rprops.range && Array.isArray(rtext) && rtext.length > 0) {
|
|
109
|
+
renderText.value = `${rtext[0] || ''}${props.rprops.separator}${rtext[1] || ''}`
|
|
110
|
+
} else {
|
|
111
|
+
renderText.value = rtext
|
|
112
|
+
}
|
|
113
|
+
return { rvalue, rtext }
|
|
105
114
|
}
|
|
106
115
|
const getBillClass = bil => {
|
|
107
116
|
return { basic: bil.fullText === '元', commafy: ['千', '百万', '十亿', '兆'].includes(bil.fullText) }
|