<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; }, }, // 需映射源数据 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() { // const { value, multiple } = this.$props; // return multiple ? "" : value; // }, 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.key); }, }, watch: { "$props.value": { handler: function (newProp) { if (!newProp) this.lastSelectData = []; }, immediate: true, }, }, methods: { // emitChange(prop) { const { type, source, multiple } = this.$props; this.$emit("change", multiple ? prop : prop[0], type, source); }, // open dialog async open() { 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; 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), }; 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.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() { if (!this.$props.multiple) { this.innerValue = ""; } }, }, created() { }, mounted() {}, destroyed() {}, }; </script> <template> <div class="popover-select"> <el-input v-model="innerValue" :size="size" :disabled="disabled" :readonly="readonly" :clearable="clearable" :placeholder="placeholder" @clear="handleClear" > <el-button :disabled="disabled" slot="append" icon="el-icon-search" @click="open" ></el-button> </el-input> <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 v-model="model.search" @change="useQuery" @keydown.enter="useQuery" > </el-input> </el-form-item> <el-form-item> <el-button icon="el-icon-refresh" @click="useReset"></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="(column, index) in TableColumnTemp" :key="index" :prop="column.key" :label="column.title" :width="column.width" show-overflow-tooltip > <template slot-scope="scope"> <dr-computed-input v-if="column.type === 'ComputedInput'" v-model="scope.row[column.key]" :source="scope.row" :computed="column.computed" :placeholder="column.placeholder" style="width: 100%" ></dr-computed-input> <span v-else> {{ scope.row[column.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="useCancel(lastSelectData)"> 取 消 </el-button> <el-button :size="size" @click="useConfirm(selectData)"> 确 定 </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></style>