multiple.vue 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. <script>
  2. import { REFER } from "../popover-select/api/index";
  3. import deepCopy from "@gby/deep-copy";
  4. export default {
  5. name: "PopoverSelectV2",
  6. props: {
  7. // v-model
  8. value: {
  9. type: [Array, String],
  10. require: true,
  11. },
  12. // 参照类型 ,对应后端
  13. referName: {
  14. type: String,
  15. require: true,
  16. },
  17. // 作为 value 唯一标识的键名,绑定值
  18. valueKey: {
  19. type: [String, null, undefined],
  20. },
  21. // 默认查询参数
  22. queryParams: {
  23. type: Function,
  24. default: () => {},
  25. },
  26. // 需映射源数据
  27. source: {
  28. type: Object,
  29. default: () => ({}),
  30. },
  31. // 参照内外映射
  32. dataMapping: {
  33. type: Object,
  34. default: () => ({}),
  35. },
  36. },
  37. components: {},
  38. data() {
  39. return {
  40. size: "mini",
  41. width: "50%",
  42. page: { pageNum: 1, pageSize: 10, total: 0 },
  43. visible: false,
  44. loading: false,
  45. scroll: false,
  46. model: {
  47. search: "",
  48. isPage: true,
  49. },
  50. data: [],
  51. selectData: [],
  52. lastSelectData: [],
  53. };
  54. },
  55. computed: {
  56. innerValue: {
  57. get() {
  58. return this.value;
  59. },
  60. set(value) {
  61. this.$emit("input", value);
  62. },
  63. },
  64. tableColumns: {
  65. get() {
  66. const { referName } = this.$props;
  67. const {
  68. default: d,
  69. } = require(`../popover-select/components/${referName}`);
  70. return d.filter(({ key }) => key);
  71. },
  72. },
  73. },
  74. watch: {
  75. innerValue: {
  76. handler: function (newValue) {
  77. if (!newValue) this.lastSelectData = [];
  78. },
  79. },
  80. },
  81. methods: {
  82. // open dialog
  83. async open() {
  84. this.visible = true;
  85. await this.useReset();
  86. },
  87. // hide dialog
  88. async hide() {
  89. this.visible = false;
  90. },
  91. // fetch list
  92. async fetchList(prop, page) {
  93. try {
  94. // try
  95. this.loading = true;
  96. const { pageNum, pageSize } = page;
  97. const { referName: type, source, queryParams } = this.$props;
  98. const { code, rows, total } = await REFER(
  99. {
  100. ...prop,
  101. ...queryParams(source),
  102. type: type,
  103. },
  104. {
  105. pageNum,
  106. pageSize,
  107. }
  108. );
  109. if (code === 200) {
  110. this.data = rows;
  111. this.page.total = total;
  112. }
  113. } catch (err) {
  114. // catch
  115. console.error(err);
  116. } finally {
  117. // finally
  118. this.loading = false;
  119. }
  120. },
  121. // reset
  122. async useReset() {
  123. this.data = [];
  124. this.model.search = null;
  125. await this.fetchList(this.model, this.page);
  126. },
  127. // query
  128. async useQuery() {
  129. await this.fetchList(this.model, this.page);
  130. },
  131. // select
  132. useSelect(prop) {
  133. this.selectData = prop;
  134. },
  135. // delete
  136. useDelete(prop) {
  137. this.selectData.splice(prop, 1);
  138. this.useConfirm(this.selectData);
  139. },
  140. // confirm
  141. useConfirm(prop) {
  142. const {
  143. $props: { valueKey },
  144. } = this;
  145. // string
  146. if (typeof valueKey === "string") {
  147. this.innerValue = prop.map((item) => item[valueKey]);
  148. }
  149. // null
  150. else {
  151. this.innerValue = prop;
  152. }
  153. //
  154. this.hide();
  155. this.lastSelectData = deepCopy(prop);
  156. this.$emit("change", prop, this.$props);
  157. },
  158. // cancel
  159. useCancel() {
  160. this.hide();
  161. },
  162. },
  163. created() {},
  164. mounted() {},
  165. destroyed() {},
  166. };
  167. </script>
  168. <template>
  169. <div class="popover-select-v2 popover-select-v2--multiple">
  170. <el-input v-bind="$attrs" @focus="open">
  171. <i class="el-icon-search" slot="suffix" @click="open"> </i>
  172. </el-input>
  173. <el-dialog
  174. :width="width"
  175. :show-close="false"
  176. :visible.sync="visible"
  177. :close-on-click-modal="false"
  178. :close-on-press-escape="false"
  179. append-to-body
  180. >
  181. <template slot="title">
  182. <div
  183. style="
  184. display: flex;
  185. justify-content: space-between;
  186. align-items: center;
  187. "
  188. >
  189. <span>选 择</span>
  190. <span>
  191. <el-button
  192. :size="size"
  193. circle
  194. icon="el-icon-check"
  195. @click="useConfirm(selectData)"
  196. >
  197. </el-button>
  198. <el-button
  199. :size="size"
  200. circle
  201. type="danger"
  202. icon="el-icon-close"
  203. @click="useCancel"
  204. ></el-button>
  205. </span>
  206. </div>
  207. </template>
  208. <el-form
  209. v-loading="loading"
  210. :inline="true"
  211. :model="model"
  212. :size="size"
  213. @submit.native.prevent
  214. >
  215. <el-form-item prop="search">
  216. <el-input
  217. v-model="model.search"
  218. @change="useQuery"
  219. @keydown.enter="useQuery"
  220. >
  221. </el-input>
  222. </el-form-item>
  223. <el-form-item>
  224. <el-button icon="el-icon-refresh" @click="useReset"></el-button>
  225. </el-form-item>
  226. <el-table
  227. ref="multipleTable"
  228. :data="data"
  229. :size="size"
  230. height="45vh"
  231. @selection-change="useSelect"
  232. >
  233. <el-table-column width="55" type="selection" align="center">
  234. </el-table-column>
  235. <el-table-column
  236. v-for="(column, index) in tableColumns"
  237. :key="index"
  238. :prop="column.key"
  239. :label="column.title"
  240. :width="column.width || 'auto'"
  241. show-overflow-tooltip
  242. >
  243. <template slot-scope="scope">
  244. <dr-computed-input
  245. v-if="column.type === 'ComputedInput'"
  246. v-model="scope.row[column.key]"
  247. :source="scope.row"
  248. :computed="column.computed"
  249. :placeholder="column.placeholder"
  250. style="width: 100%"
  251. ></dr-computed-input>
  252. <span v-else> {{ scope.row[column.key] }}</span>
  253. </template>
  254. </el-table-column>
  255. </el-table>
  256. <pagination
  257. v-show="!loading"
  258. :total="page.total"
  259. :page.sync="page.pageNum"
  260. :limit.sync="page.pageSize"
  261. @pagination="useQuery"
  262. />
  263. </el-form>
  264. </el-dialog>
  265. <el-scrollbar
  266. v-if="lastSelectData.length"
  267. :viewStyle="{
  268. display: 'flex',
  269. alignItems: 'center',
  270. padding: '5px 0 0 5px',
  271. }"
  272. class="popover-select-v2_tags"
  273. >
  274. <el-tag
  275. v-for="(tag, index) in lastSelectData"
  276. :size="size"
  277. hit
  278. closable
  279. @close="useDelete(index)"
  280. style="margin-right: 5px"
  281. >
  282. {{ tag.name || tag[valueKey] }}
  283. </el-tag>
  284. </el-scrollbar>
  285. </div>
  286. </template>
  287. <style scoped>
  288. .popover-select-v2 .el-input {
  289. width: inherit;
  290. }
  291. .popover-select-v2 .el-input .el-icon-search {
  292. cursor: pointer;
  293. }
  294. .popover-select-v2 .popover-select-v2_tags {
  295. position: absolute;
  296. left: 0;
  297. top: 50%;
  298. transform: translateY(-50%);
  299. width: calc(100% - 40px);
  300. height: 100%;
  301. }
  302. ::v-deep .el-table--mini .el-table__cell {
  303. height: 50px;
  304. }
  305. </style>