Files
AJ-Report/report-ui/src/components/AnjiPlus/anji-crud/anji-crud.vue
木子李·De 3726ce16f5 update
2021-07-18 17:10:10 +08:00

583 lines
22 KiB
Vue
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.
<template>
<div :class="[hasTreeFieldInQueryForm ? 'page-container' : 'app-container']">
<div v-if="hasTreeFieldInQueryForm" class="left-container">
<AnjiTree ref="queryFormTree" v-model.trim="queryParams[queryFormTreeField.field]" :is-open="queryFormTreeField.anjiTreeOption.isOpen" :enable-filter="queryFormTreeField.anjiTreeOption.enableFilter" :label-name="queryFormTreeField.label" :url="queryFormTreeField.anjiTreeOption.url" @node-click="handleTreeNodeCheck" />
</div>
<div class="right-container">
<!-- 查询表单开始 -->
<el-form ref="formSearch" :model="queryParams" label-width="100px" v-permission="option.buttons.query.permission">
<el-row>
<el-col v-for="(item, index) in queryFormFieldExcludeTree" :key="item.field" :span="queryFormFieldSpan(item)">
<el-form-item v-if="index <= 2 || (index > 2 && queryParams.showMoreSearch)" :label="item.label" :rules="item.rules" :prop="item.field">
<!-- 输入框 -->
<el-input v-if="item.inputType == 'input' || item.inputType == 'input-number'" v-model.trim="queryParams[item.field]" :placeholder="item.placeholder || '请输入'" :clearable="item.clearable !== false" :disabled="item.disabled" @change="(value) => queryFormChange(item.field, value)" />
<!-- 开关 -->
<el-switch v-else-if="item.inputType == 'switch'" v-model.trim="queryParams[item.field]" :disabled="item.disabled" :active-value="item.switchOption.disableValue" :inactive-value="item.switchOption.enableValue" active-color="#5887fb" inactive-color="#ccc" @change="(value) => queryFormChange(item.field, value)" />
<!-- 下拉框 -->
<anji-select v-else-if="item.inputType == 'anji-select'" v-model.trim="queryParams[item.field]" :multiple="item.anjiSelectOption.multiple" :dict-code="item.anjiSelectOption.dictCode" :url="item.anjiSelectOption.url" :method="item.anjiSelectOption.method" :query-param="item.anjiSelectOption.queryParam" :option="item.anjiSelectOption.option" :label="item.anjiSelectOption.label" :disabled-options="item.anjiSelectOption.disabledOptions" :disabled="item.disabled"
:merge-label="item.anjiSelectOption.mergeLabel" @change="(value) => queryFormChange(item.field, value)" />
<!-- 日期时间框 -->
<el-date-picker v-else-if="item.inputType.indexOf('date') >= 0" v-model="queryParams[item.field]" style="width: 100%" :placeholder="item.placeholder || '请选择'" :type="item.inputType" :clearable="item.clearable !== false" @change="(value) => queryFormChange(item.field, value)" />
<!-- 待扩展的表单类型请自行扩展 -->
<el-input v-else placeholder="组件不支持此类型表单请至组件内部自行扩展" disabled />
</el-form-item>
</el-col>
<el-col :span="6" style="text-align: center">
<el-button type="primary" @click="handleQueryForm('query')">查询</el-button>
<el-button type="danger" @click="handleResetForm()">重置</el-button>
<a style="margin-left: 8px" @click="handleToggleMoreSearch">
{{ queryParams.showMoreSearch == true ? '收起' : '展开' }}
<i :class="queryParams.showMoreSearch ? 'el-icon-arrow-up' : 'el-icon-arrow-down'" />
</a>
</el-col>
</el-row>
</el-form>
<!-- 查询表单结束 -->
<!-- 批量操作 -->
<slot name="buttonLeftOnTable" />
<el-button v-if="option.buttons.add.isShow == undefined ? true : option.buttons.add.isShow" v-permission="option.buttons.add.permission" type="primary" icon="el-icon-plus" @click="handleOpenEditView('add')">新增</el-button>
<el-button v-if="option.buttons.delete.isShow == undefined ? true : option.buttons.delete.isShow" v-permission="option.buttons.delete.permission" :disabled="disableBatchDelete" type="danger" icon="el-icon-delete" @click="handleDeleteBatch()">删除</el-button>
<!-- 表格开始 -->
<el-table :data="records" border @selection-change="handleSelectionChange" @sort-change="handleSortChange">
<!--多选-->
<el-table-column fixed type="selection" width="50" align="center" />
<!--隐藏列-->
<el-table-column v-if="tableExpandColumns.length > 0" type="expand">
<template slot-scope="scope">
<p v-for="item in tableExpandColumns" :key="item.field" class="table-expand-item">
<span class="titel"> {{ item.label }}: </span>
<span>{{ scope.row[item.field] }}</span>
</p>
</template>
</el-table-column>
<!--序号-->
<el-table-column label="序号" min-width="50" align="center">
<template slot-scope="scope">
{{ queryParams.pageSize * (queryParams.pageNumber - 1) + scope.$index + 1 }}
</template>
</el-table-column>
<template v-for="item in option.columns">
<el-table-column v-if="item.tableHide != true && item.columnType != 'expand'" :key="item.field" :prop="item.field" :label="fieldLabel(item)" :min-width="item.minWidth || 110" :sortable="item.sortable" :show-overflow-tooltip="true" align="center">
<template slot-scope="scope">
<div v-if="item.columnType == 'imgPreview'">
<!-- 图片缩略图-->
<el-image style="width: 25%; height: 50%" fit="contain" :src="scope.row[item.field]" :preview-src-list="[scope.row[item.field]]" />
</div>
<div v-else>
<span v-if="item.inputType == 'switch' && !item.colorStyle">
<el-switch v-model.trim="scope.row[item.field]" :active-value="1" :inactive-value="0" active-color="#5887fb" inactive-color="#ccc" @change="switchChange(scope.row, item.switchOption)" />
</span>
<!-- 带单位 -->
<span v-else-if="item.inputType == 'anji-input'">{{ fieldValueByAnjiInput(scope.row[item.field], item) }}</span>
<!--表格 a 合并 b上-->
<span v-else-if="item.mergeColumn">{{ scope.row[item.field] }}({{ scope.row[item.mergeColumn] }})</span>
<!-- 没有单位 -->
<span v-else-if="item.colorStyle" :class="item.colorStyle[scope.row[item.editField]]">{{ fieldValueByRowRenderer(scope.row, item) }}</span>
<span v-else>{{ fieldValueByRowRenderer(scope.row, item) }}</span>
<!-- 正常展示模式
<div v-if="!item.custom">
是第一列数据 && 需要高亮字段不为false 高亮并且可以点击
<span v-if="!index && item.operate !== false" class="view" @click="handleOpenEditView('view', scope.row)">{{ scope.row[item.field] }}</span>
<span v-else>{{ scope.row[item.field] }}</span>
</div>
-->
<!-- 自定义展示数据
<div v-else v-html="item.renderer(scope.row)" />-->
</div>
</template>
</el-table-column>
</template>
<!--操作栏-->
<el-table-column align="center" fixed="right" label="操作" :width="option.buttons.customButton && option.buttons.customButton.operationWidth ? option.buttons.customButton.operationWidth : 100">
<template slot-scope="scope">
<slot name="edit" :msg="scope.row" />
<el-button v-if="(option.buttons.query.isShow == undefined ? true : option.buttons.query.isShow) && hasPermission(option.buttons.edit.permission) == false" type="text" size="small" @click="handleOpenEditView('view', scope.row)" v-permission="option.buttons.query.permission" >查看</el-button>
<el-button v-if="option.buttons.edit.isShow == undefined ? true : option.buttons.edit.isShow" type="text" size="small" @click="handleOpenEditView('edit', scope.row)" v-permission="option.buttons.edit.permission" >编辑</el-button>
<el-button v-if="hasRowCustomButton == false && option.buttons.delete.isShow == undefined ? true : option.buttons.edit.isShow" type="text" size="small" @click="handleDeleteBatch(scope.row)" v-permission="option.buttons.delete.permission" >删除</el-button>
<el-dropdown v-if="hasRowCustomButton" trigger="click">
<span class="el-dropdown-link"> 更多<i class="el-icon-caret-bottom el-icon--right" /> </span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item class="clearfix">
<slot name="rowButton" :msg="scope.row" />
<el-button v-if="option.buttons.delete.isShow == undefined ? true : option.buttons.edit.isShow" type="text" size="small" @click="handleDeleteBatch(scope.row)" v-permission="option.buttons.delete.permission" >删除</el-button>
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</template>
</el-table-column>
</el-table>
<div class="pagination">
<el-pagination v-show="total > 0" background :current-page.sync="queryParams.pageNumber" :page-sizes="$pageSizeAll" :page-size="queryParams.pageSize" layout="total, prev, pager, next, jumper, sizes" :total="total" @size-change="handleSizeChange" @current-change="handleCurrentChange" />
<div>
<slot name="tableSelectionBtn" :selection="checkRecords" />
</div>
</div>
<!-- 表格结束 -->
<EditDialog ref="edit" :option="option" :model-type="editDialogModelType" :visible="editDialogOpen" :row-data="editDialogRowData" @closeEvent="editDialogClosedEvent">
<template v-slot:customCard>
<slot name="cardInEditPage" />
</template>
<template slot="editBtn" slot-scope="scope">
<slot name="editBtnPage" :rowData="scope" />
</template>
</EditDialog>
</div>
<slot name="pageSection" />
</div>
</template>
<script>
import AnjiTree from '@/components/AnjiPlus/anji-tree.vue'
import EditDialog from './edit'
import request from '@/utils/request'
export default {
components: {
EditDialog,
AnjiTree,
},
props: {
option: {
require: true,
type: Object,
default: () => {
return {
// 查询表单条件
queryFormFields: [],
// 按钮
buttons: {
query: {},
edit: {},
delete: {},
add: {},
},
// 表格列
columns: [],
queryFormChange: (fileName, val) => {},
}
},
},
},
data() {
return {
// 查询表单提交的值
queryParams: {
showMoreSearch: false, // 是否展开更多搜索条件
pageNumber: 1,
pageSize: 10,
order: '',
sort: '',
},
checkRecords: [], // 表格中当前选中的记录
records: [], // 接口返回的记录列表
total: 0, // 接口返回的总条数
// 编辑详情弹框
editDialogOpen: false, // 新建时主动打开编辑弹框
editDialogRowData: {}, // 编辑时的主键
editDialogModelType: 'view', // 编辑 查看
hasRowCustomButton: false, // 除了编辑删除外,还有自定义的行按钮
}
},
computed: {
// 左侧树形查询条件
queryFormTreeField() {
var treeField = this.option.queryFormFields.find(
(item) => item['inputType'] == 'anji-tree'
)
return treeField
},
// 查询条件里是否有树形控件
hasTreeFieldInQueryForm() {
return this.isNotBlank(this.queryFormTreeField)
},
// 不包含树形控件的查询条件
queryFormFieldExcludeTree() {
var treeFields = this.option.queryFormFields.filter(
(item) => item['inputType'] != 'anji-tree'
)
return treeFields
},
// 主键的列名
primaryKeyFieldName() {
var primaryKey = this.option.columns.find(
(item) => item['primaryKey'] == true
)
if (primaryKey != null) {
return primaryKey['field']
} else {
return null
console.warn(
'在columns中查找primaryKey=true失败会导致查询详情和删除失败'
)
}
},
// 表格中可展开的列
tableExpandColumns() {
var expandColumns = this.option.columns.filter(
(item) => item['columnType'] == 'expand'
)
return expandColumns
},
// 是否可以批量删除
disableBatchDelete() {
return this.checkRecords.length <= 0
},
},
created() {
// 为查询框中所有input加上默认值
this.option.queryFormFields.forEach((item) => {
// 动态添加属性
this.$set(this.queryParams, item.field, item.defaultValue || null)
})
// 查询列表
this.handleQueryForm('query')
this.queryFormChange()
},
mounted() {
if (this.$scopedSlots['rowButton'] != null) {
this.hasRowCustomButton = true
} else {
this.hasRowCustomButton = false
}
},
methods: {
queryFormFieldSpan(item) {
// console.log(item)
if (item.span != null) {
return item.span
} else {
return 6
}
// let rowLength = this.option.queryFormFields.length;
// console.log(rowLength, "ss")
// console.log(rowLength % 3)
// if (rowLength <= 3) {
// return 6
// }
// else if (rowLength % 3 == 0) {
// return 8
// } else if (rowLength > 6) {
// return 8
// }
},
// 切换更多搜索条件
handleToggleMoreSearch() {
this.queryParams.showMoreSearch = !this.queryParams.showMoreSearch
},
// 列上排序切换
handleSortChange(column) {
// {column: {…}, prop: "orgCode", order: "ascending"}
if (column == null || column.prop == null) {
console.warn('排序字段名prop为空无法排序')
return
}
var sort = column.prop // 列表查询默认排序列
var order = column.order == 'ascending' ? 'ASC' : 'DESC'
this.queryParams['sort'] = sort
this.queryParams['order'] = order
this.handleQueryForm('query')
},
// 查询按钮
handleQueryForm(from) {
// 如果是点查询按钮,把树的查询属性去掉
if (from == 'query') {
if (this.hasTreeFieldInQueryForm) {
delete this.queryParams[this.queryFormTreeField.field]
}
}
// 如果是点树查询,把查询区里的属性去掉
if (from == 'tree') {
if (this.hasTreeFieldInQueryForm) {
var treeVal = this.queryParams[this.queryFormTreeField.field]
this.queryParams = {
pageNumber: 1,
pageSize: 10,
}
this.queryParams[this.queryFormTreeField.field] = treeVal
}
}
// 默认的排序
if (
this.isBlank(this.queryParams['order']) &&
this.isNotBlank(this.option.buttons.query.order)
) {
this.queryParams['sort'] = this.option.buttons.query.sort
this.queryParams['order'] = this.option.buttons.query.order
}
this.queryParams.pageNumber = 1
this.handleQueryPageList()
},
// 列表查询
async handleQueryPageList() {
var params = this.queryParams
// 将特殊参数值urlcode处理 var params = this.urlEncodeObject(this.queryParams, 'order,sort')
const { data, code } = await this.option.buttons.query.api(params)
if (code != '200') return
this.records = data.records
this.total = data.total
},
// 重置
handleResetForm() {
this.queryParams = {
pageNumber: 1,
pageSize: 10,
}
// this.$refs['queryForm'].resetFields()
// this.records = []
// this.total = 0
},
// 树形查询条件点击回调
handleTreeNodeCheck() {
this.handleQueryForm('tree')
// 为新建页面的对应属性值,绑定上对应的默认值
var treeFieldName = this.queryFormTreeField['field']
for (var i = 0; i < this.option.columns.length; i++) {
var item = this.option.columns[i]
if (
item['editField'] == treeFieldName ||
item['field'] == treeFieldName
) {
this.$set(
this.option.columns[i],
'defaultValue',
this.queryParams[treeFieldName]
)
break
}
}
},
// 编辑和查看操作
handleOpenEditView(modelType, row) {
if (modelType == 'view' || modelType == 'edit') {
this.editDialogRowData = row
}
this.editDialogModelType = modelType
if (modelType == 'add') {
// 新增模式,不需要查询数据详情,直接打开
this.editDialogOpen = true
}
const obj = {
type: modelType,
value: row,
}
this.$emit('handleCustomValue', obj)
},
// 弹框被关闭时的回调事件
editDialogClosedEvent(value) {
// 把列表页中弹框打开标记改成已关闭
this.editDialogOpen = false
// 关闭弹出框时,如果有树,刷新下
if (
this.hasTreeFieldInQueryForm &&
this.$refs.queryFormTree != null &&
!value
) {
this.$refs.queryFormTree.queryData()
}
this.handleQueryPageList()
// 关闭时 清空表单的验证规则
this.$refs.edit.$refs.mainForm.$refs.editForm.resetFields()
},
// 批量删除
handleDeleteBatch(row) {
var ids = []
if (row != null) {
ids.push(row[this.primaryKeyFieldName]) // 删除指定的行
} else {
// 批量删除选中的行
ids = this.checkRecords.map((item) => item[this.primaryKeyFieldName])
}
this.$confirm('删除确认', '确认要删除吗?', {
type: 'warning',
confirmButtonClass: 'delete_sure',
cancelButtonClass: 'el-button--danger is-plain',
})
.then(() => {
this.option.buttons.delete.api(ids).then((res) => {
// {code: "200", message: "操作成功", data: true}
this.checkRecords = []
// 关闭弹出框时,如果有树,刷新下
if (
this.hasTreeFieldInQueryForm &&
this.$refs.queryFormTree != null
) {
this.$refs.queryFormTree.queryData()
}
this.handleQueryPageList()
})
})
.catch((e) => {
e
})
},
// 选择项改变时
handleSelectionChange(val) {
this.checkRecords = val
},
// 页码改变
handleCurrentChange(pageNumber) {
this.queryParams.pageNumber = pageNumber
this.handleQueryPageList()
},
// 每页size改变时
handleSizeChange(val) {
this.queryParams.pageNumber = 1
this.queryParams.pageSize = val
this.handleQueryPageList()
},
// table列文件缩略图
thumbnailUrl(row, field) {
// return 'http://10.108.3.123:9090/tms/file/download/79ee7e8b-2a9a-4142-b06d-706ac8089205'
// if (row.filePath) {
// if (row.filePath.endsWith('xlsx') || row.filePath.endsWith('xls')) {
// return fileExcel;
// } else if (row.filePath.endsWith('pdf')) {
// return filePdf;
// }
// return process.env.VUE_APP_BASE_API + '/tms/file/download/' + row.fileId;
// } else {
// return logo;
// }
},
// 带单位的列,需要转换
fieldLabel(columnConfig) {
if (columnConfig == null) {
return ''
}
if (
columnConfig.inputType == 'anji-input' &&
columnConfig.anjiInput != null
) {
return `${columnConfig.label}(${columnConfig.anjiInput.unit})`
} else {
return columnConfig.label
}
},
// 带单位的输入框
fieldValueByAnjiInput(value, columnConfig) {
if (columnConfig == null) {
return value
}
if (
columnConfig.inputType == 'anji-input' &&
columnConfig.anjiInput != null
) {
return value / columnConfig.anjiInput.conversion
} else {
return value
}
},
// 带表格列格式化的值
fieldValueByRowRenderer(row, columnConfig) {
if (
columnConfig == null ||
typeof columnConfig.fieldTableRowRenderer != 'function'
) {
return row[columnConfig.field]
} else {
return columnConfig.fieldTableRowRenderer(row)
}
},
// 暴露给外部crud页面回传saveForm的值
getMainEntity() {
return this.$refs.edit.getSaveForm()
},
setMainEntity(object) {
this.$refs.edit.setSaveForm(object)
},
async switchChange(val, api) {
request({
url: api.url,
method: 'put',
headers: { noPrompt: false },
data: [val.id],
}).then((response) => {
this.handleQueryPageList()
})
},
queryFormChange(fileName, fieldVal) {
if (typeof this.option.queryFormChange == 'function') {
this.option.queryFormChange(this.queryParams, fileName, fieldVal)
}
},
},
}
</script>
<style scoped lang="scss">
.style-btn {
pointer-events: none;
}
.page-container {
height: 100%;
position: relative;
.left-container {
width: 20%;
position: absolute;
top: 0;
left: 0;
background: #fff;
border-radius: 4px 0px 0px 4px;
padding: 20px 20px 0;
overflow: hidden;
overflow-y: auto;
height: 100%;
}
.right-container {
width: calc(80% - 5px);
position: absolute;
top: 0;
right: 0;
background: #fff;
border-radius: 0px 4px 4px 0px;
padding: 20px 20px 0;
height: 100%;
}
}
.el-table .cell,
.el-table td div {
overflow: hidden;
text-overflow: ellipsis;
}
.el-dropdown {
font-size: 12px;
display: inline;
color: #5887fb;
cursor: pointer;
}
.el-dropdown-menu--mini .el-dropdown-menu__item {
min-width: 80px;
max-width: 110px;
float: right;
.el-button--text {
float: right;
}
&:hover {
background: none !important;
}
.el-button--mini {
float: right;
}
.el-button + .el-button {
margin-left: 0 !important;
float: right;
}
}
.pagination {
display: flex;
flex-direction: row;
justify-content: space-between;
}
</style>