index.vue 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. <template>
  2. <view class="facility">
  3. <wd-sticky :z-index="10">
  4. <view class="facility-top">
  5. <wd-search :placeholder-left="true" placeholder="请输入内容" v-model="state.text">
  6. <template #suffix>
  7. <view style="display: flex;align-items: center;margin: 0 20rpx;">
  8. <view style="margin-right: 20rpx;">
  9. <wd-button size="small" @click="onClickSearch">
  10. 搜索
  11. </wd-button>
  12. </view>
  13. <view>
  14. <wd-button type="info" size="small" @click="onClickReset">
  15. 重置
  16. </wd-button>
  17. </view>
  18. </view>
  19. </template>
  20. </wd-search>
  21. <wd-tabs slidable="always" v-model="state.tabValue">
  22. <wd-tab v-for="(item, index) in state.tabList" :title="item.label" :key="index" />
  23. </wd-tabs>
  24. </view>
  25. </wd-sticky>
  26. <view class="facility-list">
  27. <view class="facility-list-item" v-for="(item, index) in state.list" :key="index"
  28. @click="onClickNavigate(item.id)">
  29. <view class="facility-list-item-sign">
  30. {{ item.sign }}
  31. </view>
  32. <wd-img height="300rpx" mode="heightFix" :src="item.url" />
  33. <view style="padding: 0 10rpx;">
  34. <view class="facility-list-item-title">
  35. {{ item.title }}
  36. </view>
  37. <view class="facility-list-item-text">
  38. {{ item.description }}
  39. </view>
  40. </view>
  41. </view>
  42. </view>
  43. </view>
  44. </template>
  45. <script lang="ts" setup>
  46. import { reactive } from 'vue';
  47. import { onShow, onReachBottom } from '@dcloudio/uni-app';
  48. import { apis } from '@/apis';
  49. interface State {
  50. text?: string,
  51. tabValue?: string,
  52. tabList: {
  53. label: string,
  54. value: string,
  55. }[],
  56. list: {
  57. id: string,
  58. url: string,
  59. sign: string,
  60. title: string,
  61. description: string,
  62. }[],
  63. page: {
  64. pageNum: number,
  65. pageSize: number,
  66. total: number,
  67. },
  68. };
  69. const state = reactive<State>({
  70. text: undefined,
  71. tabValue: undefined,
  72. tabList: [],
  73. list: [],
  74. page: {
  75. pageNum: 1,
  76. pageSize: 20,
  77. total: 0,
  78. },
  79. });
  80. const api = {
  81. // 获取区域列表
  82. fetchRegionList: async () => {
  83. try {
  84. const data = {
  85. dictType: 'region_type',
  86. };
  87. const res = await apis.fetchRegionList(data);
  88. const list = res.rows.map((item: any) => {
  89. return {
  90. label: item.dictLabel,
  91. value: item.dictValue,
  92. }
  93. });
  94. state.tabValue = list.length ? list[0].value : undefined;
  95. state.tabList = list;
  96. } catch (error: any) {
  97. console.error(error);
  98. }
  99. },
  100. // 获取设施列表
  101. fetchFacilityList: async (concat?: boolean) => {
  102. uni.showLoading({
  103. title: '加载中',
  104. });
  105. try {
  106. const data = {
  107. facilitiesTitle: state.text,
  108. dictType: state.tabValue,
  109. pageNum: state.page.pageNum,
  110. pageSize: state.page.pageSize,
  111. };
  112. const res = await apis.fetchFacilityList(data);
  113. const list = res.rows.map((item: any) => {
  114. return {
  115. id: item.facilitiesId,
  116. url: item.sysimg[0].url,
  117. sign: item.facilitiesName,
  118. title: item.facilitiesTitle,
  119. description: item.facilitiesDesc,
  120. };
  121. });
  122. state.list = concat ? state.list.concat(list) : list;
  123. state.page = {
  124. ...state.page,
  125. total: res.total,
  126. };
  127. } catch (error: any) {
  128. console.error(error);
  129. } finally {
  130. uni.hideLoading();
  131. }
  132. },
  133. }
  134. const init = async () => {
  135. uni.showLoading({
  136. title: '加载中',
  137. });
  138. // 获取区域列表
  139. api.fetchRegionList();
  140. // 获取设施列表
  141. api.fetchFacilityList();
  142. uni.hideLoading();
  143. };
  144. onShow(() => {
  145. state.page = {
  146. ...state.page,
  147. pageNum: 1,
  148. };
  149. init();
  150. });
  151. const onChangePagination = async () => {
  152. const { pageNum, pageSize, total } = state.page;
  153. if (total > pageNum * pageSize) {
  154. state.page = {
  155. ...state.page,
  156. pageNum: pageNum + 1,
  157. }
  158. // 获取设施列表
  159. await api.fetchFacilityList(true);
  160. }
  161. }
  162. onReachBottom(() => {
  163. onChangePagination();
  164. });
  165. // 点击搜索
  166. const onClickSearch = async () => {
  167. state.page = {
  168. ...state.page,
  169. pageNum: 1,
  170. };
  171. // 获取设施列表
  172. await api.fetchFacilityList();
  173. }
  174. // 点击重置
  175. const onClickReset = async () => {
  176. state.text = undefined;
  177. state.tabValue = undefined
  178. state.page = {
  179. ...state.page,
  180. pageNum: 1,
  181. };
  182. // 获取设施列表
  183. await api.fetchFacilityList();
  184. }
  185. // 点击跳转
  186. const onClickNavigate = (id: string) => {
  187. uni.navigateTo({
  188. url: `/pages/facility/facilityDetail/index?id=${id}`,
  189. });
  190. }
  191. </script>
  192. <style lang="scss" scoped>
  193. .facility {
  194. &-top {
  195. width: 100vw;
  196. border-bottom: 2rpx solid $border-color;
  197. }
  198. &-list {
  199. padding: 0 20rpx;
  200. display: flex;
  201. flex-wrap: wrap;
  202. margin-top: 20rpx;
  203. &-item {
  204. width: calc(50% - 10rpx);
  205. background: #F4F4F4;
  206. border-radius: $border-radius-base;
  207. margin-bottom: 20rpx;
  208. position: relative;
  209. overflow: hidden;
  210. &-sign {
  211. width: 85%;
  212. height: 50rpx;
  213. padding: 0 10rpx;
  214. background: rgba(0, 0, 0, 0.4);
  215. border-top-right-radius: $border-radius-base;
  216. display: flex;
  217. align-items: center;
  218. font-size: $font-size-mini;
  219. color: #FFFFFF;
  220. overflow: hidden;
  221. white-space: nowrap;
  222. text-overflow: ellipsis;
  223. position: absolute;
  224. top: 250rpx;
  225. left: 0;
  226. z-index: 2;
  227. }
  228. &-title {
  229. font-weight: bold;
  230. display: -webkit-box;
  231. -webkit-box-orient: vertical;
  232. -webkit-line-clamp: 2;
  233. line-clamp: 2;
  234. overflow: hidden;
  235. text-overflow: ellipsis;
  236. margin-bottom: 10rpx;
  237. }
  238. &-text {
  239. width: 100%;
  240. max-height: 300rpx;
  241. color: $gray-color;
  242. overflow: hidden;
  243. margin-bottom: 10rpx;
  244. }
  245. }
  246. &-item:nth-child(odd) {
  247. margin-right: 10rpx;
  248. }
  249. &-item:nth-child(even) {
  250. margin-left: 10rpx;
  251. }
  252. }
  253. }
  254. </style>