index.vue 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. <template>
  2. <el-select
  3. v-loading.fullscreen="companyChangeLoading"
  4. :element-loading-text="'正在切换至 ' + getUserCompany().name + ' ......'"
  5. element-loading-background="rgba(0, 0, 0, 0.8)"
  6. element-loading-spinner="el-icon-loading"
  7. :value="!global ? value : currentCompany"
  8. :remote-method="isSupertube ? handleRemoteSearch : undefined"
  9. :placeholder="placeholder"
  10. style="width:380px"
  11. :disabled="disabled"
  12. :clearable="clearable"
  13. reserve-keyword
  14. :size="size"
  15. filterable
  16. remote
  17. @change="setCurrentCompany"
  18. >
  19. <!-- 当selectAll为true 且为超管账号允许选择所有公司 -->
  20. <el-option v-if="selectAll && isSupertube" class="custom-company" :label="allCompanyLabel" value="" />
  21. <el-option
  22. v-for="(company, index) in companylist"
  23. :key="index"
  24. class="custom-company"
  25. :label="genCompanyLabel(company)"
  26. :value="company.code"
  27. />
  28. <p v-if="state.loading" class="company-loading">
  29. <i class="el-icon-loading" />
  30. 加载中...
  31. </p>
  32. <p v-if="state.noMore || !isSupertube" class="company-more">没有更多数据了...</p>
  33. </el-select>
  34. </template>
  35. <script>
  36. import { requsetSupertubeCompany, requsetUserBindingCompany } from '@/apis/user'
  37. import { isBusinessCompany, isOnlyBusinessCompanyPath } from './utils'
  38. import { userStoreActions } from '@/store/modules/user'
  39. import { accountLevels } from '@/assets/js/statusList'
  40. import { getUserCompany } from '@/utils/auth'
  41. import { convertCompanylist } from '@/utils'
  42. import { mapGetters, mapState } from 'vuex'
  43. export default {
  44. /**
  45. * @param placeholder
  46. * @param size 选择器尺寸
  47. * @param disabled 是否禁用
  48. * @param selectAll 超管账号是否可以选择所有公司
  49. * @param global 是否设置全局选中公司(全局使用/组件独立使用)
  50. */
  51. props: {
  52. selectAll: {
  53. type: Boolean,
  54. default: false
  55. },
  56. size: {
  57. type: String,
  58. default: 'small'
  59. },
  60. placeholder: {
  61. type: String,
  62. default: ''
  63. },
  64. disabled: {
  65. type: Boolean,
  66. default: false
  67. },
  68. global: {
  69. type: Boolean,
  70. default: false
  71. },
  72. value: {
  73. type: String,
  74. default: ''
  75. },
  76. isSupplier: {
  77. type: Boolean,
  78. default: false
  79. },
  80. noCompanyCode: {
  81. type: String,
  82. default: () => false
  83. },
  84. clearable: {
  85. type: Boolean,
  86. default: () => false
  87. }
  88. },
  89. computed: {
  90. allCompanyLabel() { return this.currentLevel === accountLevels.supplier ? '所有供应商' : '所有业务公司' },
  91. ...mapGetters(['currentLevel']),
  92. ...mapState({
  93. currentCompany: state => state.user.currentCompany,
  94. companylist: state => state.user.companylist,
  95. isSupertube: state => state.user.isSupertube,
  96. originLevel: state => state.user.originLevel
  97. })
  98. },
  99. data: () => ({
  100. ScrollWrapper: null,
  101. initialization: true,
  102. companyChangeLoading: false,
  103. key: 1,
  104. state: {
  105. loading: false,
  106. noMore: false
  107. },
  108. params: {
  109. name: '',
  110. page: 2,
  111. size: 10
  112. }
  113. }),
  114. watch: {
  115. currentLevel: {
  116. handler() {
  117. if (!this.isSupertube) return
  118. this.params = {
  119. name: '',
  120. page: 1,
  121. size: 10
  122. }
  123. this.state = {
  124. loading: false,
  125. noMore: false
  126. }
  127. this.initalData()
  128. }
  129. }
  130. },
  131. async mounted() {
  132. this.isSupertube && await this.initalData()
  133. this.ScrollWrapper = await this.getScrollWrapper()
  134. this.ScrollWrapper && this.bindEvent(this.ScrollWrapper)
  135. },
  136. beforeDestroy() {
  137. this.ScrollWrapper && this.removeEvent(this.ScrollWrapper)
  138. },
  139. methods: {
  140. getUserCompany,
  141. genCompanyLabel(company) {
  142. const { name, code } = company
  143. if (this.noCompanyCode) return name
  144. return `${code}/${name}`
  145. },
  146. async initalData() {
  147. // 区分是否超管用户请求不同接口
  148. this.state.loading = true
  149. const api = this.isSupertube || this.isSupplier ? requsetSupertubeCompany : requsetUserBindingCompany
  150. const isSupplier = this.currentLevel === accountLevels.supplier
  151. const { page, size, name } = this.params
  152. const params = {
  153. ...(this.isSupertube ? { type: isSupplier ? '3' : '1' } : {}),
  154. [this.isSupertube ? 'name' : 'companyName']: name,
  155. page,
  156. size
  157. }
  158. const { data } = await api(params)
  159. if (data.list.length < 10) this.state.noMore = true
  160. this.state.loading = false
  161. this.params.page++
  162. const _list = this.isSupertube ? data.list : convertCompanylist(data.list)
  163. // const __list = this.isSupertube && this.currentLevel === '1' ? _list.map(item => ({ ...item, code: item.relation_code })) : _list
  164. this.$store.commit('user/setCompanylist', [...this.companylist, ..._list])
  165. return this.isSupertube ? data.list : convertCompanylist(data.list)
  166. },
  167. setCurrentCompany(currentCompany) {
  168. this.$emit('update:value', currentCompany)
  169. this.$emit('change', currentCompany)
  170. // 作为通用组件使用不设置全局选中公司
  171. if (!this.global) return null
  172. // 只能选择业务公司的页面
  173. const { path } = this.$route
  174. if (isOnlyBusinessCompanyPath(path) && !isBusinessCompany(currentCompany)) {
  175. this.$message.warning('该页面只能选择业务公司')
  176. return
  177. }
  178. if (!currentCompany) { // 选择所有公司重置选项
  179. this.handleRemoteSearch()
  180. }
  181. this.$store.commit(userStoreActions.setCurrentCompany, currentCompany)
  182. if (this.isSupertube) return null // 超管用户不刷新路由
  183. this.changeRouterWithCompany()
  184. },
  185. async changeRouterWithCompany() {
  186. const { path, query } = this.$route
  187. query.redirect = path
  188. const keys = Object.keys(query).filter(key => key && key !== 'error')
  189. // 1.保存透传参数
  190. // 1.2 是否详情页
  191. const isDetailPath = path.indexOf('Detail') >= 0
  192. let queryString = ''
  193. const chunk = (qs, key, index) => {
  194. const next = `${key}=${query[key]}${index === keys.length ? '' : '&'}`
  195. return qs + next
  196. }
  197. // 2.重新获取用户信息和菜单
  198. this.companyChangeLoading = true
  199. const result = await this.$store.dispatch(userStoreActions.reloadMenu)
  200. this.companyChangeLoading = false
  201. switch (result) {
  202. case 'noToken': // 登出
  203. await this.$store.dispatch('user/logout')
  204. await this.$router.push(`/login`)
  205. break
  206. case 'disabled': // 角色异常或该公司禁用清空菜单返回首页
  207. await this.$store.dispatch('user/disabledCompany')
  208. break
  209. default: // 切换路由
  210. queryString = isDetailPath ? this.parsePathDetail2List(path) : keys.reduce(chunk, '?')
  211. await this.$router.replace('/reload' + queryString)
  212. break
  213. }
  214. },
  215. parsePathDetail2List(path) {
  216. const chunks = path.split('Detail')
  217. return `?redirect=${chunks[0]}`
  218. },
  219. getScrollWrapper() {
  220. return new Promise(resolve => {
  221. setTimeout(() => {
  222. let optionEl = document.querySelector('.custom-company')
  223. if (optionEl && (optionEl = optionEl.parentElement)) {
  224. resolve(optionEl.parentElement)
  225. return
  226. }
  227. resolve(null)
  228. }, 500)
  229. })
  230. },
  231. async handleScroll() {
  232. const ScrollWrapper = this.ScrollWrapper
  233. const height = ScrollWrapper.clientHeight
  234. const scrollTop = ScrollWrapper.scrollTop
  235. const scrollHeight = ScrollWrapper.scrollHeight
  236. const { loading, noMore } = this.state
  237. // 是否允许下拉加载
  238. const isAllowLoad = !loading && !noMore
  239. if (height + scrollTop >= scrollHeight && isAllowLoad) {
  240. const list = await this.loadMore()
  241. const _list = this.isSupertube ? list : convertCompanylist(list)
  242. // const __list = this.isSupertube && this.currentLevel === '1' ? _list.map(item => ({ ...item, code: item.relation_code })) : _list
  243. // 保存到全局
  244. this.$store.commit(userStoreActions.setCompanyList, [...this.companylist, ..._list])
  245. }
  246. },
  247. async loadMore() {
  248. // 区分超管用户和普通用户
  249. const api = this.isSupertube ? requsetSupertubeCompany : requsetUserBindingCompany
  250. const isSupplier = this.currentLevel === accountLevels.supplier
  251. this.state.loading = true
  252. const { page, size, name } = this.params
  253. const nameProp = this.isSupertube ? 'name' : 'companyName'
  254. const params = {
  255. [nameProp]: name,
  256. page,
  257. size
  258. }
  259. const { data } = await api({
  260. ...params,
  261. ...(this.isSupertube ? { type: isSupplier ? '3' : '1' } : {})
  262. })
  263. this.state.loading = false
  264. const isTransborder = this.companylist.length >= Number(data.count) // 是否越界
  265. if (isTransborder) {
  266. this.state.noMore = true
  267. this.state.loading = false
  268. return []
  269. }
  270. this.params.page++
  271. return data.list
  272. },
  273. async handleRemoteSearch(name) {
  274. // 清空全局业务公司列表
  275. this.$store.commit(userStoreActions.setCompanyList, [])
  276. this.params.name = name
  277. this.params.page = 1
  278. this.state.noMore = false
  279. this.state.loading = false
  280. // 获取列表数据
  281. const result = await this.initalData()
  282. // const list = this.isSupertube && this.currentLevel === '1' ? result.map(item => ({ ...item, code: item.relation_code })) : result
  283. if (result) this.$store.commit(userStoreActions.setCompanyList, result)
  284. },
  285. selectAllCompany() {
  286. this.value = ''
  287. this.$nextTick(() => (this.key = this.key + 1))
  288. this.global && this.$store.commit(userStoreActions.setCurrentCompany, '')
  289. },
  290. bindEvent(ScrollWrapper) { this.isSupertube && ScrollWrapper.addEventListener('scroll', this.handleScroll) },
  291. removeEvent(ScrollWrapper) { this.isSupertube && ScrollWrapper.removeEventListener('scroll', this.handleScroll) }
  292. }
  293. }
  294. </script>
  295. <style lang="scss" scoped>
  296. .company-more {
  297. text-align: center;
  298. color: #999;
  299. font-size: 14px;
  300. line-height: 38px;
  301. }
  302. .company-loading {
  303. display: flex;
  304. font-size: 14px;
  305. justify-content: center;
  306. align-items: center;
  307. color: #999;
  308. gap: 10px;
  309. line-height: 38px;
  310. }
  311. </style>