index.vue 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. <template>
  2. <van-field
  3. ref="input"
  4. v-model="inputValue"
  5. :label="label"
  6. :name="name"
  7. :size="size"
  8. :placeholder="placeholder"
  9. :border="border"
  10. :disabled="disabled"
  11. :required="required"
  12. :clearable="clearable"
  13. :clickable="clickable"
  14. :is-link="isLink"
  15. :error="error"
  16. :error-message="errorMessage"
  17. :arrow-direction="arrowDirection"
  18. :label-class="labelClass"
  19. :label-width="labelWidth"
  20. :label-align="labelAlign"
  21. :input-align="inputAlign"
  22. :error-message-align="errorMessageAlign"
  23. :autosize="autosize"
  24. :left-icon="leftIcon"
  25. :right-icon="rightIcon"
  26. :icon-prefix="iconPrefix"
  27. :rules="editable ? rules : null"
  28. readonly
  29. @click-input="onClick"
  30. >
  31. <template #label>
  32. {{ label
  33. }}<van-icon
  34. v-if="desc && descPosition === 'lableIcon'"
  35. name="warning"
  36. class="ibps-dialog-icon"
  37. @click="$action.descDialog({ title: label, message: desc })"
  38. />
  39. </template>
  40. <template v-if="editable" #right-icon>
  41. <van-icon
  42. v-if="showClear"
  43. name="clear"
  44. class="van-field__clear"
  45. @click.native.stop="onRightIconClick"
  46. />
  47. <van-icon
  48. v-else
  49. :name="showPopup ? 'arrow-up' : 'arrow-down'"
  50. @click.native.stop="onClick"
  51. />
  52. <van-popup
  53. v-model="showPopup"
  54. get-container="body"
  55. position="bottom"
  56. @opened="onOpened"
  57. >
  58. <van-picker
  59. ref="picker"
  60. :title="title"
  61. show-toolbar
  62. :default-index="defaultIndex"
  63. :columns="columns"
  64. :value-key="labelKey"
  65. @confirm="onConfirm"
  66. @cancel="showPopup = false"
  67. />
  68. </van-popup>
  69. </template>
  70. </van-field>
  71. </template>
  72. <script>
  73. import { isDef, isObject } from 'vant/lib/utils'
  74. import FieldMixin from '@/mixins/field'
  75. export default {
  76. name: 'ibps-select',
  77. mixins: [FieldMixin],
  78. props: {
  79. title: {
  80. type: String
  81. },
  82. options: {
  83. type: Array,
  84. default: () => {
  85. return []
  86. }
  87. },
  88. valueKey: {
  89. type: String,
  90. default: 'value'
  91. },
  92. labelKey: {
  93. type: String,
  94. default: 'label'
  95. },
  96. otherOptionKey: {
  97. type: String,
  98. default: 'include_other_option'
  99. },
  100. otherOptionValue: {
  101. type: String,
  102. default: ''
  103. },
  104. desc: String
  105. },
  106. data() {
  107. return {
  108. showPopup: false,
  109. otherOption: '',
  110. otherOptionPlaceholder: '其他选项',
  111. defaultIndex: 0
  112. }
  113. },
  114. computed: {
  115. showClear() {
  116. return (
  117. this.clearable &&
  118. this.$utils.isNotEmpty(this.value) &&
  119. isDef(this.value) &&
  120. this.editable
  121. )
  122. },
  123. cacheOptions() {
  124. const arr = this.options
  125. if (!arr || arr.length === 0) {
  126. return {}
  127. }
  128. const cacheOptions = {}
  129. for (let i = 0; i < arr.length; i++) {
  130. const option = arr[i]
  131. if (option instanceof String) {
  132. cacheOptions[option] = {
  133. [this.labelKey]: option
  134. }
  135. } else {
  136. cacheOptions[option[this.valueKey]] = option
  137. }
  138. }
  139. return cacheOptions
  140. },
  141. hasOtherOption() {
  142. return this.isIncludeOtherOption(this.value)
  143. },
  144. columns() {
  145. return this.options
  146. }
  147. },
  148. watch: {
  149. value: {
  150. handler(val, oldVal) {
  151. this.setInputValue()
  152. this.validate()
  153. },
  154. immediate: true
  155. },
  156. otherOption() {
  157. this.changeOtherOption(this.otherOption)
  158. }
  159. },
  160. methods: {
  161. setInputValue() {
  162. let inputValue = ''
  163. if (this.$utils.isEmpty(this.value)) {
  164. inputValue = ''
  165. } else {
  166. if (this.cacheOptions[this.value]) {
  167. inputValue = this.cacheOptions[this.value][this.labelKey]
  168. } else {
  169. inputValue = isObject(this.value) ? '' : this.value
  170. }
  171. }
  172. this.inputValue = inputValue
  173. },
  174. initSelected() {
  175. if (this.value) {
  176. return this.options.findIndex((option) => {
  177. return option[this.valueKey] === this.value
  178. })
  179. } else {
  180. return 0
  181. }
  182. },
  183. onClick() {
  184. if (!this.editable) {
  185. return
  186. }
  187. this.defaultIndex = this.initSelected()
  188. this.showPopup = true
  189. },
  190. onOpened() {},
  191. onRightIconClick() {
  192. this.showClear ? this.onClear() : this.onClick()
  193. },
  194. onClear() {
  195. this.otherOption = ''
  196. this.$emit('input', '')
  197. this.$emit('change', '')
  198. },
  199. onConfirm(data, index) {
  200. this.showPopup = false
  201. this.$emit('input', data[this.valueKey])
  202. this.$emit('change', data[this.valueKey], data, index)
  203. },
  204. setOtherOptionValue() {
  205. if (this.hasOtherOption) {
  206. this.otherOption = this.otherOptionValue
  207. }
  208. },
  209. isIncludeOtherOption(value) {
  210. if (this.cacheOptions[value]) {
  211. return !!this.cacheOptions[value][this.otherOptionKey]
  212. }
  213. return false
  214. },
  215. changeOtherOption(value) {
  216. this.$emit('change-other-option', value)
  217. }
  218. }
  219. }
  220. </script>