|
|
@@ -0,0 +1,429 @@
|
|
|
+<template>
|
|
|
+ <el-table-column
|
|
|
+ :prop="itemCol.prop"
|
|
|
+ :show-overflow-tooltip="itemCol.tooltip"
|
|
|
+ :align="handleAlign(itemCol)"
|
|
|
+ :label="itemCol.label"
|
|
|
+ :fixed="itemCol.fixed ? itemCol.fixed : false"
|
|
|
+ :width="itemCol.width"
|
|
|
+ :formatter="itemCol.formatter"
|
|
|
+ :min-width="itemCol.minWidth"
|
|
|
+ >
|
|
|
+ <!-- 单列中嵌套多列数据 -->
|
|
|
+ <template v-if="itemCol.type === 'innerColumn' && itemCol.children && itemCol.children.length">
|
|
|
+ <TableColumn
|
|
|
+ v-for="(innerItem, index) in itemCol.children"
|
|
|
+ :key="index"
|
|
|
+ :align="innerItem && innerItem.align"
|
|
|
+ :itemCol="innerItem">
|
|
|
+ <!-- 传递插槽 -->
|
|
|
+ <template v-for="(slot, name) in $scopedSlots" :slot="name" slot-scope="slotScope">
|
|
|
+ {{slot}}
|
|
|
+ <slot :name="name" v-bind="slotScope"></slot>
|
|
|
+ </template>
|
|
|
+ </TableColumn>
|
|
|
+ </template>
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <!-- 操作列 -->
|
|
|
+ <div v-if="itemCol.prop == 'operation'">
|
|
|
+ <template v-if="!itemCol.type">
|
|
|
+ <span v-for="oper in itemCol.children" :key="oper.key">
|
|
|
+ <el-button
|
|
|
+ v-if="!oper.popover && scope.row[oper.key] != 'hide' && !oper.hide"
|
|
|
+ class="btn-item"
|
|
|
+ :class="{ 'danger': oper.key === 'delete'}"
|
|
|
+ type="text"
|
|
|
+ size="small"
|
|
|
+ @click="operClick(scope, oper.click)"
|
|
|
+ >
|
|
|
+ {{ oper.name }}
|
|
|
+ </el-button>
|
|
|
+ <el-button
|
|
|
+ v-if="scope.row[oper.key] == 'hide' || oper.hide"
|
|
|
+ class="btn-item"
|
|
|
+ type="text"
|
|
|
+ size="small"
|
|
|
+ >
|
|
|
+ </el-button>
|
|
|
+ <el-popover
|
|
|
+ v-if="
|
|
|
+ oper.popover &&
|
|
|
+ scope.row[oper.key] != 'hide' &&
|
|
|
+ oper.hide !== 'hide'
|
|
|
+ "
|
|
|
+ placement="top"
|
|
|
+ width="160"
|
|
|
+ v-model="oper.visible"
|
|
|
+ >
|
|
|
+ <p>{{ oper.content }}</p>
|
|
|
+ <div style="text-align: right; margin: 0">
|
|
|
+ <el-button size="mini" type="text" @click="oper.visible = false">取消</el-button>
|
|
|
+ <el-button type="primary" size="mini" @click="operClick(scope, oper.click); oper.visible = false">确定</el-button>
|
|
|
+ </div>
|
|
|
+ <el-button
|
|
|
+ slot="reference"
|
|
|
+ class="btn-item"
|
|
|
+ type="text"
|
|
|
+ :class="{ 'danger': oper.key === 'delete' || oper.key === 'obsolete' }"
|
|
|
+ size="small"
|
|
|
+ >{{ oper.name }}</el-button
|
|
|
+ >
|
|
|
+ </el-popover>
|
|
|
+ </span>
|
|
|
+ </template>
|
|
|
+ <template v-if="itemCol.type == 'custom'">
|
|
|
+ <slot name="operation" v-bind="scope.row"></slot>
|
|
|
+ </template>
|
|
|
+ </div>
|
|
|
+ <!-- 序号列 -->
|
|
|
+ <div v-else-if="itemCol.prop == 'seq'">
|
|
|
+ <span>
|
|
|
+ {{itemCol.getIndex ? itemCol.getIndex(scope.$index) : scope.$index + 1 }}
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ <!-- 小图预览 -->
|
|
|
+ <div v-else-if="itemCol.type == 'imagePreview'">
|
|
|
+ <el-image
|
|
|
+ style="width: 50px; height: 50px"
|
|
|
+ :src="scope.row[itemCol.prop]"
|
|
|
+ @click="onPreview(scope.row, itemCol)"
|
|
|
+ v-if="scope.row[itemCol.prop]"
|
|
|
+ fit="cover"
|
|
|
+ />
|
|
|
+ <span v-else>--</span>
|
|
|
+ </div>
|
|
|
+ <!-- 字段合并 -->
|
|
|
+ <div v-else-if="itemCol.type == 'merge'">
|
|
|
+ <span>{{scope.row[itemCol.prop.split(',')[0]] || '--'}}{{scope.row[itemCol.prop.split(',')[1]]}}</span>
|
|
|
+ </div>
|
|
|
+ <!-- 表格可编辑列 -->
|
|
|
+ <div v-else-if="itemCol.type == 'editItem'">
|
|
|
+ <el-input
|
|
|
+ @change="editItemChange(scope.row, itemCol)"
|
|
|
+ v-if="itemCol.tag == 'input'"
|
|
|
+ v-model="scope.row[itemCol.prop]"
|
|
|
+ :disabled="isDisabled"
|
|
|
+ placeholder="请输入"
|
|
|
+ clearable
|
|
|
+ size="small"
|
|
|
+ />
|
|
|
+ <el-input-number
|
|
|
+ @change="editItemNumChange(scope.row, itemCol)"
|
|
|
+ v-if="itemCol.tag == 'inputNumber'"
|
|
|
+ v-model="scope.row[itemCol.prop]"
|
|
|
+ :disabled="isDisabled"
|
|
|
+ placeholder="请输入"
|
|
|
+ size="small"
|
|
|
+ :precision="itemCol.precision"
|
|
|
+ :step="itemCol.step"
|
|
|
+ clearable
|
|
|
+ />
|
|
|
+ <el-select v-if="itemCol.tag == 'select'" v-model="scope.row[itemCol.prop]" :disabled="isDisabled" clearable filterable placeholder="" size="small">
|
|
|
+ <el-option v-for="(ele, idx) in itemCol.oprion" :key="idx" :label="ele[itemCol.optionLabel]" :value="ele[itemCol.optionValue]" />
|
|
|
+ </el-select>
|
|
|
+ </div>
|
|
|
+ <!-- 链接跳转 -->
|
|
|
+ <div v-else-if="itemCol.type == 'link'">
|
|
|
+ <el-button
|
|
|
+ type="text"
|
|
|
+ size="small"
|
|
|
+ class="linkBtn"
|
|
|
+ v-if="!scope.row['disabled'] && scope.row[itemCol.prop] !== '无'"
|
|
|
+ @click="operClick(scope, itemCol.click)"
|
|
|
+ >
|
|
|
+ <!-- 除0外,其他空值(null、undefined)转为'--'-->
|
|
|
+ {{
|
|
|
+ scope.row[itemCol.prop] === ""
|
|
|
+ ? "--"
|
|
|
+ : (scope.row[itemCol.prop] !== null && scope.row[itemCol.prop] !== undefined) ? scope.row[itemCol.prop] : "--"
|
|
|
+ }}
|
|
|
+ </el-button>
|
|
|
+ <span class="text-disable linkBtn" v-else>{{
|
|
|
+ scope.row[itemCol.prop] === ""
|
|
|
+ ? "--"
|
|
|
+ : (scope.row[itemCol.prop] !== null && scope.row[itemCol.prop] !== undefined) ? scope.row[itemCol.prop] : "--"
|
|
|
+ }}</span>
|
|
|
+ </div>
|
|
|
+ <!-- 单选/多选 -->
|
|
|
+ <div v-else-if="itemCol.type == 'choice'">
|
|
|
+ <div v-if="scope.row[itemCol.prop]">
|
|
|
+ <div
|
|
|
+ v-if="
|
|
|
+ scope.row[itemCol.isRadioChecked] == '0' ||
|
|
|
+ (scope.row[itemCol.prop] && scope.row[itemCol.prop][0] && scope.row[itemCol.prop][0][itemCol.isRadioChecked] == '0')
|
|
|
+ "
|
|
|
+ >
|
|
|
+ <el-radio-group
|
|
|
+ :value="scope.row[itemCol.model].join()"
|
|
|
+ class="ml-4"
|
|
|
+ >
|
|
|
+ <el-radio
|
|
|
+ v-for="radioItem in scope.row[itemCol.prop]"
|
|
|
+ :label="radioItem.argumentsCode"
|
|
|
+ size="large"
|
|
|
+ :key="radioItem.argumentsName"
|
|
|
+ >{{ radioItem.argumentsName }}</el-radio
|
|
|
+ >
|
|
|
+ </el-radio-group>
|
|
|
+ </div>
|
|
|
+ <div v-else>
|
|
|
+ <el-checkbox-group :value="scope.row[itemCol.model]">
|
|
|
+ <el-checkbox
|
|
|
+ v-for="checkboxItem in scope.row[itemCol.prop]"
|
|
|
+ :label="checkboxItem.argumentsCode"
|
|
|
+ size="large"
|
|
|
+ :key="checkboxItem.argumentsCode"
|
|
|
+ >{{ checkboxItem.argumentsName }}</el-checkbox
|
|
|
+ >
|
|
|
+ </el-checkbox-group>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <!-- 需要遍历查找 -->
|
|
|
+ <div v-else-if="itemCol.type == 'find'">
|
|
|
+ <el-tooltip
|
|
|
+ v-if="Boolean(scope.row[itemCol.customTip])"
|
|
|
+ effect="dark"
|
|
|
+ :content="scope.row[itemCol.customTip]"
|
|
|
+ placement="top"
|
|
|
+ >
|
|
|
+ <span>{{
|
|
|
+ toLabel(
|
|
|
+ itemCol.option,
|
|
|
+ scope.row[itemCol.prop],
|
|
|
+ itemCol.optionValue,
|
|
|
+ itemCol.optionLabel,
|
|
|
+ itemCol.isNum
|
|
|
+ )
|
|
|
+ }}</span>
|
|
|
+ </el-tooltip>
|
|
|
+ <span v-else>{{
|
|
|
+ toLabel(
|
|
|
+ itemCol.option,
|
|
|
+ scope.row[itemCol.prop],
|
|
|
+ itemCol.optionValue,
|
|
|
+ itemCol.optionLabel,
|
|
|
+ itemCol.isNum
|
|
|
+ )
|
|
|
+ }}</span>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div v-else-if="itemCol.type == 'tooltips'">
|
|
|
+ <el-tooltip placement="top">
|
|
|
+ <template slot="content" v-if="!itemCol.customTip">
|
|
|
+ <p style="max-width: 15vw">
|
|
|
+ {{ scope.row[itemCol.prop] }}
|
|
|
+ </p>
|
|
|
+ </template>
|
|
|
+ <template slot="content" v-if="itemCol.customTip" >
|
|
|
+ <p style="max-width: 15vw">
|
|
|
+ {{ scope.row[itemCol.customTip] }}
|
|
|
+ </p>
|
|
|
+ </template>
|
|
|
+ <div
|
|
|
+ class="table-ellipsis"
|
|
|
+ :style="`color:${itemCol.color}`"
|
|
|
+ style="
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ white-space: nowrap;
|
|
|
+ overflow: hidden;
|
|
|
+ "
|
|
|
+ >
|
|
|
+ {{ scope.row[itemCol.prop] }}
|
|
|
+ </div>
|
|
|
+ </el-tooltip>
|
|
|
+ </div>
|
|
|
+ <!-- 转化数据字典,支持显示多选结果 -->
|
|
|
+ <span v-else-if="itemCol.type == 'dict2Name'">
|
|
|
+ <template v-if="scope.row[itemCol.prop]">
|
|
|
+ {{ parseDictValue2Name(scope.row[itemCol.prop], itemCol.dictList, itemCol) }}
|
|
|
+ </template>
|
|
|
+ <template v-else>--</template>
|
|
|
+ </span>
|
|
|
+ <!-- 自定义 -->
|
|
|
+ <span v-else-if="itemCol.type == 'diy'">
|
|
|
+ <slot :name="itemCol.prop" v-bind="scope.row"></slot>
|
|
|
+ <span v-if="!$scopedSlots[itemCol.prop]">{{ scope.row[itemCol.prop] === '' ? '--' : scope.row[itemCol.prop] }}</span>
|
|
|
+ </span>
|
|
|
+ <span :style="`color:${itemCol.color}`" v-else>
|
|
|
+ {{ scope.row[itemCol.prop] === '' ? '--' : scope.row[itemCol.prop] }}
|
|
|
+ </span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+import TableColumn from "./TableColumn.vue";
|
|
|
+
|
|
|
+export default {
|
|
|
+ name: "TableColumn",
|
|
|
+ components: {
|
|
|
+ TableColumn,
|
|
|
+ },
|
|
|
+ props: {
|
|
|
+ // 编辑时可传
|
|
|
+ isDisabled: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false,
|
|
|
+ },
|
|
|
+ itemCol: {
|
|
|
+ type: Object,
|
|
|
+ default: function() {
|
|
|
+ return {};
|
|
|
+ },
|
|
|
+ },
|
|
|
+ selection: {
|
|
|
+ type: Boolean,
|
|
|
+ default: true,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ showViewer: false,
|
|
|
+ };
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ customSlots() {
|
|
|
+ return {
|
|
|
+ ...this.$slots,
|
|
|
+ };
|
|
|
+ },
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ toLabel(
|
|
|
+ option = [],
|
|
|
+ val,
|
|
|
+ value = "value",
|
|
|
+ label = "label",
|
|
|
+ isNum = false
|
|
|
+ ) {
|
|
|
+ // 该代码以后删掉
|
|
|
+ if (isNum) {
|
|
|
+ val = Number(val);
|
|
|
+ }
|
|
|
+ let labelName = option.find((item) => item[value] == val);
|
|
|
+ return labelName ? labelName[label] : "--";
|
|
|
+ },
|
|
|
+ handleSelection(row) {
|
|
|
+ return !row.selectionDisabled;
|
|
|
+ },
|
|
|
+ handleAlign(item) {
|
|
|
+ if (item.align == "center") {
|
|
|
+ return "center";
|
|
|
+ }
|
|
|
+ if (item.type == "innerColumn") {
|
|
|
+ return "center";
|
|
|
+ }
|
|
|
+ if (item.prop == "seq") {
|
|
|
+ return "center";
|
|
|
+ } else {
|
|
|
+ return "left";
|
|
|
+ }
|
|
|
+ // return item.align
|
|
|
+ },
|
|
|
+ operClick(scope, funName) {
|
|
|
+ if (typeof funName === 'function') {
|
|
|
+ funName(scope.row, scope.column, scope.$index);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 根据字典中的value转为name
|
|
|
+ parseDictValue2Name(val, list, item) {
|
|
|
+ if (!item || !item.multiple) {
|
|
|
+ let name = '';
|
|
|
+ list.map((e) => {
|
|
|
+ if (e.value == val) {
|
|
|
+ name = e.label;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ return name || val || '--';
|
|
|
+ } else {
|
|
|
+ let str = '';
|
|
|
+ let arr = val.split(',');
|
|
|
+ list.map((e) => {
|
|
|
+ if (arr.includes(e.value)) {
|
|
|
+ str += e.label + '、';
|
|
|
+ }
|
|
|
+ });
|
|
|
+ return str ? str.slice(0, str.length - 1) : '--';
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 图片展示弹框显示
|
|
|
+ onPreview(row, itemCol) {
|
|
|
+ // 判断该图片展示是否需要接口查询 (处理字段为base64的情况)
|
|
|
+ if (itemCol && itemCol.imgQuery) {
|
|
|
+ let axios = itemCol.imgQuery.queryFn;
|
|
|
+ if (axios) {
|
|
|
+ axios({
|
|
|
+ id: row[itemCol.imgQuery.primaryKey],
|
|
|
+ }).then((res) => {
|
|
|
+ if (res.code == 200) {
|
|
|
+ if (res.data[[itemCol.prop]].indexOf("/file") === -1) {
|
|
|
+ // 使用base64时,拼接标识处理
|
|
|
+ this.$emit("imgPreview", [
|
|
|
+ `data:image/png;base64, ${res.data[[itemCol.prop]]}`,
|
|
|
+ ]);
|
|
|
+ } else {
|
|
|
+ // 使用链接时直接反回
|
|
|
+ this.$emit("imgPreview", [res.data[itemCol.prop]]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ this.$emit("imgPreview", row[itemCol.prop] ? row[itemCol.prop].split(",") : []);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ editItemChange(val, itemCol) {
|
|
|
+ this.$emit("editItemChange", val, itemCol);
|
|
|
+ },
|
|
|
+ editItemNumChange(val, itemCol) {
|
|
|
+ this.$emit("editItemNumChange", val, itemCol);
|
|
|
+ },
|
|
|
+ },
|
|
|
+};
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+.btn-item {
|
|
|
+ margin: 0 10px;
|
|
|
+}
|
|
|
+.btn-item:nth-child(1) {
|
|
|
+ margin-left: 0;
|
|
|
+}
|
|
|
+// 2.1.9版本之后新增此样式
|
|
|
+.btn-item.el-button--small:nth-child(1) {
|
|
|
+ padding-left: 0 !important;
|
|
|
+}
|
|
|
+.danger {
|
|
|
+ color: #f56455 !important;
|
|
|
+}
|
|
|
+
|
|
|
+.linkBtn {
|
|
|
+ font-size: 14px;
|
|
|
+ white-space: normal;
|
|
|
+ line-height: 16px;
|
|
|
+ text-align: left;
|
|
|
+ height: auto;
|
|
|
+}
|
|
|
+
|
|
|
+// ::v-deep(.linkBtn) {
|
|
|
+// padding: 0;
|
|
|
+// >span {
|
|
|
+// overflow: hidden;
|
|
|
+// text-overflow: ellipsis;
|
|
|
+// white-space: nowrap;
|
|
|
+// width: 80px;
|
|
|
+// display: block;
|
|
|
+// }
|
|
|
+// }
|
|
|
+
|
|
|
+.text-disable {
|
|
|
+ // padding-left: 12px;
|
|
|
+}
|
|
|
+
|
|
|
+.el-input,.el-input-number,.el-select{
|
|
|
+ width: 100%;
|
|
|
+ border: 1px solid #dedede;
|
|
|
+}
|
|
|
+</style>
|
|
|
+
|