index.vue 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. <script>
  2. export default {
  3. name: "PopoverSelect",
  4. props: {
  5. // 参照类型 ,对应后端
  6. type: {
  7. type: String,
  8. require: true,
  9. },
  10. // v-model
  11. value: {
  12. type: [Array, String],
  13. require: true,
  14. },
  15. // 参照弹窗标题
  16. title: {
  17. type: String,
  18. default: "TITLE",
  19. },
  20. // 作为 value 唯一标识的键名,绑定值
  21. valueKey: {
  22. type: String,
  23. default: "name",
  24. },
  25. // 作为 value 唯一标识的键名,显示值
  26. showKey: {
  27. type: String,
  28. },
  29. showKey: {
  30. type: String,
  31. default: "name",
  32. },
  33. // 默认查询参数
  34. queryParams: {
  35. type: Object,
  36. default: () => ({}),
  37. },
  38. // 组件大小
  39. size: {
  40. type: String,
  41. default: "mini",
  42. },
  43. // 提示
  44. placeholder: {
  45. type: String,
  46. default: "",
  47. },
  48. // 是否可读
  49. readonly: {
  50. type: Boolean,
  51. default: false,
  52. },
  53. // 是否禁止
  54. disabled: {
  55. type: Boolean,
  56. default: false,
  57. },
  58. // 是否清除
  59. clearable: {
  60. type: Boolean,
  61. default: false,
  62. },
  63. // 是否多选
  64. multiple: {
  65. type: Boolean,
  66. default: false,
  67. },
  68. // 需映射源数据
  69. source: Object,
  70. // 参照内外映射
  71. dataMapping: Object,
  72. },
  73. emits: ["hide"],
  74. components: {
  75. TableDialog: () => import("./components/index.vue"),
  76. },
  77. data() {
  78. return {
  79. // popover宽度
  80. width: "",
  81. // 选中data
  82. data: [],
  83. };
  84. },
  85. computed: {
  86. showValue() {
  87. const { showKey, valueKey } = this.$props;
  88. return this.data.length === 1 ? this.data[0][showKey || valueKey] : "";
  89. },
  90. },
  91. watch: {
  92. "$props.value": {
  93. handler: function (newProp, oldProp) {
  94. if (!newProp) {
  95. this.data = [];
  96. }
  97. },
  98. immediate: true,
  99. },
  100. },
  101. methods: {
  102. // 打开弹窗
  103. handleAsyncOpenDialog() {
  104. this.$nextTick(() => {
  105. const { setVisible } = this.$refs.TableDialog;
  106. setVisible(true);
  107. });
  108. },
  109. // 新增操作
  110. handleAdd(prop) {
  111. this.data = prop;
  112. this.handleUpdate(this.data);
  113. },
  114. // 删除操作
  115. handleDelete(prop) {
  116. this.data.splice(prop, 1);
  117. this.handleUpdate(this.data);
  118. },
  119. // 更新操作
  120. handleUpdate(prop) {
  121. const { source, multiple, valueKey, dataMapping } = this.$props;
  122. console.log(this.$props, 'this.$props');
  123. // 多选
  124. if (multiple) {
  125. const updateData = prop.map((item) => item[valueKey]);
  126. this.$emit("input", updateData);
  127. }
  128. // 单选
  129. if (!multiple) {
  130. const updateData = prop[0][valueKey];
  131. this.$emit("input", updateData);
  132. // 更新映射数据
  133. for (let key in dataMapping) {
  134. source[key] = prop[0][dataMapping[key]];
  135. console.log(source[key]);
  136. console.log(prop[0][dataMapping[key]]);
  137. }
  138. console.log("prop", prop, source, this.$props);
  139. this.$emit("update:source", source);
  140. }
  141. //
  142. this.$emit("change", prop, source);
  143. },
  144. },
  145. created() {
  146. this.$nextTick(() => {
  147. const { clientWidth } = this.$refs.PopoverSelect;
  148. this.width = clientWidth;
  149. });
  150. },
  151. mounted() { },
  152. destroyed() { },
  153. };
  154. </script>
  155. <template>
  156. <div ref="PopoverSelect" style="position: relative">
  157. <el-input v-model="showValue" :size="size" :disabled="disabled" :clearable="clearable" :placeholder="placeholder"
  158. readonly style="width: 100%; cursor: pointer" @click.native.stop="handleAsyncOpenDialog">
  159. <template #suffix>
  160. <el-icon class="el-icon-more"></el-icon>
  161. </template>
  162. </el-input>
  163. <div style="
  164. position: absolute;
  165. left: 10px;
  166. top: 50%;
  167. transform: translateY(-50%);
  168. padding-right: 30px;
  169. overflow: hidden;
  170. ">
  171. <div v-if="multiple && data.length > 1">
  172. <el-popover :offset="-10" :width="width" :visible-arrow="false" title="" content="" trigger="click"
  173. placement="bottom-start">
  174. <el-tag slot="reference" :size="size" style="margin-right: 10px">
  175. + {{ data.length }}
  176. </el-tag>
  177. <el-tag
  178. v-for="(item, index) in data"
  179. :size="size"
  180. hit
  181. closable
  182. :style="{
  183. display: 'flex',
  184. justifyContent: 'space-between',
  185. alignItems: 'center',
  186. margin: data.length - 1 === index ? '0' : '0 0 5px 0',
  187. }"
  188. @close="handleDelete(index)"
  189. >
  190. {{ item[showKey || valueKey] }}
  191. </el-tag>
  192. </el-popover>
  193. </div>
  194. </div>
  195. <table-dialog v-model="data" ref="TableDialog" :type="type" :title="title" :multiple="multiple"
  196. :queryParams="queryParams" @confirm="handleAdd"></table-dialog>
  197. </div>
  198. </template>
  199. <style scoped></style>