You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

769 lines
23 KiB

<template>
<!-- 解决el-table 数据量过大导致卡顿现象 -->
<u-table
:id="_uid"
:key="isUpdate"
v-loading="tableLoading"
element-loading-text="拼命加载中..."
@sort-change="sortChange"
@selection-change="handleSelectionChange"
ref="multipleTable"
:data="tableData"
:row-key="rowKey"
:border="tableBorder"
style="width: 100%"
:cell-style="cellStyle"
use-virtual
:row-height="50"
:height="uTableHeight"
header-row-class-name="uTableHeader"
>
<!-- :tree-props="treeProps" 与 “height” 不能共存, 此组件暂不支持tree的格式-->
<u-table-column v-if="selectionTable" fixed="left" type="selection" :reserve-selection="true" />
<u-table-column v-if="isShowIndex" type="index" fixed="left" label="序号" width="50" />
<template v-for="(item, index) in TableSize">
<u-table-column
:key="index"
:prop="item.showProp ? item.prop + '.' + item.showProp : item.prop"
:sortable="item.sortable"
:fixed="setItemFixed(item,index)"
:show-overflow-tooltip="true"
:width="item.width"
:align="item.tableAlign"
:header-align="item.tableHeaderAlign"
v-if="item.istrue==null?true:item.istrue"
>
<template #header>
<span>{{ item.label }}</span>
<i style="color: #f56c6c" v-if="item.rules && requiredRules">*</i>
</template>
<template slot-scope="scope">
<el-form>
<el-form-item
v-if="item.type == 'input'"
:onkeyup="itemOnKeyUp(item,searchData[item.prop])"
:prop="'details.' + scope.$index + '.' + item.prop"
:rules="item.rules"
>
<el-input
:placeholder="'请输入' + item.label"
:disabled="Boolean(item.disabled) || Boolean(scope.row['disabled'])"
v-model="scope.row[item.prop]"
@blur="
inputPlaceholder($event, item, 'blur',scope.row)
"
@focus="inputPlaceholder($event, item, 'focus')"
clearable
>
</el-input>
</el-form-item>
<!-- 输入框(数字) onkeyup: 正则表达式,用于前端输入校验工作-->
<el-form-item
v-if="item.type == 'inputNumber'"
:prop="'details.' + scope.$index + '.' + item.prop"
:rules="item.rules"
>
<el-input
v-model="searchData[item.prop]"
:maxlength="item.maxlength"
:onkeyup="typeNumberOnkeyup(item,searchData[item.prop])"
clearable
:disabled="Boolean(item.disabled)"
:placeholder="'请输入' + item.label"
:prefix-icon="item.icon"
:show-password="item.showPassword"
@change="changeInput(item.prop,$event)"
@clear="clearInput(item.prop,$event)"
@blur="
inputPlaceholder($event, item, 'blur',searchData)
"
@focus="inputPlaceholder($event, item, 'focus')"
></el-input>
</el-form-item>
<el-form-item
v-if="item.type == 'objectInput'"
:prop="
'details.' + scope.$index + '.' + item.prop + '.' + item.showProp
"
:rules="item.rules"
>
<el-input
:placeholder="'请输入' + item.label"
v-model="scope.row[item.prop][item.showProp]"
:disabled="Boolean(item.disabled) || Boolean(scope.row['disabled'])"
@blur="
inputPlaceholder($event, item, 'blur', scope.row)
"
@focus="inputPlaceholder($event, item, 'focus')"
clearable
>
</el-input>
</el-form-item>
<!-- 下拉框 -->
<el-select
v-if="item.type === 'select'"
v-model="scope.row[item.prop]"
:loading="selectLoading"
:clearable="item.clearable"
:multiple="item.multiple"
:disabled="Boolean(item.disabled) || Boolean(scope.row['disabled'])"
:filterable="item.filterable"
:allow-create="item.allowCreate"
style="width: 100%"
:placeholder="'请输入' + item.label"
>
<el-option
v-for="(op, index) in selectOptions(item.options) ||
searchOptions['options']"
:label="op[item.optionsLabel] || op.label"
:value="op[item.optionsValue] || op.value"
:key="index"
></el-option>
</el-select>
<!--对象下拉框 -->
<el-select
v-if="item.type === 'objectSelect'"
v-model="scope.row[item.prop][item.showProp]"
:loading="selectLoading"
:clearable="item.clearable"
:multiple="item.multiple"
:disabled="Boolean(item.disabled) || Boolean(scope.row['disabled'])"
:filterable="item.filterable"
:allow-create="item.allowCreate"
style="width: 100%"
:placeholder="'请输入' + item.label"
>
<el-option
v-for="(op, index) in selectOptions(item.options) ||
searchOptions['options']"
:label="op[item.optionsLabel] || op.label"
:value="op[item.optionsValue] || op.value"
:key="index"
></el-option>
</el-select>
<!--查询下拉-->
<el-form-item
v-if="item.type === 'autocomplete'"
:prop="'details.' + scope.$index + '.' + item.prop"
:rules="item.rules"
>
<el-autocomplete
class="inline-input"
style="width: 100%"
:disabled="Boolean(item.disabled) || Boolean(scope.row['disabled'])"
v-model="scope.row[item.prop]"
:fetch-suggestions="
(queryString, cb) => {
querySearch(queryString, cb, item, scope);
}
"
:placeholder="'请输入' + item.label"
@select="handleSelect($event, item, scope)"
>
<!-- <template slot-scope="{item}">
<div class="name" style="color:green">{{item.value = item.name}}</div>
<div class="name" >{{item.address = item.code}}</div>
</template> -->
<el-button
v-if="item.click"
slot="append"
icon="el-icon-search"
@click="item.click({ scope, item })"
style="color: #1890ff; background-color: #ffffff"
></el-button>
</el-autocomplete>
</el-form-item>
<!-- 对象查询下拉 -->
<el-form-item
v-if="item.type === 'objectAutocomplete'"
:prop="
'details.' + scope.$index + '.' + item.prop + '.' + item.showProp
"
:rules="item.rules"
>
<el-autocomplete
class="inline-input"
style="width: 100%"
:disabled="Boolean(item.disabled) || Boolean(scope.row['disabled'])"
v-model="scope.row[item.prop][item.showProp]"
:fetch-suggestions="
(queryString, cb) => {
querySearch(queryString, cb, item, scope);
}
"
:placeholder="'请输入' + item.label"
@select="handleSelect($event, item, scope)"
>
<!-- <template slot-scope="{item}">
<div class="name" style="color:green">{{item.value = item.name}}</div>
<div class="name" >{{item.address = item.code}}</div>
</template> -->
<el-button
v-if="item.click"
slot="append"
icon="el-icon-search"
@click="item.click({ scope, item })"
style="color: #1890ff; background-color: #ffffff"
></el-button>
</el-autocomplete>
</el-form-item>
<!-- <el-form-item v-if="item.type == 'inputEnum'" :prop="item.prop">
<el-input
placeholder="请输入内容"
v-model="scope.row[item.prop]"
clearable
>
</el-input>
</el-form-item> -->
<el-form-item
v-if="item.type == 'dateTimeInput'"
:prop="'details.' + scope.$index + '.' + item.prop"
:rules="item.rules"
>
<el-date-picker
type="datetime"
v-model="scope.row[item.prop]"
placeholder="选择日期"
style="width: 100%"
:disabled="Boolean(item.disabled) || Boolean(scope.row['disabled'])"
value-format="yyyy-MM-ddTHH:mm:ss.sssZ"
format="yyyy-MM-dd"
></el-date-picker>
</el-form-item>
<el-form-item
v-if="item.type == 'objectDateTimeInput'"
:prop="'details.' + scope.$index + '.' + item.prop + '.' + item.showProp"
:rules="item.rules"
>
<el-date-picker
type="datetime"
v-model="scope.row[item.prop][item.showProp]"
placeholder="选择日期"
style="width: 100%"
:disabled="Boolean(item.disabled) || Boolean(scope.row['disabled'])"
value-format="yyyy-MM-ddTHH:mm:ss.sssZ"
format="yyyy-MM-dd"
></el-date-picker>
</el-form-item>
<!-- table表添加按钮事件 v-show="scope.row.number == 'PRJ202210060001'" -->
<!-- <el-form-item v-if="item.type == 'button'" > -->
<div v-if="item.type == 'button'">
<el-button
v-show="scope.row[item.prop]==undefined?true:false"
type="primary"
size="mini"
@click="buttonClick(scope.row, scope.$index, item.label)"
>{{item.label}}</el-button>
</div>
<!-- </el-form-item> -->
<!-- table表添加操作列 -->
<div v-if="item.type == 'buttonOperation'">
<el-button
class="buttonOperation-btn"
v-for="(itemButton, indexButton) in item.buttonText.split('|')"
:key="indexButton"
type="text"
size="mini"
@click="buttonOperationClick(scope.row, item.buttonName.split('|')[indexButton])"
>{{itemButton}}</el-button>
</div>
<span v-if="item.type == 'object'">
{{ scope.row[item.prop] ? scope.row[item.prop][item.showProp] : "" }}
</span>
<span v-if="item.type == 'objectDateTime'">
{{ scope.row[item.prop]? scope.row[item.prop][item.showProp]: "" | formatDate }}
</span>
<span v-if="item.type == 'dateTime'">
{{ scope.row[item.prop] | formatDate }}
</span>
<!-- 调用主表信息 -->
<span v-else-if="item.type && item.type == 'outerMainFilter'">
{{ propsData[item.showProp] }}
</span>
<el-tag
v-if="item.type == 'tagFilter'"
:effect="'dark'"
size="medium"
class="tagFilterTypeDarkItem"
:color="scope.row[item.prop] | trigger(item.filters, 'background')"
>
{{ scope.row[item.prop] | trigger(item.filters, "label") }}
</el-tag>
<span
v-if="item.type == 'filter'"
:style="scope.row[item.prop]"
>
{{ scope.row[item.prop] | trigger(item.filters, "label", item.dictType) }}
</span>
<span
v-if="item.type == 'objectFilter'"
:style="scope.row[item.prop][item.showProp]"
>
{{ scope.row[item.prop][item.showProp] | trigger(item.filters, "label") }}
</span>
<span v-else-if="item.type == 'filterList'" >
{{ scope.row[item.prop] | triggerList(item.filters, "label") }}
</span>
<span
v-if="item.type == 'name' || !item.type"
@click="item.type == 'name' && inlineDialog(scope.row)"
:class="{ spamHover: item.type == 'name' }"
>{{ scope.row[item.prop] }}</span
>
</el-form>
</template>
</u-table-column>
</template>
<slot></slot>
</u-table>
</template>
<script>
import { formatTimeStrToStr } from "@/utils/formatTime";
import _ from "lodash";
import { getMatchRegConformValue } from "@/utils/index"
export default {
name: "currenTable",
filters: {
formatDate(time) {
if (time == null) {
return '-'
}
return formatTimeStrToStr(time)
},
},
props: {
// table是否有border
tableBorder: {
type: Boolean,
default: false,
},
// 是否为第一个浮动,如果是,则item中的fixed无效(应用场景:主列表,因为用户排序不定元素为第一项)
firstFixed: {
type: Boolean,
default: false,
},
propsData: {
type: Object,
default: () => {
return {};
},
},
tableData: {
type: Array,
default: () => {
return [];
},
},
tableLoading: {
type: Boolean,
default: false,
},
tableColumns: {
type: Array,
default: () => {
return [];
},
},
selectionTable: {
type: Boolean,
default: true,
},
requiredRules: {
type: Boolean,
default: true,
},
searchOptions: {
type: Object,
default: () => {
return {};
},
},
treeProps: {
type: Object,
default: () => {
return {};
}
},
// table key 字段设置顺序后需更新该值
isUpdate: {
type: Boolean,
default: () => {
return false
}
},
rowKey:{
type: String,
default: 'id',
},
isShowIndex: {
type: Boolean,
default: false,
},
cellStyle: {
type: Function,
default: () => {
return Function;
}
},
// 已app-main高度为100% 需要减掉的高度
setUTableHeight: {
type: Number,
default: () => {
return 280;
}
}
},
data() {
return {
dropCol: null,
selectLoading: false,
random: '',
uTableHeight:null,//表格撑开高度
};
},
computed: {
selectOptions() {
return (val) => {
if (val) {
let options = this.$staticOptions[val];
if (options) {
return options();
} else {
return [];
}
} else {
return false;
}
};
},
TableSize(){
return this.tableColumnsFilter()
}
},
watch: {
tableData: {
handler(val, oldVal) {
this.$nextTick(() => {
if (this.$refs.multipleTable && this.$refs.multipleTable.doLayout) {
this.$refs.multipleTable.doLayout()
}
});
},
immediate: false,
},
tableColumns: {
handler(val, oldVal) {
this.$nextTick(() => {
if (this.$refs.multipleTable && this.$refs.multipleTable.doLayout) {
this.$refs.multipleTable.doLayout()
}
});
},
immediate: false,
},
setUTableHeight(n,o){
this.setTableHeightHandle(n)
}
},
activated() {
this.$refs.multipleTable.doLayout();
},
mounted() {
this.random = this._uid
this.setTableHeightHandle()
},
methods: {
// 设置表格高度
setTableHeightHandle(height){
let _height = height || this.setUTableHeight
let _app_height = document.getElementsByClassName('app-main')[0].clientHeight
this.uTableHeight = Number(_app_height) - Number(_height)
},
// 获取表格高度 误删 业务当中有用
getTableHeight(){
return this.uTableHeight
},
setItemFixed(item,index){
let _re = false
if(this.firstFixed){
if(index == 0)_re = true
}else{
_re = item.fixed
}
return _re
},
// type=input情况下,框实时校验
itemOnKeyUp(item,value){
if(item.onkeyup){
return item.onkeyup()
}else{
if(value && item.validType){
this.searchData[item.prop]=getMatchRegConformValue(item.validType,value,item.pointNumberFixed)
}
}
},
// 数字类型input框onkeyup最大最小值处理
typeNumberOnkeyup(item,value){
if(value){
let _match = String(value).match(/\d+/)//正整数
this.searchData[item.prop] = _match?_match[0]:_match
}
if(this.searchData[item.prop] > item.max){
this.searchData[item.prop] = item.max
}
if(this.searchData[item.prop] && this.searchData[item.prop] < item.min){
this.searchData[item.prop] = item.min
}
if(item.onkeyup)item.onkeyup()
},
tableColumnsFilter() {
let widthSize = _.cloneDeep(this.tableColumns);
for(let i = 0;i<widthSize.length;i++){
let item = widthSize[i]
if (item.type == "autocomplete" || item.type == "objectAutocomplete") {
item.width = item.width ? item.width: "300px";
} else if (item.type == "input" || item.type == "objectInput") {
if (item.width == '100%') {
item.width = ''
} else {
item.width = item.width ? item.width: "200px";
}
} else if (
item.type == "dateTimeInput" ||
item.type == "objectDateTimeInput"
) {
item.width =item.width ? item.width: "200px";
} else if (item.type == "objectDateTime" || item.type == "dateTime") {
item.width =item.width ? item.width: "200px";
} else if (item.width == '100%') {
item.width = ''
} else {
item.width =item.width ? item.width: "150px";
}
}
return widthSize
},
inputPlaceholder(val, item, type, func) {
if (item.valueType) {
if (type == "focus") {
val.target.placeholder = "请输入" + item.label;
if (val.target.value != "") {
val.target.placeholder = val.target.value;
val.target.value = "";
}
} else if (type == "blur") {
// val.target.value = "0"
val.target.value = val.target.value.toString().replace(/[^\d.]/g,'')
if (val.target.value == "") {
// if (val.target.placeholder.indexOf('请输入') == -1) {
val.target.value = val.target.placeholder;
// }
}
if(item.showProp){
func[item.prop][item.showProp]= Number(val.target.value)
}else{
func[item.prop]= Number(val.target.value)
}
}
}
},
//autocomplete下拉
querySearch(queryString, cb, val, row) {
const { options, optionsValue, optionsLabel } = val;
let func = val.focus;
let data = {
scope: row,
};
if (queryString) {
data.filter = [
{
logic: "And",
column: optionsValue,
action: "Like",
value: queryString,
},
];
}
func(data).then((res) => {
var restaurants = this.searchOptions["options"];
let results = queryString
? restaurants.filter(
this.createFilter(queryString, optionsValue, optionsLabel)
)
: restaurants;
results.forEach((key) => {
if (typeof optionsValue === "string") {
key.value = key[optionsValue] + "----" + key[optionsLabel];
} else {
key.value =
key[optionsValue[0]][optionsValue[1]] +
"----" +
key[optionsLabel];
}
});
// 调用 callback 返回建议列表的数据
cb(results);
});
},
createFilter(queryString, optionsValue, optionsLabel) {
return (restaurant) => {
if (typeof optionsValue === "string") {
restaurant.value =
restaurant[optionsValue] + "----" + restaurant[optionsLabel];
} else {
restaurant.value =
restaurant[optionsValue[0]][optionsValue[1]] +
"----" +
restaurant[optionsLabel];
}
return (
restaurant.value.toLowerCase().indexOf(queryString.toLowerCase()) !=
-1
);
};
},
handleSelect(item, val, scope) {
let data = this.tableData[scope.$index];
if (!val.showProp) {
if (typeof val.optionsValue === "string") {
data[val.prop] = item[val.optionsValue];
} else {
data[val.prop] = item[val.optionsValue[0]][val.optionsValue[1]];
}
} else {
if (typeof val.optionsValue === "string") {
data[val.prop][val.showProp] = item[val.optionsValue];
} else {
data[val.prop][val.showProp] =
item[val.optionsValue[0]][val.optionsValue[1]];
}
}
this.$emit("push", item, scope, val);
},
getMaxLength(arr) {
return arr.reduce((acc, item) => {
if (item) {
const calcLen = this.getTexWidth(item);
if (acc < calcLen) {
acc = calcLen;
}
}
return acc;
}, 0);
},
getTexWidth(str) {
let width = 0;
const html = document.createElement("span");
html.innerText = str;
html.className = "getTextWidth";
document.querySelector("body").appendChild(html);
width = document.querySelector(".getTextWidth").offsetWidth;
document.querySelector(".getTextWidth").remove();
return width;
},
flexColumnWidth(label, prop) {
const arr = this.tableData.map((x) => {
if (typeof prop !== "string") {
return x[prop[0]][prop[1]];
} else {
return x[prop];
}
});
arr.push(label);
return this.getMaxLength(arr) + 60 + "px";
},
//排序
sortChange(data) {
this.$emit("sortChange", data);
},
//点击selection框
handleSelectionChange(val) {
this.$emit("handleSelectionChange", val);
},
//点击name提交emit打开编辑页面
inlineDialog(row) {
this.$emit("inlineDialog", row);
},
//点击按钮打开自定义弹窗
buttonClick(row, index, label) {
this.$emit("buttonClick", row, index, label);
},
//点击table操作列按钮
buttonOperationClick(row, label) {
this.$emit("buttonOperationClick", row, label);
},
},
};
</script>
<style lang="scss" scoped>
::v-deep .uTableHeader th{
background: #f6f7fb !important;
border: none !important;
&:last-child{
background: unset !important;
}
}
::v-deep .el-form-item__error{
position: relative;
}
::v-deep .el-table__fixed {
display: block-inline !important;
height: auto !important;
bottom: 13px !important;
.el-table__fixed-header-wrapper {
z-index: auto !important;
}
.el-table__fixed-body-wrapper {
z-index: auto !important;
}
}
::v-deep .el-table__fixed-right {
display: block-inline !important;
height: auto !important;
bottom: 13px !important;
.el-table__fixed-header-wrapper {
z-index: auto !important;
}
.el-table__fixed-body-wrapper {
z-index: auto !important;
}
}
::v-deep .el-table__fixed::before,
.el-table__fixed-right::before {
z-index: auto !important;
}
.buttonOperation-btn{
padding: 0;
}
.spamHover {
color: #409eff;
cursor: pointer;
}
.spamHover:hover {
border-bottom: 1px solid #409eff;
color: blue;
}
span {
white-space: pre;
}
::v-deep .el-select {
.el-input__inner {
padding: 0 30px 0 15px;
}
.el-input__prefix {
width: 100% !important;
left: 0;
.el-button {
position: absolute;
top: 0;
right: 0;
}
}
}
.u-table::before {
height: 0px;
}
</style>