siteServeH6.vue 9.1 KB

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