|
@@ -1,4 +1,5 @@
|
|
|
<script>
|
|
|
+import { REFER } from "./api/index";
|
|
|
export default {
|
|
|
name: "PopoverTreeSelect",
|
|
|
props: {
|
|
@@ -20,16 +21,12 @@ export default {
|
|
|
// 作为 value 唯一标识的键名,绑定值
|
|
|
valueKey: {
|
|
|
type: String,
|
|
|
- default: "name",
|
|
|
- },
|
|
|
- // 作为 value 唯一标识的键名,显示值
|
|
|
- showKey: {
|
|
|
- type: String,
|
|
|
+ default: "code",
|
|
|
},
|
|
|
// 默认查询参数
|
|
|
queryParams: {
|
|
|
- type: Object,
|
|
|
- default: () => ({}),
|
|
|
+ type: Function,
|
|
|
+ default: () => {},
|
|
|
},
|
|
|
// 组件大小
|
|
|
size: {
|
|
@@ -66,99 +63,226 @@ export default {
|
|
|
// 参照内外映射
|
|
|
dataMapping: Object,
|
|
|
},
|
|
|
- components: {
|
|
|
- TableDialog: () => import("./components/index.vue"),
|
|
|
- },
|
|
|
+ components: {},
|
|
|
data() {
|
|
|
return {
|
|
|
- // popover宽度
|
|
|
- width: "",
|
|
|
- // 选中data
|
|
|
+ width: "50%",
|
|
|
+ visible: false,
|
|
|
+ loading: false,
|
|
|
+ params: {
|
|
|
+ search: "",
|
|
|
+ isPage: true,
|
|
|
+ },
|
|
|
data: [],
|
|
|
+ selectData: [],
|
|
|
+ defaultProps: {
|
|
|
+ label: "name",
|
|
|
+ children: "children",
|
|
|
+ },
|
|
|
};
|
|
|
},
|
|
|
computed: {
|
|
|
- showValue() {
|
|
|
- const { showKey, valueKey } = this.$props;
|
|
|
- return this.data.length === 1 ? this.data[0][showKey || valueKey] : "";
|
|
|
+ innerValue() {
|
|
|
+ const { value, multiple } = this.$props;
|
|
|
+ return multiple ? "" : value;
|
|
|
+ },
|
|
|
+ TableColumnTemp() {
|
|
|
+ const { type } = this.$props;
|
|
|
+ const documents = require(`./components/${type}`).default;
|
|
|
+ return documents.filter((document) => document.key);
|
|
|
},
|
|
|
},
|
|
|
watch: {
|
|
|
"$props.value": {
|
|
|
- handler: function (newProp, oldProp) {
|
|
|
- if (!newProp) {
|
|
|
- this.data = [];
|
|
|
- }
|
|
|
+ handler: function (newProp) {
|
|
|
+ if (!newProp) this.selectData = [];
|
|
|
},
|
|
|
immediate: true,
|
|
|
},
|
|
|
},
|
|
|
methods: {
|
|
|
- // 打开弹窗
|
|
|
- handleAsyncOpenDialog() {
|
|
|
- this.$nextTick(() => {
|
|
|
- const { setVisible } = this.$refs.TableDialog;
|
|
|
- setVisible(true);
|
|
|
- });
|
|
|
- },
|
|
|
- // 新增操作
|
|
|
- handleAdd(prop) {
|
|
|
- this.data = prop;
|
|
|
- this.handleUpdate(this.data);
|
|
|
- },
|
|
|
- // 删除操作
|
|
|
- handleDelete(prop) {
|
|
|
- this.data.splice(prop, 1);
|
|
|
- this.handleUpdate(this.data);
|
|
|
- },
|
|
|
- // 更新操作
|
|
|
- handleUpdate(prop) {
|
|
|
- const { source, multiple, valueKey, dataMapping } = this.$props;
|
|
|
- // 多选
|
|
|
- if (multiple) {
|
|
|
- const updateData = prop.map((item) => item[valueKey]);
|
|
|
- this.$emit("input", updateData);
|
|
|
- }
|
|
|
- // 单选
|
|
|
- if (!multiple) {
|
|
|
- const updateData = prop[0][valueKey];
|
|
|
- this.$emit("input", updateData);
|
|
|
- // 更新映射数据
|
|
|
- for (let key in dataMapping) {
|
|
|
- source[key] = prop[0][dataMapping[key]];
|
|
|
+ // open dialog
|
|
|
+ async open() {
|
|
|
+ this.visible = true;
|
|
|
+ await this.useReset();
|
|
|
+ },
|
|
|
+ // hide dialog
|
|
|
+ async hide() {
|
|
|
+ this.visible = false;
|
|
|
+ },
|
|
|
+ // fetch list
|
|
|
+ async fetchList(prop) {
|
|
|
+ try {
|
|
|
+ this.loading = true;
|
|
|
+ const { code, rows, total } = await REFER(prop);
|
|
|
+ if (code === 200) {
|
|
|
+ this.data = rows;
|
|
|
}
|
|
|
- this.$emit("update:source", source);
|
|
|
+ } catch (err) {
|
|
|
+ // catch
|
|
|
+ console.error(err);
|
|
|
+ } finally {
|
|
|
+ // finally
|
|
|
+ this.loading = false;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // reset list
|
|
|
+ async useReset() {
|
|
|
+ const { type, source, queryParams } = this.$props;
|
|
|
+ this.model = {
|
|
|
+ type,
|
|
|
+ search: "",
|
|
|
+ ...this.model,
|
|
|
+ ...queryParams(source),
|
|
|
+ };
|
|
|
+ await this.fetchList(this.model);
|
|
|
+ },
|
|
|
+ // query list
|
|
|
+ async useQuery() {
|
|
|
+ await this.fetchList(this.model);
|
|
|
+ },
|
|
|
+ // confirm
|
|
|
+ async useConfirm(prop) {
|
|
|
+ const { multiple } = this.$props;
|
|
|
+ await this.hide();
|
|
|
+ await this.useUpdate(multiple ? prop : prop[0]);
|
|
|
+ },
|
|
|
+ // delete tag
|
|
|
+ useDelete(prop) {
|
|
|
+ this.selectData.splice(prop, 1);
|
|
|
+ this.useUpdate(this.selectData);
|
|
|
+ },
|
|
|
+ // update
|
|
|
+ useUpdate(prop) {
|
|
|
+ const { source, multiple, valueKey, dataMapping, type } = this.$props;
|
|
|
+ // update v-model
|
|
|
+ const vModel = multiple
|
|
|
+ ? prop.map((item) => item[valueKey])
|
|
|
+ : prop[valueKey];
|
|
|
+ this.$emit("input", vModel);
|
|
|
+ // update data mapping
|
|
|
+ for (let key in dataMapping) {
|
|
|
+ source[key] = prop[dataMapping[key]];
|
|
|
+ }
|
|
|
+ this.$emit("update:source", source);
|
|
|
+ // emit change
|
|
|
+ this.$emit("change", prop, type, source);
|
|
|
+ },
|
|
|
+ // click select row data
|
|
|
+ handleSelect(data) {
|
|
|
+ this.selectData = [data];
|
|
|
+ },
|
|
|
+ // double click select row data and confirm
|
|
|
+ handleDoubleClickSelect(row) {
|
|
|
+ this.useConfirm([row]);
|
|
|
+ },
|
|
|
+ // multiple select row data
|
|
|
+ handleMultipleSelect(prop, data) {
|
|
|
+ if (prop) {
|
|
|
+ this.selectData.push(data);
|
|
|
+ } else {
|
|
|
+ const { code } = data;
|
|
|
+ const index = this.selectData.findIndex((item) => item.code === code);
|
|
|
+ this.selectData.splice(index, 1);
|
|
|
}
|
|
|
- //
|
|
|
- this.$emit("change", prop, source);
|
|
|
},
|
|
|
},
|
|
|
- created() {
|
|
|
- this.$nextTick(() => {
|
|
|
- const { clientWidth } = this.$refs.PopoverTreeSelect;
|
|
|
- this.width = clientWidth;
|
|
|
- });
|
|
|
- },
|
|
|
+ created() {},
|
|
|
mounted() {},
|
|
|
destroyed() {},
|
|
|
};
|
|
|
</script>
|
|
|
<template>
|
|
|
- <div ref="PopoverTreeSelect" style="position: relative">
|
|
|
+ <div class="popover-tree-select">
|
|
|
<el-input
|
|
|
- v-model="showValue"
|
|
|
+ v-model="innerValue"
|
|
|
:size="size"
|
|
|
:disabled="disabled"
|
|
|
+ :readonly="readonly"
|
|
|
:clearable="clearable"
|
|
|
:placeholder="placeholder"
|
|
|
- readonly
|
|
|
- style="width: 100%; cursor: pointer"
|
|
|
- @click.native.stop="handleAsyncOpenDialog"
|
|
|
>
|
|
|
- <template #suffix>
|
|
|
- <el-icon class="el-icon-more"></el-icon>
|
|
|
- </template>
|
|
|
+ <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
|
|
|
+ @close="hide"
|
|
|
+ >
|
|
|
+ <el-form
|
|
|
+ v-loading="loading"
|
|
|
+ :size="size"
|
|
|
+ :inline="true"
|
|
|
+ :model="params"
|
|
|
+ @submit.native.prevent
|
|
|
+ >
|
|
|
+ <el-form-item prop="search">
|
|
|
+ <el-input
|
|
|
+ v-model="params.search"
|
|
|
+ @keydown.enter="useQuery"
|
|
|
+ @change="useQuery"
|
|
|
+ >
|
|
|
+ </el-input>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item>
|
|
|
+ <el-button icon="el-icon-refresh" @click="useReset"></el-button>
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ <el-tree
|
|
|
+ v-if="multiple"
|
|
|
+ :data="data"
|
|
|
+ :props="defaultProps"
|
|
|
+ accordion
|
|
|
+ node-key="id"
|
|
|
+ >
|
|
|
+ <div slot-scope="{ node, data }">
|
|
|
+ <el-checkbox
|
|
|
+ v-model="data.checked"
|
|
|
+ @click.native.stop
|
|
|
+ @change="handleMultipleSelect($event, data)"
|
|
|
+ style="margin: 0 5px 0 0"
|
|
|
+ >
|
|
|
+ </el-checkbox>
|
|
|
+ <span> {{ data.name }}</span>
|
|
|
+ </div>
|
|
|
+ </el-tree>
|
|
|
+ <el-radio-group v-else v-model="radio" style="width: 100%">
|
|
|
+ <el-tree
|
|
|
+ v-loading="loading"
|
|
|
+ :data="data"
|
|
|
+ :props="defaultProps"
|
|
|
+ accordion
|
|
|
+ node-key="id"
|
|
|
+ >
|
|
|
+ <div slot-scope="{ node, data }">
|
|
|
+ <el-radio
|
|
|
+ :label="data.code"
|
|
|
+ @click.native.stop="handleSelect(data)"
|
|
|
+ @dblclick.native.stop="handleDoubleClickSelect(data)"
|
|
|
+ style="margin: 0 5px 0 0"
|
|
|
+ >
|
|
|
+ {{ data.name }}
|
|
|
+ </el-radio>
|
|
|
+ </div>
|
|
|
+ </el-tree>
|
|
|
+ </el-radio-group>
|
|
|
+ <div style="margin-top: 20px; text-align: right">
|
|
|
+ <el-button :size="size" @click="visible = false">取 消</el-button>
|
|
|
+ <el-button :size="size" type="primary" @click="useConfirm(selectData)"
|
|
|
+ >确 定</el-button
|
|
|
+ >
|
|
|
+ </div>
|
|
|
+ </el-dialog>
|
|
|
<div
|
|
|
style="
|
|
|
position: absolute;
|
|
@@ -169,7 +293,7 @@ export default {
|
|
|
overflow: hidden;
|
|
|
"
|
|
|
>
|
|
|
- <div v-if="multiple && data.length">
|
|
|
+ <div v-if="multiple && selectData.length">
|
|
|
<el-popover
|
|
|
:offset="-10"
|
|
|
:width="width"
|
|
@@ -180,10 +304,10 @@ export default {
|
|
|
placement="bottom-start"
|
|
|
>
|
|
|
<el-tag slot="reference" :size="size" style="margin-right: 10px">
|
|
|
- + {{ data.length }}
|
|
|
+ + {{ selectData.length }}
|
|
|
</el-tag>
|
|
|
<el-tag
|
|
|
- v-for="(item, index) in data"
|
|
|
+ v-for="(tag, index) in selectData"
|
|
|
:size="size"
|
|
|
hit
|
|
|
closable
|
|
@@ -191,23 +315,15 @@ export default {
|
|
|
display: 'flex',
|
|
|
justifyContent: 'space-between',
|
|
|
alignItems: 'center',
|
|
|
- margin: data.length - 1 === index ? '0' : '0 0 5px 0',
|
|
|
+ margin: selectData.length - 1 === index ? '0' : '0 0 5px 0',
|
|
|
}"
|
|
|
- @close="handleDelete(index)"
|
|
|
+ @close="useDelete(index)"
|
|
|
>
|
|
|
- {{ item.name }}
|
|
|
+ {{ tag.name }}
|
|
|
</el-tag>
|
|
|
</el-popover>
|
|
|
</div>
|
|
|
</div>
|
|
|
- <table-dialog
|
|
|
- ref="TableDialog"
|
|
|
- :type="type"
|
|
|
- :title="title"
|
|
|
- :multiple="multiple"
|
|
|
- :query-params="queryParams"
|
|
|
- @confirm="handleAdd"
|
|
|
- ></table-dialog>
|
|
|
</div>
|
|
|
</template>
|
|
|
<style scoped></style>
|