sh-view 2.8.5 → 2.8.6

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/.eslintrc.js CHANGED
@@ -3,10 +3,11 @@ module.exports = {
3
3
  env: {
4
4
  node: true
5
5
  },
6
- extends: ['plugin:vue/vue3-essential', '@vue/typescript/recommended', 'plugin:prettier/recommended'],
6
+ extends: ['plugin:vue/vue3-essential', 'plugin:prettier/recommended'], // 开启typescript 需要加入 '@vue/typescript/recommended'
7
7
  plugins: ['vue', 'prettier'],
8
8
  parserOptions: {
9
- ecmaVersion: 2020
9
+ parser: '@babel/eslint-parser'
10
+ // ecmaVersion: 2020
10
11
  },
11
12
  rules: {
12
13
  'prettier/prettier': 'error',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sh-view",
3
- "version": "2.8.5",
3
+ "version": "2.8.6",
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",
@@ -15,6 +15,7 @@
15
15
  "author": "神秘的sh",
16
16
  "license": "ISC",
17
17
  "dependencies": {
18
+ "@babel/eslint-parser": "^7.23.10",
18
19
  "@codemirror/lang-javascript": "^6.1.9",
19
20
  "@codemirror/lang-json": "^6.0.1",
20
21
  "@codemirror/lang-sql": "^6.5.2",
@@ -26,21 +27,20 @@
26
27
  "countup.js": "^2.8.0",
27
28
  "cron-parser": "^4.8.1",
28
29
  "docx-preview": "^0.1.18",
29
- "exceljs": "^4.3.0",
30
+ "exceljs": "^4.4.0",
30
31
  "jspdf": "^2.5.1",
31
32
  "jszip": "^3.10.1",
32
33
  "lunar-typescript": "^1.6.10",
33
34
  "popper.js": "^1.16.1",
34
- "sh-tools": "^2.2.6",
35
+ "sh-tools": "^2.2.7",
35
36
  "tinymce": "^5.10.5",
36
37
  "vue": "^3.3.4",
37
38
  "vue-masonry": "^0.16.0",
38
39
  "vue-router": "^4.2.4",
39
- "vxe-table": "^4.5.13",
40
- "vxe-table-plugin-export-pdf": "^3.0.4",
41
- "vxe-table-plugin-export-xlsx": "^3.0.5",
42
- "xe-clipboard": "^1.10.2",
43
- "xe-utils": "^3.5.13"
40
+ "vxe-table": "^4.5.20",
41
+ "vxe-table-plugin-export-pdf": "^4.0.1",
42
+ "vxe-table-plugin-export-xlsx": "^4.0.1",
43
+ "xe-clipboard": "^1.10.2"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@typescript-eslint/eslint-plugin": "^6.9.0",
@@ -1,5 +1,5 @@
1
1
  import { computed, onBeforeMount, ref, watch } from 'vue'
2
- import { getFieldsRules } from '../../sh-table/js/tableMethods'
2
+ import { getFieldRules } from '../../sh-table/js/tableMethods'
3
3
 
4
4
  // 表单默认配置
5
5
  const formConfigDefault = {
@@ -88,12 +88,10 @@ export default function (props, context, proxy, isForm) {
88
88
  }
89
89
  // 初始化表单项
90
90
  const initFormItems = () => {
91
- let rules = getFieldsRules(props.items)
92
- initEditRules(rules)
93
-
94
91
  let formItemsArr = props.items
95
92
  if (props.transformitem) {
96
- let { groupItemsArr, flatItemsArr } = generateFormItem(formItemsArr)
93
+ let { groupItemsArr, flatItemsArr, rules } = generateFormItem(formItemsArr)
94
+ initEditRules(rules)
97
95
  // 表单支持分组 搜索组件不需要分组
98
96
  formItemsArr = isForm ? groupItemsArr : flatItemsArr
99
97
  }
@@ -140,6 +138,7 @@ export default function (props, context, proxy, isForm) {
140
138
  let notRenderName = ['seq', 'checkbox', 'radio', '$vImg', '$vHref', '$vGlobalOption']
141
139
  let renderItems = $vUtils.searchTree(items, item => !((item.renderName && notRenderName.includes(item.renderName)) || notRenderName.includes(item.type)))
142
140
  let flatItemsArr = []
141
+ let rules = {}
143
142
  let groupItemsArr = $vUtils.mapTree(renderItems, ori => {
144
143
  let tar = Object.assign({}, ori)
145
144
  if (ori.children && ori.children.length > 0) {
@@ -150,6 +149,8 @@ export default function (props, context, proxy, isForm) {
150
149
  name: ori.renderName || '$vInput',
151
150
  props: Object.assign({}, ori.renderProps || {})
152
151
  }
152
+ // 首先提取校验配置
153
+ getFieldRules(ori, rules)
153
154
  if (readonly || disabled) {
154
155
  renderConfig.props.disabled = true
155
156
  }
@@ -157,7 +158,7 @@ export default function (props, context, proxy, isForm) {
157
158
  flatItemsArr.push(tar)
158
159
  return tar
159
160
  })
160
- return { groupItemsArr, flatItemsArr }
161
+ return { groupItemsArr, flatItemsArr, rules }
161
162
  }
162
163
 
163
164
  watch(
@@ -178,8 +179,8 @@ export default function (props, context, proxy, isForm) {
178
179
  )
179
180
  watch(
180
181
  () => props.rules,
181
- nv => {
182
- initEditRules(nv)
182
+ value => {
183
+ initEditRules(value)
183
184
  },
184
185
  {
185
186
  deep: true,
@@ -52,8 +52,6 @@
52
52
  .sh-table-toolbar-wrap{
53
53
  display: flex;
54
54
  flex: 0 0 auto;
55
- align-items: flex-end;
56
- font-size: 0;
57
55
  .sh-table-toolbar-item{
58
56
  display: inline-block;
59
57
  vertical-align: baseline;
@@ -57,6 +57,7 @@
57
57
  <div v-if="slots.toolbarRight" class="sh-table-toolbar-item">
58
58
  <slot name="toolbarRight"></slot>
59
59
  </div>
60
+ <div v-if="tableMoneyConfig.enabled" class="sh-table-toolbar-item">单位:<sh-select v-model="tableMoneyUnit" v-bind="tableMoneyConfig" /></div>
60
61
  <div v-if="tableGlobalConfig.zoom" class="sh-table-toolbar-item">
61
62
  <vxe-button v-if="!tableIsFullscreen" v-ripple :size="size" icon="vxe-icon-zoom-out" @click="handleTableZoomBtn(true)">全屏</vxe-button>
62
63
  <vxe-button v-else v-ripple :size="size" icon="vxe-icon-zoom-in" @click="handleTableZoomBtn(false)">退出全屏</vxe-button>
@@ -112,8 +112,7 @@ export default {
112
112
  type: [Function]
113
113
  },
114
114
  keepSource: {
115
- type: Boolean,
116
- default: true
115
+ type: Boolean
117
116
  },
118
117
  emptyIcon: {
119
118
  type: String
@@ -193,10 +192,7 @@ export default {
193
192
  }
194
193
  },
195
194
  mouseConfig: {
196
- type: Object,
197
- default() {
198
- return {}
199
- }
195
+ type: Object
200
196
  },
201
197
  customConfig: {
202
198
  type: Object,
@@ -269,6 +265,12 @@ export default {
269
265
  return {}
270
266
  }
271
267
  },
268
+ moneyConfig: {
269
+ type: Object,
270
+ default() {
271
+ return {}
272
+ }
273
+ },
272
274
  footerCalculate: {
273
275
  type: Object,
274
276
  default() {
@@ -32,11 +32,9 @@ export const columnDefaultFilterMethod = ({ column, $columnIndex }) => {
32
32
  }
33
33
 
34
34
  // 默认求底部计算方法(已改用footer渲染器,其他需要自行计算)
35
- export const tableFooterCompute = (columns, data, computeType, typeObj = {}) => {
36
- let emptyString = ''
37
- let computeName = typeObj.name || ''
38
- let computeData = typeObj.data || {}
39
- let textIndex = 0
35
+ export const tableFooterCompute = (columns, fullData, computeType, typeObj = {}) => {
36
+ const { emptyText = '', name, data = {} } = typeObj
37
+ let computeName = name || ''
40
38
  if (!computeName) {
41
39
  switch (computeType) {
42
40
  case 'subTotal':
@@ -52,16 +50,20 @@ export const tableFooterCompute = (columns, data, computeType, typeObj = {}) =>
52
50
  }
53
51
  }
54
52
  return columns.map((column, columnIndex) => {
55
- let result = null
56
- if (column.type === 'seq' || column.type === 'total') {
57
- result = computeName
58
- textIndex = columnIndex
59
- } else {
60
- result = computeData[column.property] || emptyString
61
- $vUtils.set(column, `rfooter.index`, textIndex)
62
- $vUtils.set(column, `rfooter.${computeName}`, { computeType, result, typeObj })
53
+ if (['seq', 'total'].includes(column.type)) {
54
+ return computeName
55
+ }
56
+ let renderName = column.editRender?.name || column.cellRender?.name
57
+ let renderProps = column.editRender?.props || column.cellRender?.props
58
+ let footerValue = data[column.property] || emptyText
59
+ if (renderName === '$vMoney' || renderProps.calculate) {
60
+ if (computeType === 'subTotal') {
61
+ footerValue = $vUtils.sum(fullData, column.property)
62
+ } else if (computeType === 'mean') {
63
+ footerValue = $vUtils.mean(fullData, column.property)
64
+ }
63
65
  }
64
- return result
66
+ return footerValue
65
67
  })
66
68
  }
67
69
  // 转化表头过滤配置
@@ -84,28 +86,25 @@ export const turnColumnItemFilters = (column, props) => {
84
86
  }
85
87
  }
86
88
  // 转换表头校验规则
87
- export const getFieldsRules = columns => {
88
- let rules = {}
89
- $vUtils.eachTree(columns, column => {
90
- // 首先提取校验配置
91
- if (isTrue(column['renderRequire'])) {
92
- // 若配置了校验参数则走校验参数,没配置则给默认校验条件
93
- if (column['requireProps'] && Array.isArray(column['requireProps']) && column['requireProps'].length > 0) {
94
- rules[column['field']] = column['requireProps']
95
- } else {
96
- let dataType = 'string'
97
- let arrayType = ['$vCheckgroup', '$vUpload', '$vTable']
98
- if (arrayType.includes(column['renderName']) || ((column['renderName'] === '$vSelect' || column['renderName'] === '$vTree') && isTrue(column.renderProps?.multiple))) {
99
- dataType = 'array'
100
- }
101
- rules[column['field']] = [{ required: true, message: getDefaultMessage(column['renderName'], column['title']), type: dataType }]
102
- }
89
+ export const getFieldRules = (ori, rules) => {
90
+ if (isTrue(ori['renderRequire'])) {
91
+ let dataType = 'string'
92
+ let arrayType = ['$vCheckgroup', '$vUpload', '$vTable']
93
+ if (arrayType.includes(ori['renderName']) || (['$vSelect', '$vTree'].includes(ori['renderName']) && isTrue(ori.renderProps?.multiple))) {
94
+ dataType = 'array'
103
95
  }
104
- })
105
- return rules
96
+ let defaultRuleOption = { message: getDefaultMessage(ori['renderName'], ori['title']), type: dataType, trigger: 'blur' }
97
+ let fieldRules = [{ required: true, ...defaultRuleOption }]
98
+ // 若配置了校验参数则走校验参数,没配置则给默认校验条件
99
+ if (ori['requireProps'] && Array.isArray(ori['requireProps']) && ori['requireProps'].length > 0) {
100
+ fieldRules = ori['requireProps'].map(rule => ({ ...defaultRuleOption, ...rule }))
101
+ }
102
+ rules[ori['field']] = fieldRules
103
+ }
106
104
  }
107
105
  // 转换生成新表头数据
108
106
  export const getTransfarFields = (oriArr = [], columnObj, isSearch) => {
107
+ let rules = {}
109
108
  let columnsFlatArr = []
110
109
  let formItemsArr = []
111
110
  let columnsArr = $vUtils.mapTree(oriArr, ori => {
@@ -116,41 +115,38 @@ export const getTransfarFields = (oriArr = [], columnObj, isSearch) => {
116
115
  } else {
117
116
  let renderConfig = {
118
117
  name: ori.renderName || '$vInput',
119
- props: Object.assign({}, ori.renderProps || {})
118
+ props: Object.assign({}, ori.renderProps)
120
119
  }
120
+ // 首先提取校验配置
121
+ getFieldRules(ori, rules)
122
+ // 初始化排序条件
123
+ if (Number(tar.sortable) === 0 || tar.sortable === 'false') tar.sortable = false
121
124
  // 个性化设置
122
125
  if (tar.renderName === '$vGlobalOption' || ['$vImg', '$vHref', '$vUpload'].includes(tar.renderName)) {
123
- tar.filter = false
124
- tar.sortable = false
126
+ Object.assign(tar, { filter: false, sortable: false })
125
127
  }
126
- if (tar.renderName === '$vGlobalOption') {
127
- tar.resizable = false
128
- }
129
- if (tar.renderName === '$vMoney' || ['number', 'float', 'integer'].includes(renderConfig.props.type)) {
128
+
129
+ if (tar.renderName === '$vGlobalOption') tar.resizable = false
130
+ if (tar.renderName === '$vMoney' || ['number', 'float', 'integer'].includes(ori.renderProps?.type)) {
130
131
  tar.cellType = 'number'
131
132
  }
132
- if (tar.renderName === '$vMoney' && renderConfig.props.bill) {
133
+ if (tar.renderName === '$vMoney' && ori.renderProps?.bill) {
133
134
  tar.filter = false
134
135
  tar.headerClassName += ' header-bill-cell'
135
136
  }
136
- // 初始化排序条件
137
- if (Number(tar.sortable) === 0 || tar.sortable === 'false') {
138
- tar.sortable = false
139
- }
140
137
  // 判断单元格是否可编辑
141
138
  if (ori.readonly || ori.slots?.default || (!ori.renderName && !(tar.editRender && tar.editRender.name))) {
142
- tar.cellRender = Object.assign({}, renderConfig, tar.cellRender || {})
139
+ tar.cellRender = Object.assign(renderConfig, tar.cellRender)
143
140
  } else {
144
- tar.editRender = Object.assign({}, renderConfig, tar.editRender || {})
141
+ tar.editRender = Object.assign(renderConfig, tar.editRender)
145
142
  }
146
143
  // 初始化表单查询配置
147
144
  if (isSearch) {
148
145
  let editFixedNames = ['$vImg', '$vHref', '$vUpload']
149
- let formItem = Object.assign({}, tar)
150
- formItem.itemRender = Object.assign({}, renderConfig, tar.editRender || {}, tar.itemRender || {})
146
+ let formItem = { ...tar }
147
+ formItem.itemRender = Object.assign({ name: '$vInput' }, renderConfig, tar.editRender, tar.itemRender)
151
148
  delete formItem.cellRender
152
149
  delete formItem.editRender
153
- formItem.itemRender.name = formItem.itemRender.name || '$vInput'
154
150
  // 此处修正, 对其不进行默认渲染
155
151
  if (formItem.search && formItem.search !== '0' && !editFixedNames.includes(formItem.itemRender.name)) {
156
152
  formItemsArr.push(formItem)
@@ -164,5 +160,5 @@ export const getTransfarFields = (oriArr = [], columnObj, isSearch) => {
164
160
  columnsFlatArr.push(tar)
165
161
  return tar
166
162
  })
167
- return { columnsArr, columnsFlatArr, formItemsArr }
163
+ return { columnsArr, columnsFlatArr, formItemsArr, rules }
168
164
  }
@@ -1,5 +1,5 @@
1
- import { computed, reactive, ref, watch } from 'vue'
2
- import { columnDefaultFilterMethod, tableFooterCompute, getTransfarFields, getFieldsRules, turnColumnItemFilters } from './tableMethods'
1
+ import { computed, onMounted, reactive, ref, watch } from 'vue'
2
+ import { columnDefaultFilterMethod, tableFooterCompute, getTransfarFields } from './tableMethods'
3
3
 
4
4
  // 记录自定义参数,传给vxe要过滤掉
5
5
  let omitProps = [
@@ -58,7 +58,7 @@ const columnsMapDefault = {
58
58
  }
59
59
 
60
60
  export default function (props, context, proxy, isGrid) {
61
- const { $vUtils, $vxePluginNames } = proxy
61
+ const { $vUtils, $vTableSetup, $vxePluginNames } = proxy
62
62
  const { emit, slots } = context
63
63
 
64
64
  const tableRef = ref()
@@ -66,6 +66,7 @@ export default function (props, context, proxy, isGrid) {
66
66
  const selectedRowKeys = ref([]) // table选中keys
67
67
  const selectionRows = ref([]) // table选中records
68
68
  const tableColumnsFixed = ref([]) // 表格格式化后表头
69
+ const tableMoneyUnit = ref(props.moneyConfig?.defaultValue || 1) // 表格金额单位
69
70
  const tableFilterData = ref(null) // 表格全表搜索数据
70
71
  const tableColumnsFlat = ref([]) // 多层转一维后表头
71
72
  const tableFormItems = ref([]) // 根据表格表头生成表单项配置
@@ -120,6 +121,9 @@ export default function (props, context, proxy, isGrid) {
120
121
  }
121
122
  }
122
123
  })
124
+ const tableMoneyConfig = computed(() => {
125
+ return Object.assign({ enabled: true, options: $vTableSetup.moneyUnitConstants, style: { width: '60px' } }, props.moneyConfig, tableVmConfig.value)
126
+ })
123
127
  const tableExportConfig = computed(() =>
124
128
  Object.assign(
125
129
  {
@@ -148,10 +152,17 @@ export default function (props, context, proxy, isGrid) {
148
152
  Object.assign({ enabled: !props.disabled, showStatus: !props.disabled, showUpdateStatus: !props.disabled, showInsertStatus: !props.disabled }, props.editConfig)
149
153
  )
150
154
  const tableQueryConfig = computed(() => {
151
- let otherConfig = isGrid ? { transformitem: false, items: tableFormItems.value } : { items: props.columns }
152
155
  return Object.assign(
153
- { data: props.queryData, rules: tableEditRules.value, validConfig: props.validConfig, globalConfig: tableGlobalConfig.value, valid: false, footer: true },
154
- otherConfig,
156
+ {
157
+ data: props.queryData,
158
+ rules: tableEditRules.value,
159
+ validConfig: props.validConfig,
160
+ globalConfig: tableGlobalConfig.value,
161
+ items: tableFormItems.value,
162
+ transformitem: false,
163
+ valid: false,
164
+ footer: true
165
+ },
155
166
  tableVmConfig.value
156
167
  )
157
168
  })
@@ -162,9 +173,7 @@ export default function (props, context, proxy, isGrid) {
162
173
  })
163
174
  const tableBindConfig = computed(() => {
164
175
  let defaultProps = { footerMethod: tableFooterMethod, footerSpanMethod: tableFooterSpanMethod }
165
- let tableProps = $vUtils.omit(props, (val, key) => {
166
- return omitProps.includes(key) || $vUtils.isNone(val)
167
- })
176
+ let tableProps = $vUtils.omit(props, (val, key) => omitProps.includes(key) || $vUtils.isNone(val))
168
177
  let shProps = {
169
178
  data: tableViewData.value,
170
179
  stripe: props.stripe && !tableTreeConfig.value,
@@ -175,7 +184,9 @@ export default function (props, context, proxy, isGrid) {
175
184
  editConfig: tableEditConfig.value,
176
185
  editRules: tableEditRules.value,
177
186
  exportConfig: tableExportConfig.value,
178
- printConfig: tablePrintConfig.value
187
+ printConfig: tablePrintConfig.value,
188
+ moneyConfig: tableMoneyConfig.value,
189
+ moneyUnit: tableMoneyUnit.value
179
190
  }
180
191
  return Object.assign(defaultProps, tableProps, shProps)
181
192
  })
@@ -220,12 +231,13 @@ export default function (props, context, proxy, isGrid) {
220
231
  }
221
232
 
222
233
  // 默认求底部绑定方法vxe
223
- const tableFooterMethod = ({ columns, data }) => {
234
+ const tableFooterMethod = ({ columns }) => {
224
235
  const { footerCalculate } = props
236
+ const fullData = getFullData()
225
237
  let footerData = []
226
238
  let footerCalculateList = footerCalculate.calculate || []
227
- footerCalculateList.forEach(key => {
228
- footerData.push(tableFooterCompute(columns, data, key, footerCalculate[key]))
239
+ footerCalculateList.forEach(computeType => {
240
+ footerData.push(tableFooterCompute(columns, fullData, computeType, footerCalculate[computeType]))
229
241
  })
230
242
  return footerData
231
243
  }
@@ -238,6 +250,15 @@ export default function (props, context, proxy, isGrid) {
238
250
  }
239
251
  return { rowspan: 1, colspan: 1 }
240
252
  }
253
+ const updateSelection = rows => {
254
+ let selections = []
255
+ let radioRecord = tableRef.value && tableRef.value.getRadioRecord()
256
+ let checkRecords = tableRef.value && tableRef.value.getCheckboxRecords()
257
+ if (rows) selections = rows
258
+ else if (tableGlobalConfig.value.selectType === 'radio' && radioRecord) selections = [radioRecord]
259
+ else if (tableGlobalConfig.value.selectType === 'checkbox' && checkRecords) selections = checkRecords
260
+ selectionRows.value = selections
261
+ }
241
262
 
242
263
  // -------- 表格
243
264
  // 当前行变化
@@ -247,7 +268,7 @@ export default function (props, context, proxy, isGrid) {
247
268
  }
248
269
  // 单选框变化
249
270
  const onRadioChange = params => {
250
- selectionRows.value = [params.row]
271
+ updateSelection([params.row])
251
272
  emit('radio-change', selectionRows.value, params)
252
273
  }
253
274
  // 复选框变化
@@ -266,7 +287,7 @@ export default function (props, context, proxy, isGrid) {
266
287
  })
267
288
  records = records.filter(row => !childRowsKeys.includes(row[keyField]))
268
289
  }
269
- selectionRows.value = records
290
+ updateSelection(records)
270
291
  emit('selection-change', selectionRows.value, params)
271
292
  }
272
293
  // 单元格点击事件
@@ -328,7 +349,7 @@ export default function (props, context, proxy, isGrid) {
328
349
  }
329
350
  // 分页变化触发
330
351
  const onPageChange = params => {
331
- selectionRows.value = []
352
+ updateSelection([])
332
353
  emit('page-change', params)
333
354
  }
334
355
 
@@ -372,14 +393,14 @@ export default function (props, context, proxy, isGrid) {
372
393
  }
373
394
 
374
395
  // 初始化生成新表头数据
375
- const initTableColumns = (columns = []) => {
376
- let rules = getFieldsRules(columns)
377
- initEditRules(rules)
378
- if (isGrid) {
379
- let { columnsArr, columnsFlatArr, formItemsArr } = getTransfarFields(columns, tableColumnObjConfig.value, tableGlobalConfig.value.search)
380
- tableColumnsFlat.value = columnsFlatArr
381
- tableFormItems.value = formItemsArr
382
- tableColumnsFixed.value = $vUtils.clone(columnsArr, true)
396
+ const initTableColumns = () => {
397
+ let transResult = getTransfarFields(props.columns, tableColumnObjConfig.value, tableGlobalConfig.value.search)
398
+ tableColumnsFlat.value = transResult.columnsFlatArr
399
+ tableFormItems.value = transResult.formItemsArr
400
+ tableColumnsFixed.value = transResult.columnsArr
401
+ initEditRules(transResult.rules)
402
+ if (!isGrid) {
403
+ tableRef.value.loadColumn(tableColumns.value)
383
404
  }
384
405
  }
385
406
  // 初始化验证规则
@@ -510,27 +531,27 @@ export default function (props, context, proxy, isGrid) {
510
531
  if (!result) return
511
532
  }
512
533
  await tableRef.value.remove(deleteRows)
513
- if (selectionRows.value && selectionRows.value.length > 0) {
514
- let keyField = props.rowConfig.keyField || proxy.$vTableSetup.table.rowConfig.keyField
515
- selectionRows.value = selectionRows.value.filter(sr => !deleteRows.find(dr => dr[keyField] === sr[keyField]))
516
- }
534
+ updateSelection()
517
535
  if (isTool) emit('toolbaroption', 'delete', deleteRows, tableRef.value)
518
536
  }
519
537
 
538
+ onMounted(() => {
539
+ initTableColumns()
540
+ })
541
+
520
542
  watch(
521
543
  () => props.columns,
522
544
  value => {
523
- initTableColumns(value)
545
+ initTableColumns()
524
546
  },
525
547
  {
526
- deep: true,
527
- immediate: true
548
+ deep: true
528
549
  }
529
550
  )
530
551
  watch(
531
552
  () => props.dataSourse,
532
553
  value => {
533
- selectionRows.value = []
554
+ updateSelection([])
534
555
  },
535
556
  {
536
557
  immediate: true
@@ -566,6 +587,8 @@ export default function (props, context, proxy, isGrid) {
566
587
  selectionRows,
567
588
  tableBindConfig,
568
589
  importBindConfig,
590
+ tableMoneyUnit,
591
+ tableMoneyConfig,
569
592
  onCurrentChange,
570
593
  onRadioChange,
571
594
  onSelectionChange,
@@ -597,6 +620,6 @@ export default function (props, context, proxy, isGrid) {
597
620
  getFullData,
598
621
  handleTableAddRow,
599
622
  handleTableDeleteRow,
600
- turnColumnItemFilters
623
+ initTableColumns
601
624
  }
602
625
  }
@@ -31,6 +31,7 @@
31
31
  <div v-if="slots.toolbarRight" class="sh-table-toolbar-item">
32
32
  <slot name="toolbarRight"></slot>
33
33
  </div>
34
+ <div v-if="tableMoneyConfig.enabled" @click.stop class="sh-table-toolbar-item">单位:<sh-select v-model="tableMoneyUnit" v-bind="tableMoneyConfig" /></div>
34
35
  <template v-for="(tool, toolIndex) in tableTools" :key="toolIndex">
35
36
  <div class="sh-table-toolbar-item">
36
37
  <vxe-button v-ripple :size="size" v-bind="tool" @click="handleTableTool(tool)"></vxe-button>
@@ -70,14 +71,6 @@
70
71
  <template v-if="customLayout">
71
72
  <slot></slot>
72
73
  </template>
73
- <template v-else>
74
- <template v-for="(column, columnIndex) in tablePrevColumns" :key="columnIndex">
75
- <vxe-column v-bind="column"></vxe-column>
76
- </template>
77
- <template v-for="(column, columnIndex) in columns" :key="columnIndex">
78
- <sh-column :column="column"></sh-column>
79
- </template>
80
- </template>
81
74
  <template #empty>
82
75
  <sh-empty :icon="emptyIcon" :content="emptyText"></sh-empty>
83
76
  </template>
@@ -107,13 +100,11 @@ import { computed, defineComponent, getCurrentInstance, provide, ref, reactive }
107
100
  import './css/index.scss'
108
101
 
109
102
  import props from './js/props'
110
- import shColumn from './components/sh-column.vue'
111
103
  import importModal from './components/importModal.vue'
112
104
  import useTable from './js/useTable'
113
105
  export default defineComponent({
114
106
  name: 'ShTable',
115
107
  components: {
116
- shColumn,
117
108
  importModal
118
109
  },
119
110
  props: {
@@ -172,15 +163,6 @@ export default defineComponent({
172
163
  const isPagerSlot = computed(() => useTableHooks.tablePagerConfig.value.enabled)
173
164
  const isBottomSlot = computed(() => Boolean(slots.bottom))
174
165
 
175
- provide(
176
- 'ShTableInstance',
177
- reactive({
178
- columnObjConfig: useTableHooks.tableColumnObjConfig,
179
- turnColumnItemFilters: useTableHooks.turnColumnItemFilters,
180
- slots: useTableHooks.slots
181
- })
182
- )
183
-
184
166
  const handleResize = e => {
185
167
  if (useTableHooks.wrapHeight.value === 'auto') return
186
168
  let slotRefs = [topSlotRef, formSlotRef, toolbarSlotRef, headSlotRef, footSlotRef, pagerSlotRef, bottomSlotRef]
@@ -1,5 +1,5 @@
1
1
  /*size*/
2
- $vxe-border-radius: 2px !default;
2
+ $vxe-border-radius: 3px !default;
3
3
 
4
4
  /*color*/
5
5
  $vxe-font-color: #515a6e !default;
@@ -2,6 +2,7 @@ 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 { jsPDF } from 'jspdf'
5
6
  import XEClipboard from 'xe-clipboard'
6
7
  import ShValidators from 'sh-tools/packages/utils/validate'
7
8
  import { publicRenders, extraRenders, filterRenders, publicRendersNames } from './render/globalRenders.jsx'
@@ -154,17 +155,43 @@ let vxeOptions = {
154
155
  loading: {
155
156
  icon: 'vxe-icon-spinner roll',
156
157
  text: '加载中...'
157
- }
158
+ },
159
+ moneyUnitConstants: [
160
+ { value: 1, label: '元', digits: 2 },
161
+ { value: 1000, label: '千元', digits: 4 },
162
+ { value: 10000, label: '万元', digits: 6 }
163
+ ],
164
+ cnGroups: [
165
+ { shortText: '兆', fullText: '兆', value: '' },
166
+ { shortText: '千', fullText: '千亿', value: '' },
167
+ { shortText: '百', fullText: '百亿', value: '' },
168
+ { shortText: '十', fullText: '十亿', value: '' },
169
+ { shortText: '亿', fullText: '亿', value: '' },
170
+ { shortText: '千', fullText: '千万', value: '' },
171
+ { shortText: '百', fullText: '百万', value: '' },
172
+ { shortText: '十', fullText: '十万', value: '' },
173
+ { shortText: '万', fullText: '万', value: '' },
174
+ { shortText: '千', fullText: '千', value: '' },
175
+ { shortText: '百', fullText: '百', value: '' },
176
+ { shortText: '十', fullText: '十', value: '' },
177
+ { shortText: '元', fullText: '元', value: '' },
178
+ { shortText: '角', fullText: '角', value: '' },
179
+ { shortText: '分', fullText: '分', value: '' },
180
+ { shortText: '毫', fullText: '毫', value: '' },
181
+ { shortText: '厘', fullText: '厘', value: '' }
182
+ ]
158
183
  }
159
184
 
160
185
  let vxePdfOptions = {
161
- // 设置全局默认字体
162
- fontName: 'SourceHanSans-Normal',
163
- beforeMethod: ({ $pdf, options, columns, datas }) => {}
186
+ jsPDF,
187
+ fonts: [{ fontName: 'SourceHanSansNormal' }]
164
188
  }
165
-
189
+ let vxeXlsxOptions = {}
166
190
  Object.keys(ShValidators).forEach(key => {
167
191
  VXETable.validators.add(key, {
192
+ itemValidatorMethod({ itemValue }) {
193
+ return ShValidators[key](itemValue)
194
+ },
168
195
  cellValidatorMethod({ cellValue }) {
169
196
  return ShValidators[key](cellValue)
170
197
  }
@@ -174,15 +201,15 @@ Object.keys(ShValidators).forEach(key => {
174
201
  VXETable.renderer.mixin(publicRenders)
175
202
  VXETable.renderer.mixin(extraRenders)
176
203
  VXETable.renderer.mixin(filterRenders)
177
- VXETable.use(VXETablePluginExportXLSX)
178
- VXETable.use(VXETablePluginExportPDF)
179
204
 
180
205
  const index = {
181
- install(Vue, { vxeOption = {}, vxePdfOption = {} }) {
206
+ install(Vue, { vxeOption = {}, vxePdfOption = {}, vxeXlsxOption }) {
182
207
  let setupOption = Object.assign(vxeOptions, vxeOption)
208
+ let xlsxSetUpOption = Object.assign(vxeXlsxOptions, vxeXlsxOption)
183
209
  let pdfSetUpOption = Object.assign(vxePdfOptions, vxePdfOption)
184
210
  VXETable.setup(setupOption)
185
- VXETablePluginExportPDF.setup(pdfSetUpOption)
211
+ VXETable.use(VXETablePluginExportXLSX, xlsxSetUpOption)
212
+ VXETable.use(VXETablePluginExportPDF, pdfSetUpOption)
186
213
  Vue.use(VXETable)
187
214
  Vue.config.globalProperties.$vTable = VXETable
188
215
  Vue.config.globalProperties.$vTableSetup = setupOption
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <span>{{ getFooterData() }}</span>
2
+ <span v-html="renderText"></span>
3
3
  </template>
4
4
 
5
5
  <script>
@@ -5,7 +5,7 @@
5
5
  </template>
6
6
  </div>
7
7
  <template v-else>
8
- <span class="blue">{{ getFooterData() }}</span>
8
+ <span class="blue" v-html="renderText"></span>
9
9
  </template>
10
10
  </template>
11
11
 
@@ -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' },
42
+ $vInput: { type: 'text', placeholder: '请输入', transfer: true, digits: 2, prefixType: 'text', suffixType: 'text', immediate: false },
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' },
@@ -64,7 +64,7 @@ let defaultProps = {
64
64
  // 统一处理传参boolean与配置String问题
65
65
  const getFixedProp = (renderOpts, params) => {
66
66
  let { name, props = {} } = renderOpts
67
- let { column, $table } = params
67
+ let { column, $grid, $table } = params
68
68
  let rturnProps = Object.assign({}, defaultPublicProps, defaultProps[name], props)
69
69
  let transKeys = ['transfer', 'disabled', 'multiple', 'isLeaf', 'commafy', 'border', 'filterable', 'showWordCount', 'editable']
70
70
  transKeys.forEach(key => {
@@ -72,6 +72,13 @@ const getFixedProp = (renderOpts, params) => {
72
72
  rturnProps[key] = Boolean(+rturnProps[key])
73
73
  }
74
74
  })
75
+ const contextAttrs = $grid?.context?.attrs || $table?.context?.attrs || {}
76
+ if (['$vMoney'].includes(name) && contextAttrs.moneyConfig?.enabled && contextAttrs.moneyUnit && !rturnProps.bill && rturnProps.bill !== '0') {
77
+ let moneyOption = contextAttrs.moneyConfig?.options.find(item => item.value === contextAttrs.moneyUnit)
78
+ rturnProps.moneyUnit = contextAttrs.moneyUnit
79
+ rturnProps.moneyOption = moneyOption
80
+ if (moneyOption && moneyOption.digits) rturnProps.digits = moneyOption.digits
81
+ }
75
82
  if (column) {
76
83
  column.rname = name
77
84
  column.rprops = rturnProps
@@ -106,7 +113,7 @@ const publicRenders = {
106
113
  },
107
114
  renderFooter(renderOpts, params) {
108
115
  let props = getFixedProp(renderOpts, params)
109
- return [<vxeFooterInput redit={false} rparams={params} rname={renderOpts.name} rprops={props.rprops} rkey={props.rkey} rdata={props.rdata} />]
116
+ return [<vxeFooterInput rparams={params} rname={renderOpts.name} rprops={props.rprops} rkey={props.rkey} />]
110
117
  }
111
118
  },
112
119
  $vTextArea: {
@@ -252,11 +259,11 @@ const publicRenders = {
252
259
  },
253
260
  renderHeader(renderOpts, params) {
254
261
  let props = getFixedProp(renderOpts, params)
255
- return [<vxeHeaderMoney redit={false} rparams={params} rname={renderOpts.name} rprops={props.rprops} rkey={props.rkey} rdata={props.rdata} />]
262
+ return [<vxeHeaderMoney rparams={params} rname={renderOpts.name} rprops={props.rprops} rkey={props.rkey} />]
256
263
  },
257
264
  renderFooter(renderOpts, params) {
258
265
  let props = getFixedProp(renderOpts, params)
259
- return [<vxeFooterMoney redit={false} rparams={params} rname={renderOpts.name} rprops={props.rprops} rkey={props.rkey} rdata={props.rdata} />]
266
+ return [<vxeFooterMoney rparams={params} rname={renderOpts.name} rprops={props.rprops} rkey={props.rkey} />]
260
267
  },
261
268
  exportMethod({ row, column }) {
262
269
  return utils.get(row, column.property)
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <span>
3
3
  {{ rparams.column.title }}
4
- <span v-if="moneyUnitText" class="header-money-unit-text">({{ moneyUnitText }})</span>
4
+ <span v-if="rprops.moneyOption?.label && !rprops.bill" class="header-money-unit-text">({{ rprops.moneyOption?.label }})</span>
5
5
  </span>
6
6
  <div v-if="rprops.bill" class="header-bill-box">
7
7
  <template v-for="(bil, bilindex) in billGroups" :key="bilindex">
@@ -1,32 +1,7 @@
1
1
  import { computed, ref, watch } from 'vue'
2
2
 
3
- let moneyUnitConstants = [
4
- { value: 1, label: '元' },
5
- { value: 1000, label: '千元' },
6
- { value: 10000, label: '万元' }
7
- ]
8
- let cnGroups = [
9
- { shortText: '兆', fullText: '兆', value: '' },
10
- { shortText: '千', fullText: '千亿', value: '' },
11
- { shortText: '百', fullText: '百亿', value: '' },
12
- { shortText: '十', fullText: '十亿', value: '' },
13
- { shortText: '亿', fullText: '亿', value: '' },
14
- { shortText: '千', fullText: '千万', value: '' },
15
- { shortText: '百', fullText: '百万', value: '' },
16
- { shortText: '十', fullText: '十万', value: '' },
17
- { shortText: '万', fullText: '万', value: '' },
18
- { shortText: '千', fullText: '千', value: '' },
19
- { shortText: '百', fullText: '百', value: '' },
20
- { shortText: '十', fullText: '十', value: '' },
21
- { shortText: '元', fullText: '元', value: '' },
22
- { shortText: '角', fullText: '角', value: '' },
23
- { shortText: '分', fullText: '分', value: '' },
24
- { shortText: '毫', fullText: '毫', value: '' },
25
- { shortText: '厘', fullText: '厘', value: '' }
26
- ]
27
-
28
3
  export default function (props, context, proxy) {
29
- const { $vUtils } = proxy
4
+ const { $vUtils, $vTableSetup } = proxy
30
5
 
31
6
  const renderValue = ref(null)
32
7
  const renderText = ref('')
@@ -37,15 +12,11 @@ export default function (props, context, proxy) {
37
12
  const isEditAll = computed(() => {
38
13
  return props.rparams.$table?.props?.editConfig?.enabled && reditmode.value === 'all' && props.rparams.column.editRender
39
14
  })
40
- const moneyUnitText = computed(() => {
41
- let moneyConstant = moneyUnitConstants.find(item => item.value === props.rprops.moneyUnit)
42
- return moneyConstant && moneyConstant.label
43
- })
44
15
  const billGroups = computed(() => {
45
16
  let { billStart = '分', billEnd = '亿' } = props.rprops
46
- let startIndex = cnGroups.findIndex(cn => cn.fullText === billEnd)
47
- let endIndex = cnGroups.findIndex(cn => cn.fullText === billStart)
48
- return cnGroups.slice(startIndex, endIndex)
17
+ let startIndex = $vTableSetup.cnGroups.findIndex(cn => cn.fullText === billEnd)
18
+ let endIndex = $vTableSetup.cnGroups.findIndex(cn => cn.fullText === billStart)
19
+ return $vTableSetup.cnGroups.slice(startIndex, endIndex + 1)
49
20
  })
50
21
  const psButtonConfig = computed(() => {
51
22
  return { disabled: props.rprops.disabled, size: props.rsize, status: 'primary' }
@@ -117,51 +88,28 @@ export default function (props, context, proxy) {
117
88
  }
118
89
  // 格式化值formatValue
119
90
  const formatValueFun = (value, editable) => {
91
+ if (props.rparams.type === 'footer') {
92
+ const { items, itemIndex } = props.rparams
93
+ const { moneyUnit, digits } = props.rprops
94
+ let footerText = items[itemIndex]
95
+ if (props.rname === '$vMoney') footerText = $vUtils.truncate($vUtils.divide(items[itemIndex], moneyUnit), digits)
96
+ if (props.rprops.commafy) footerText = $vUtils.commafy(footerText, { digits })
97
+ renderValue.value = items[itemIndex]
98
+ renderText.value = footerText
99
+ return
100
+ }
120
101
  let formatObj = $vUtils.formatRender(value, props.rkey, props.rdata, props.rname, props.rprops, proxy, editable)
121
102
  renderValue.value = ['$vMoney'].includes(props.rname) ? formatObj.rtext : formatObj.rvalue
122
103
  renderText.value = formatObj.rtext
123
104
  return formatObj
124
105
  }
125
- // 格式化底部值
126
- const getFooterData = (qianfen = true) => {
127
- let { $table, items, itemIndex, column } = props.rparams
128
- let tableData = $table.internalData.afterFullData
129
- let { rname, rprops, rfooter, property } = column
130
- let { digits, moneyUnit, commafy, type, calculate } = rprops
131
- let footerValue = items[itemIndex]
132
- if (rfooter) {
133
- let caculateObj = rfooter[items[rfooter.index || 0]]
134
- if (caculateObj && (rname === '$vMoney' || (['number', 'float', 'integer'].includes(type) && calculate))) {
135
- let tableColumnData = $vUtils.mapTree(tableData, row => row[property])
136
- let { computeType, result, typeObj } = caculateObj
137
- switch (computeType) {
138
- case 'subTotal':
139
- footerValue = $vUtils.sum(tableColumnData)
140
- break
141
- case 'allTotal':
142
- footerValue = typeObj[property] || result
143
- break
144
- case 'mean':
145
- footerValue = $vUtils.mean(tableColumnData)
146
- break
147
- default:
148
- footerValue = result
149
- break
150
- }
151
- if (rname === '$vMoney') footerValue = $vUtils.truncate($vUtils.divide(footerValue, moneyUnit), digits)
152
- if (qianfen && commafy) footerValue = $vUtils.commafy(footerValue, { digits })
153
- }
154
- }
155
- return footerValue
156
- }
157
106
  const getBillClass = bil => {
158
107
  return { basic: bil.fullText === '元', commafy: ['千', '百万', '十亿', '兆'].includes(bil.fullText) }
159
108
  }
160
109
  // 获取单据值
161
- const getBillValue = (index, total = false) => {
162
- let value = total ? getFooterData(false) : renderValue.value
163
- if (!value) return ''
164
- let fullValue = $vUtils.formatMoneyPad(value)
110
+ const getBillValue = index => {
111
+ if (!renderValue.value) return ''
112
+ let fullValue = $vUtils.formatMoneyPad(renderValue.value)
165
113
  let fullList = fullValue.replace('.', '').split('')
166
114
  return fullList[index]
167
115
  }
@@ -171,6 +119,10 @@ export default function (props, context, proxy) {
171
119
  () => initData(),
172
120
  { deep: true, immediate: true }
173
121
  )
122
+ watch(
123
+ () => props.rprops,
124
+ () => initData()
125
+ )
174
126
 
175
127
  return {
176
128
  renderValue,
@@ -178,7 +130,6 @@ export default function (props, context, proxy) {
178
130
  rsize,
179
131
  rform,
180
132
  isEditAll,
181
- moneyUnitText,
182
133
  billGroups,
183
134
  psButtonConfig,
184
135
  prefixButton,
@@ -190,7 +141,6 @@ export default function (props, context, proxy) {
190
141
  vxeRadioCallBack,
191
142
  vxeCheckCallBack,
192
143
  vxeBlurCallback,
193
- getFooterData,
194
144
  getBillClass,
195
145
  getBillValue,
196
146
  setRenderValue