sh-view 2.8.15 → 2.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sh-view",
3
- "version": "2.8.15",
3
+ "version": "2.9.1",
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,7 +32,7 @@
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",
@@ -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 => {
@@ -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: {
@@ -297,6 +295,7 @@ export default {
297
295
  return {}
298
296
  }
299
297
  },
298
+ insertDefault: Object,
300
299
  onToolbarBtnAddBefore: {
301
300
  type: Function
302
301
  },
@@ -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
1
  import { computed, onMounted, reactive, ref, watch, nextTick } from 'vue'
2
- import { columnDefaultFilterMethod, tableFooterCompute, getTransfarFields } from './tableMethods'
2
+ import { columnDefaultFilterMethod, tableFooterCompute, getTransfarFields, formulaReplaceAll } from './tableMethods'
3
3
 
4
4
  // 记录自定义参数,传给vxe要过滤掉
5
5
  let omitProps = [
@@ -39,6 +39,7 @@ const exportAndPrintDefault = {
39
39
  isAllExpand: true,
40
40
  download: true,
41
41
  useStyle: false,
42
+ isUnit: false,
42
43
  columnFilterMethod: columnDefaultFilterMethod
43
44
  }
44
45
  const menuConfigDefault = {
@@ -96,7 +97,6 @@ export default function (props, context, proxy, isGrid) {
96
97
  const tableEditRules = ref({}) // 表格根据表头自动生成验证规则
97
98
  const tableFilterText = ref('') // 全局过滤关键字
98
99
  const tableCurrentRowData = ref(null) // 表格当前高亮行
99
- const tableRowDefaultData = ref({}) // 根据表头生成行默认值
100
100
 
101
101
  const wrapHeight = computed(() => ([100, '100%', 'auto'].includes(props.height) ? '100%' : 'auto'))
102
102
  const hasTree = computed(() => props.columns.some(_ => _.treeNode))
@@ -129,18 +129,19 @@ export default function (props, context, proxy, isGrid) {
129
129
  return hasTree.value ? Object.assign({}, props.treeConfig) : null
130
130
  })
131
131
  const tableSeqConfig = computed(() => {
132
+ const pagerConfig = tablePagerConfig.value
133
+ const pageStart = (+pagerConfig.pageSize || 50) * ((+pagerConfig.currentPage || 1) - 1)
132
134
  return {
133
- seqMethod: ({ $table, seq, $seq, $$seq, $rowIndex }) => {
134
- const tablePage = tablePagerConfig.value.enabled
135
- if ($$seq) {
136
- return $$seq
137
- } else if (tablePage) {
138
- const pageStart = (+tablePagerConfig.value.pageSize || 50) * ((+tablePagerConfig.value.currentPage || 1) - 1)
139
- return hasTree.value && $seq ? Number(pageStart) + Number($seq) + '.' + seq : Number(pageStart) + Number(seq)
140
- } else if (hasTree.value) {
141
- return $seq ? $seq + '.' + seq : seq
135
+ seqMethod: ({ $table, seq, $rowIndex }) => {
136
+ if (pagerConfig && pagerConfig.enabled) {
137
+ if (String(seq).includes('.')) {
138
+ const seqIndex = seq.indexOf('.')
139
+ const seqStart = seq.substr(0, seqIndex)
140
+ return $vUtils.add(pageStart, seqStart) + seq.substr(seqIndex)
141
+ }
142
+ return $vUtils.add(pageStart, seq)
142
143
  }
143
- return seq === -1 ? $rowIndex + 1 : seq
144
+ return seq
144
145
  }
145
146
  }
146
147
  })
@@ -201,6 +202,11 @@ export default function (props, context, proxy, isGrid) {
201
202
  const tableBindConfig = computed(() => {
202
203
  let defaultProps = { id: `sh-table-${$route.fullPath}`, footerMethod: tableFooterMethod, footerSpanMethod: tableFooterSpanMethod }
203
204
  let tableProps = $vUtils.omit(props, (val, key) => omitProps.includes(key) || $vUtils.isNone(val))
205
+ let formulaMap = {}
206
+ $vUtils.eachTree(props.columns, column => {
207
+ let rformula = $vUtils.get(column, 'renderProps.formula')
208
+ if (rformula) formulaMap[column.field] = rformula
209
+ })
204
210
  let shProps = {
205
211
  data: tableViewData.value,
206
212
  stripe: props.stripe && !tableTreeConfig.value,
@@ -214,7 +220,8 @@ export default function (props, context, proxy, isGrid) {
214
220
  printConfig: tablePrintConfig.value,
215
221
  moneyConfig: tableMoneyConfig.value,
216
222
  moneyUnit: tableMoneyUnit.value,
217
- menuConfig: tableMenuConfig.value
223
+ menuConfig: tableMenuConfig.value,
224
+ formulaMap: formulaReplaceAll(formulaMap)
218
225
  }
219
226
  if (tableMenuConfig.value.enabled) shProps.menuConfig = tableMenuConfig.value
220
227
  return Object.assign(defaultProps, tableProps, shProps)
@@ -243,8 +250,8 @@ export default function (props, context, proxy, isGrid) {
243
250
  // 获取全部数据
244
251
  // visible为true获取视图数据
245
252
  const getFullData = params => {
246
- const { visible = false, deleteXid = false } = params || {}
247
- let fullData = tableRef.value.internalData.afterFullData
253
+ const { visible = false, deleteXid = false, datas = null } = params || {}
254
+ let fullData = datas || tableRef.value.internalData.afterFullData
248
255
  let data = $vUtils.clone(fullData, true)
249
256
  const columns = tableRef.value.getColumns()
250
257
  let rnameColumns = columns.filter(col => col.rname)
@@ -252,8 +259,14 @@ export default function (props, context, proxy, isGrid) {
252
259
  let { property, rname, rprops } = col
253
260
  data.forEach(row => {
254
261
  let cellValue = $vUtils.get(row, property)
255
- let { rvalue, rtext } = $vUtils.formatRender(cellValue, property, row, rname, rprops, proxy)
256
- $vUtils.set(row, property, visible ? rtext : rvalue)
262
+ let { rvalue, rtext } = $vUtils.formatRender(cellValue, property, row, rname, { ...rprops, commafy: false }, proxy)
263
+ if (rprops.bill && rprops.bill !== '0') {
264
+ $vUtils.set(row, property, rvalue)
265
+ } else if (visible) {
266
+ $vUtils.set(row, property, rtext)
267
+ } else {
268
+ $vUtils.set(row, property, rvalue)
269
+ }
257
270
  if (deleteXid) delete row._XID
258
271
  })
259
272
  })
@@ -262,10 +275,18 @@ export default function (props, context, proxy, isGrid) {
262
275
  // 表格打印、导出统一导出前渲染数据
263
276
  const getExportPrintDataByOption = (obj = {}, type) => {
264
277
  let { options, content } = obj
265
- let { data, columns, mode, original } = options
266
- if (!data) {
267
- options.data = mode === 'selected' ? getSelectionData() : getFullData({ visible: !original })
268
- }
278
+ let { data, columns, mode, original, isUnit } = options
279
+ let exportDatas = data
280
+ $vUtils.eachTree(columns, col => {
281
+ const { rname, rprops } = col
282
+ if (rname === '$vMoney' && isUnit && rprops.moneyOption?.label && !col.headerExportMethod && !original) {
283
+ col.headerExportMethod = () => {
284
+ return `${col.title}(${rprops.moneyOption.label})`
285
+ }
286
+ }
287
+ })
288
+ if (mode === 'selected') exportDatas = getSelectionData()
289
+ options.data = getFullData({ deleteXid: true, visible: !original, datas: exportDatas })
269
290
  return type === 'print' ? content : obj
270
291
  }
271
292
 
@@ -274,8 +295,9 @@ export default function (props, context, proxy, isGrid) {
274
295
  const { footerCalculate } = props
275
296
  let footerData = []
276
297
  let footerCalculateList = footerCalculate.calculate || []
298
+ let fullData = getFullData({ deleteXid: true, datas: data })
277
299
  footerCalculateList.forEach(computeType => {
278
- footerData.push(tableFooterCompute(columns, data, computeType, footerCalculate[computeType]))
300
+ footerData.push(tableFooterCompute(columns, fullData, computeType, footerCalculate[computeType]))
279
301
  })
280
302
  return footerData
281
303
  }
@@ -369,19 +391,6 @@ export default function (props, context, proxy, isGrid) {
369
391
  }
370
392
  // 只对 edit-config 配置时有效,单元格编辑状态下被关闭时会触发该事件
371
393
  const onEditClosed = params => {
372
- // 此操作火狐浏览器(bug(vxe):编辑后不触发渲染器的blur问题)
373
- const userAgent = navigator.userAgent
374
- if (userAgent.indexOf('Firefox') !== -1) {
375
- let { row, column } = params
376
- let editModel = $vUtils.get(column, 'params.__RowEditModelValue')
377
- if (editModel !== undefined) {
378
- if (['$vMoney'].includes(column.rname) && !$vUtils.isNone(editModel)) editModel = $vUtils.multiply(editModel, column.rprops.moneyUnit || 1)
379
- let { rvalue, rtext } = $vUtils.formatRender(editModel, column.property, row, column.rname, column.rprops, proxy, true)
380
- editModel = rvalue
381
- $vUtils.set(row, column.property, editModel)
382
- delete column.params.__RowEditModelValue
383
- }
384
- }
385
394
  emit('edit-closed', params)
386
395
  }
387
396
  // 只对 edit-config 配置时有效,单元格被激活编辑时会触发该事件
@@ -559,8 +568,8 @@ export default function (props, context, proxy, isGrid) {
559
568
  }
560
569
  // 新增行按钮
561
570
  const handleTableAddRow = async (rows, index = -1, isTool = false) => {
562
- let addRows = rows ? $vUtils.clone(rows, true) : tableRowDefaultData.value
563
- if (!isTool && typeof props.onToolbarBtnAddBefore === 'function') {
571
+ let addRows = rows ? $vUtils.clone(rows, true) : props.insertDefault
572
+ if (typeof props.onToolbarBtnAddBefore === 'function') {
564
573
  addRows = await props.onToolbarBtnAddBefore(addRows)
565
574
  }
566
575
  // 删除主键,以防排序冲突
@@ -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">
@@ -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 {