管理系统PC端
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

217 line
5.4 KiB

  1. <!-- 下拉列表表单组件 zhao -->
  2. <template>
  3. <div>
  4. <van-field
  5. :readonly="true"
  6. :clickable="!readonly"
  7. :name="name"
  8. :value="visibleValue"
  9. :label="label"
  10. :placeholder="placeholder"
  11. @click="openPopup"
  12. input-align="right"
  13. right-icon="arrow-down"
  14. :rules="rules"
  15. :required="required"
  16. :label-width="labelWidth || 'auto'"
  17. >
  18. </van-field>
  19. <van-popup v-model="popupVisible" position="bottom">
  20. <van-picker
  21. ref="picker"
  22. :title="label"
  23. show-toolbar
  24. :columns="columns ? columns : remoteColumns"
  25. :readonly="readonly"
  26. :value-key="valueKey"
  27. :loading="loading"
  28. @confirm="onConfirm"
  29. @cancel="onCancel"
  30. @change="onChanged"
  31. />
  32. </van-popup>
  33. </div>
  34. </template>
  35. <script>
  36. import request from "@/utils/request";
  37. export default {
  38. name: "fieldCascadeSelect",
  39. props: [
  40. 'name', 'readonly', 'value', 'label', 'placeholder', 'required', 'rules', 'labelWidth',
  41. 'columns', // 列表数据 Array
  42. 'valueKey', // 名称键名 String
  43. 'dataKey', // 值键名 String
  44. 'remoteUrl', // 远程列表加载地址 String
  45. 'onRemoteResponse', // 远程获取到结果的处理回调 String|Function 如果是函数需返回数组, 如果是字符串支持.分割
  46. 'clearable', // 点击取消时清空绑定值
  47. ],
  48. watch: {
  49. value: function (newVal, oldVal) {
  50. this.internalValue = newVal;
  51. this.visibleValue = newVal ? newVal.join(' / ') : '';
  52. this.syncIndex();
  53. },
  54. columns: function (newVal, oldVal) {
  55. this.syncIndex();
  56. },
  57. remoteUrl: function (newVal, oldVal) {
  58. this.requestRemote();
  59. },
  60. onRemoteResponse: function (newVal, oldVal) {
  61. this.parseRemote();
  62. }
  63. },
  64. created() {
  65. if(this.remoteUrl)
  66. this.requestRemote();
  67. },
  68. data() {
  69. return {
  70. popupVisible: false,
  71. internalValue: this.value,
  72. visibleValue: '',
  73. defaultIndex: [],
  74. remoteColumns: null,
  75. loading: false,
  76. remoteResponse: null,
  77. };
  78. },
  79. methods: {
  80. openPopup() {
  81. if(!this.readonly)
  82. {
  83. this.popupVisible = true;
  84. this.$nextTick(() => {
  85. this.$refs.picker.setIndexes(this.defaultIndex);
  86. })
  87. }
  88. },
  89. closePopup() {
  90. this.popupVisible = false;
  91. },
  92. onChanged(data) {
  93. this.$emit('change', data);
  94. },
  95. onConfirm(data) {
  96. this.syncValue(data);
  97. this.$emit('input', this.internalValue);
  98. this.$emit('confirm', this.internalValue);
  99. this.closePopup();
  100. },
  101. onCancel() {
  102. this.closePopup();
  103. this.$emit('cancel');
  104. if(this.clearable)
  105. {
  106. this.visibleValue = '';
  107. this.internalValue = [];
  108. this.$emit('input', this.internalValue);
  109. }
  110. },
  111. getValue(data) {
  112. return typeof(data) === 'object' && this.dataKey ? data[this.dataKey] : data;
  113. },
  114. getLabel(data) {
  115. return typeof(data) === 'object' && this.valueKey ? data[this.valueKey] : data;
  116. },
  117. syncValue(data) {
  118. let res = [];
  119. for(let a of data)
  120. {
  121. res.push(this.getValue(a));
  122. }
  123. this.internalValue = res;
  124. res = [];
  125. for(let a of data)
  126. {
  127. res.push(this.getLabel(a));
  128. }
  129. this.visibleValue = res.join(' / ');
  130. },
  131. syncIndex() {
  132. let columns = this.getColumns();
  133. if(!columns)
  134. return -1;
  135. let arr = [];
  136. let dataArr = [];
  137. let ptr = columns;
  138. for(let i = 0; i < this.internalValue.length; i++)
  139. {
  140. if(!ptr)
  141. break;
  142. let p = null;
  143. for(let m = 0; m < ptr.length; m++)
  144. {
  145. if(this.getValue(ptr[m]) == this.internalValue[i]) {
  146. arr.push(m);
  147. dataArr.push(ptr[m]);
  148. p = ptr[m];
  149. break;
  150. }
  151. }
  152. if(p)
  153. ptr = p.children;
  154. }
  155. if(arr.length)
  156. {
  157. this.defaultIndex = arr;
  158. this.visibleValue = dataArr.map((x) => this.getLabel(x)).join(' / ');
  159. this.onChanged(dataArr);
  160. return dataArr;
  161. }
  162. if(1) // 不存在
  163. {
  164. this.defaultIndex = [];
  165. this.visibleValue = (this.internalValue || []).join(' / ');
  166. this.onChanged([]);
  167. }
  168. return -1;
  169. },
  170. getColumns() {
  171. return this.columns ? this.columns : this.remoteColumns;
  172. },
  173. requestRemote() {
  174. if(!this.remoteUrl)
  175. return;
  176. this.loading = true;
  177. this.remoteColumns = [];
  178. let promise = typeof(this.remoteUrl) === 'function' ? this.remoteUrl() : (this.remoteUrl instanceof Promise ? this.remoteUrl : request(this.remoteUrl));
  179. promise.then((resp) => {
  180. this.remoteResponse = resp;
  181. this.parseRemote();
  182. this.syncIndex();
  183. }).catch((e) => {
  184. console.error(e);
  185. }).finally(() => {
  186. this.loading = false;
  187. })
  188. },
  189. parseRemote() {
  190. if(!this.remoteResponse)
  191. return;
  192. let type = typeof(this.onRemoteResponse);
  193. if(type === 'function')
  194. this.remoteColumns = this.onRemoteResponse(this.remoteResponse);
  195. else if(type === 'string')
  196. {
  197. let arr = this.onRemoteResponse.split('.');
  198. let ptr = this.remoteResponse;
  199. for(let i in arr)
  200. {
  201. ptr = this.remoteResponse[arr[i]];
  202. }
  203. this.remoteColumns = ptr;
  204. }
  205. else
  206. this.remoteColumns = this.remoteResponse;
  207. },
  208. },
  209. }
  210. </script>
  211. <style scoped>
  212. </style>