dialog.vue 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. <template>
  2. <el-dialog
  3. v-if="dialogVisible"
  4. ref="dialog"
  5. :show-close="showClose"
  6. :close-on-click-modal="closeOnClickModal"
  7. :close-on-press-escape="closeOnPressEscape"
  8. :visible.sync="dialogVisible"
  9. :width="width"
  10. :top="marginTop"
  11. lock-scroll
  12. append-to-body
  13. custom-class="ibps-selector-dialog"
  14. class="ibps-selector-dialog__wrapper"
  15. @close="handleClose"
  16. >
  17. <slot slot="title" name="title" />
  18. <div
  19. :style="{ height: multiple ? '35px' : '35px' }"
  20. class="ibps-selector-header"
  21. >
  22. <el-tag
  23. v-for="(item, index) in selectedItems"
  24. :key="index"
  25. closable
  26. @close="handleRemove(index, true)"
  27. >{{ item }}</el-tag
  28. >
  29. </div>
  30. <div>
  31. <slot :multiple="multiple" :height="height" :value="value" />
  32. </div>
  33. <div
  34. v-if="buttonGroup && buttonGroup.length > 0"
  35. slot="footer"
  36. class="el-dialog--center"
  37. >
  38. <el-button
  39. v-for="(button, index) in buttonGroup"
  40. :key="index"
  41. :type="button.type"
  42. :icon="button.icon"
  43. :disabled="button.key === 'confirm' ? isDisabled : false"
  44. @click="button.action"
  45. >
  46. {{ button.label }}
  47. </el-button>
  48. </div>
  49. </el-dialog>
  50. </template>
  51. <script>
  52. import ActionUtils from '@/utils/action'
  53. export default {
  54. props: {
  55. visible: Boolean, // 是否可见
  56. title: {
  57. // 标题
  58. type: String,
  59. default: '选择器'
  60. },
  61. marginTop: {
  62. // Dialog CSS 中的 margin-top 值
  63. type: String,
  64. default: '5vh'
  65. },
  66. width: {
  67. // 宽
  68. type: String,
  69. default: '60%'
  70. },
  71. height: {
  72. // 高
  73. type: String,
  74. default: '400px'
  75. },
  76. closeOnClickModal: {
  77. // 是否可以通过点击 modal 关闭 Dialog
  78. type: Boolean,
  79. default: false
  80. },
  81. closeOnPressEscape: {
  82. // 是否可以通过按下 ESC 关闭 Dialog
  83. type: Boolean,
  84. default: false
  85. },
  86. showClose: {
  87. // 是否显示关闭按钮
  88. type: Boolean,
  89. default: true
  90. },
  91. beforeClose: {
  92. // 关闭前的回调,会暂停 Dialog 的关闭
  93. type: Function
  94. },
  95. fullscreen: {
  96. // 是否为全屏 Dialog
  97. type: Boolean,
  98. default: false
  99. },
  100. labelKey: {
  101. // 展示的值
  102. type: [String, Function],
  103. default: 'name'
  104. },
  105. value: {
  106. // 值
  107. type: [Object, Array],
  108. default() {
  109. return this.multiple ? [] : {}
  110. }
  111. },
  112. cleanClose: {
  113. // 按钮清空并关闭
  114. type: Boolean,
  115. default: false
  116. },
  117. defaultButton: {
  118. type: Boolean,
  119. default: true
  120. },
  121. buttons: {
  122. // 按钮组
  123. type: Array,
  124. default() {
  125. return []
  126. }
  127. },
  128. confirmButtonText: {
  129. type: String
  130. },
  131. cleanButtonText: {
  132. type: String
  133. },
  134. cancelButtonText: {
  135. type: String
  136. },
  137. multiple: {
  138. // 是否多选
  139. type: Boolean,
  140. default: false
  141. },
  142. isDisabled: {
  143. // 是否多选
  144. type: Boolean,
  145. default: false
  146. }
  147. },
  148. data() {
  149. return {
  150. dialogVisible: this.visible
  151. }
  152. },
  153. computed: {
  154. selectedItems() {
  155. if (this.$utils.isEmpty(this.value)) {
  156. return []
  157. }
  158. if (this.multiple) {
  159. const items = []
  160. this.value.forEach((item) => {
  161. items.push(this.handleLabel(item))
  162. })
  163. return items
  164. } else {
  165. return [this.handleLabel(this.value)]
  166. }
  167. },
  168. bodyStyle() {
  169. return {
  170. height: this.height,
  171. overflow: 'hidden'
  172. }
  173. },
  174. buttonGroup() {
  175. let buttons = []
  176. if (this.$utils.isEmpty(this.buttons) && this.defaultButton) {
  177. buttons = buttons.concat([
  178. {
  179. key: 'confirm',
  180. label: this.confirmButtonText || '确定',
  181. icon: 'ibps-icon-ok',
  182. type: 'primary',
  183. action: () => this.handleOk()
  184. },
  185. {
  186. key: 'clean',
  187. label: this.cleanButtonText || '清空',
  188. icon: 'ibps-icon-clean',
  189. type: 'info',
  190. action: () => this.handleClean()
  191. },
  192. {
  193. key: 'cleanAndClose',
  194. label: '清空并关闭',
  195. icon: 'ibps-icon-clean',
  196. type: 'warning',
  197. action: () => this.handleCleanAndClose()
  198. },
  199. {
  200. key: 'cancel',
  201. label: this.cancelButtonText || '取消',
  202. icon: 'ibps-icon-cancel',
  203. action: () => this.handleCancel()
  204. }
  205. ])
  206. } else {
  207. buttons = this.buttons
  208. }
  209. if (this.$utils.isEmpty(buttons)) {
  210. return []
  211. }
  212. return buttons.map((button) => {
  213. if (button.action) {
  214. const action = button.action
  215. button.action = (e) => action(() => {}, this, e)
  216. }
  217. return button
  218. })
  219. }
  220. },
  221. watch: {
  222. visible: {
  223. handler: function (val, oldVal) {
  224. this.dialogVisible = this.visible
  225. },
  226. immediate: true
  227. }
  228. },
  229. methods: {
  230. handleLabel(data) {
  231. const config = this.labelKey
  232. if (data[this.labelKey + '_label_value']) {
  233. return data[this.labelKey + '_label_value']
  234. }
  235. if (typeof config === 'function') {
  236. return config(data)
  237. } else if (typeof config === 'string') {
  238. return data[config]
  239. } else if (typeof config === 'undefined') {
  240. const dataProp = data['name']
  241. return dataProp === undefined ? '' : dataProp
  242. }
  243. },
  244. // 确定
  245. handleOk() {
  246. const data = this.multiple ? this.value.slice(0) : this.value
  247. if (this.$utils.isEmpty(data)) {
  248. ActionUtils.warning('请选择记录!')
  249. return
  250. }
  251. this.$emit('input', data)
  252. this.$emit('action-event', 'confirm', data)
  253. },
  254. // 清空
  255. handleClean() {
  256. const data = this.multiple ? [] : {}
  257. if (!this.cleanClose) {
  258. this.$emit('input', data)
  259. }
  260. this.$emit('action-event', 'clean', data)
  261. },
  262. // 清空并关闭
  263. handleCleanAndClose() {
  264. const data = this.multiple ? [] : {}
  265. this.$emit('input', data)
  266. this.$emit('action-event', 'confirm', data)
  267. this.handleClose()
  268. },
  269. // 取消
  270. handleCancel() {
  271. this.handleClose()
  272. this.$emit('action-event', 'cancel')
  273. },
  274. // 关闭窗口
  275. handleClose() {
  276. this.$emit('close', false)
  277. },
  278. /**
  279. * 删除
  280. */
  281. handleRemove(index, bool) {
  282. let res
  283. let removeValue
  284. if (this.multiple) {
  285. const selected = JSON.parse(JSON.stringify(this.value))
  286. selected.splice(index, 1)
  287. res = selected
  288. removeValue = this.value[index]
  289. } else {
  290. res = {}
  291. removeValue = res
  292. }
  293. this.$emit('input', res)
  294. this.$emit('remove-select', removeValue)
  295. }
  296. }
  297. }
  298. </script>