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.
 
 
 
 
 
 

762 lines
23 KiB

<template>
<!-- <div> -->
<el-table
:id="_uid"
v-loading="tableLoading"
element-loading-text="拼命加载中..."
@sort-change="sortChange"
@selection-change="handleSelectionChange"
ref="multipleTable"
:data="tableData"
height="85%"
row-key="id"
stripe
border
style="width: 100%"
:tree-props="treeProps"
:cell-style="cellStyle"
>
<el-table-column v-if="selectionTable" fixed="left" type="selection" />
<el-table-column v-if="isShowIndex" type="index" fixed="left" label="序号" width="50" />
<el-table-column
v-for="(item, index) in TableSize"
:key="index"
:prop="item.showProp ? item.prop + '.' + item.showProp : item.prop"
:sortable="item.sortable"
:fixed="item.fixed"
:show-overflow-tooltip="true"
:width="item.width"
align="center"
>
<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'" >
<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>
</el-form-item>
<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-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>
</el-table-column>
<slot></slot>
</el-table>
<!-- <pre style="text-align: left">
{{ tableColumns }}
</pre>
<hr />
<pre style="text-align: left">
{{ tableData }}
</pre> -->
<!-- </div> -->
</template>
<script>
import Sortable from "sortablejs";
import { formatTimeStrToStr } from "@/utils/formatTime";
import { getMatchRegConformValue } from "@/utils/index"
import _ from "lodash";
export default {
name: "currenTable",
filters: {
formatDate(time) {
if (time == null) {
return '-'
}
return formatTimeStrToStr(time)
},
},
props: {
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 {};
}
},
isShowIndex: {
type: Boolean,
default: false,
},
cellStyle: {
type: Function,
default: () => {
return Function;
}
}
},
data() {
return {
dropCol: null,
selectLoading: false,
// TableSize: [],
random: ''
};
},
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(() => {
this.$refs.multipleTable.doLayout();
// this.$forceUpdate()
});
},
immediate: false,
}
},
activated() {
this.$refs.multipleTable.doLayout();
},
created() {
},
// beforeUpdate () {
// this.$nextTick(() => {
// this.$refs.multipleTable.doLayout()
// })
// },
mounted() {
// this.tableColumnsFilter()
this.random = this._uid
// this.rowDrop()
// this.columnDrop();
// this.tableColumns.forEach(item => {
// if (item.focus) {
// item.focus()
// }
// })
},
methods: {
// 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";
}
}
// this.TableSize = widthSize;
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)
}
// item.valueType
// ? (this.searchData[item.prop] = item.valueType(
// this.searchData[item.prop]
// ))
// : () => {
// return;
// }
}
}
},
// handeleInput (et, item) {
// const { optionsValue } = item
// let func = item.focus
// let filter = {
// logic: "And",
// column: optionsValue,
// action: "Like",
// value: et
// }
// debounce(func(filter), 2000,true)
// },
//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,
},
// {
// logic: "Or",
// column: optionsLabel,
// 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);
},
// selectFocus (val, item) {
// this.selectLoading = true;
// let func = item.focus
// func({}).then(res => {
// this.selectLoading = false;
// })
// },
// dataFilter (query, item, row) {
// const { options, optionsValue, optionsLabel } = item
// let func = item.focus
// let data = {
// scope: row
// }
// this.selectLoading = true;
// if (query) {
// data.filter = {
// logic: "And",
// column: optionsLabel,
// action: "Like",
// value: query
// }
// }
// setTimeout(() => {
// func(data).then(res => {
// this.selectLoading = false;
// })
// }, 200);
// },
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);
},
rowDrop() {
const tbody = this.$refs.multipleTable.$el.querySelector(
".el-table__body-wrapper tbody"
);
const _this = this;
Sortable.create(tbody, {
onEnd({ newIndex, oldIndex }) {
const currRow = _this.tableData.splice(oldIndex, 1)[0];
_this.tableData.splice(newIndex, 0, currRow);
},
});
},
//列拖拽
columnDrop() {
const wrapperTr = this.$refs.multipleTable.$el.querySelector(
".el-table__header-wrapper tr"
);
let bomIndex = this.selectionTable ? 1 : 0;
this.sortable = Sortable.create(wrapperTr, {
animation: 180,
delay: 0,
onEnd: (evt) => {
const oldItem = this.TableSize[evt.oldIndex - bomIndex];
this.TableSize.splice(evt.oldIndex - bomIndex, 1);
this.TableSize.splice(evt.newIndex - bomIndex, 0, oldItem);
},
});
},
},
};
</script>
<style lang="scss" scoped>
::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::before,
.el-table__fixed-right::before {
z-index: auto !important;
}
.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;
}
}
}
</style>