siteServe.vue 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. <template>
  2. <view class="serve-content" :style="{'height':height +'px' }">
  3. <view class="serve-title">可以办事项</view>
  4. <view class="serve-search">
  5. <input confirm-type="search" ref="searchInputRef" class="search-input" :auto-blur="true" type="text"
  6. placeholder="搜索服务事项" v-model="matterName" @confirm="getMatterList" />
  7. <view class="search-btn" @click.stop="getMatterList"> 搜 索 </view>
  8. </view>
  9. <view class="matter-loading" v-if="MatterListLoading">
  10. <u-loading-icon />
  11. </view>
  12. <view class="serve" :style="{'height':scrollH +'px' }" v-else-if="MatterList">
  13. <scroll-view class="scroll-lable" :style="{'height':scrollH +'px' }" scroll-y="true"
  14. :show-scrollbar="false">
  15. <template v-for="(value, key , index) in MatterList">
  16. <view :class="['lable one-row' , index === activeIndex ? 'active-lable' : '' ]"
  17. @click.stop="openTyle(index)">{{ key }}</view>
  18. </template>
  19. </scroll-view>
  20. <scroll-view class="scroll-val" :scroll-into-view="scrollIntoView" @scroll="scrollService"
  21. :style="{'height':scrollH +'px' }" scroll-y="true" :show-scrollbar="false">
  22. <template v-for="(value, key , index) in MatterList">
  23. <view class="val-content" :id="`service_${index}`">
  24. <view class="val-name">{{key}}</view>
  25. <template v-for="item in (value || [])">
  26. <view class="val" @click.stop="LookMatterDetails(item)">
  27. <text class="val-text one-row">{{ item.name }}</text>
  28. <svg t="1734508422065" class="val-icon" viewBox="0 0 1024 1024" version="1.1"
  29. xmlns="http://www.w3.org/2000/svg" p-id="4279"
  30. xmlns:xlink="http://www.w3.org/1999/xlink">
  31. <path
  32. d="M492.675886 904.817574L885.696074 511.797385 492.675886 118.777197c-12.258185-12.258185-12.432147-32.892131 0.187265-45.51052 12.707416-12.707416 32.995485-12.703323 45.511543-0.187265l411.660734 411.660734c7.120165 7.120165 10.163477 17.065677 8.990768 26.624381 1.500167 9.755178-1.5104 20.010753-8.990768 27.491121L538.374694 950.515359c-12.258185 12.258185-32.892131 12.432147-45.511543-0.187265-12.707416-12.707416-12.703323-32.995485-0.187265-45.51052z"
  33. p-id="4280"></path>
  34. </svg>
  35. </view>
  36. </template>
  37. </view>
  38. </template>
  39. </scroll-view>
  40. </view>
  41. <view v-else class="matter-loading">
  42. <u-empty mode="data" :iconSize="emptySize" text="暂无可办事项" />
  43. </view>
  44. </view>
  45. </template>
  46. <script>
  47. import { getMapMatterList_Api } from "@/api/map.js"
  48. export default {
  49. props: {
  50. height: {
  51. type: Number,
  52. default: 0
  53. },
  54. mapLocationId: {
  55. type: Number | String,
  56. default: null
  57. }
  58. },
  59. data() {
  60. return {
  61. scrollH: 0,
  62. matterName: '',
  63. MatterList: null,
  64. MatterListLoading: false,
  65. activeIndex: undefined,
  66. scrollIntoView: undefined,
  67. scrollStatus: true,
  68. oldScrollNum: 0,
  69. RightTopArr: [],
  70. emptySize: uni.upx2px(130)
  71. }
  72. },
  73. watch: {
  74. height: {
  75. handler(newH) {
  76. // 区域高度 - 标题高度 - 搜索区域高度
  77. this.scrollH = newH - uni.upx2px(60) - uni.upx2px(100);
  78. },
  79. immediate: true
  80. },
  81. mapLocationId: {
  82. handler(newId) {
  83. this.getMatterList(newId)
  84. },
  85. immediate: true
  86. },
  87. },
  88. created() {
  89. },
  90. methods: {
  91. getLabel(item) {
  92. console.log("getLabel = ", item)
  93. const label = Object.keys(item)[0];
  94. return label;
  95. },
  96. getMatterList() {
  97. this.MatterListLoading = true;
  98. const parmas = {
  99. mapLocationId: this.mapLocationId,
  100. matterName: this.matterName
  101. };
  102. getMapMatterList_Api(parmas).then(res => {
  103. const keys = Object.keys(res || {});
  104. if (keys && keys.length > 0) {
  105. this.MatterList = res;
  106. this.activeIndex = 0;
  107. this.getNodesInfo()
  108. } else {
  109. this.MatterList = null;
  110. this.activeIndex = undefined;
  111. }
  112. }).catch(err => {
  113. this.MatterList = null;
  114. this.activeIndex = undefined;
  115. }).finally(() => {
  116. setTimeout(() => {
  117. this.MatterListLoading = false;
  118. }, 300)
  119. })
  120. },
  121. openTyle(index) {
  122. this.scrollStatus = false;
  123. this.activeIndex = index
  124. this.scrollIntoView = `service_${index}`
  125. setTimeout(() => {
  126. this.scrollStatus = true;
  127. }, 200)
  128. },
  129. scrollService(event) {
  130. if (!this.scrollStatus) return
  131. const { scrollTop } = event.detail;
  132. let scrollNums = scrollTop;
  133. if (this.oldScrollNum > scrollTop) {
  134. scrollNums = scrollTop + 80;
  135. };
  136. try {
  137. this.RightTopArr.forEach((el, index) => {
  138. let data = this.RightTopArr[index];
  139. if (scrollNums >= data.height && index == this.RightTopArr.length - 1 ? true :
  140. scrollNums < this.RightTopArr[parseInt(index) + 1].height) {
  141. this.activeIndex = index;
  142. throw new Error()
  143. }
  144. })
  145. } catch (e) {
  146. //TODO handle the exception
  147. }
  148. this.oldScrollNum = scrollTop;
  149. },
  150. // 查看事项详情
  151. LookMatterDetails(item) {
  152. // pages/map/matterDetails
  153. // 在起始页面跳转到test.vue页面,并监听test.vue发送过来的事件数据
  154. uni.navigateTo({
  155. url: '/pages/map/matterDetails',
  156. success: function(res) {
  157. // 通过eventChannel向被打开页面传送数据
  158. res.eventChannel.emit('acceptDataFromOpenerPage', item)
  159. }
  160. })
  161. },
  162. getNodesInfo() {
  163. new Promise(resolve => {
  164. let selectorQuery = uni.createSelectorQuery();
  165. // 获取节点的位置信息
  166. selectorQuery.selectAll('.val-content').boundingClientRect((rects) => {
  167. // 如果节点尚未生成,rects值为[](因为用selectAll,所以返回的是数组),循环调用执行
  168. if (!rects.length) {
  169. setTimeout(() => {
  170. this.$nextTick(() => {
  171. this.getNodesInfo();
  172. })
  173. }, 10);
  174. return;
  175. }
  176. this.RightTopArr = [];
  177. // 生成之后开始添加进去数组
  178. rects.forEach((rect) => {
  179. // 这里减去rects[0].top,是因为第一项顶部不是贴到导航栏=>每一个商品距离顶部的高度,如果此页面顶部没有其他的view那就不用减去rects[0].top,自己视情况而定。
  180. let tops = rect.top - rects[0].top;
  181. this.RightTopArr.push({
  182. height: tops,
  183. id: rect.id
  184. });
  185. })
  186. resolve();
  187. }).exec()
  188. });
  189. },
  190. }
  191. }
  192. </script>
  193. <style lang="scss" scoped>
  194. .serve-content {
  195. border-top: 1rpx solid #F0F0F0;
  196. .serve-title {
  197. color: #7D7D7D;
  198. font-size: 32rpx;
  199. height: 60rpx;
  200. line-height: 60rpx;
  201. }
  202. .serve-search {
  203. width: 100%;
  204. padding: 20rpx 0;
  205. display: flex;
  206. justify-content: space-between;
  207. align-items: stretch;
  208. .search-input {
  209. flex: 1;
  210. height: 60rpx;
  211. border: 1rpx solid #F0F0F0;
  212. border-radius: 10rpx;
  213. padding: 0 15rpx;
  214. font-size: 28rpx;
  215. }
  216. .search-btn {
  217. width: 120rpx;
  218. background-color: #3291F8;
  219. margin-left: 20rpx;
  220. line-height: 60rpx;
  221. text-align: center;
  222. color: #fff;
  223. font-size: 28rpx;
  224. border-radius: 10rpx;
  225. }
  226. }
  227. .serve {
  228. width: 100%;
  229. display: flex;
  230. align-items: stretch;
  231. .scroll-lable {
  232. width: 200rpx;
  233. .lable {
  234. width: 100%;
  235. height: 60rpx;
  236. font-size: 30rpx;
  237. line-height: 60rpx;
  238. text-align: center;
  239. border-left: 6rpx solid transparent;
  240. padding: 0 10rpx;
  241. }
  242. .active-lable {
  243. color: #3291F8;
  244. font-weight: 600;
  245. border-left-color: #3291F8;
  246. }
  247. }
  248. .scroll-val {
  249. width: calc(100% - 200rpx);
  250. padding: 0 0 0 20rpx;
  251. .val-content {
  252. // height: 300px;
  253. }
  254. .val-name {
  255. font-size: 30rpx;
  256. padding: 15rpx 0;
  257. }
  258. .val {
  259. width: 100%;
  260. height: 100rpx;
  261. padding: 0 20rpx;
  262. border: 1rpx solid #F0F0F0;
  263. display: flex;
  264. justify-content: space-between;
  265. align-items: center;
  266. margin-bottom: 20rpx;
  267. .val-text {
  268. flex: 1;
  269. width: 1px;
  270. font-size: 30rpx;
  271. }
  272. .val-icon {
  273. width: 34rpx;
  274. height: 34rpx;
  275. }
  276. }
  277. }
  278. }
  279. .matter-loading {
  280. padding-top: 50rpx;
  281. text-align: center;
  282. }
  283. }
  284. </style>