sh-view 2.8.13 → 2.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sh-view",
3
- "version": "2.8.13",
3
+ "version": "2.9.0",
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",
@@ -32,14 +32,15 @@
32
32
  "jszip": "^3.10.1",
33
33
  "lunar-typescript": "^1.6.10",
34
34
  "popper.js": "^1.16.1",
35
- "sh-tools": "^2.2.10",
35
+ "sh-tools": "^2.2.12",
36
36
  "tinymce": "^5.10.5",
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 {
@@ -1,5 +1,5 @@
1
1
  import { computed, onBeforeMount, ref, watch } from 'vue'
2
- import { getFieldRules } from '../../sh-table/js/tableMethods'
2
+ import { formulaReplaceAll, getFieldRules } from '../../sh-table/js/tableMethods'
3
3
 
4
4
  // 表单默认配置
5
5
  const formConfigDefault = {
@@ -35,11 +35,17 @@ export default function (props, context, proxy, isForm) {
35
35
  const formRules = ref({})
36
36
 
37
37
  const formBindConfig = computed(() => {
38
+ let formulaMap = {}
39
+ $vUtils.eachTree(props.items, column => {
40
+ let rformula = $vUtils.get(column, 'renderProps.formula')
41
+ if (rformula) formulaMap[column.field] = rformula
42
+ })
38
43
  return Object.assign({ size: isForm ? 'medium' : 'small' }, formConfigDefault, props.formConfig, {
39
44
  items: formItems.value,
40
45
  data: props.data,
41
46
  rules: props.valid ? formRules.value : {},
42
- validConfig: props.validConfig
47
+ validConfig: props.validConfig,
48
+ formulaMap: formulaReplaceAll(formulaMap)
43
49
  })
44
50
  })
45
51
 
@@ -63,8 +69,8 @@ export default function (props, context, proxy, isForm) {
63
69
  }
64
70
  // 表单项编辑回调
65
71
  const onFormEditClosed = async params => {
66
- emit('edit-closed', params)
67
72
  Object.assign(props.data, params.data)
73
+ emit('edit-closed', params)
68
74
  }
69
75
  // 表单校验不通过
70
76
  const onFormSubmitInvalid = params => {
@@ -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,
@@ -240,12 +240,10 @@ export default {
240
240
  return {}
241
241
  }
242
242
  },
243
- scrollX: {
244
- type: Object
245
- },
246
- scrollY: {
247
- type: Object
248
- },
243
+ scrollX: Object,
244
+ scrollY: Object,
245
+ params: Object,
246
+ footerData: Array,
249
247
 
250
248
  // 扩展配置
251
249
  disabled: {
@@ -270,6 +268,12 @@ export default {
270
268
  return {}
271
269
  }
272
270
  },
271
+ menuConfig: {
272
+ type: Object,
273
+ default() {
274
+ return {}
275
+ }
276
+ },
273
277
  footerCalculate: {
274
278
  type: Object,
275
279
  default() {
@@ -171,3 +171,22 @@ export const getTransfarFields = (oriArr = [], { slots, columnObj, isSearch }) =
171
171
  })
172
172
  return { columnsArr, columnsFlatArr, formItemsArr, rules }
173
173
  }
174
+ // 递归替换嵌套依赖公式
175
+ export const formulaReplaceAll = formulaMap => {
176
+ Object.keys(formulaMap).forEach(key => {
177
+ let dowhile = true
178
+ while (dowhile) {
179
+ let regUKey = formulaMap[key].match(/\$?[a-zA-Z0-9_.]{0,}\{[A-Za-z0-9_.]{1,}\}/gi) || []
180
+ regUKey = regUKey.filter(item => item.startsWith('${') || item.startsWith('{')).map((key, keyIndex) => key.replace(/\$?{|}/gi, ''))
181
+ dowhile = !regUKey.every((keyc, indexkey) => {
182
+ if (formulaMap[keyc]) {
183
+ formulaMap[key] = formulaMap[key].replace('{' + keyc + '}', '(' + formulaMap[keyc] + ')')
184
+ return false
185
+ } else {
186
+ return true
187
+ }
188
+ })
189
+ }
190
+ })
191
+ return formulaMap
192
+ }
@@ -1,5 +1,5 @@
1
- import { computed, onMounted, reactive, ref, watch } from 'vue'
2
- import { columnDefaultFilterMethod, tableFooterCompute, getTransfarFields } from './tableMethods'
1
+ import { computed, onMounted, reactive, ref, watch, nextTick } from 'vue'
2
+ import { columnDefaultFilterMethod, tableFooterCompute, getTransfarFields, formulaReplaceAll } from './tableMethods'
3
3
 
4
4
  // 记录自定义参数,传给vxe要过滤掉
5
5
  let omitProps = [
@@ -39,14 +39,37 @@ const exportAndPrintDefault = {
39
39
  isAllExpand: true,
40
40
  download: true,
41
41
  useStyle: false,
42
+ isUnit: false,
42
43
  columnFilterMethod: columnDefaultFilterMethod
43
44
  }
45
+ const menuConfigDefault = {
46
+ header: {
47
+ options: [
48
+ [
49
+ { code: 'HIDDEN_COLUMN', name: '隐藏' },
50
+ { code: 'RESET_COLUMN', name: '取消隐藏' },
51
+ { code: 'FIXED_LEFT_COLUMN', name: '固定到左侧' },
52
+ { code: 'FIXED_RIGHT_COLUMN', name: '固定到右侧' },
53
+ { code: 'CLEAR_FIXED_COLUMN', name: '取消固定' }
54
+ ]
55
+ ]
56
+ },
57
+ body: {
58
+ options: [
59
+ [
60
+ { code: 'SORT_ASC', name: '升序', prefixIcon: 'fa fa-sort-alpha-desc' },
61
+ { code: 'SORT_DESC', name: '倒序', prefixIcon: 'fa fa-sort-alpha-desc' },
62
+ { code: 'CLEAR_SORT', name: '清除排序' }
63
+ ]
64
+ ]
65
+ }
66
+ }
44
67
  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: '打印' }
68
+ { status: 'primary', code: 'addRow', icon: 'vxe-icon-square-plus', title: '新增行', circle: true },
69
+ { status: 'danger', code: 'deleteRow', icon: 'vxe-icon-square-minus', title: '删除行', circle: true },
70
+ { status: 'primary', code: 'import', icon: 'vxe-icon-upload', title: '导入', circle: true },
71
+ { status: 'success', code: 'export', icon: 'vxe-icon-download', title: '导出', circle: true },
72
+ { status: 'warning', code: 'print', icon: 'vxe-icon-print', title: '打印', circle: true }
50
73
  ]
51
74
  // 表头默认值
52
75
  const columnObjDefault = { minWidth: 120, sortable: true, filter: true }
@@ -58,10 +81,11 @@ const columnsMapDefault = {
58
81
  }
59
82
 
60
83
  export default function (props, context, proxy, isGrid) {
61
- const { $vUtils, $vTableSetup, $vxePluginNames } = proxy
84
+ const { $vUtils, $vTableSetup, $vxePluginNames, $route } = proxy
62
85
  const { emit, slots } = context
63
86
 
64
87
  const tableRef = ref()
88
+ const toolbarRef = ref()
65
89
  const renderKey = ref(1) // 渲染key值
66
90
  const selectedRowKeys = ref([]) // table选中keys
67
91
  const selectionRows = ref([]) // table选中records
@@ -106,18 +130,19 @@ export default function (props, context, proxy, isGrid) {
106
130
  return hasTree.value ? Object.assign({}, props.treeConfig) : null
107
131
  })
108
132
  const tableSeqConfig = computed(() => {
133
+ const pagerConfig = tablePagerConfig.value
134
+ const pageStart = (+pagerConfig.pageSize || 50) * ((+pagerConfig.currentPage || 1) - 1)
109
135
  return {
110
- seqMethod: ({ $table, seq, $seq, $$seq, $rowIndex }) => {
111
- const tablePage = tablePagerConfig.value.enabled
112
- if ($$seq) {
113
- return $$seq
114
- } else if (tablePage) {
115
- const pageStart = (+tablePagerConfig.value.pageSize || 50) * ((+tablePagerConfig.value.currentPage || 1) - 1)
116
- return hasTree.value && $seq ? Number(pageStart) + Number($seq) + '.' + seq : Number(pageStart) + Number(seq)
117
- } else if (hasTree.value) {
118
- return $seq ? $seq + '.' + seq : seq
136
+ seqMethod: ({ $table, seq, $rowIndex }) => {
137
+ if (pagerConfig && pagerConfig.enabled) {
138
+ if (String(seq).includes('.')) {
139
+ const seqIndex = seq.indexOf('.')
140
+ const seqStart = seq.substr(0, seqIndex)
141
+ return $vUtils.add(pageStart, seqStart) + seq.substr(seqIndex)
142
+ }
143
+ return $vUtils.add(pageStart, seq)
119
144
  }
120
- return seq === -1 ? $rowIndex + 1 : seq
145
+ return seq
121
146
  }
122
147
  }
123
148
  })
@@ -166,14 +191,23 @@ export default function (props, context, proxy, isGrid) {
166
191
  tableVmConfig.value
167
192
  )
168
193
  })
194
+ const tableToolbarConfig = computed(() => {
195
+ return Object.assign({ perfect: true, zoom: tableGlobalConfig.value.zoom, custom: tableGlobalConfig.value.custom }, props.toolbarConfig, tableVmConfig.value)
196
+ })
197
+ const tableMenuConfig = computed(() => Object.assign({ enabled: false }, menuConfigDefault, props.menuConfig))
169
198
  const tableFilterConfig = computed(() => Object.assign({ clearable: true, type: 'search', placeholder: '全局关键字搜索' }, tableVmConfig.value))
170
199
  const tableSlots = computed(() => {
171
200
  let disSlots = ['top', 'head', 'foot', 'form', 'toolbar', 'formLeft', 'formRight', 'toolbarLeft', 'toolbarRight', 'pagerLeft', 'pagerRight']
172
201
  return Object.keys(slots).filter(key => !disSlots.includes(key))
173
202
  })
174
203
  const tableBindConfig = computed(() => {
175
- let defaultProps = { footerMethod: tableFooterMethod, footerSpanMethod: tableFooterSpanMethod }
204
+ let defaultProps = { id: `sh-table-${$route.fullPath}`, footerMethod: tableFooterMethod, footerSpanMethod: tableFooterSpanMethod }
176
205
  let tableProps = $vUtils.omit(props, (val, key) => omitProps.includes(key) || $vUtils.isNone(val))
206
+ let formulaMap = {}
207
+ $vUtils.eachTree(props.columns, column => {
208
+ let rformula = $vUtils.get(column, 'renderProps.formula')
209
+ if (rformula) formulaMap[column.field] = rformula
210
+ })
177
211
  let shProps = {
178
212
  data: tableViewData.value,
179
213
  stripe: props.stripe && !tableTreeConfig.value,
@@ -186,8 +220,11 @@ export default function (props, context, proxy, isGrid) {
186
220
  exportConfig: tableExportConfig.value,
187
221
  printConfig: tablePrintConfig.value,
188
222
  moneyConfig: tableMoneyConfig.value,
189
- moneyUnit: tableMoneyUnit.value
223
+ moneyUnit: tableMoneyUnit.value,
224
+ menuConfig: tableMenuConfig.value,
225
+ formulaMap: formulaReplaceAll(formulaMap)
190
226
  }
227
+ if (tableMenuConfig.value.enabled) shProps.menuConfig = tableMenuConfig.value
191
228
  return Object.assign(defaultProps, tableProps, shProps)
192
229
  })
193
230
  const importBindConfig = reactive({
@@ -197,6 +234,15 @@ export default function (props, context, proxy, isGrid) {
197
234
  importConfig: props.importConfig,
198
235
  importRules: tableEditRules.value
199
236
  })
237
+ const isToolbarSlot = computed(() => {
238
+ const globalFg = tableGlobalConfig.value
239
+ const toolbarFg = tableToolbarConfig.value
240
+ const toolsFg = tableTools.value
241
+ const globalTool = globalFg.title || globalFg.globalFilter
242
+ const toolbarTool = toolbarFg.import || toolbarFg.export || toolbarFg.print || toolbarFg.refresh || toolbarFg.custom
243
+ const slotsTool = slots.toolbar || slots.toolbarLeft || slots.toolbarRight
244
+ return globalTool || toolbarTool || slotsTool || toolsFg.length > 0
245
+ })
200
246
 
201
247
  // 获取选中数据
202
248
  const getSelectionData = () => {
@@ -205,16 +251,23 @@ export default function (props, context, proxy, isGrid) {
205
251
  // 获取全部数据
206
252
  // visible为true获取视图数据
207
253
  const getFullData = params => {
208
- const { visible = false, deleteXid = false } = params || {}
209
- let data = $vUtils.clone(tableRef.value.getTableData().fullData, true)
254
+ const { visible = false, deleteXid = false, datas = null } = params || {}
255
+ let fullData = datas || tableRef.value.internalData.afterFullData
256
+ let data = $vUtils.clone(fullData, true)
210
257
  const columns = tableRef.value.getColumns()
211
258
  let rnameColumns = columns.filter(col => col.rname)
212
259
  rnameColumns.forEach(col => {
213
260
  let { property, rname, rprops } = col
214
261
  data.forEach(row => {
215
262
  let cellValue = $vUtils.get(row, property)
216
- let { rvalue, rtext } = $vUtils.formatRender(cellValue, property, row, rname, rprops, proxy)
217
- $vUtils.set(row, property, visible ? rtext : rvalue)
263
+ let { rvalue, rtext } = $vUtils.formatRender(cellValue, property, row, rname, { ...rprops, commafy: false }, proxy)
264
+ if (rprops.bill && rprops.bill !== '0') {
265
+ $vUtils.set(row, property, rvalue)
266
+ } else if (visible) {
267
+ $vUtils.set(row, property, rtext)
268
+ } else {
269
+ $vUtils.set(row, property, rvalue)
270
+ }
218
271
  if (deleteXid) delete row._XID
219
272
  })
220
273
  })
@@ -223,10 +276,18 @@ export default function (props, context, proxy, isGrid) {
223
276
  // 表格打印、导出统一导出前渲染数据
224
277
  const getExportPrintDataByOption = (obj = {}, type) => {
225
278
  let { options, content } = obj
226
- let { data, columns, mode, original } = options
227
- if (!data) {
228
- options.data = mode === 'selected' ? getSelectionData() : getFullData({ visible: !original })
229
- }
279
+ let { data, columns, mode, original, isUnit } = options
280
+ let exportDatas = data
281
+ $vUtils.eachTree(columns, col => {
282
+ const { rname, rprops } = col
283
+ if (rname === '$vMoney' && isUnit && rprops.moneyOption?.label && !col.headerExportMethod && !original) {
284
+ col.headerExportMethod = () => {
285
+ return `${col.title}(${rprops.moneyOption.label})`
286
+ }
287
+ }
288
+ })
289
+ if (mode === 'selected') exportDatas = getSelectionData()
290
+ options.data = getFullData({ deleteXid: true, visible: !original, datas: exportDatas })
230
291
  return type === 'print' ? content : obj
231
292
  }
232
293
 
@@ -235,8 +296,9 @@ export default function (props, context, proxy, isGrid) {
235
296
  const { footerCalculate } = props
236
297
  let footerData = []
237
298
  let footerCalculateList = footerCalculate.calculate || []
299
+ let fullData = getFullData({ deleteXid: true, datas: data })
238
300
  footerCalculateList.forEach(computeType => {
239
- footerData.push(tableFooterCompute(columns, data, computeType, footerCalculate[computeType]))
301
+ footerData.push(tableFooterCompute(columns, fullData, computeType, footerCalculate[computeType]))
240
302
  })
241
303
  return footerData
242
304
  }
@@ -330,19 +392,6 @@ export default function (props, context, proxy, isGrid) {
330
392
  }
331
393
  // 只对 edit-config 配置时有效,单元格编辑状态下被关闭时会触发该事件
332
394
  const onEditClosed = params => {
333
- // 此操作火狐浏览器(bug(vxe):编辑后不触发渲染器的blur问题)
334
- const userAgent = navigator.userAgent
335
- if (userAgent.indexOf('Firefox') !== -1) {
336
- let { row, column } = params
337
- let editModel = $vUtils.get(column, 'params.__RowEditModelValue')
338
- if (editModel !== undefined) {
339
- if (['$vMoney'].includes(column.rname) && !$vUtils.isNone(editModel)) editModel = $vUtils.multiply(editModel, column.rprops.moneyUnit || 1)
340
- let { rvalue, rtext } = $vUtils.formatRender(editModel, column.property, row, column.rname, column.rprops, proxy, true)
341
- editModel = rvalue
342
- $vUtils.set(row, column.property, editModel)
343
- delete column.params.__RowEditModelValue
344
- }
345
- }
346
395
  emit('edit-closed', params)
347
396
  }
348
397
  // 只对 edit-config 配置时有效,单元格被激活编辑时会触发该事件
@@ -479,6 +528,7 @@ export default function (props, context, proxy, isGrid) {
479
528
  handleTablePrintBtn()
480
529
  break
481
530
  }
531
+ emit('toolbar-btn-click', code)
482
532
  }
483
533
  // 表格导出按钮
484
534
  const handleTableExportBtn = options => {
@@ -498,6 +548,17 @@ export default function (props, context, proxy, isGrid) {
498
548
  }
499
549
  return tableRef.value.openPrint(options)
500
550
  }
551
+ // 关联toolbar
552
+ const connectToolbar = () => {
553
+ nextTick(() => {
554
+ // 将表格和工具栏进行关联
555
+ const $table = tableRef.value
556
+ const $toolbar = toolbarRef.value
557
+ if ($table && $toolbar) {
558
+ $table.connect($toolbar)
559
+ }
560
+ })
561
+ }
501
562
 
502
563
  // 自定义操作列点击事件
503
564
  const handleGoptionClick = async (btnObj, dataObj) => {
@@ -554,9 +615,7 @@ export default function (props, context, proxy, isGrid) {
554
615
  value => {
555
616
  initTableColumns()
556
617
  },
557
- {
558
- deep: true
559
- }
618
+ { deep: true }
560
619
  )
561
620
  watch(
562
621
  () => props.dataSourse,
@@ -564,24 +623,27 @@ export default function (props, context, proxy, isGrid) {
564
623
  updateSelection([])
565
624
  updateExpended()
566
625
  },
567
- {
568
- immediate: true
569
- }
626
+ { immediate: true }
570
627
  )
571
628
  watch(
572
629
  () => props.editRules,
573
630
  value => {
574
631
  initEditRules(value)
575
632
  },
576
- {
577
- deep: true,
578
- immediate: true
579
- }
633
+ { deep: true, immediate: true }
634
+ )
635
+ watch(
636
+ () => isToolbarSlot.value,
637
+ () => {
638
+ connectToolbar()
639
+ },
640
+ { deep: true, immediate: true }
580
641
  )
581
642
 
582
643
  return {
583
644
  slots,
584
645
  tableRef,
646
+ toolbarRef,
585
647
  renderKey,
586
648
  wrapHeight,
587
649
  tableGlobalConfig,
@@ -590,11 +652,13 @@ export default function (props, context, proxy, isGrid) {
590
652
  tableColumnObjConfig,
591
653
  tablePagerConfig,
592
654
  tableQueryConfig,
655
+ tableToolbarConfig,
593
656
  tableFilterText,
594
657
  tableFilterConfig,
595
658
  tableFilterData,
596
659
  tableTools,
597
660
  tableSlots,
661
+ isToolbarSlot,
598
662
  selectionRows,
599
663
  tableBindConfig,
600
664
  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
  })
@@ -6,7 +6,7 @@
6
6
  <span v-else @click="vxeInputPrefixClick">{{ rprops.prefixText }}</span>
7
7
  </span>
8
8
  <span v-else-if="controlButton" class="control-btn before" @click="vxeControlClick(false)">-</span>
9
- <vxe-input v-model="renderValue" v-bind="rprops" :size="rsize" @change="vxeInputChange" @blur="vxeBlurCallback" @clear="vxeBlurCallback"></vxe-input>
9
+ <vxe-input v-model="renderValue" v-bind="rprops" :size="rsize" :immediate="false" @change="vxeInputChange" @blur="vxeBlurCallback" @clear="vxeBlurCallback"></vxe-input>
10
10
  <span v-if="rprops.suffixText && rform" class="suffix">
11
11
  <vxe-button v-if="suffixButton" v-bind="psButtonConfig" @click="vxeInputSuffixClick">{{ rprops.suffixText }}</vxe-button>
12
12
  <span v-else @click="vxeInputSuffixClick">{{ rprops.suffixText }}</span>
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <span class="vxe-render--inner" :class="{ 'form-render': rform, 'td-render': !rform, 'td-all': rprops.bill }">
3
3
  <template v-if="redit || isEditAll">
4
- <vxe-input v-model="renderValue" type="number" v-bind="rprops" :size="rsize" @change="vxeInputChange" @blur="vxeBlurCallback" @clear="vxeBlurCallback" />
4
+ <vxe-input v-model="renderValue" type="number" v-bind="rprops" :size="rsize" :immediate="false" @change="vxeInputChange" @blur="vxeBlurCallback" @clear="vxeBlurCallback" />
5
5
  </template>
6
6
  <template v-else-if="rprops.bill">
7
7
  <template v-for="(bil, bilindex) in billGroups" :key="bilindex">
@@ -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 {
@@ -39,7 +39,7 @@ let defaultPublicProps = {
39
39
 
40
40
  // 渲染器个性化默认配置
41
41
  let defaultProps = {
42
- $vInput: { type: 'text', placeholder: '请输入', transfer: true, digits: 2, prefixType: 'text', suffixType: 'text', immediate: false },
42
+ $vInput: { type: 'text', placeholder: '请输入', transfer: true, digits: 2, prefixType: 'text', suffixType: 'text' },
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' },
@@ -73,12 +73,13 @@ const getFixedProp = (renderOpts, params) => {
73
73
  }
74
74
  })
75
75
  const contextAttrs = $grid?.context?.attrs || $table?.context?.attrs || {}
76
- if (['$vMoney'].includes(name) && contextAttrs.moneyConfig?.enabled && contextAttrs.moneyUnit && !rturnProps.bill && rturnProps.bill !== '0') {
76
+ if (['$vMoney'].includes(name) && contextAttrs.moneyConfig?.enabled && contextAttrs.moneyUnit) {
77
77
  let moneyOption = contextAttrs.moneyConfig?.options.find(item => item.value === contextAttrs.moneyUnit)
78
78
  rturnProps.moneyUnit = contextAttrs.moneyUnit
79
79
  rturnProps.moneyOption = moneyOption
80
80
  if (moneyOption && moneyOption.digits) rturnProps.digits = moneyOption.digits
81
81
  }
82
+ rturnProps.formulaMap = contextAttrs.formulaMap
82
83
  if (column) {
83
84
  column.rname = name
84
85
  column.rprops = rturnProps
@@ -27,7 +27,6 @@ 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
31
30
  formatValueFun(keyValue)
32
31
  }
33
32
 
@@ -48,12 +47,7 @@ export default function (props, context, proxy) {
48
47
  }
49
48
  }
50
49
  // 输入框变化
51
- const vxeInputChange = async ({ value, $event }) => {
52
- // 此操作火狐浏览器(bug(vxe):编辑后不触发渲染器的blur问题)触发edit-closed,故在edit-close重新赋值
53
- if (!rform.value) {
54
- $vUtils.set(props.rparams.column, 'params.__RowEditModelValue', value)
55
- }
56
- }
50
+ const vxeInputChange = async ({ value, $event }) => {}
57
51
  // 输入框变化回调
58
52
  const vxeChangeCallBack = async ({ value, $event }) => {
59
53
  setRenderValue(value)
@@ -81,26 +75,28 @@ export default function (props, context, proxy) {
81
75
  let { rvalue, rtext } = formatValueFun(cellValue, true)
82
76
  cellValue = rvalue
83
77
  }
78
+ $vUtils.set(props.rdata, props.rkey, cellValue)
84
79
  if (rform.value) {
85
80
  let { $form } = props.rparams
86
81
  $form.context.emit('edit-closed', props.rparams)
87
82
  }
88
- $vUtils.set(props.rdata, props.rkey, cellValue)
89
83
  }
90
84
  // 格式化值formatValue
91
85
  const formatValueFun = (value, editable) => {
92
86
  if (props.rparams.type === 'footer') {
93
87
  const { items, itemIndex } = props.rparams
94
- const { moneyUnit, digits } = props.rprops
88
+ const { moneyUnit, digits, type, commafy } = props.rprops
95
89
  let footerText = items[itemIndex]
96
90
  if (props.rname === '$vMoney') footerText = $vUtils.truncate($vUtils.divide(items[itemIndex], moneyUnit), digits)
97
- if (props.rprops.commafy) footerText = $vUtils.commafy(footerText, { digits })
91
+ else if (['integer'].includes(type)) footerText = $vUtils.toInteger(footerText)
92
+ else if (['number', 'float'].includes(type)) footerText = $vUtils.truncate(footerText, digits)
93
+ if (commafy) footerText = $vUtils.commafy(footerText, { digits })
98
94
  renderValue.value = items[itemIndex]
99
95
  renderText.value = footerText
100
96
  return
101
97
  }
102
98
  const { rvalue, rtext } = $vUtils.formatRender(value, props.rkey, props.rdata, props.rname, props.rprops, proxy, editable)
103
- if (['$vMoney'].includes(props.rname)) {
99
+ if (props.rname === '$vMoney' && !props.rprops.bill && props.rprops.bill !== '0') {
104
100
  renderValue.value = rtext
105
101
  } else {
106
102
  renderValue.value = rvalue
@@ -125,12 +121,19 @@ export default function (props, context, proxy) {
125
121
 
126
122
  watch(
127
123
  () => props.rdata,
128
- () => initData(),
124
+ () => {
125
+ let keyValue = $vUtils.get(props.rdata, props.rkey)
126
+ let keyFormula = $vUtils.get(props.rprops, 'formula')
127
+ if (keyValue && $vUtils.isEqual(keyValue, renderValue.value) && !keyFormula) return
128
+ initData()
129
+ },
129
130
  { deep: true, immediate: true }
130
131
  )
131
132
  watch(
132
133
  () => props.rprops,
133
- () => initData()
134
+ () => {
135
+ initData()
136
+ }
134
137
  )
135
138
 
136
139
  return {