Files
laws_chery_client/src/mixins/ConfigurableTableMixin.js
T

619 lines
21 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 表头通过标签管理配置的模块的表格数据的混入
*/
import { downFile, downloadFile, postAction } from '@api/manage'
import Vue from 'vue'
import { ACCESS_TOKEN } from '@/store/mutation-types'
import store from '@/store'
import { isHasPermission } from '../utils/hasPermission.js'
import { FieldType } from '../enums/commonEnums.js'
import { filterObj } from '../utils/util.js'
import { mapGetters } from 'vuex'
let importModalLoading
// 需要数据字段翻译的属性类型
const NEED_DICT_FIELD_TYPE = [
FieldType.USER_SINGLE.value,
FieldType.ORGAN_SINGLE.value,
FieldType.ORGAN_MORE.value,
FieldType.FILE_UP.value,
FieldType.OPTION_SINGLE.value,
FieldType.OPTION_MORE.value,
FieldType.TREE.value,
FieldType.TREE_SINGLE.value,
FieldType.TREE_MODAL_SELECT.value,
FieldType.TREE_MODAL_SELECT_SEARCH_DIFF.value,
FieldType.TREE_MODAL_SELECT_SEARCH_CHILD.value
]
const ZH = 'zh-cn'
export const ConfigurableTableMixin = {
data () {
return {
/* 分页参数 */
ipagination: {
current: 1,
pageSize: 10,
pageSizeOptions: ['10', '30', '50', '100', '150', '200'],
showTotal: (total, range) => {
return range[0] + '-' + range[1] + ' ' + this.$t('total') + ' ' + total + ' ' + this.$t('strip')
},
showQuickJumper: true,
showSizeChanger: true,
total: 0
},
/* 排序参数 */
isorter: {
column: '',
order: 'desc'
},
columns: [],
selectedRowKeys: [],
selectionRows: [],
dataSource: [],
isTrue: false, // 是否显示
searchParams: {},
loading: false,
orderBy: '1',
orderByField: '',
operateMaxNum: 1,
// 操作列的column
operateColumn: {
title: this.$t('operation'),
align: 'center',
fixed: 'right',
scopedSlots: { customRender: 'operation' }
},
// type: '', // 这个字段不知道什么含义
filters: {}, // 固定的搜索条件
needFilterTableBtn: true, // 是否需要过滤没有权限的按钮
getTableHeaderFunc: null, // 获取表头的方法
tableSlotField: [], // 表格需要使用插槽的字段,dbFieldName
disabledMixinsCreate: false,
isBackTitle: false, // 是否是详情页有返回的标题
defaultSearchParams: {}
}
},
computed: {
...mapGetters(['defaultHeight']),
yScrollHeight () {
/**
* 前几个使用变量是为了配合iframe嵌套,算出页面显示范围的高度
* 48px:分页器的高度
* 48pxa-card的padding(上24+下24
* 54px:表头行的高度
*/
return `calc(100vh - ${this.defaultHeight['user-info-height']} - ${this.defaultHeight['breadcrumb-height']} - ${this.defaultHeight.oneLineSearchHeight} - ${this.defaultHeight.oneLineOperationHeight} - 48px - 48px - 54px - ${this.isBackTitle ? '56px' : '0px'})`
},
importExcelUrl () {
return `${window._CONFIG.domianURL}${this.url.importUrl}`
},
tokenHeader () {
const head = { 'X-Access-Token': Vue.ls.get(ACCESS_TOKEN) }
let language = localStorage.getItem('language') || ''
if (!language) {
language = 'zh-cn'
}
const cut = language === 'zh-cn' ? 'zh' : 'en'
head.Language = cut
return head
},
},
mounted () {
if (this.disabledMixinsCreate) {
return
}
this.searchParams = Object.assign({}, this.defaultSearchParams)
this.getTableHeader()
this.loadData()
// 过滤没有权限的按钮
if (this.needFilterTableBtn) {
this.operationList = this.operationList.filter(item => !item.has || isHasPermission(item.has))
console.log(this.operationList)
}
},
methods: {
/**
* 查询,通过search组件$emit事件获取查询参数
* @param queryParam
*/
searchQuery (queryParam) {
Object.keys(queryParam).forEach(res => {
if (queryParam[res] instanceof Array) {
queryParam[res] = queryParam[res].join(',')
}
})
this.searchParams = queryParam
this.getTableHeader()
this.loadData(1)
},
/**
* 重置查询
*/
searchReset () {
this.searchParams = {}
this.selectedRowKeys = []
this.getTableHeader()
this.loadData(1)
},
/**
* 获取表头数据
*/
getTableHeader () {
if (!this.getTableHeaderFunc && typeof this.getTableHeaderFunc !== 'function') {
return
}
const params = { module: this.flag }
this.getTableHeaderFunc(params).then(res => {
if (res.success) {
this.columns = this.dealColumns(res.result || [])
console.log(this.columns)
this.isTrue = false
this.$nextTick(() => {
this.isTrue = true
})
}
})
},
/**
* 处理表头数据
* @param columns
* @returns {*[]}
*/
dealColumns (columns) {
const tempColumns = []
columns.forEach(item => {
// 可点击项加入插槽
if (item.urlClick === 'true') {
item.scopedSlots = {
customRender: 'urlClick'
}
}
// 是否可排序
item.sorter = item.sortFlag === '1'
item.width = 215
item.title = this.isChinese() ? item.dbFieldTxt : item.dbFieldEnName
if (NEED_DICT_FIELD_TYPE.includes(item.fieldShowType)) {
item.dataIndex = this.isChinese() ? item.dbFieldName + '_dictText' : item.dbFieldName + '_dictTextEn'
} else {
item.dataIndex = item.dbFieldName
}
// 在各自页面写此页面需要使用插槽的字段
if (this.tableSlotField && this.tableSlotField.includes(item.dbFieldName)) {
item.scopedSlots = {
customRender: item.dbFieldName
}
}
tempColumns.push(item)
})
if (this.showAction && this.operateColumn) {
let width = 0
if (this.operationList && this.operationList.length > this.operateMaxNum + 1) {
width += this.getTextWith(this.operationList[0].text) + this.getTextWith(this.$t('more'))
} else if (this.operationList && this.operationList.length > 1) {
width += this.getTextWith(this.operationList[0].text) + this.getTextWith(this.operationList[1].text)
console.log(width)
}
const operateColumn = JSON.parse(JSON.stringify(this.operateColumn))
operateColumn.width = width || 100
tempColumns.push(operateColumn)
}
return tempColumns
},
/**
* 通过文字获取列宽
* @param text
* @param fontStyle
* @returns {number}
*/
getTextWith (text, fontStyle) {
const canvas = document.createElement('canvas')
const context = canvas.getContext('2d')
context.font = fontStyle || '14px' // 设置字体样式
const dimension = context.measureText(text)
return dimension.width + 60
},
getQueryParams () {
const param = Object.assign({}, this.searchParams, this.isorter, this.filters)
param.pageNo = this.ipagination.current
param.pageSize = this.ipagination.pageSize
console.log(param)
return filterObj(param)
},
loadData (arg) {
if (!this.url.list) {
this.$message.warning('请设置url.list属性!')
return
}
// 加载数据 若传入参数1则加载第一页的内容
if (arg === 1) {
this.ipagination.current = 1
}
const params = this.getQueryParams()
this.loading = true
postAction(this.url.list, params).then((res) => {
if (res.success) {
if (res.result.current > 1 && res.result.records.length === 0) {
this.ipagination.current = res.result.current - 1
this.loadData()
return
}
this.dataSource = res.result.records || []
this.ipagination.total = res.result.total
} else {
this.$message.warn(res.message)
}
}).finally(() => {
this.loading = false
})
},
tableOnChange (pagination, filters, sorter) {
if (this.$refs.tableRef && this.$refs.tableRef.resizing) {
// 解决表格调整列宽触发排序的问题
const classNameOne = window.event.target.parentNode.children[0].children[0].children[1].children[0].children[0].className
const classNameTwo = window.event.target.parentNode.children[0].children[0].children[1].children[0].children[1].className
const target = window.event.target
this.$nextTick(() => {
target.parentNode.children[0].children[0].children[1].children[0].children[0].className = classNameOne
target.parentNode.children[0].children[0].children[1].children[0].children[1].className = classNameTwo
})
return
}
console.log(sorter)
if (Object.keys(sorter).length > 0) {
if (sorter.field.split('_')[sorter.field.split('_').length - 1] === 'dictText') {
this.isorter.column = sorter.order ? sorter.field.slice(0, -9) : ''
} else {
this.isorter.column = sorter.order ? sorter.field : ''
}
this.isorter.order = sorter.order === 'ascend' ? 'asc' : 'desc'
}
this.ipagination = pagination
this.loadData()
},
onSelectChange (selectedRowKeys, selectionRows) {
this.selectedRowKeys = selectedRowKeys
this.selectionRows = selectionRows
},
/* 导入 */
handleImportExcel (info) {
// 限制导入大于 importMaxSize, 各个模块可以单独设置大小
if (this.importMaxSize && info.file.size > 1024 * 1024 * this.importMaxSize) {
this.$message.error(this.$t('importMaxMsg', { size: this.importMaxSize }))
info.fileList.pop()
return
}
// 限制导入大于500MB
if (info.file.size > 1024 * 1024 * 500) {
this.$message.error('导入文件最大500MB')
info.fileList.pop()
return
}
// 加一个大的提示
if (!this.loading) {
importModalLoading = this.$info({
title: this.$t('tips'),
content: <span>{this.$t('importTip')} <a-spin size="small" /></span>,
keyboard: false
})
}
this.loading = true
// 把知道了这个按钮去掉
this.$nextTick(() => {
if (document.getElementsByClassName('ant-modal-confirm-btns')[0]) {
document.getElementsByClassName('ant-modal-confirm-btns')[0].style = 'display:none'
}
})
if (info.file.status !== 'uploading') {
console.log(info.file, info.fileList)
}
if (info.file.status === 'done') {
// 销毁这个提示
importModalLoading && importModalLoading.destroy()
this.loading = false
if (info.file.response.success) {
// this.$message.success(`${info.file.name} 文件上传成功`);
if (info.file.response.code === 201) {
const { message, result: { msg, fileUrl, fileName } } = info.file.response
const href = window._CONFIG.domianURL + fileUrl
this.$warning({
title: message,
content: (
<div>
<span>{msg}</span><br />
<span>具体详情请 <a href={href} target="_blank" download={fileName}>点击下载</a> </span>
</div>
)
})
} else {
this.$message.success(info.file.response.message || `${info.file.name} ${this.$t('fileUploadSuccess')}`)
}
this.loadData()
} else {
if (Array.isArray(info.file.response.result) && info.file.response.result.length > 0) {
this.messageLineFeed(this.$t('fileImportError'), info.file.response.result)
} else if (info.file.response.message.indexOf('</br>') !== -1) {
this.messageLineFeedByBr(this.$t('fileImportError'), info.file.response.message)
} else {
this.$message.warning(`${info.file.name} ${info.file.response.message}`)
}
}
} else if (info.file.status === 'error') {
// 销毁这个提示
importModalLoading && importModalLoading.destroy()
this.loading = false
if (info.file.response.status === 500) {
const data = info.file.response
const token = Vue.ls.get(ACCESS_TOKEN)
if (token && data.message.includes('Token失效')) {
this.error({
title: this.$t('loginExpired'),
content: this.$t('loginExpiredMessage'),
okText: this.$t('logInAgain'),
mask: false,
onOk: () => {
store.dispatch('Logout').then(() => {
Vue.ls.remove(ACCESS_TOKEN)
window.location.reload()
})
}
})
}
} else {
this.$message.warning(`${this.$t('fileUploadFailed')}: ${info.file.msg} `)
}
}
},
/**
* 导出
* @param fileName
* @param fileSuffix
*/
handleExportXls (fileName, fileSuffix = '.xls') {
if (!fileName || typeof fileName !== 'string') {
fileName = this.$t('exportFile')
}
const param = this.getQueryParams()
if (this.selectedRowKeys && this.selectedRowKeys.length > 0) {
param.selections = this.selectedRowKeys.join(',')
}
// 加一个大的提示
const modalLoading = this.$info({
title: this.$t('tips'),
content: <span>{this.$t('exportTip')}
<a-spin size="small" /></span>,
keyboard: false
})
// 把知道了这个按钮去掉
this.$nextTick(() => {
document.getElementsByClassName('ant-modal-confirm-btns')[0].style = 'display:none'
})
downFile(this.url.exportXlsUrl, param).then((data) => {
if (!data) {
this.$message.warning(this.$t('fileDownloadFail'))
return
}
if (typeof window.navigator.msSaveBlob !== 'undefined') {
window.navigator.msSaveBlob(new Blob([data], { type: 'application/vnd.ms-excel' }), fileName + fileSuffix)
} else {
const url = window.URL.createObjectURL(new Blob([data], { type: 'application/vnd.ms-excel' }))
const link = document.createElement('a')
link.style.display = 'none'
link.href = url
link.setAttribute('download', fileName + fileSuffix)
document.body.appendChild(link)
link.click()
document.body.removeChild(link) // 下载完成移除元素
window.URL.revokeObjectURL(url) // 释放掉blob对象
}
}).finally(() => {
// 销毁这个提示
modalLoading.destroy()
})
},
/**
* 带文件导出
* @param fileName
*/
handleFileExport (fileName) {
if (!fileName || typeof fileName !== 'string') {
fileName = this.$t('exportWithFiles')
}
const param = this.getQueryParams()
if (this.selectedRowKeys && this.selectedRowKeys.length > 0) {
param.selections = this.selectedRowKeys.join(',')
}
// 加一个大的提示
const modalLoading = this.$info({
title: this.$t('tips'),
content: <span>{this.$t('exportTip')}
<a-spin size="small" /></span>,
keyboard: false
})
// 把知道了这个按钮去掉
this.$nextTick(() => {
document.getElementsByClassName('ant-modal-confirm-btns')[0].style = 'display:none'
})
downFile(this.url.exportZipUrl, param).then((data) => {
if (!data) {
this.$message.warning(this.$t('fileDownloadFail'))
}
}).finally(() => {
// 销毁这个提示
modalLoading.destroy()
})
},
// 下载导入模板
downTemplate (fileName, fileSuffix = '.xls') {
if (!fileName || typeof fileName !== 'string') {
fileName = this.$t('templateFile')
}
downloadFile(this.url.downTemplateUrl, fileName + fileSuffix)
},
/**
* 批量删除
*/
batchDel () {
if (!this.url.delete) {
this.$message.warning('请设置url.deleteBatch属性!')
return
}
if (this.selectedRowKeys.length <= 0) {
this.$message.warning(this.$t('selectARecord'))
return
}
const ids = this.selectedRowKeys.join(',')
this.$confirm({
title: this.$t('confirmBatchDeletion'),
content: this.$t('deleteAData'),
onOk: () => {
this.loading = true
postAction(this.url.deleteBatch, { ids: ids }).then((res) => {
if (res.success) {
// 重新计算分页问题
this.reCalculatePage(this.selectedRowKeys.length)
this.$message.success(res.message)
this.loadData()
this.onClearSelected()
} else {
this.$message.warning(res.message)
}
}).finally(() => {
this.loading = false
})
}
})
},
reCalculatePage (count) {
// 总数量-count
const total = this.ipagination.total - count
// 获取删除后的分页数
const currentIndex = Math.ceil(total / this.ipagination.pageSize)
// 删除后的分页数<所在当前页
if (currentIndex < this.ipagination.current) {
this.ipagination.current = currentIndex
}
console.log('currentIndex', currentIndex)
},
/**
* 删除
* @param id
*/
handleDelete (id) {
if (!this.url.delete) {
this.$message.warning('请设置url.delete属性!')
return
}
const that = this
this.$confirm({
title: this.$t('confirmDeletion'),
content: this.$t('areYouSure'),
onOk: () => {
postAction(that.url.delete, { ids: id }).then((res) => {
if (res.success) {
that.$message.success(res.message)
// 判断当前删除的数据是否是最后一页的最后一条数据,如果是的话页码减一
if (that.ipagination.current > 1 && ((that.ipagination.current - 1) * that.ipagination.pageSize) + 1 === that.ipagination.total) {
that.ipagination.current -= 1
}
that.loadData()
} else {
that.$message.warning(res.message)
}
})
}
})
},
handleEdit (record) {
this.$refs.modalForm.edit(record)
this.$refs.modalForm.title = this.$t('edit')
this.$refs.modalForm.disableSubmit = false
},
handleAdd () {
this.$refs.modalForm.add()
this.$refs.modalForm.title = this.$t('newlyAdded')
this.$refs.modalForm.disableSubmit = false
},
modalFormOk () {
// 新增/修改 成功时,重载列表
this.loadData()
// 清空列表选中
this.onClearSelected()
},
onClearSelected () {
this.selectedRowKeys = []
this.selectionRows = []
},
handleImportByFileId (fileId) {
// TODO 完善通过文件id上传文件的方法
},
/**
* 循环操作按钮的操作
* @param operation
* @param record
*/
operationClick (operation, record) {
if (operation.clickEvent === 'handleDelete') {
this.handleDelete(record.id)
} else {
this[operation.clickEvent](record)
}
},
/**
* 对数组形式后端错误信息进行处理
* @param title
* @param content
*/
messageLineFeed (title, content) {
const htmlDom = []
content.map(tt => {
if (tt) {
htmlDom.push((<div>{tt}</div>))
}
})
this.$warning({
title: title,
closable: true,
width: 800,
content: () => <div>
{htmlDom}
</div>
})
this.$nextTick(() => {
document.getElementsByClassName('ant-modal-confirm-btns')[0].style = 'display: inline-block'
document.getElementsByClassName('ant-modal-confirm-content')[0].style = 'max-height: calc(100vh - 300px);overflow-y: auto;'
})
},
/**
* 对包含<br/>的后端错误信息进行处理
* @param title
* @param content
*/
messageLineFeedByBr (title, content) {
// 可以用分号和<br/>换行
content = content.replaceAll(`</br>`, ';')
const messageArr = content.split(';')
const htmlDom = []
messageArr.map(tt => {
if (tt) {
htmlDom.push((<div>{tt}</div>))
}
})
this.$warning({
title: title,
closable: true,
width: 800,
content: () => <div>
{htmlDom}
</div>
})
this.$nextTick(() => {
document.getElementsByClassName('ant-modal-confirm-btns')[0].style = 'display: inline-block'
document.getElementsByClassName('ant-modal-confirm-content')[0].style = 'max-height: calc(100vh - 300px);overflow-y: auto;'
})
}
}
}