index.vue 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. <script setup lang="ts">
  2. import type { Paging } from '@/model/base'
  3. import type { Article, ArticleParams, Category, CreateCarousalsRequest, Recommends } from '@/model/pet-manual'
  4. import carousalApi from '@/api/carousal'
  5. import CardList from '@/pages/pet-manual/components/CardList.vue'
  6. import circle from '@/static/image/feed-plan/circle.png'
  7. import message from '@/static/image/feed-plan/message.png'
  8. import ToolApi from '@/utils'
  9. interface DotStyle {
  10. backgroundColor: string
  11. selectedBackgroundColor: string
  12. selectedBorder: string
  13. border: string
  14. }
  15. const listModel = ref<Article[]>([])
  16. const safeHeight = ToolApi.getSafeHeight()
  17. const searchValue = ref<string>('')
  18. const cardState = ref<'update' | 'updatePage'>('update')
  19. const info = ref<CreateCarousalsRequest[]>([
  20. {
  21. imageUrl: '',
  22. targetId: '',
  23. targetType: '',
  24. targetUrl: '',
  25. },
  26. ])
  27. const current = ref<number>(0)
  28. const dotStyle = ref<DotStyle>({
  29. backgroundColor: '#DCDCDC',
  30. selectedBackgroundColor: '#0052D9',
  31. selectedBorder: 'none',
  32. border: 'none',
  33. })
  34. function change(e: CustomEvent<{ current: number }>): void {
  35. current.value = e.detail.current
  36. }
  37. const typeList = ref<Category[]>([])
  38. const articleParams = ref<ArticleParams>({
  39. page: 1,
  40. size: 10,
  41. title: '',
  42. categoryId: '',
  43. })
  44. const articlePaging = ref<Paging>({
  45. page: 1,
  46. size: 10,
  47. total: 0,
  48. })
  49. async function handleClickType(item: Category) {
  50. typeList.value.forEach(i => (i.isClick = false))
  51. item.isClick = true
  52. articleParams.value.categoryId = item.id
  53. cardState.value = 'update'
  54. await updateArticleList()
  55. }
  56. const isSearch = ref<boolean>(true)
  57. const isSearchSource = ref<boolean>(false)
  58. function handleSearchFocus() {
  59. isSearch.value = false
  60. isSearchSource.value = false
  61. updateSearchList()
  62. }
  63. async function handleSearchBlur() {
  64. if (searchValue.value !== '') {
  65. isSearchSource.value = true
  66. reset()
  67. articleParams.value.title = searchValue.value
  68. await updateArticleList()
  69. }
  70. }
  71. function handleSearchKeyword(keyword: string): void {
  72. searchValue.value = keyword
  73. handleSearchBlur()
  74. }
  75. async function handleCancel() {
  76. isSearch.value = true
  77. reset()
  78. articleParams.value.categoryId = typeList.value.filter(item => item.isClick === true)[0].id
  79. await updateArticleList()
  80. }
  81. function handleSearchClear() {
  82. isSearchSource.value = false
  83. }
  84. const historyList = ref<string[]>([])
  85. const findList = ref<Recommends[]>([])
  86. async function updateArticleList() {
  87. const articleListApi = await carousalApi.getArticleList(articleParams.value)
  88. if (cardState.value === 'update') {
  89. listModel.value = articleListApi.data
  90. }
  91. else if (cardState.value === 'updatePage') {
  92. listModel.value.push(...articleListApi.data)
  93. }
  94. else {
  95. listModel.value = articleListApi.data
  96. }
  97. articlePaging.value = articleListApi.pagination
  98. }
  99. async function handleLoadArticle() {
  100. articleParams.value.page += 1
  101. cardState.value = 'updatePage'
  102. await updateArticleList()
  103. }
  104. async function updateSearchList() {
  105. historyList.value = await carousalApi.getSearchRecords()
  106. findList.value = await carousalApi.getSearchRecommends()
  107. }
  108. async function init() {
  109. info.value = await carousalApi.getCarousalList()
  110. typeList.value = (await carousalApi.getTypeList()).map((item, index) => {
  111. return {
  112. name: item.name,
  113. id: item.id,
  114. code: item.code,
  115. isClick: index === 0,
  116. }
  117. })
  118. articleParams.value.categoryId = typeList.value[0].id
  119. await updateArticleList()
  120. await updateSearchList()
  121. }
  122. function reset() {
  123. articleParams.value = {
  124. page: 1,
  125. size: 10,
  126. title: '',
  127. categoryId: '',
  128. }
  129. listModel.value = []
  130. }
  131. function handleJumpUrl(item: CreateCarousalsRequest) {
  132. if (item.targetType === 'url') {
  133. uni.navigateTo({
  134. url: item.targetUrl,
  135. })
  136. }
  137. }
  138. init()
  139. </script>
  140. <template>
  141. <view class="flex flex-col bg-[#F5F6F7] overflow-y-auto" :style="`height:calc(100vh - ${safeHeight}px)`">
  142. <view class="mx-[6px]">
  143. <uni-search-bar
  144. v-model="searchValue"
  145. placeholder="请搜索你想要的内容"
  146. bg-color="white" clear-button="auto"
  147. :cancel-button="isSearch ? 'none' : 'always'"
  148. :radius="20"
  149. @focus="handleSearchFocus"
  150. @cancel="handleCancel"
  151. @blur="handleSearchBlur"
  152. @clear="handleSearchClear"
  153. />
  154. </view>
  155. <view v-show="!isSearch" class=" mt-4">
  156. <view v-show="!isSearchSource" class="mx-4">
  157. <text class="text-[18px] font-600">
  158. 历史记录
  159. </text>
  160. <view class="mt-4 flex gap-2 flex-wrap text-[12px] text-[#999] font-400 leading-5">
  161. <view v-for="(item, index) in historyList" :key="index" class="px-2 py-0.5 flex justify-center items-center bg-[white] rounded-sm" @click="handleSearchKeyword(item)">
  162. {{ item }}
  163. </view>
  164. </view>
  165. <view class="mt-8">
  166. <text class="text-[18px] font-600">
  167. 搜索发现
  168. </text>
  169. <view class="mt-4 flex gap-2 flex-wrap text-[12px] text-[#999] font-400 leading-5">
  170. <view v-for="(item, index) in findList" :key="index" class="px-2 py-0.5 flex justify-center items-center bg-[white] rounded-sm gap-1" @click="handleSearchKeyword(item.keyword)">
  171. <view class="flex items-center justify-center">
  172. <uni-icons color="#999999" size="14" type="search" />
  173. </view>
  174. <view class="flex items-center justify-center">
  175. {{ item.keyword }}
  176. </view>
  177. </view>
  178. </view>
  179. </view>
  180. </view>
  181. <CardList v-show="isSearchSource" :card-list="listModel" @load-more="handleLoadArticle" />
  182. </view>
  183. <view v-show="isSearch">
  184. <view class="ml-4 mt-4 text-[20px] font-600">
  185. 热门推荐
  186. </view>
  187. <view class="mx-4 mt-4">
  188. <uni-swiper-dot :info="info" :current="current" field="content" mode="dot" :dots-styles="dotStyle">
  189. <swiper class="swiper-box" @change="change">
  190. <swiper-item v-for="(item, index) in info" :key="index">
  191. <view class="swiper-item w-full h-full flex items-center justify-center">
  192. <image :src="item.imageUrl" mode="heightFix" class="w-full h-full" @tap="handleJumpUrl(item)" />
  193. </view>
  194. </swiper-item>
  195. </swiper>
  196. </uni-swiper-dot>
  197. </view>
  198. <view class="ml-4 mt-5 text-[20px] font-600">
  199. 养宠贴士
  200. </view>
  201. <view class="mx-4 sticky top-0 bg-[#f5f6f7]">
  202. <scroll-view class="scroll mt-2" scroll-x="auto">
  203. <view class="group h-[40px] mt-1">
  204. <view
  205. v-for="(item, index) in typeList" :key="index" class="item h-[30px] w-[28%] rounded-15px relative" style="border: 1px solid #E7E7E7"
  206. @tap="handleClickType(item)"
  207. >
  208. <view v-if="item.isClick">
  209. <image :src="message" class="absolute w-full" style="height: calc(100% + 5px)" />
  210. <image :src="circle" class="w-[14px] h-[14px] absolute right-2 top-[-4px]" />
  211. </view>
  212. <view class="w-full h-full flex items-center justify-center text-[14px] z-20 relative font-600" :class="item.isClick ? 'type_select_span' : 'type_span'">
  213. {{ item.name }}
  214. </view>
  215. </view>
  216. </view>
  217. </scroll-view>
  218. </view>
  219. <CardList :card-list="listModel" @load-more="handleLoadArticle" />
  220. </view>
  221. </view>
  222. </template>
  223. <style scoped>
  224. .scroll{
  225. box-sizing: border-box;
  226. .group{
  227. white-space: nowrap;
  228. .item{
  229. display: inline-block;
  230. margin-right: 10px;
  231. }
  232. }
  233. }
  234. .type_span{
  235. color:#999
  236. }
  237. .type_select_span{
  238. color:#FFF
  239. }
  240. </style>