b373946908ed24e0cd5dfba395ce542fc876b61a.svn-base 48 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445
  1. import XEUtils from 'xe-utils'
  2. import PropTypes from 'ant-design-vue/es/_util/vue-types'
  3. import { JVXETypes } from '@/components/jeecg/JVxeTable/jvxeTypes'
  4. import VxeWebSocketMixins from '../mixins/vxe.web.socket.mixins'
  5. import { initDictOptions } from '@/components/dict/JDictSelectUtil'
  6. import { getRefPromise } from '../utils/vxeUtils'
  7. import { getEnhancedMixins, replaceProps } from '../utils/cellUtils'
  8. import JVxeToolbar from './JVxeToolbar'
  9. import JVxeSubPopover from './JVxeSubPopover'
  10. import JVxeDetailsModal from './JVxeDetailsModal'
  11. import JVxePagination from './JVxePagination'
  12. import { cloneObject, getVmParentByName, pushIfNotExist, randomString, simpleDebounce } from '@/utils/util'
  13. import { UtilTools } from 'vxe-table/packages/tools/src/utils'
  14. import { getNoAuthCols } from '@/utils/authFilter'
  15. export default {
  16. name: 'JVxeTable',
  17. provide() {
  18. return {
  19. superTrigger: (name, event) => this.trigger(name, event)
  20. }
  21. },
  22. mixins: [VxeWebSocketMixins],
  23. components: {JVxeToolbar, JVxeSubPopover, JVxeDetailsModal, JVxePagination},
  24. props: {
  25. rowKey: PropTypes.string.def('id'),
  26. // 列信息
  27. columns: {
  28. type: Array,
  29. required: true
  30. },
  31. // 数据源
  32. dataSource: {
  33. type: Array,
  34. required: true
  35. },
  36. authPre: {
  37. type: String,
  38. required: false,
  39. default: ''
  40. },
  41. // 是否显示工具栏
  42. toolbar: PropTypes.bool.def(false),
  43. // 工具栏配置
  44. toolbarConfig: PropTypes.object.def(() => ({
  45. // prefix 前缀;suffix 后缀;
  46. slots: ['prefix', 'suffix'],
  47. // add 新增按钮;remove 删除按钮;clearSelection 清空选择按钮;collapse 展开收起
  48. btns: ['add', 'remove', 'clearSelection'],
  49. })),
  50. // 是否显示行号
  51. rowNumber: PropTypes.bool.def(false),
  52. // 是否可选择行
  53. rowSelection: PropTypes.bool.def(false),
  54. // 选择行类型
  55. rowSelectionType: PropTypes.oneOf(['checkbox', 'radio']).def('checkbox'),
  56. // 是否可展开行
  57. rowExpand: PropTypes.bool.def(false),
  58. // 展开行配置
  59. expandConfig: PropTypes.object.def(() => ({})),
  60. // 页面是否在加载中
  61. loading: PropTypes.bool.def(false),
  62. height: PropTypes.instanceOf([Number, String]).def('auto'),
  63. // 最大高度
  64. maxHeight: {
  65. type: Number,
  66. default: () => null,
  67. },
  68. // 要禁用的行 TODO 未实现
  69. disabledRows: PropTypes.object.def(() => ({})),
  70. // 是否禁用全部组件
  71. disabled: PropTypes.bool.def(false),
  72. // 是否可拖拽排序 TODO 仅实现上下排序,未实现拖拽排序(可能无法实现或较为困难)
  73. dragSort: PropTypes.bool.def(false),
  74. // 排序字段保存的Key
  75. dragSortKey: PropTypes.string.def('orderNum'),
  76. // 大小,可选值有:medium(中)、small(小)、mini(微)、tiny(非常小)
  77. size: PropTypes.oneOf(['medium', 'small', 'mini', 'tiny']).def('medium'),
  78. // 是否显示边框线
  79. bordered: PropTypes.bool.def(false),
  80. // 分页器参数,设置了即可显示分页器
  81. pagination: PropTypes.object.def(() => ({})),
  82. // 点击行时是否显示子表单
  83. clickRowShowSubForm: PropTypes.bool.def(false),
  84. // 点击行时是否显示主表单
  85. clickRowShowMainForm: PropTypes.bool.def(false),
  86. // 是否点击选中行,优先级最低
  87. clickSelectRow: PropTypes.bool.def(false),
  88. // 是否开启 reload 数据效果
  89. reloadEffect: PropTypes.bool.def(false),
  90. // 校验规则
  91. editRules: PropTypes.object.def(() => ({})),
  92. // 是否异步删除行,如果你要实现异步删除,那么需要把这个选项开启,
  93. // 在remove事件里调用confirmRemove方法才会真正删除(除非删除的全是新增的行)
  94. asyncRemove: PropTypes.bool.def(false),
  95. // 是否一直显示组件,如果为false则只有点击的时候才出现组件
  96. // 注:该参数不能动态修改;如果行、列字段多的情况下,会根据机器性能造成不同程度的卡顿。
  97. alwaysEdit: PropTypes.bool.def(false),
  98. // 联动配置,数组,详情配置见文档
  99. linkageConfig: PropTypes.array.def(() => []),
  100. },
  101. data() {
  102. return {
  103. isJVXETable: true,
  104. // caseId,表格唯一标识
  105. caseId: `_j-vxe-${randomString(8)}_`,
  106. // 内置columns
  107. _innerColumns: [],
  108. // 内置 EditRules
  109. _innerEditRules: [],
  110. // 记录滚动条位置
  111. scroll: {top: 0, left: 0},
  112. // 当前是否正在滚动
  113. scrolling: false,
  114. // vxe 默认配置
  115. defaultVxeProps: {
  116. 'row-id': this.rowKey,
  117. // 高亮hover的行
  118. 'highlight-hover-row': true,
  119. // 溢出隐藏并显示tooltip
  120. 'show-overflow': true,
  121. // 表头溢出隐藏并显示tooltip
  122. 'show-header-overflow': true,
  123. 'show-footer-overflow': true,
  124. // 可编辑配置
  125. 'edit-config': {trigger: 'click', mode: 'cell', showStatus: true},
  126. 'expand-config': {
  127. iconClose: 'ant-table-row-expand-icon ant-table-row-collapsed',
  128. iconOpen: 'ant-table-row-expand-icon ant-table-row-expanded'
  129. },
  130. // 虚拟滚动配置,y轴大于30条数据时启用虚拟滚动
  131. // 'scroll-y': {
  132. // gt: 30
  133. // },
  134. // 'scroll-x': {
  135. // gt: 15
  136. // },
  137. 'radio-config': {highlight: true},
  138. 'checkbox-config': {highlight: true},
  139. },
  140. // 绑定左侧选择框
  141. selectedRows: [],
  142. // 绑定左侧选择框已选择的id
  143. selectedRowIds: [],
  144. // 统计列配置
  145. statistics: {
  146. has: false,
  147. sum: [],
  148. average: [],
  149. },
  150. // 允许执行刷新特效的行ID
  151. reloadEffectRowKeysMap: {},
  152. //配置了但是没有授权的按钮和列 集合
  153. excludeCode:[],
  154. // 联动下拉选项(用于隔离不同的下拉选项)
  155. // 内部联动配置,map
  156. _innerLinkageConfig: null,
  157. }
  158. },
  159. computed: {
  160. // vxe 最终 columns
  161. vxeColumns() {
  162. this._innerColumns.forEach(column => {
  163. let renderOptions = {
  164. caseId: this.caseId,
  165. bordered: this.bordered,
  166. disabled: this.disabled,
  167. scrolling: this.scrolling,
  168. reloadEffect: this.reloadEffect,
  169. reloadEffectRowKeysMap: this.reloadEffectRowKeysMap,
  170. listeners: this.cellListeners,
  171. }
  172. if (column.$type === JVXETypes.rowDragSort) {
  173. renderOptions.dragSortKey = this.dragSortKey
  174. }
  175. // slot 组件特殊处理
  176. if (column.$type === JVXETypes.slot) {
  177. if (this.$scopedSlots.hasOwnProperty(column.slotName)) {
  178. renderOptions.slot = this.$scopedSlots[column.slotName]
  179. renderOptions.target = this
  180. }
  181. }
  182. // 处理联动列,联动列只能作用于 select 组件
  183. if (column.$type === JVXETypes.select && this._innerLinkageConfig != null) {
  184. // 判断当前列是否是联动列
  185. if (this._innerLinkageConfig.has(column.key)) {
  186. renderOptions.linkage = {
  187. config: this._innerLinkageConfig.get(column.key),
  188. getLinkageOptionsSibling: this.getLinkageOptionsSibling,
  189. getLinkageOptionsAsync: this.getLinkageOptionsAsync,
  190. linkageSelectChange: this.linkageSelectChange,
  191. }
  192. }
  193. }
  194. if (column.editRender) {
  195. Object.assign(column.editRender, renderOptions)
  196. }
  197. if (column.cellRender) {
  198. Object.assign(column.cellRender, renderOptions)
  199. }
  200. // update--begin--autor:lvdandan-----date:20201019------for:LOWCOD-882 【新行编辑】列表上带按钮的遮挡问题
  201. if (column.$type === JVXETypes.file || column.$type === JVXETypes.image) {
  202. if (column.width && column.width.endsWith('px')) {
  203. column.width = Number.parseInt(column.width.substr(0,column.width.length-2))+Number.parseInt(1)+'px';
  204. }
  205. }
  206. // update--begin--autor:lvdandan-----date:20201019------for:LOWCOD-882 【新行编辑】列表上带按钮的遮挡问题
  207. // update--begin--autor:lvdandan-----date:20201211------for:JT-118 【online】 日期、时间控件长度较小
  208. if (column.$type === JVXETypes.datetime || column.$type === JVXETypes.userSelect || column.$type === JVXETypes.departSelect) {
  209. let width = column.width && column.width.endsWith('px')?Number.parseInt(column.width.substr(0,column.width.length-2)):0;
  210. if(width <= 190){
  211. column.width = '190px'
  212. }
  213. }
  214. if (column.$type === JVXETypes.date) {
  215. let width = column.width && column.width.endsWith('px')?Number.parseInt(column.width.substr(0,column.width.length-2)):0;
  216. if(width <= 135){
  217. column.width = '135px'
  218. }
  219. }
  220. // update--end--autor:lvdandan-----date:20201211------for:JT-118 【online】 日期、时间控件长度较小
  221. })
  222. return this._innerColumns
  223. },
  224. // vxe 最终 editRules
  225. vxeEditRules() {
  226. return Object.assign({}, this.editRules, this._innerEditRules)
  227. },
  228. // vxe 最终 props
  229. vxeProps() {
  230. let expandConfig = Object.assign({}, this.defaultVxeProps['expand-config'], this.expandConfig)
  231. return Object.assign({}, this.defaultVxeProps, {
  232. showFooter: this.statistics.has,
  233. }, this.$attrs, {
  234. loading: this.loading,
  235. columns: this.vxeColumns,
  236. editRules: this.vxeEditRules,
  237. // data: this.dataSource,
  238. height: this.height === 'auto' ? null : this.height,
  239. maxHeight: this.maxHeight,
  240. border: this.bordered,
  241. expandConfig: expandConfig,
  242. footerMethod: this.handleFooterMethod,
  243. // footerSpanMethod: this.handleFooterSpanMethod,
  244. })
  245. },
  246. // vxe 最终 events
  247. vxeEvents() {
  248. // 内置事件
  249. let events = {
  250. 'scroll': this.handleVxeScroll,
  251. 'cell-click': this.handleCellClick,
  252. 'edit-closed': this.handleEditClosed,
  253. 'edit-actived': this.handleEditActived,
  254. 'radio-change': this.handleVxeRadioChange,
  255. 'checkbox-all': this.handleVxeCheckboxAll,
  256. 'checkbox-change': this.handleVxeCheckboxChange,
  257. }
  258. // 用户传递的事件,进行合并操作
  259. Object.keys(this.$listeners).forEach(key => {
  260. let listen = this.$listeners[key]
  261. if (events.hasOwnProperty(key)) {
  262. if (Array.isArray(listen)) {
  263. listen.push(events[key])
  264. } else {
  265. listen = [events[key], listen]
  266. }
  267. }
  268. events[key] = listen
  269. })
  270. return events
  271. },
  272. // 组件监听事件
  273. cellListeners() {
  274. return {
  275. trigger: (name, event) => this.trigger(name, event),
  276. valueChange: event => this.trigger('valueChange', event),
  277. /** 当前行向上移一位 */
  278. rowMoveUp: rowIndex => this.rowResort(rowIndex, rowIndex - 1),
  279. /** 当前行向下移一位 */
  280. rowMoveDown: rowIndex => this.rowResort(rowIndex, rowIndex + 1),
  281. /** 在当前行下面插入一行 */
  282. rowInsertDown: rowIndex => this.insertRows({}, rowIndex + 1),
  283. }
  284. },
  285. },
  286. watch: {
  287. dataSource: {
  288. // deep: true,
  289. immediate: true,
  290. async handler() {
  291. let vxe = await getRefPromise(this, 'vxe')
  292. this.dataSource.forEach((data, idx) => {
  293. // 开启了排序就自动计算排序值
  294. if (this.dragSort) {
  295. this.$set(data, this.dragSortKey, idx + 1)
  296. }
  297. // 处理联动回显数据
  298. if (this._innerLinkageConfig != null) {
  299. for (let configItem of this._innerLinkageConfig.values()) {
  300. this.autoSetLinkageOptionsByData(data, '', configItem, 0)
  301. }
  302. }
  303. })
  304. // 阻断vue监听大数据,提高性能
  305. vxe.loadData(this.dataSource)
  306. // TODO 解析disabledRows
  307. // let disabled = false
  308. //
  309. // let disabledRowIds = (this.disabledRowIds || [])
  310. // // 解析disabledRows
  311. // Object.keys(this.disabledRows).forEach(disabledColKey => {
  312. // // 判断是否有该属性
  313. // if (data.hasOwnProperty(disabledColKey)) {
  314. // if (disabled !== true) {
  315. // let temp = this.disabledRows[disabledColKey]
  316. // // 禁用规则可以是一个数组
  317. // if (Array.isArray(temp)) {
  318. // disabled = temp.includes(data[disabledColKey])
  319. // } else {
  320. // disabled = (temp === data[disabledColKey])
  321. // }
  322. // if (disabled) {
  323. // disabledRowIds.push(row.id)
  324. // }
  325. // }
  326. // }
  327. // })
  328. },
  329. },
  330. columns: {
  331. immediate: true,
  332. handler(columns) {
  333. //获取不需要显示列
  334. this.loadExcludeCode()
  335. let _innerColumns = []
  336. let _innerEditRules = {}
  337. let {rowNumber, rowSelection, rowExpand, dragSort} = this
  338. let expandColumn, seqColumn, checkboxColumn, radioColumn, dragSortColumn
  339. if (Array.isArray(columns)) {
  340. this.statistics.has = false
  341. this.statistics.sum = []
  342. this.statistics.average = []
  343. // 处理成vxe可识别的columns
  344. columns.forEach(column => {
  345. if(this.excludeCode.indexOf(column.key)>=0){
  346. return false
  347. }
  348. let col = {...column}
  349. let {type} = col
  350. const enhanced = getEnhancedMixins(type)
  351. if (type === JVXETypes.rowNumber) {
  352. seqColumn = col
  353. } else if (type === JVXETypes.rowCheckbox) {
  354. checkboxColumn = col
  355. } else if (type === JVXETypes.rowRadio) {
  356. radioColumn = col
  357. } else if (type === JVXETypes.rowExpand) {
  358. expandColumn = col
  359. } else if (type === JVXETypes.rowDragSort) {
  360. dragSortColumn = col
  361. } else {
  362. col.field = col.key
  363. // 防止和vxeTable自带的type起冲突
  364. col.$type = col.type
  365. delete col.type
  366. let renderName = 'cellRender', renderOptions = {name: JVXETypes._prefix + type}
  367. if (type) {
  368. // hidden 是特殊的组件
  369. if (type === JVXETypes.hidden) {
  370. col.visible = false
  371. } else if (enhanced.switches.editRender) {
  372. renderName = 'editRender'
  373. renderOptions.type = (enhanced.switches.visible || this.alwaysEdit) ? 'visible' : 'default'
  374. }
  375. } else {
  376. renderOptions.name = JVXETypes._prefix + JVXETypes.normal
  377. }
  378. col[renderName] = renderOptions
  379. // 处理字典
  380. if (col.dictCode) {
  381. this._loadDictConcatToOptions(col)
  382. }
  383. // 处理校验
  384. if (col.validateRules) {
  385. let rules = []
  386. if (Array.isArray(col.validateRules)) {
  387. for (let rule of col.validateRules) {
  388. let replace = {
  389. message: replaceProps(col, rule.message)
  390. }
  391. if (rule.unique || rule.pattern === 'only') {
  392. // 唯一校验器
  393. rule.validator = uniqueValidator.bind(this)
  394. } else if (rule.pattern) {
  395. // 非空
  396. if (rule.pattern === fooPatterns[0].value) {
  397. rule.required = true
  398. delete rule.pattern
  399. } else {
  400. // 兼容Online表单的特殊规则
  401. for (let foo of fooPatterns) {
  402. if (foo.value === rule.pattern) {
  403. rule.pattern = foo.pattern
  404. break
  405. }
  406. }
  407. }
  408. } else if (typeof rule.handler === 'function') {
  409. // 自定义函数校验
  410. rule.validator = handlerConvertToValidator.bind(this)
  411. }
  412. rules.push(Object.assign({}, rule, replace))
  413. }
  414. }
  415. _innerEditRules[col.key] = rules
  416. }
  417. // 处理统计列
  418. // sum = 求和、average = 平均值
  419. if (Array.isArray(col.statistics)) {
  420. this.statistics.has = true
  421. col.statistics.forEach(item => {
  422. let arr = this.statistics[item.toLowerCase()]
  423. if (Array.isArray(arr)) {
  424. pushIfNotExist(arr, col.key)
  425. }
  426. })
  427. }
  428. _innerColumns.push(col)
  429. }
  430. })
  431. }
  432. // 判断是否开启了序号
  433. if (rowNumber) {
  434. let col = {type: 'seq', title: '#', width: 60, fixed: 'left', align: 'center'}
  435. if (seqColumn) {
  436. col = Object.assign(col, seqColumn, {type: 'seq'})
  437. }
  438. _innerColumns.unshift(col)
  439. }
  440. // 判断是否开启了可选择行
  441. if (rowSelection) {
  442. let width = 40
  443. if (this.statistics.has && !rowExpand && !dragSort) {
  444. width = 60
  445. }
  446. let col = {type: this.rowSelectionType, width, fixed: 'left', align: 'center'}
  447. // radio
  448. if (this.rowSelectionType === 'radio' && radioColumn) {
  449. col = Object.assign(col, radioColumn, {type: 'radio'})
  450. }
  451. // checkbox
  452. if (this.rowSelectionType === 'checkbox' && checkboxColumn) {
  453. col = Object.assign(col, checkboxColumn, {type: 'checkbox'})
  454. }
  455. _innerColumns.unshift(col)
  456. }
  457. // 是否可展开行
  458. if (rowExpand) {
  459. let width = 40
  460. if (this.statistics.has && !dragSort) {
  461. width = 60
  462. }
  463. let col = {type: 'expand', title: '', width, fixed: 'left', align: 'center', slots: {content: 'expandContent'}}
  464. if (expandColumn) {
  465. col = Object.assign(col, expandColumn, {type: 'expand'})
  466. }
  467. _innerColumns.unshift(col)
  468. }
  469. // 是否可拖动排序
  470. if (dragSort) {
  471. let width = 40
  472. if (this.statistics.has) {
  473. width = 60
  474. }
  475. let col = {type: JVXETypes.rowDragSort, title: '', width, fixed: 'left', align: 'center', cellRender: {name: JVXETypes._prefix + JVXETypes.rowDragSort}}
  476. if (dragSortColumn) {
  477. col = Object.assign(col, dragSortColumn, {type: JVXETypes.rowDragSort})
  478. }
  479. _innerColumns.unshift(col)
  480. }
  481. this._innerColumns = _innerColumns
  482. this._innerEditRules = _innerEditRules
  483. }
  484. },
  485. // watch linkageConfig
  486. // 整理多级联动配置
  487. linkageConfig: {
  488. immediate: true,
  489. handler() {
  490. if (Array.isArray(this.linkageConfig) && this.linkageConfig.length > 0) {
  491. // 获取联动的key顺序
  492. let getLcKeys = (key, arr) => {
  493. let col = this._innerColumns.find(col => col.key === key)
  494. if (col) {
  495. arr.push(col.key)
  496. if (col.linkageKey) {
  497. return getLcKeys(col.linkageKey, arr)
  498. }
  499. }
  500. return arr
  501. }
  502. let configMap = new Map()
  503. this.linkageConfig.forEach(lc => {
  504. let keys = getLcKeys(lc.key, [])
  505. // 多个key共享一个,引用地址
  506. let configItem = {
  507. ...lc, keys,
  508. optionsMap: new Map()
  509. }
  510. keys.forEach(k => configMap.set(k, configItem))
  511. })
  512. this._innerLinkageConfig = configMap
  513. } else {
  514. this._innerLinkageConfig = null
  515. }
  516. }
  517. },
  518. },
  519. created() {
  520. },
  521. mounted() {
  522. this.handleTabsChange()
  523. },
  524. methods: {
  525. /**
  526. * 自动判断父级是否是 <a-tabs/> 组件,然后添加事件监听,自动重置表格
  527. */
  528. handleTabsChange() {
  529. // 获取父级
  530. const tabs = getVmParentByName(this, 'ATabs')
  531. const tabPane = getVmParentByName(this, 'ATabPane')
  532. if (tabs && tabPane) {
  533. // 用户自定义的 key
  534. const currentKey = tabPane.$vnode.key
  535. // 添加 activeKey 监听
  536. const unwatch = tabs.$children[0].$watch('$data._activeKey', async (key) => {
  537. // 切换到自己时重新计算
  538. if (currentKey === key) {
  539. await this.$nextTick()
  540. await this.refreshScroll()
  541. await this.recalculate()
  542. }
  543. })
  544. // 当前实例销毁时取消监听
  545. this.$on('beforeDestroy', () => unwatch())
  546. }
  547. },
  548. handleVxeScroll(event) {
  549. let {$refs, scroll} = this
  550. // 记录滚动条的位置
  551. scroll.top = event.scrollTop
  552. scroll.left = event.scrollLeft
  553. $refs.subPopover ? $refs.subPopover.close() : null
  554. this.scrolling = true
  555. this.closeScrolling()
  556. },
  557. // 当手动勾选单选时触发的事件
  558. handleVxeRadioChange(event) {
  559. let row = event.$table.getRadioRecord()
  560. this.selectedRows = row ? [row] : []
  561. this.handleSelectChange('radio', this.selectedRows, event)
  562. },
  563. // 当手动勾选全选时触发的事件
  564. handleVxeCheckboxAll(event) {
  565. this.selectedRows = event.$table.getCheckboxRecords()
  566. this.handleSelectChange('checkbox-all', this.selectedRows, event)
  567. },
  568. // 当手动勾选并且值发生改变时触发的事件
  569. handleVxeCheckboxChange(event) {
  570. this.selectedRows = event.$table.getCheckboxRecords()
  571. this.handleSelectChange('checkbox', this.selectedRows, event)
  572. },
  573. // 行选择change事件
  574. handleSelectChange(type, selectedRows, $event) {
  575. let action
  576. if (type === 'radio') {
  577. action = 'selected'
  578. } else if (type === 'checkbox') {
  579. action = selectedRows.includes($event.row) ? 'selected' : 'unselected'
  580. } else {
  581. action = 'selected-all'
  582. }
  583. this.selectedRowIds = selectedRows.map(row => row.id)
  584. this.trigger('selectRowChange', {
  585. type: type,
  586. action: action,
  587. $event: $event,
  588. row: $event.row,
  589. selectedRows: this.selectedRows,
  590. selectedRowIds: this.selectedRowIds
  591. })
  592. },
  593. // 点击单元格时触发的事件
  594. handleCellClick(event) {
  595. let {row, column, $event, $table} = event
  596. let {$refs} = this
  597. // 点击了可编辑的
  598. if (column.editRender) {
  599. $refs.subPopover ? $refs.subPopover.close() : null
  600. return
  601. }
  602. // 显示详细信息
  603. if (column.own.showDetails) {
  604. // 两个如果同时存在的话会出现死循环
  605. $refs.subPopover ? $refs.subPopover.close() : null
  606. $refs.detailsModal ? $refs.detailsModal.open(event) : null
  607. } else if ($refs.subPopover) {
  608. $refs.subPopover.toggle(event)
  609. } else if (this.clickSelectRow) {
  610. let className = $event.target.className || ''
  611. className = typeof className === 'string' ? className : className.toString()
  612. // 点击的是expand,不做处理
  613. if (className.includes('vxe-table--expand-btn')) {
  614. return
  615. }
  616. // 点击的是checkbox,不做处理
  617. if (className.includes('vxe-checkbox--icon') || className.includes('vxe-cell--checkbox')) {
  618. return
  619. }
  620. // 点击的是radio,不做处理
  621. if (className.includes('vxe-radio--icon') || className.includes('vxe-cell--radio')) {
  622. return
  623. }
  624. if (this.rowSelectionType === 'radio') {
  625. $table.setRadioRow(row)
  626. this.handleVxeRadioChange(event)
  627. } else {
  628. $table.toggleCheckboxRow(row)
  629. this.handleVxeCheckboxChange(event)
  630. }
  631. }
  632. },
  633. // 单元格编辑状态下被关闭时会触发该事件
  634. handleEditClosed({column}) {
  635. // 执行增强
  636. getEnhancedMixins(column.own.$type, 'aopEvents').editClosed.apply(this, arguments)
  637. },
  638. // 单元格被激活编辑时会触发该事件
  639. handleEditActived({column}) {
  640. // 执行增强
  641. getEnhancedMixins(column.own.$type, 'aopEvents').editActived.apply(this, arguments)
  642. },
  643. /** 表尾数据处理方法,用于显示统计信息 */
  644. handleFooterMethod({columns, data}) {
  645. const {statistics} = this
  646. let footers = []
  647. if (statistics.has) {
  648. if (statistics.sum.length > 0) {
  649. footers.push(this.getFooterStatisticsMap({
  650. columns: columns,
  651. title: '合计',
  652. checks: statistics.sum,
  653. method: (column) => XEUtils.sum(data, column.property)
  654. }))
  655. }
  656. if (statistics.average.length > 0) {
  657. footers.push(this.getFooterStatisticsMap({
  658. columns: columns,
  659. title: '平均',
  660. checks: statistics.average,
  661. method: (column) => XEUtils.mean(data, column.property)
  662. }))
  663. }
  664. }
  665. return footers
  666. },
  667. getFooterStatisticsMap({columns, title, checks, method}) {
  668. return columns.map((column, columnIndex) => {
  669. if (columnIndex === 0) {
  670. return title
  671. }
  672. if (checks.includes(column.property)) {
  673. return method(column, columnIndex)
  674. }
  675. return null
  676. })
  677. },
  678. /** 表尾单元格合并方法 */
  679. handleFooterSpanMethod(event) {
  680. if (event.columnIndex === 0) {
  681. return {colspan: 2}
  682. }
  683. },
  684. /*--- 外部可调用接口方法 ---*/
  685. /**
  686. * 重置滚动条Top位置
  687. * @param top 新top位置,留空则滚动到上次记录的位置,用于解决切换tab选项卡时导致白屏以及自动将滚动条滚动到顶部的问题
  688. */
  689. resetScrollTop(top) {
  690. this.scrollTo(null, (top == null || top === '') ? this.scroll.top : top)
  691. },
  692. /**
  693. * 加载新数据,和 loadData 不同的是,用该方法加载的数据都是相当于点新增按钮新增的数据。
  694. * 适用于不是数据库里查出来的没有id的临时数据
  695. * @param dataSource
  696. */
  697. async loadNewData(dataSource) {
  698. if (Array.isArray(dataSource)) {
  699. let {xTable} = this.$refs.vxe.$refs
  700. // issues/2784
  701. // 先清空所有数据
  702. xTable.loadData([])
  703. dataSource.forEach((data, idx) => {
  704. // 开启了排序就自动计算排序值
  705. if (this.dragSort) {
  706. this.$set(data, this.dragSortKey, idx + 1)
  707. }
  708. // 处理联动回显数据
  709. if (this._innerLinkageConfig != null) {
  710. for (let configItem of this._innerLinkageConfig.values()) {
  711. this.autoSetLinkageOptionsByData(data, '', configItem, 0)
  712. }
  713. }
  714. })
  715. // 再新增
  716. return xTable.insertAt(dataSource)
  717. }
  718. return []
  719. },
  720. // 校验table,失败返回errMap,成功返回null
  721. async validateTable() {
  722. const errMap = await this.validate().catch(errMap => errMap)
  723. return errMap ? errMap : null
  724. },
  725. // 完整校验
  726. async fullValidateTable() {
  727. const errMap = await this.fullValidate().catch(errMap => errMap)
  728. return errMap ? errMap : null
  729. },
  730. /** 设置某行某列的值 */
  731. setValues(values) {
  732. if (!Array.isArray(values)) {
  733. console.warn(`JVxeTable.setValues:必须传递数组`)
  734. return
  735. }
  736. values.forEach((item, idx) => {
  737. let {rowKey, values: record} = item
  738. let {row} = this.getIfRowById(rowKey)
  739. if (!row) {
  740. return
  741. }
  742. Object.keys(record).forEach(colKey => {
  743. let column = this.getColumnByKey(colKey)
  744. if (column) {
  745. let oldValue = row[colKey]
  746. let newValue = record[colKey]
  747. if (newValue !== oldValue) {
  748. this.$set(row, colKey, newValue)
  749. // 触发 valueChange 事件
  750. this.trigger('valueChange', {
  751. type: column.own.$type,
  752. value: newValue,
  753. oldValue: oldValue,
  754. col: column.own,
  755. column: column,
  756. isSetValues: true,
  757. })
  758. }
  759. } else {
  760. console.warn(`JVxeTable.setValues:没有找到key为"${colKey}"的列`)
  761. }
  762. })
  763. })
  764. },
  765. /** 获取所有的数据,包括values、deleteIds */
  766. getAll() {
  767. return {
  768. tableData: this.getTableData(),
  769. deleteData: this.getDeleteData()
  770. }
  771. },
  772. /** 获取表格表单里的值 */
  773. getValues(callback, rowIds) {
  774. let tableData = this.getTableData({rowIds: rowIds})
  775. callback('', tableData)
  776. },
  777. /** 获取表格数据 */
  778. getTableData(options = {}) {
  779. let {rowIds} = options
  780. let tableData
  781. // 仅查询指定id的行
  782. if (Array.isArray(rowIds) && rowIds.length > 0) {
  783. tableData = []
  784. rowIds.forEach(rowId => {
  785. let {row} = this.getIfRowById(rowId)
  786. if (row) {
  787. tableData.push(row)
  788. }
  789. })
  790. } else {
  791. // 查询所有行
  792. tableData = this.$refs.vxe.getTableData().fullData
  793. }
  794. return this.filterNewRows(tableData, false)
  795. },
  796. /** 仅获取新增的数据 */
  797. getNewData() {
  798. let newData = cloneObject(this.$refs.vxe.getInsertRecords())
  799. newData.forEach(row => delete row.id)
  800. return newData
  801. },
  802. /** 仅获取新增的数据,带有id */
  803. getNewDataWithId() {
  804. let newData = cloneObject(this.$refs.vxe.getInsertRecords())
  805. return newData
  806. },
  807. /** 根据ID获取行,新增的行也能查出来 */
  808. getIfRowById(id) {
  809. let row = this.getRowById(id), isNew = false
  810. if (!row) {
  811. row = this.getNewRowById(id)
  812. if (!row) {
  813. console.warn(`JVxeTable.getIfRowById:没有找到id为"${id}"的行`)
  814. return {row: null}
  815. }
  816. isNew = true
  817. }
  818. return {row, isNew}
  819. },
  820. /** 通过临时ID获取新增的行 */
  821. getNewRowById(id) {
  822. let records = this.getInsertRecords()
  823. for (let record of records) {
  824. if (record.id === id) {
  825. return record
  826. }
  827. }
  828. return null
  829. },
  830. /** 仅获取被删除的数据(新增又被删除的数据不会被获取到) */
  831. getDeleteData() {
  832. return cloneObject(this.$refs.vxe.getRemoveRecords())
  833. },
  834. /**
  835. * 添加一行或多行
  836. *
  837. * @param rows
  838. * @param isOnlJs 是否是onlineJS增强触发的
  839. * @return
  840. */
  841. async addRows(rows = {}, isOnlJs) {
  842. return this._addOrInsert(rows, -1, 'added', isOnlJs)
  843. },
  844. /**
  845. * 添加一行或多行
  846. *
  847. * @param rows
  848. * @param index 添加下标,数字,必填
  849. * @return
  850. */
  851. async insertRows(rows, index) {
  852. if (typeof index !== 'number' || index < 0) {
  853. console.warn(`【JVXETable】insertRows:index必须传递数字,且大于-1`)
  854. return
  855. }
  856. return this._addOrInsert(rows, index, 'inserted')
  857. },
  858. /**
  859. * 添加一行或多行临时数据,不会填充默认值,传什么就添加进去什么
  860. * @param rows
  861. * @param options 选项
  862. * @param options.setActive 是否激活最后一行的编辑模式
  863. */
  864. async pushRows(rows = {}, options = {}) {
  865. let {xTable} = this.$refs.vxe.$refs
  866. let {setActive, index} = options
  867. setActive = setActive == null ? false : !!setActive
  868. index = index == null ? -1 : index
  869. index = index === -1 ? index : xTable.tableFullData[index]
  870. // 插入行
  871. let result = await xTable.insertAt(rows, index)
  872. if (setActive) {
  873. // 激活最后一行的编辑模式
  874. xTable.setActiveRow(result.rows[result.rows.length - 1])
  875. }
  876. await this._recalcSortNumber()
  877. return result
  878. },
  879. /** 清空选择行 */
  880. clearSelection() {
  881. let event = {$table: this.$refs.vxe, target: this}
  882. if (this.rowSelectionType === JVXETypes.rowRadio) {
  883. this.$refs.vxe.clearRadioRow()
  884. this.handleVxeRadioChange(event)
  885. } else {
  886. this.$refs.vxe.clearCheckboxRow()
  887. this.handleVxeCheckboxChange(event)
  888. }
  889. },
  890. /** 删除一行或多行数据 */
  891. async removeRows(rows) {
  892. const res = await this._remove(rows)
  893. await this._recalcSortNumber()
  894. return res
  895. },
  896. /** 根据id删除一行或多行 */
  897. removeRowsById(rowId) {
  898. let rowIds
  899. if (Array.isArray(rowId)) {
  900. rowIds = rowId
  901. } else {
  902. rowIds = [rowId]
  903. }
  904. let rows = rowIds.map((id) => {
  905. let {row} = this.getIfRowById(id)
  906. if (!row) {
  907. return
  908. }
  909. if (row) {
  910. return row
  911. } else {
  912. console.warn(`【JVXETable】removeRowsById:${id}不存在`)
  913. return null
  914. }
  915. }).filter((row) => row != null)
  916. return this.removeRows(rows)
  917. },
  918. getColumnByKey() {
  919. return this.$refs.vxe.getColumnByField.apply(this.$refs.vxe, arguments)
  920. },
  921. /* --- 辅助方法 ---*/
  922. // 触发事件
  923. trigger(name, event = {}) {
  924. event.$target = this
  925. event.$table = this.$refs.vxe
  926. //online增强参数兼容
  927. event.target = this
  928. this.$emit(name, event)
  929. },
  930. /** 【多级联动】获取同级联动下拉选项 */
  931. getLinkageOptionsSibling(row, col, config, request) {
  932. // 如果当前列不是顶级列
  933. let key = ''
  934. if (col.key !== config.key) {
  935. // 就找出联动上级列
  936. let idx = config.keys.findIndex(k => col.key === k)
  937. let parentKey = config.keys[idx - 1]
  938. key = row[parentKey]
  939. // 如果联动上级列没有选择数据,就直接返回空数组
  940. if (key === '' || key == null) {
  941. return []
  942. }
  943. } else {
  944. key = 'root'
  945. }
  946. let options = config.optionsMap.get(key)
  947. if (!Array.isArray(options)) {
  948. if (request) {
  949. let parent = key === 'root' ? '' : key
  950. return this.getLinkageOptionsAsync(config, parent)
  951. } else {
  952. options = []
  953. }
  954. }
  955. return options
  956. },
  957. /** 【多级联动】获取联动下拉选项(异步) */
  958. getLinkageOptionsAsync(config, parent) {
  959. return new Promise(resolve => {
  960. let key = parent ? parent : 'root'
  961. let options
  962. if (config.optionsMap.has(key)) {
  963. options = config.optionsMap.get(key)
  964. if (options instanceof Promise) {
  965. options.then(opt => {
  966. config.optionsMap.set(key, opt)
  967. resolve(opt)
  968. })
  969. } else {
  970. resolve(options)
  971. }
  972. } else if (typeof config.requestData === 'function') {
  973. // 调用requestData方法,通过传入parent来获取子级
  974. let promise = config.requestData(parent)
  975. config.optionsMap.set(key, promise)
  976. promise.then(opt => {
  977. config.optionsMap.set(key, opt)
  978. resolve(opt)
  979. })
  980. } else {
  981. resolve([])
  982. }
  983. })
  984. },
  985. // 【多级联动】 用于回显数据,自动填充 optionsMap
  986. autoSetLinkageOptionsByData(data, parent, config, level) {
  987. if (level === 0) {
  988. this.getLinkageOptionsAsync(config, '')
  989. } else {
  990. this.getLinkageOptionsAsync(config, parent)
  991. }
  992. if (config.keys.length - 1 > level) {
  993. let value = data[config.keys[level]]
  994. if (value) {
  995. this.autoSetLinkageOptionsByData(data, value, config, level + 1)
  996. }
  997. }
  998. },
  999. // 【多级联动】联动组件change时,清空下级组件
  1000. linkageSelectChange(row, col, config, value) {
  1001. if (col.linkageKey) {
  1002. this.getLinkageOptionsAsync(config, value)
  1003. let idx = config.keys.findIndex(k => k === col.key)
  1004. let values = {}
  1005. for (let i = idx; i < config.keys.length; i++) {
  1006. values[config.keys[i]] = ''
  1007. }
  1008. // 清空后几列的数据
  1009. this.setValues([{rowKey: row.id, values}])
  1010. }
  1011. },
  1012. /** 加载数据字典并合并到 options */
  1013. _loadDictConcatToOptions(column) {
  1014. initDictOptions(column.dictCode).then((res) => {
  1015. if (res.success) {
  1016. let newOptions = (column.options || [])// .concat(res.result)
  1017. res.result.forEach(item => {
  1018. // 过滤重复数据
  1019. for (let option of newOptions) if (option.value === item.value) return
  1020. newOptions.push(item)
  1021. })
  1022. this.$set(column, 'options', newOptions)
  1023. } else {
  1024. console.group(`JVxeTable 查询字典(${column.dictCode})发生异常`)
  1025. console.warn(res.message)
  1026. console.groupEnd()
  1027. }
  1028. })
  1029. },
  1030. //options自定义赋值 刷新
  1031. virtualRefresh(){
  1032. this.scrolling = true
  1033. this.closeScrolling()
  1034. },
  1035. // 设置 this.scrolling 防抖模式
  1036. closeScrolling: simpleDebounce(function () {
  1037. this.scrolling = false
  1038. }, 100),
  1039. /**
  1040. * 过滤添加的行
  1041. * @param rows 要筛选的行数据
  1042. * @param remove true = 删除新增,false=只删除id
  1043. * @param handler function
  1044. */
  1045. filterNewRows(rows, remove = true, handler) {
  1046. let insertRecords = this.$refs.vxe.getInsertRecords()
  1047. let records = []
  1048. for (let row of rows) {
  1049. let item = cloneObject(row)
  1050. if (insertRecords.includes(row)) {
  1051. handler ? handler({item, row, insertRecords}) : null
  1052. if (remove) {
  1053. continue
  1054. }
  1055. delete item.id
  1056. }
  1057. records.push(item)
  1058. }
  1059. return records
  1060. },
  1061. // 删除选中的数据
  1062. async removeSelection() {
  1063. let res = await this._remove(this.selectedRows)
  1064. this.clearSelection()
  1065. await this._recalcSortNumber()
  1066. return res
  1067. },
  1068. /**
  1069. * 【删除指定行数据】(重写vxeTable的内部方法,添加了从keepSource中删除)
  1070. * 如果传 row 则删除一行
  1071. * 如果传 rows 则删除多行
  1072. * 如果为空则删除所有
  1073. */
  1074. _remove(rows) {
  1075. const xTable = this.$refs.vxe.$refs.xTable
  1076. const {afterFullData, tableFullData, tableSourceData, editStore, treeConfig, checkboxOpts, selection, isInsertByRow, scrollYLoad} = xTable
  1077. const {actived, removeList, insertList} = editStore
  1078. const {checkField: property} = checkboxOpts
  1079. let rest = []
  1080. const nowData = afterFullData
  1081. if (treeConfig) {
  1082. throw new Error(UtilTools.getLog('vxe.error.noTree', ['remove']))
  1083. }
  1084. if (!rows) {
  1085. rows = tableFullData
  1086. } else if (!XEUtils.isArray(rows)) {
  1087. rows = [rows]
  1088. }
  1089. // 如果是新增,则保存记录
  1090. rows.forEach(row => {
  1091. if (!isInsertByRow(row)) {
  1092. removeList.push(row)
  1093. }
  1094. })
  1095. // 如果绑定了多选属性,则更新状态
  1096. if (!property) {
  1097. XEUtils.remove(selection, row => rows.indexOf(row) > -1)
  1098. }
  1099. // 从数据源中移除
  1100. if (tableFullData === rows) {
  1101. rows = rest = tableFullData.slice(0)
  1102. tableFullData.length = 0
  1103. nowData.length = 0
  1104. } else {
  1105. rest = XEUtils.remove(tableFullData, row => rows.indexOf(row) > -1)
  1106. XEUtils.remove(nowData, row => rows.indexOf(row) > -1)
  1107. }
  1108. // 【从keepSource中删除】
  1109. if (xTable.keepSource) {
  1110. let rowIdSet = new Set(rows.map(row => row.id))
  1111. XEUtils.remove(tableSourceData, row => rowIdSet.has(row.id))
  1112. }
  1113. // 如果当前行被激活编辑,则清除激活状态
  1114. if (actived.row && rows.indexOf(actived.row) > -1) {
  1115. xTable.clearActived()
  1116. }
  1117. // 从新增中移除已删除的数据
  1118. XEUtils.remove(insertList, row => rows.indexOf(row) > -1)
  1119. xTable.handleTableData()
  1120. xTable.updateFooter()
  1121. xTable.updateCache()
  1122. xTable.checkSelectionStatus()
  1123. if (scrollYLoad) {
  1124. xTable.updateScrollYSpace()
  1125. }
  1126. return xTable.$nextTick().then(() => {
  1127. xTable.recalculate()
  1128. return {row: rest.length ? rest[rest.length - 1] : null, rows: rest}
  1129. })
  1130. },
  1131. /** 行重新排序 */
  1132. async rowResort(oldIndex, newIndex) {
  1133. const xTable = this.$refs.vxe.$refs.xTable
  1134. window.xTable = xTable
  1135. const sort = (array) => {
  1136. // 存储旧数据,并删除旧项目
  1137. let row = array.splice(oldIndex, 1)[0]
  1138. // 向新项目里添加旧数据
  1139. array.splice(newIndex, 0, row)
  1140. }
  1141. sort(xTable.tableFullData)
  1142. if (xTable.keepSource) {
  1143. sort(xTable.tableSourceData)
  1144. }
  1145. await this.$nextTick()
  1146. await this._recalcSortNumber()
  1147. },
  1148. /** 重新计算排序字段的数值 */
  1149. async _recalcSortNumber() {
  1150. const xTable = this.$refs.vxe.$refs.xTable
  1151. if (this.dragSort) {
  1152. xTable.tableFullData.forEach((data, idx) => data[this.dragSortKey] = (idx + 1))
  1153. }
  1154. await xTable.updateCache(true)
  1155. return await xTable.updateData()
  1156. },
  1157. async _addOrInsert(rows = {}, index, triggerName, isOnlJs) {
  1158. let {xTable} = this.$refs.vxe.$refs
  1159. let records
  1160. if (Array.isArray(rows)) {
  1161. records = rows
  1162. } else {
  1163. records = [rows]
  1164. }
  1165. // 遍历添加默认值
  1166. records.forEach(record => this._createRow(record))
  1167. let result = await this.pushRows(records, {index: index, setActive: true})
  1168. // 遍历插入的行
  1169. // update--begin--autor:lvdandan-----date:20201117------for:LOWCOD-987 【新行编辑】js增强附表内置方法调用问题 #1819
  1170. // online js增强时以传过来值为准,不再赋默认值
  1171. if (isOnlJs != true) {
  1172. for (let i = 0; i < result.rows.length; i++) {
  1173. let row = result.rows[i]
  1174. this.trigger(triggerName, {
  1175. row: row,
  1176. $table: xTable,
  1177. target: this,
  1178. })
  1179. }
  1180. }
  1181. // update--end--autor:lvdandan-----date:20201117------for:LOWCOD-987 【新行编辑】js增强附表内置方法调用问题 #1819
  1182. return result
  1183. },
  1184. // 创建新行,自动添加默认值
  1185. _createRow(record = {}) {
  1186. let {xTable} = this.$refs.vxe.$refs
  1187. // 添加默认值
  1188. xTable.tableFullColumn.forEach(column => {
  1189. let col = column.own
  1190. if (col.key && (record[col.key] == null || record[col.key] === '')) {
  1191. // 设置默认值
  1192. let createValue = getEnhancedMixins(col.$type || col.type, 'createValue')
  1193. record[col.key] = createValue({row: record, column, $table: xTable})
  1194. }
  1195. // update-begin--author:sunjianlei---date:20210819------for: 处理联动列,联动列只能作用于 select 组件
  1196. if (col.$type === JVXETypes.select && this._innerLinkageConfig != null) {
  1197. // 判断当前列是否是联动列
  1198. if (this._innerLinkageConfig.has(col.key)) {
  1199. let configItem = this._innerLinkageConfig.get(col.key)
  1200. this.getLinkageOptionsAsync(configItem, '')
  1201. }
  1202. }
  1203. // update-end--author:sunjianlei---date:20210819------for: 处理联动列,联动列只能作用于 select 组件
  1204. })
  1205. return record
  1206. },
  1207. /*--- 渲染函数 ---*/
  1208. // 渲染 vxe
  1209. renderVxeGrid(h) {
  1210. return h('vxe-grid', {
  1211. ref: 'vxe',
  1212. class: ['j-vxe-table'],
  1213. props: this.vxeProps,
  1214. on: this.vxeEvents,
  1215. // 作用域插槽的格式为
  1216. scopedSlots: this.$scopedSlots,
  1217. })
  1218. },
  1219. // 渲染工具栏
  1220. renderToolbar(h) {
  1221. if (this.toolbar) {
  1222. return h('j-vxe-toolbar', {
  1223. props: {
  1224. toolbarConfig: this.toolbarConfig,
  1225. excludeCode: this.excludeCode,
  1226. size: this.size,
  1227. disabled: this.disabled,
  1228. disabledRows: this.disabledRows,
  1229. selectedRowIds: this.selectedRowIds,
  1230. },
  1231. on: {
  1232. // 新增事件
  1233. add: () => this.addRows(),
  1234. // 保存事件
  1235. save: () => this.trigger('save', {
  1236. $table: this.$refs.vxe,
  1237. target: this,
  1238. }),
  1239. // 删除事件
  1240. remove: () => {
  1241. let $table = this.$refs.vxe
  1242. let deleteRows = this.filterNewRows(this.selectedRows)
  1243. // 触发删除事件
  1244. if (deleteRows.length > 0) {
  1245. let removeEvent = {deleteRows, $table, target: this}
  1246. if (this.asyncRemove) {
  1247. // 确认删除,只有调用这个方法才会真删除
  1248. removeEvent.confirmRemove = () => this.removeSelection()
  1249. } else {
  1250. this.removeSelection()
  1251. }
  1252. this.trigger('remove', removeEvent)
  1253. } else {
  1254. this.removeSelection()
  1255. }
  1256. },
  1257. // 清除选择事件
  1258. clearSelection: this.clearSelection
  1259. },
  1260. scopedSlots: {
  1261. toolbarPrefix: this.$scopedSlots.toolbarPrefix,
  1262. toolbarSuffix: this.$scopedSlots.toolbarSuffix,
  1263. },
  1264. })
  1265. }
  1266. return null
  1267. },
  1268. // 渲染 toolbarAfter 插槽
  1269. renderToolbarAfterSlot() {
  1270. if (this.$scopedSlots['toolbarAfter']) {
  1271. return this.$scopedSlots['toolbarAfter']()
  1272. }
  1273. return null
  1274. },
  1275. // 渲染点击时弹出的子表
  1276. renderSubPopover(h) {
  1277. if (this.clickRowShowSubForm && this.$scopedSlots.subForm) {
  1278. return h('j-vxe-sub-popover', {
  1279. ref: 'subPopover',
  1280. scopedSlots: {
  1281. subForm: this.$scopedSlots.subForm,
  1282. }
  1283. })
  1284. }
  1285. return null
  1286. },
  1287. // 渲染点击时弹出的详细信息
  1288. renderDetailsModal(h) {
  1289. if (this.clickRowShowMainForm && this.$scopedSlots.mainForm) {
  1290. return h('j-vxe-details-modal', {
  1291. ref: 'detailsModal',
  1292. scopedSlots: {
  1293. subForm: this.clickRowShowSubForm ? this.$scopedSlots.subForm : null,
  1294. mainForm: this.$scopedSlots.mainForm
  1295. }
  1296. })
  1297. }
  1298. },
  1299. // 渲染分页器
  1300. renderPagination(h) {
  1301. if (this.pagination && Object.keys(this.pagination).length > 0) {
  1302. return h('j-vxe-pagination', {
  1303. props: {
  1304. size: this.size,
  1305. disabled: this.disabled,
  1306. pagination: this.pagination
  1307. },
  1308. on: {
  1309. change: (e) => this.trigger('pageChange', e)
  1310. },
  1311. })
  1312. }
  1313. return null
  1314. },
  1315. loadExcludeCode(){
  1316. if(!this.authPre || this.authPre.length==0){
  1317. this.excludeCode = []
  1318. }else{
  1319. let pre = this.authPre
  1320. if(!pre.endsWith(':')){
  1321. pre += ':'
  1322. }
  1323. this.excludeCode = getNoAuthCols(pre)
  1324. }
  1325. }
  1326. },
  1327. render(h) {
  1328. return h('div', {
  1329. class: ['j-vxe-table-box', `size--${this.size}`]
  1330. }, [
  1331. this.renderSubPopover(h),
  1332. this.renderDetailsModal(h),
  1333. this.renderToolbar(h),
  1334. this.renderToolbarAfterSlot(),
  1335. this.renderVxeGrid(h),
  1336. this.renderPagination(h),
  1337. ])
  1338. },
  1339. beforeDestroy() {
  1340. this.$emit('beforeDestroy')
  1341. }
  1342. }
  1343. // 兼容 online 的规则
  1344. const fooPatterns = [
  1345. {title: '非空', value: '*', pattern: /^.+$/},
  1346. {title: '6到16位数字', value: 'n6-16', pattern: /^\d{6,16}$/},
  1347. {title: '6到16位任意字符', value: '*6-16', pattern: /^.{6,16}$/},
  1348. {title: '6到18位字母', value: 's6-18', pattern: /^[a-z|A-Z]{6,18}$/},
  1349. {title: '网址', value: 'url', pattern: /^(?:([A-Za-z]+):)?(\/{0,3})([0-9.\-A-Za-z]+)(?::(\d+))?(?:\/([^?#]*))?(?:\?([^#]*))?(?:#(.*))?$/},
  1350. {title: '电子邮件', value: 'e', pattern: /^([\w]+\.*)([\w]+)@[\w]+\.\w{3}(\.\w{2}|)$/},
  1351. {title: '手机号码', value: 'm', pattern: /^1[3456789]\d{9}$/},
  1352. {title: '邮政编码', value: 'p', pattern: /^[1-9]\d{5}$/},
  1353. {title: '字母', value: 's', pattern: /^[A-Z|a-z]+$/},
  1354. {title: '数字', value: 'n', pattern: /^-?\d+(\.?\d+|\d?)$/},
  1355. {title: '整数', value: 'z', pattern: /^-?\d+$/},
  1356. {title: '金额', value: 'money', pattern: /^(([1-9][0-9]*)|([0]\.\d{0,2}|[1-9][0-9]*\.\d{0,2}))$/},
  1357. ]
  1358. /** 旧版handler转为新版Validator */
  1359. function handlerConvertToValidator(event) {
  1360. const {column, rule} = event
  1361. return new Promise((resolve, reject) => {
  1362. rule.handler(event, (flag, msg) => {
  1363. let message = rule.message
  1364. if (typeof msg === 'string') {
  1365. message = replaceProps(column.own, msg)
  1366. }
  1367. if (flag == null) {
  1368. resolve(message)
  1369. } else if (!!flag) {
  1370. resolve(message)
  1371. } else {
  1372. reject(new Error(message))
  1373. }
  1374. }, this, event)
  1375. })
  1376. }
  1377. /** 唯一校验器 */
  1378. function uniqueValidator(event) {
  1379. const {cellValue, column, rule} = event
  1380. let tableData = this.getTableData()
  1381. let findCount = 0
  1382. for (let rowData of tableData) {
  1383. if (rowData[column.own.key] === cellValue) {
  1384. if (++findCount >= 2) {
  1385. return Promise.reject(new Error(rule.message))
  1386. }
  1387. }
  1388. }
  1389. return Promise.resolve()
  1390. }