selectProject.vue 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. <template>
  2. <el-select v-model="selectedValue" :size="size" filterable remote @change="updateValue" :placeholder="placeholder"
  3. :clearable="clearable" :remote-method="projectListRemotemethod" :loading="newProjectListLoading" :style="`width: ${width}`"
  4. @visible-change="visibleChangeProjrct" @focus="peojectFocus">
  5. <div ref="mySelectProject" class="select-project-class">
  6. <el-option v-for="item in newProjectList" :key="item.id" :label="item.projectName + '\u3000' + item.projectCode"
  7. :value="item.id">
  8. <span style="float: left; color: #8492a6; font-size: 13px;">{{ item.projectCode }}</span>
  9. <span style="float: right;margin-left: 20px">{{ item.projectName }}</span>
  10. </el-option>
  11. <div class="itemsLoading" v-if="loadingInProgress">
  12. 加载中...
  13. </div>
  14. </div>
  15. </el-select>
  16. </template>
  17. <script>
  18. export default {
  19. name: 'selectProject',
  20. props: {
  21. value: {
  22. type: [String, Number],
  23. required: true
  24. },
  25. size: {
  26. type: [String],
  27. default: 'mini'
  28. },
  29. placeholder: {
  30. type: [String],
  31. default: '请选择'
  32. },
  33. clearable: {
  34. type: [Boolean],
  35. default: false
  36. },
  37. width: {
  38. type: [String],
  39. default: '200px'
  40. }
  41. },
  42. data() {
  43. return {
  44. newProjectListLoading: false,
  45. newProjectList: [],
  46. selectedValue: this.value,
  47. newProjectListPage: 1,
  48. newProjectListSize: 20,
  49. newProjectListTotal: 0,
  50. loadingInProgress: false,
  51. loadingInProgressHight: 0,
  52. refRollVal: null,
  53. scrollListener: null,
  54. infoString: ''
  55. }
  56. },
  57. watch: {
  58. value(newValue) {
  59. this.selectedValue = newValue;
  60. },
  61. selectedValue(newValue) {
  62. this.$emit('input', newValue);
  63. }
  64. },
  65. methods: {
  66. projectListRemotemethod: _.debounce(function (val) {
  67. this.newProjectListPage = 1
  68. this.getNewProjectList(val)
  69. }, 300),
  70. peojectFocus() {
  71. this.newProjectListPage = 1
  72. this.getNewProjectList()
  73. },
  74. getNewProjectList(infoString = '') {
  75. this.infoString = infoString
  76. this.newProjectListLoading = true
  77. this.postData(`/project/getProjectListByPage`, {
  78. pageIndex: this.newProjectListPage,
  79. pageSize: this.newProjectListSize,
  80. id: this.value,
  81. forReport: 0,
  82. infoString,
  83. }).then((res) => {
  84. this.newProjectList = res.data.data
  85. this.newProjectListTotal = res.data.total
  86. }).finally(() => {
  87. this.newProjectListLoading = false
  88. })
  89. },
  90. addNewProjectList() {
  91. this.loadingInProgress = true
  92. this.postData(`/project/getProjectListByPage`, {
  93. pageIndex: this.newProjectListPage,
  94. pageSize: this.newProjectListSize,
  95. id: this.value,
  96. forReport: 0,
  97. infoString: this.infoString,
  98. }).then((res) => {
  99. this.newProjectList = [...this.newProjectList, ...res.data.data]
  100. }).finally(() => {
  101. setTimeout(() => {
  102. this.loadingInProgress = false
  103. }, 500)
  104. })
  105. },
  106. handleScroll(event) {
  107. const container = event.target;
  108. const { scrollTop, scrollHeight, clientHeight } = container;
  109. const totalPage = Math.ceil(this.newProjectListTotal / this.newProjectListSize);
  110. if (scrollTop + clientHeight >= scrollHeight - 20 && this.newProjectListPage < totalPage && !this.loadingInProgress) {
  111. this.loadMoreData()
  112. }
  113. },
  114. loadMoreData() {
  115. this.newProjectListPage += 1;
  116. this.addNewProjectList();
  117. },
  118. visibleChangeProjrct(flag) {
  119. if (flag) {
  120. this.$nextTick(() => {
  121. this.addScrollListener();
  122. });
  123. } else {
  124. this.removeScrollListener();
  125. }
  126. },
  127. addScrollListener() {
  128. const container = this.$refs.mySelectProject;
  129. const scrollbar = container.closest('.el-scrollbar__wrap');
  130. if (scrollbar) {
  131. this.loadingInProgressHight = scrollbar.clientHeight - 40
  132. this.removeScrollListener();
  133. const debouncedHandleScroll = _.debounce(this.handleScroll, 200);
  134. scrollbar.addEventListener('scroll', debouncedHandleScroll);
  135. this.scrollListener = debouncedHandleScroll;
  136. }
  137. },
  138. removeScrollListener() {
  139. const container = this.$refs.mySelectProject;
  140. const scrollbar = container.closest('.el-scrollbar__wrap');
  141. if (scrollbar && this.scrollListener) {
  142. scrollbar.removeEventListener('scroll', this.scrollListener);
  143. this.scrollListener = null;
  144. }
  145. },
  146. async postData(urls, param) {
  147. return new Promise((resolve, reject) => {
  148. this.http.post(urls, { ...param },
  149. res => {
  150. if (res.code == 'ok') {
  151. resolve(res)
  152. } else {
  153. this.$message({
  154. message: res.msg,
  155. type: 'error'
  156. })
  157. reject(res)
  158. }
  159. resolve(res)
  160. },
  161. error => {
  162. this.$message({
  163. message: error,
  164. type: "error"
  165. });
  166. reject(error)
  167. }
  168. )
  169. });
  170. },
  171. updateValue(value) {
  172. this.$emit('input', value);
  173. this.$emit('change', value);
  174. }
  175. },
  176. created() {
  177. },
  178. mounted() {
  179. this.getNewProjectList()
  180. },
  181. beforeDestroy() {
  182. this.removeScrollListener();
  183. }
  184. }
  185. </script>
  186. <style lang="scss" scoped>
  187. .select-project-class {
  188. position: relative;
  189. .itemsLoading {
  190. position: absolute;
  191. left: 0;
  192. bottom: -2px;
  193. width: 100%;
  194. text-align: center;
  195. padding: 10px;
  196. background: #fff;
  197. box-shadow: 0px -4px 20px 0px #999;
  198. font-size: 12px;
  199. color: #999;
  200. z-index: 99;
  201. box-sizing: border-box;
  202. }
  203. }
  204. </style>