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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sh-view",
3
- "version": "2.8.12",
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.20",
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": {
@@ -568,7 +568,7 @@ export default defineComponent({
568
568
  padding-top: 0;
569
569
  }
570
570
  &.is-month {
571
- padding: 20px 5px;
571
+ padding: 10px 5px;
572
572
  }
573
573
  }
574
574
  &-body {
@@ -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-wrap{
53
- display: flex;
54
- flex: 0 0 auto;
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
- font-size: 14px;
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-wrap">
41
- <div class="sh-table-toolbar-left">
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
- </div>
56
- <div class="sh-table-toolbar-right">
57
- <div v-if="slots.toolbarRight" class="sh-table-toolbar-item">
58
- <slot name="toolbarRight"></slot>
59
- </div>
60
- <template v-for="(tool, toolIndex) in tableTools" :key="toolIndex">
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
- <div v-if="tableMoneyConfig.enabled" class="sh-table-toolbar-item">单位:<sh-select v-model="tableMoneyUnit" v-bind="tableMoneyConfig" /></div>
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: 'shtable'
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', content: '新增行' },
46
- { status: 'danger', code: 'deleteRow', content: '删除行' },
47
- { status: 'primary', code: 'import', icon: 'vxe-icon-upload', content: '导入' },
48
- { status: 'success', code: 'export', icon: 'vxe-icon-download', content: '导出' },
49
- { status: 'warning', code: 'print', icon: 'vxe-icon-print', content: '打印' }
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 data = $vUtils.clone(tableRef.value.getTableData().fullData, true)
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
- deep: true,
578
- immediate: true
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
- <div class="sh-table-toolbar-wrap">
15
- <div class="sh-table-toolbar-left">
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
- </div>
30
- <div class="sh-table-toolbar-right">
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
- <template v-for="(tool, toolIndex) in tableTools" :key="toolIndex">
35
- <div class="sh-table-toolbar-item">
36
- <vxe-button v-ripple :size="size" v-bind="tool" @click="handleTableTool(tool)"></vxe-button>
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
- </div>
41
- </div>
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, provide, ref, reactive } from 'vue'
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-ripple v-bind="getTabItemBind(tab, tabIndex)" @click="handleChange(tab)">
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.2em 0 0.7em;
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;
@@ -34,7 +34,7 @@
34
34
  }
35
35
 
36
36
  .sh-tree-select-dropdown {
37
- height: 230px
37
+ height: 230px;
38
38
  }
39
39
 
40
40
  .sh-vxe-tree-table{
@@ -94,7 +94,7 @@ export default defineComponent({
94
94
  return ''
95
95
  })
96
96
  const selectConfigIn = computed(() => {
97
- return Object.assign({ transfer: true, popupClassName: 'sh-tree-select-dropdown' }, props.globalConfig?.selectConfig, checkConfig.value)
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)
@@ -162,9 +162,6 @@ button:focus, .vxe-button.type--button:not(.is--disabled):focus{
162
162
  .vxe-cell-href-a{
163
163
  text-decoration: underline;
164
164
  }
165
- .vxe-cell--sort{
166
- font-size: .9em;
167
- }
168
165
  }
169
166
  }
170
167
 
@@ -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 = {}, vxePdfOption = {}, vxeXlsxOption }) {
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 vxetable = null
3
+ let globalVxetable = null
4
+ let globalExcelJS = null
5
5
 
6
6
  const defaultHeaderBackgroundColor = '80c1ff'
7
- const defaultCellFontColor = '606266'
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 } = vxetable
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, field, renderWidth, headerExportMethod } = column
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, headerExportMethod } = column
133
+ const { _colSpan, _rowSpan } = column
133
134
  const validColumn = getValidColumn(column)
134
135
  const columnIndex = columns.indexOf(validColumn)
135
- groupHead[validColumn.id] = headerExportMethod ? headerExportMethod({ column, $table }) : original ? validColumn.field : column.getTitle()
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
- if (useStyle && sheetMethod) {
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 } = vxetable
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 } = vxetable
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 } = vxetable
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 表格的增强插件,支持导出 xlsx 格式
433
+ * 基于 vxe-table 表格的扩展插件,支持导出 xlsx 格式
425
434
  */
426
435
  export const VXETablePluginExportXLSX = {
427
- install(vxetablecore) {
428
- const { setup, interceptor } = vxetablecore
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
- vxetable = vxetablecore
442
+ globalVxetable = vxetable
443
+ globalExcelJS = options ? options.ExcelJS : null
431
444
 
432
- setup({
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
  })
@@ -58,7 +58,7 @@ export default defineComponent({
58
58
  $vUtils.set(props.rdata, fromKey, fromvalue)
59
59
  })
60
60
  }
61
- useCell.setRenderValue(rvalue, true)
61
+ useCell.setRenderValue(rvalue)
62
62
  }
63
63
 
64
64
  return {
@@ -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
- let formatObj = $vUtils.formatRender(value, props.rkey, props.rdata, props.rname, props.rprops, proxy, editable)
102
- renderValue.value = ['$vMoney'].includes(props.rname) ? formatObj.rtext : formatObj.rvalue
103
- renderText.value = formatObj.rtext
104
- return formatObj
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) }