<script> import { REFER } from "./api/index"; import deepCopy from "@gby/deep-copy"; export default { name: "PopoverSelect", props: { // 参照类型 ,对应后端 type: { type: String, require: true, }, // v-model value: { type: [Array, String], require: true, }, // 参照弹窗标题 title: { type: String, dafault: () => { return "TITEL"; }, }, // 作为 value 唯一标识的键名,绑定值 valueKey: { type: String, dafault: () => { return "code"; }, }, // 默认查询参数 queryParams: { type: Function, default: () => {}, }, // 组件大小 size: { type: String, dafault: () => { return "mini"; }, }, // 提示 placeholder: { type: String, dafault: () => { return ""; }, }, // 是否可读 readonly: { type: Boolean, dafault: () => { return false; }, }, // 是否禁止 disabled: { type: Boolean, dafault: () => { return false; }, }, // 是否清除 clearable: { type: Boolean, dafault: () => { return false; }, }, // 是否多选 multiple: { type: Boolean, dafault: () => { return false; }, }, copy: { type: Boolean, default: () => { return false; }, }, // 需映射源数据 source: Object, // 参照内外映射 dataMapping: Object, }, components: {}, data() { return { width: "50%", page: { pageNum: 1, pageSize: 10, total: 0 }, visible: false, loading: false, model: { search: "", isPage: true, }, data: [], selectData: [], lastSelectData: [], }; }, computed: { innerValue: { get() { const { value, multiple } = this.$props; return multiple ? "" : value; }, set(val) { this.$emit("input", val); }, }, TableColumnTemp() { const { type } = this.$props; const documents = require(`./components/${type}`).default; return documents.filter((document) => document.item.key); }, }, watch: { "$props.value": { handler: function (newProp) { if (!newProp) this.lastSelectData = []; }, immediate: true, }, innerValue: { handler: function (newValue) { if (!newValue) { const { $props: { source, dataMapping }, } = this; for (let key in dataMapping) { source[key] = undefined; } this.$emit("update:source", source); } }, }, }, methods: { // emitChange(prop) { const { type, source, multiple } = this.$props; this.$emit("change", multiple ? prop : prop[0], type, source); }, // open dialog async open() { if (!this.disabled) { this.visible = true; await this.useReset(); } }, // hide dialog async hide() { this.visible = false; }, // fetch list async fetchList(prop, page) { try { this.loading = true; const { pageNum, pageSize } = page; const { code, rows, total } = await REFER(prop, { pageNum, pageSize, }); if (code === 200) { this.data = rows; // 处理新增字段无法映射 let that = this; this.TableColumnTemp.forEach(({ item, attr }) => { that.data = that.data.map((d) => { if (!attr.is && attr.formatter) { d[item.key] = attr.formatter(d); } return d; }); }); this.page.total = total; } } catch (err) { // console.error(err); } finally { this.loading = false; } }, // reset async useReset() { const { type, source, queryParams } = this.$props; this.model = { type, ...this.model, search: "", ...queryParams(source), }; console.log(source, "source"); await this.fetchList(this.model, this.page); }, // query async useQuery() { await this.fetchList(this.model, this.page); }, // cancel useCancel(prop) { if (prop.length) { const { multiple } = this.$props; this.useUpdate(multiple ? prop : prop[0]); } this.hide(); }, // confirm useConfirm(prop) { const { multiple } = this.$props; this.selectData = [...prop]; console.log(this.selectData, "this.selectData"); this.useUpdate(multiple ? prop : prop[0]); this.emitChange(this.selectData); this.lastSelectData = deepCopy(this.selectData); this.hide(); }, // delete useDelete(prop) { this.selectData.splice(prop, 1); this.useUpdate(this.selectData); this.emitChange(this.selectData); this.lastSelectData = deepCopy(this.selectData); }, // update useUpdate(prop) { const { source, multiple, valueKey, dataMapping } = this.$props; // update data mapping if (multiple) { const vModel = prop.map((item) => item[valueKey]); this.$emit("input", vModel); } else { const vModel = prop[valueKey]; this.$emit("input", vModel); for (let key in dataMapping) { source[key] = prop[dataMapping[key]]; } this.$emit("update:source", source); } }, // row click onceClick(prop) { const { multiple } = this.$props; // 单选 if (!multiple) this.$refs.multipleTable.clearSelection(); [prop].forEach((row) => this.$refs.multipleTable.toggleRowSelection(row)); }, // row double click doubleClick(prop) { const { multiple } = this.$props; if (!multiple) this.useConfirm([prop]); }, // selection change selectionChange(prop) { if (prop && prop.length) { this.selectData = prop; } }, handleClear() { const { source, multiple, dataMapping } = this.$props; if (!multiple) { this.innerValue = ""; // for (let key in dataMapping) { // source[key] = ""; // } // this.$emit("update:source", source); } }, async useAutocomplete(prop, cb) { const { type, source, queryParams } = this.$props; if (prop) { this.page.pageSize = 10; this.model = { ...this.model, search: prop, type: type, ...queryParams(source), }; // await this.fetchList(this.model, this.page); await cb(this.data); } else { cb([]); } }, async handleChange() { const { type, source } = this.$props; this.$emit("copyChange", this.innerValue.split(/,|,|\s+/)); }, useBlur() { const { $props: { source, dataMapping, multiple }, } = this; if (!multiple) { for (let key in dataMapping) { if (dataMapping[key] === "id" || dataMapping[key] === "code") { if (!source[key] || source[key] === "") { this.innerValue = ""; } } } } }, handleKeyupDel() { console.log("focus"); const { $props: { source, dataMapping }, } = this; for (let key in dataMapping) { if (dataMapping[key] === "id" || dataMapping[key] === "code") { if (source[key] && source[key] !== "") { source[key] = undefined; } } } }, }, created() {}, mounted() {}, destroyed() {}, }; </script> <template> <div class="popover-select"> <el-input v-if="copy" v-model="innerValue" :size="size" :disabled="disabled" :readonly="readonly" :clearable="clearable" :placeholder="placeholder" @clear="handleClear" @change="handleChange" @keyup.enter.native="handleChange" > <i :size="size" class="el-icon-search" slot="suffix" @click="open"> </i> </el-input> <el-autocomplete v-else clearable v-bind="$attrs" v-model="innerValue" :size="size" :disabled="disabled" :value-key="valueKey" :fetch-suggestions="useAutocomplete" @blur="useBlur" @select="useConfirm([$event])" @keyup.delete.native="handleKeyupDel" style="width: 100%" > <i :size="size" class="el-icon-search" slot="suffix" @click="open"> </i> <template slot-scope="{ item }"> <p style=" text-overflow: ellipsis; overflow: hidden; line-height: 15px; margin: 5px 0; " > {{ item.name }} </p> <p style=" font-size: 12px; color: #b4b4b4; line-height: 15px; margin: 5px 0; " > {{ item.code }} </p> </template> </el-autocomplete> <el-dialog :title="`${title}(${multiple ? '多选' : '单选'})`" :width="width" :visible.sync="visible" :close-on-click-modal="false" :close-on-press-escape="false" append-to-body > <el-form v-loading="loading" :size="size" :inline="true" :model="model" @submit.native.prevent > <el-form-item prop="search"> <el-input size="mini" v-model="model.search" @change="useQuery" @keydown.enter="useQuery" > </el-input> </el-form-item> <el-form-item> <el-button @click="useQuery" size="mini">搜 索</el-button> <el-button icon="el-icon-refresh" @click="useReset" size="mini" ></el-button> </el-form-item> <el-table ref="multipleTable" :data="data" :size="size" height="45vh" highlight-current-row style="width: 100%; margin-bottom: 20px" @row-click="onceClick" @row-dblclick="doubleClick" @selection-change="selectionChange" > <el-table-column v-if="multiple" width="55" type="selection" align="center" > </el-table-column> <el-table-column v-for="({ item, attr }, index) in TableColumnTemp" :key="index" :prop="item.key" :label="item.title" :width="item.width" show-overflow-tooltip > <template slot-scope="scope"> <dr-computed-input v-if="attr.type === 'ComputedInput'" v-model="scope.row[item.key]" :source="scope.row" :formatter="attr.formatter" :placeholder="attr.placeholder" style="width: 100%" ></dr-computed-input> <span v-else> {{ scope.row[item.key] }}</span> </template> </el-table-column> </el-table> <pagination :total="page.total" :page.sync="page.pageNum" :limit.sync="page.pageSize" @pagination="useQuery" /> </el-form> <div style="margin-top: 20px; text-align: right"> <el-button :size="size" @click="useConfirm(selectData)"> 确 定 </el-button> <el-button :size="size" @click="useCancel(lastSelectData)"> 取 消 </el-button> </div> </el-dialog> <div style=" position: absolute; left: 10px; top: 50%; transform: translateY(-50%); padding-right: 30px; overflow: hidden; " > <div v-if="multiple && lastSelectData.length"> <el-popover :offset="-10" :width="width" :visible-arrow="false" title="" content="" trigger="click" placement="bottom-start" > <el-tag slot="reference" :size="size" style="margin-right: 10px"> + {{ lastSelectData.length }} </el-tag> <el-tag v-for="(tag, index) in lastSelectData" :size="size" hit closable :style="{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', margin: lastSelectData.length - 1 === index ? '0' : '0 0 5px 0', }" @close="useDelete(index)" > {{ tag.name }} </el-tag> </el-popover> </div> </div> </div> </template> <style scoped> .popover-select .el-autocomplete { width: inherit; } .popover-select .el-autocomplete .el-icon-search { cursor: pointer; } ::v-deep .el-table--mini .el-table__cell { height: 50px; } </style>