index copy.vue 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984
  1. <template>
  2. <view :style="{ height: windowHeight + 'px' }">
  3. <!-- <view style="display: flex; justify-content: flex-end">
  4. <view class="view0 step1"></view>
  5. </view>
  6. <view class="view1 step2"></view>
  7. <view class="view2 step3"></view>
  8. <view class="view3 step4"></view>
  9. <view class="view4 step5"></view>
  10. <view class="view5 step6"></view>
  11. <view style="display: flex; justify-content: flex-end">
  12. <view class="view6 step7"></view>
  13. </view> -->
  14. <z-paging :use-custom-refresher="false" ref="paging" v-model="dataList" :auto="false"
  15. :style="{ height: windowHeight - 80 + 'px' }" :show-scrollbar="false" :refresher-enabled="true"
  16. @refresherrefresh="onRefresh" @refresherrestore="onRefresherRestore" @query="queryLists" :fixed="true"
  17. :safe-area-inset-bottom="true" :loading-more-enabled="true" :loading-more-no-more-text="'没有更多了'"
  18. :loading-more-loading-text="'加载中...'" :loading-more-fail-text="'加载失败,点击重试'" :loading-more-default-text="'上拉加载更多'"
  19. :loading-more-loading-style="{ color: '#999' }" :loading-more-no-more-style="{ color: '#999' }"
  20. :loading-more-fail-style="{ color: '#999' }" :loading-more-default-style="{ color: '#999' }"
  21. @loadingMore="onLoadingMore">
  22. <template #top>
  23. <page-navbar>
  24. <template #navCenter>
  25. <view class="top" style="display: flex">
  26. <!-- 手动选择城市功能隐藏 -->
  27. <!-- <view class="topBox" @click="lhSelectCityFun"> -->
  28. <view class="topBox" @click="lhSelectCityFun">
  29. <text style="
  30. margin-left: 10rpx;
  31. margin-right: 20rpx;
  32. font-size: 44rpx;
  33. font-weight: 600;
  34. ">
  35. {{ currentCity }}
  36. </text>
  37. <!-- <image src="@/static/home/home-bom.png"
  38. style="width: 36rpx; height: 36rpx;margin-left: 15rpx;margin-right: 30rpx;"></image> -->
  39. </view>
  40. <view class="weather">
  41. <p>
  42. {{ weather.weather }}<i :class="'qi-' + weather.icon"></i>️{{
  43. weather.temp
  44. }}
  45. </p>
  46. <p>{{ getDayOfWeek }}</p>
  47. </view>
  48. </view>
  49. <view class="search" @click="goPage('/pages/index/Search')">
  50. <uv-input placeholder="🔥 潮玩大作战 派对季重磅开启!" border="none"
  51. :custom-style="{ background: '#fff', paddingLeft: '25rpx' }" shape="circle">
  52. <image class="testImg" src="@/static/home/icon-hot.png" style="width: 22rpx; height: 30rpx"></image>
  53. <template #suffix>
  54. <view class="input-box">
  55. <image src="@/static/icon/search.png" style="width: 32rpx; height: 32rpx">
  56. </image>
  57. </view>
  58. </template>
  59. </uv-input>
  60. </view>
  61. </template>
  62. </page-navbar>
  63. </template>
  64. <z-paging-cell class="benner-box">
  65. <sortble :default-sorts="['uvSwiper', 'classModel', 'uvSwiperCard']">
  66. <template #uvSwiper>
  67. <uv-swiper :list="bannerList" :autoplay="true" circular :interval="5000" indicator indicator-mode="dot"
  68. height="200" radius="0"></uv-swiper>
  69. </template>
  70. <template #classModel>
  71. <view class="classModel">
  72. <image src="@/static/home/benner-iconBom.png" class="benner-iconBom" mode=""></image>
  73. <image src="@/static/home/benner-icontop.png" class="benner-icontop" mode=""></image>
  74. <view class="benner-box benner-left-box" @click="goPage('/pages/my/job')">
  75. <view class="text1"> 获取奖励 </view>
  76. <view class="btn"> 立即前往 </view>
  77. </view>
  78. <view class="benner-box benner-right-box" ref="classModel1">
  79. <view class="guard">
  80. <view class="text"> 潮玩IP </view>
  81. </view>
  82. <view class="match">
  83. <view class="text"> 社交 </view>
  84. </view>
  85. </view>
  86. </view>
  87. </template>
  88. </sortble>
  89. </z-paging-cell>
  90. <z-paging-cell style="background: #fff">
  91. <view class="tab-nav">
  92. <view v-for="(tab, index) in tabs" :key="index" :class="['tab-item', currentTab === index ? 'active' : '']"
  93. @click="switchTab(index)">
  94. {{ tab }}
  95. <view class="indicator-triangle"> </view>
  96. </view>
  97. </view>
  98. <SwipeDetector @swipeLeft="swipeLeft()" @swipeRight="swipeRight()">
  99. <!-- 根据当前标签显示不同样式的列表 -->
  100. <!-- 关注列表 - 类似my.vue -->
  101. <view v-show="currentTab === 0" class="follow-list">
  102. <block v-if="followList.length > 0">
  103. <w-waterfall :data="followList">
  104. <template v-slot:content="{ item, width }">
  105. <card :item="formatItem(item)" :width="width" :custom-style="{ background: '#fff' }" textColor="#000">
  106. </card>
  107. </template>
  108. </w-waterfall>
  109. </block>
  110. <view class="no-data" v-else-if="!isLoadingFollow">
  111. <text>暂无关注数据</text>
  112. </view>
  113. </view>
  114. <!-- 推荐列表 - 瀑布流样式 -->
  115. <template>
  116. <w-waterfall v-show="currentTab === 1 && recommendList.length > 0" :data="recommendList">
  117. <template v-slot:content="{ item, width }">
  118. <card :item="formatItem(item)" :width="width" :custom-style="{ background: '#fff' }" textColor="#000">
  119. </card>
  120. </template>
  121. </w-waterfall>
  122. <view class="no-data" v-if="
  123. currentTab === 1 &&
  124. recommendList.length === 0 &&
  125. !isLoadingRecommend
  126. ">
  127. <text>暂无推荐数据</text>
  128. </view>
  129. </template>
  130. <!-- 探索列表 - 热点新闻已经有现成的热搜资讯组件,只需添加新闻列表 -->
  131. <template>
  132. <view v-if="currentTab === 2" class="hot-topics">
  133. <view class="hot-topics-header">
  134. <image class="hot-topics-title" src="@/static/home/hot-topics-title.png" mode=""></image>
  135. </view>
  136. <swiper class="hot-topics-swiper" :current="currentTopicPage" @change="handleTopicPageChange">
  137. <swiper-item v-for="(page, pageIndex) in topicPages" :key="pageIndex">
  138. <view class="hot-topics-list">
  139. <view v-for="(topic, index) in page" :key="index" class="topic-item"
  140. @click="goToArticleDetail(topic.id)">
  141. <view class="hot-topics-left">
  142. <image v-if="pageIndex * 4 + index == 0" src="@/static/icon/icon-first.png"
  143. class="topic-index topic-index-img" mode=""></image>
  144. <image v-else-if="pageIndex * 4 + index == 1" src="@/static/icon/icon-second.png"
  145. class="topic-index topic-index-img" mode=""></image>
  146. <image v-else-if="pageIndex * 4 + index == 2" src="@/static/icon/icon-third.png"
  147. class="topic-index topic-index-img" mode=""></image>
  148. <text v-else class="topic-index">{{
  149. pageIndex * 4 + index + 1
  150. }}</text>
  151. <view class="topic-content toe">
  152. {{ topic.title }}
  153. </view>
  154. <image v-if="topic.isHot" src="@/static/icon/icon-hot.png" class="hot-tag" mode=""></image>
  155. </view>
  156. <text class="topic-participants">{{ topic.num_like }}人正在热议</text>
  157. </view>
  158. </view>
  159. </swiper-item>
  160. </swiper>
  161. <view class="indicator-dots">
  162. <view v-for="i in 2" :key="i" :class="['dot', currentTopicPage === i - 1 ? 'active' : '']">
  163. </view>
  164. </view>
  165. </view>
  166. <view v-show="currentTab === 2 && newsList.length > 0" class="news-list">
  167. <w-waterfall v-show="currentTab === 2 && newsList.length > 0" :data="newsList">
  168. <template v-slot:content="{ item, width }">
  169. <card :item="formatItem(item)" :width="width" goLink="/pages/index/articleDetail?id="
  170. :custom-style="{ background: '#fff' }" textColor="#000"></card>
  171. </template>
  172. </w-waterfall>
  173. </view>
  174. <view class="no-data" v-if="currentTab === 2 && newsList.length === 0 && !isLoadingNews">
  175. <text>暂无新闻数据</text>
  176. </view>
  177. </template>
  178. </SwipeDetector>
  179. </z-paging-cell>
  180. <view class="blankHeight"></view>
  181. </z-paging>
  182. <tabbar-vue :tabbars="tabbars" :currentIndex="0" ref="tabbar"></tabbar-vue>
  183. <!-- 添加浮动按钮 -->
  184. <view v-if="currentTab === 2" class="float-btn" @click="goToMake">
  185. <image src="/static/home/release-btn.png" class="float-btn-icon"></image>
  186. </view>
  187. <!-- <novice-guidance :step="step"></novice-guidance> -->
  188. <lhSelectCity style="height: 100vh" class="lhSelectCity" :currentCity="currentCity" :windowHeight="windowHeight"
  189. :hotCitys="hotCitys" @onSelect="City" v-if="lhSelectCityFalg" @closeLhSelectCityFun="closeLhSelectCityFun()" />
  190. </view>
  191. </template>
  192. <script>
  193. import sortble from "@/components/sortble/sortble.vue";
  194. import tabbarVue from "@/components/tabbar/tabbar.vue";
  195. import pageNavbar from "@/components/page-navbar/page-navbar.vue";
  196. import wWaterfall from "@/components/w-waterfall/w-waterfall.vue";
  197. import tabbar from "@/mixins/tabbar";
  198. import card from "@/components/card/card.vue";
  199. import lhSelectCity from "@/components/lh-select-city/index.vue";
  200. import { getStorage, setStorage, removeStorage } from "@/common/util.js";
  201. // import noviceGuidance from "@/components/novice-guidance/index.vue";
  202. export default {
  203. components: {
  204. sortble,
  205. tabbarVue,
  206. pageNavbar,
  207. wWaterfall,
  208. lhSelectCity,
  209. card,
  210. // noviceGuidance
  211. },
  212. mixins: [tabbar],
  213. data() {
  214. return {
  215. isFirstLoad: true, // 添加标记,用于判断是否是第一次加载
  216. step: {
  217. name: "workbenchSet5",
  218. guideList: [
  219. {
  220. el: ".step1",
  221. tips: "这里是第一步的介绍~",
  222. next: "下一步",
  223. },
  224. {
  225. el: ".step2",
  226. tips: "这里是第二步的介绍~",
  227. next: "下一步",
  228. },
  229. {
  230. el: ".step3",
  231. tips: "这里是第三步的介绍~",
  232. next: "下一步",
  233. },
  234. {
  235. el: ".step4",
  236. tips: "这里是第四步的介绍~",
  237. next: "下一步",
  238. },
  239. {
  240. el: ".step5",
  241. tips: "这里是第五步的介绍~",
  242. next: "下一步",
  243. },
  244. {
  245. el: ".step6",
  246. tips: "这里是第六步的介绍~",
  247. next: "下一步",
  248. },
  249. {
  250. el: ".step7",
  251. tips: "最后一步啦~",
  252. next: "完成",
  253. },
  254. ],
  255. },
  256. windowHeight: uni.getWindowInfo().windowHeight,
  257. bannerList: [
  258. "../../static/dome/home-swper.png",
  259. "../../static/dome/home-swper.png",
  260. "../../static/dome/home-swper.png",
  261. ],
  262. cardList: [
  263. {
  264. img: "/static/img/img-1.png",
  265. bgimg: "/static/image/bg-2.png",
  266. },
  267. {
  268. img: "/static/img/img-3.png",
  269. bgimg: "/static/image/bg-3.png",
  270. },
  271. {
  272. img: "/static/img/img-2.png",
  273. bgimg: "/static/image/bg-1.png",
  274. },
  275. ],
  276. list: [], // 瀑布流全部数据
  277. dataList: [],
  278. tabs: ["关注", "推荐", "探索"],
  279. currentTab: 1,
  280. currentTopicPage: 0,
  281. followList: [], // 关注列表数据
  282. recommendList: [], // 推荐列表数据
  283. exploreList: [], // 探索列表数据
  284. hotNewsList: [], // 热点新闻数据
  285. newsList: [], // 新闻列表数据
  286. followOffset: 0, // 关注列表偏移量
  287. recommendOffset: 0, // 推荐列表偏移量
  288. exploreOffset: 0, // 探索列表偏移量
  289. newsOffset: 0, // 新闻列表偏移量
  290. hasMoreFollow: true, // 是否有更多关注列表数据
  291. hasMoreRecommend: true, // 是否有更多推荐列表数据
  292. hasMoreExplore: true, // 是否有更多探索列表数据
  293. hasMoreNews: true, // 是否有更多新闻列表数据
  294. isLoadingFollow: false, // 是否正在加载关注列表
  295. isLoadingRecommend: false, // 是否正在加载推荐列表
  296. isLoadingExplore: false, // 是否正在加载探索列表
  297. isLoadingNews: false, // 是否正在加载新闻列表
  298. hotTopics: [],
  299. lhSelectCityFalg: false,
  300. hotCitys: [
  301. "杭州",
  302. "天津",
  303. "北京",
  304. "上海",
  305. "深圳",
  306. "广州",
  307. "成都",
  308. "重庆",
  309. "厦门",
  310. ],
  311. currentCity: "北京",
  312. windowHeight: "",
  313. weather: {
  314. city: "",
  315. weather: "",
  316. temp: "0℃",
  317. icon: 101,
  318. },
  319. isContentRecommendation: true,
  320. };
  321. },
  322. computed: {
  323. getDayOfWeek() {
  324. const days = [
  325. "星期日",
  326. "星期一",
  327. "星期二",
  328. "星期三",
  329. "星期四",
  330. "星期五",
  331. "星期六",
  332. ];
  333. const today = new Date();
  334. const dayOfWeek = days[today.getDay()];
  335. return dayOfWeek;
  336. },
  337. currentList() {
  338. switch (this.currentTab) {
  339. case 0:
  340. return this.followList;
  341. case 1:
  342. return this.recommendList; // 使用专门的推荐列表
  343. case 2:
  344. return this.exploreList;
  345. default:
  346. return [];
  347. }
  348. },
  349. topicPages() {
  350. const pages = [];
  351. for (let i = 0; i < this.hotTopics.length; i += 4) {
  352. pages.push(this.hotTopics.slice(i, i + 4));
  353. }
  354. return pages;
  355. },
  356. },
  357. onLoad() {
  358. let that = this;
  359. // 计算出可用高度
  360. this.windowHeight = uni.getSystemInfoSync().windowHeight + "px";
  361. // 不在onLoad中直接加载数据,避免与z-paging组件重复请求
  362. // 让z-paging组件通过queryList方法控制数据加载
  363. this.getWeather();
  364. // this.queryList();
  365. },
  366. onShow() {
  367. var isContentRecommendation = getStorage("isContentRecommendation");
  368. console.log(isContentRecommendation, "isContentRecommendation");
  369. if (isContentRecommendation != "false") {
  370. isContentRecommendation = true;
  371. } else {
  372. isContentRecommendation = false;
  373. }
  374. this.isContentRecommendation = isContentRecommendation;
  375. if (isContentRecommendation == false) {
  376. this.tabs = ["关注"];
  377. this.currentTab = 0;
  378. this.queryList();
  379. } else {
  380. this.tabs = ["关注", "推荐", "探索"];
  381. this.currentTab = 1;
  382. }
  383. },
  384. // 修改触底加载方法
  385. onReachBottom() {
  386. console.log('触底加载更多');
  387. // 根据当前标签页加载更多数据
  388. switch (this.currentTab) {
  389. case 0:
  390. if (this.hasMoreFollow && !this.isLoadingFollow) {
  391. this.loadFollowList();
  392. }
  393. break;
  394. case 1:
  395. if (this.hasMoreRecommend && !this.isLoadingRecommend) {
  396. this.loadRecommendList();
  397. }
  398. break;
  399. case 2:
  400. if (this.hasMoreNews && !this.isLoadingNews) {
  401. this.loadNewsList();
  402. }
  403. break;
  404. }
  405. },
  406. // 下拉刷新数据
  407. methods: {
  408. swipeRight() {
  409. let index =this.currentTab
  410. index--
  411. if (index < 0) {
  412. index =this.tabs.length-1
  413. }
  414. this.switchTab(index)
  415. console.log('向右滑动')
  416. },
  417. swipeLeft() {
  418. let index =this.currentTab
  419. index++
  420. if (index>this.tabs.length-1) {
  421. index=0
  422. }
  423. this.switchTab(index)
  424. console.log('向左滑动')
  425. },
  426. getWeather(city) {
  427. uni.request({
  428. url: this.$apiHost + "/Index/getAreaInfo",
  429. data: {
  430. uuid: getApp().globalData.uuid,
  431. skey: getApp().globalData.skey,
  432. city: city || (this.currentCity == "北京" ? "" : this.currentCity),
  433. },
  434. header: {
  435. "content-type": "application/json",
  436. sign: getApp().globalData.headerSign,
  437. },
  438. success: (res) => {
  439. console.log(this.weather, "天气数据", res.data);
  440. if (res.data.city) {
  441. this.currentCity = res.data.city;
  442. this.weather = res.data;
  443. }
  444. },
  445. complete: () => { },
  446. fail: (e) => { },
  447. });
  448. },
  449. lhSelectCityFun() {
  450. this.lhSelectCityFalg = true;
  451. },
  452. // 选中事件
  453. City(city) {
  454. this.currentCity = city;
  455. setTimeout(() => {
  456. this.lhSelectCityFalg = false;
  457. }, 300);
  458. },
  459. closeLhSelectCityFun() {
  460. this.lhSelectCityFalg = false;
  461. },
  462. queryList() {
  463. // 根据当前标签刷新数据
  464. switch (this.currentTab) {
  465. case 0:
  466. // 重置关注列表
  467. this.followList = [];
  468. this.followOffset = 0;
  469. this.hasMoreFollow = true;
  470. this.loadFollowList();
  471. break;
  472. case 1:
  473. // 重置推荐列表
  474. this.recommendList = [];
  475. this.recommendOffset = 0;
  476. this.hasMoreRecommend = true;
  477. this.loadRecommendList();
  478. break;
  479. case 2:
  480. // 重置热点新闻和新闻列表
  481. this.hotNewsList = [];
  482. this.newsList = [];
  483. this.newsOffset = 0;
  484. this.hasMoreNews = true;
  485. // 加载热点新闻和新闻列表
  486. this.loadHotNews();
  487. this.loadNewsList();
  488. break;
  489. }
  490. },
  491. queryLists() {
  492. // 根据当前标签刷新数据
  493. switch (this.currentTab) {
  494. case 0:
  495. // 重置关注列表
  496. // this.followList = [];
  497. // this.followOffset = 0;
  498. // this.hasMoreFollow = true;
  499. this.loadFollowList();
  500. break;
  501. case 1:
  502. // 重置推荐列表
  503. // this.recommendList = [];
  504. // this.recommendOffset = 0;
  505. // this.hasMoreRecommend = true;
  506. this.loadRecommendList();
  507. break;
  508. case 2:
  509. // 重置热点新闻和新闻列表
  510. // this.hotNewsList = [];
  511. // this.newsList = [];
  512. // this.newsOffset = 0;
  513. // this.hasMoreNews = true;
  514. // 加载热点新闻和新闻列表
  515. this.loadHotNews();
  516. // this.loadNewsList();
  517. break;
  518. }
  519. // 第一次加载完成后,将标记设置为false
  520. this.isFirstLoad = false;
  521. },
  522. switchTab(index) {
  523. if (this.currentTab === index) return;
  524. this.currentTab = index;
  525. // 重置当前标签页的数据
  526. switch (index) {
  527. case 0:
  528. this.followList = [];
  529. this.followOffset = 0;
  530. this.hasMoreFollow = true;
  531. break;
  532. case 1:
  533. this.recommendList = [];
  534. this.recommendOffset = 0;
  535. this.hasMoreRecommend = true;
  536. break;
  537. case 2:
  538. this.newsList = [];
  539. this.hotTopics = [];
  540. this.newsOffset = 0;
  541. this.hasMoreNews = true;
  542. break;
  543. }
  544. // 加载新标签页的数据
  545. this.loadTabData(index);
  546. },
  547. loadTabData(index) {
  548. switch (index) {
  549. case 0:
  550. this.loadFollowList();
  551. break;
  552. case 1:
  553. this.loadRecommendList();
  554. break;
  555. case 2:
  556. this.loadHotNews();
  557. this.loadNewsList();
  558. break;
  559. }
  560. },
  561. // 修改关注列表加载方法
  562. loadFollowList() {
  563. if (this.isLoadingFollow) return;
  564. this.isLoadingFollow = true;
  565. // 保存当前列表数据
  566. const currentList = [...this.followList];
  567. uni.request({
  568. url: this.$apiHost + "/Work/getlist",
  569. data: {
  570. uuid: getApp().globalData.uuid,
  571. skey: getApp().globalData.skey,
  572. type: "attention",
  573. offset: this.followOffset,
  574. },
  575. header: {
  576. "content-type": "application/json",
  577. sign: getApp().globalData.headerSign,
  578. },
  579. success: (res) => {
  580. console.log("关注列表数据:", res.data);
  581. if (res.data.success == "yes" && res.data.list && res.data.list.length > 0) {
  582. // 使用 Vue.set 确保响应式更新
  583. if (this.followOffset === 0) {
  584. this.followList = res.data.list;
  585. } else {
  586. // 使用 Vue.set 更新数组,避免数据闪烁
  587. this.followList = currentList.concat(res.data.list);
  588. }
  589. this.followOffset += res.data.list.length;
  590. this.hasMoreFollow = res.data.list.length >= 20;
  591. } else {
  592. this.hasMoreFollow = false;
  593. }
  594. // 使用 nextTick 确保数据更新后再通知组件
  595. this.$nextTick(() => {
  596. if (this.$refs.paging) {
  597. this.$refs.paging.complete(this.followList);
  598. }
  599. });
  600. },
  601. complete: () => {
  602. this.isLoadingFollow = false;
  603. },
  604. fail: (e) => {
  605. console.log("请求关注列表失败:", e);
  606. this.isLoadingFollow = false;
  607. if (this.$refs.paging) {
  608. this.$refs.paging.complete(false);
  609. }
  610. },
  611. });
  612. },
  613. // 修改推荐列表加载方法
  614. loadRecommendList() {
  615. if (this.isLoadingRecommend) return;
  616. this.isLoadingRecommend = true;
  617. // 保存当前列表数据
  618. const currentList = [...this.recommendList];
  619. uni.request({
  620. url: this.$apiHost + "/Work/getlist",
  621. data: {
  622. uuid: getApp().globalData.uuid,
  623. skey: getApp().globalData.skey,
  624. type: "recommend",
  625. offset: this.recommendOffset,
  626. },
  627. header: {
  628. "content-type": "application/json",
  629. sign: getApp().globalData.headerSign,
  630. },
  631. success: (res) => {
  632. console.log("推荐列表数据:", res.data);
  633. if (res.data.success == "yes" && res.data.list && res.data.list.length > 0) {
  634. if (this.recommendOffset === 0) {
  635. this.recommendList = res.data.list;
  636. } else {
  637. this.recommendList = currentList.concat(res.data.list);
  638. }
  639. this.recommendOffset += res.data.list.length;
  640. this.hasMoreRecommend = res.data.list.length >= 20;
  641. } else {
  642. this.hasMoreRecommend = false;
  643. }
  644. this.$nextTick(() => {
  645. if (this.$refs.paging) {
  646. this.$refs.paging.complete(this.recommendList);
  647. }
  648. });
  649. },
  650. complete: () => {
  651. this.isLoadingRecommend = false;
  652. },
  653. fail: (e) => {
  654. console.log("请求推荐列表失败:", e);
  655. this.isLoadingRecommend = false;
  656. if (this.$refs.paging) {
  657. this.$refs.paging.complete(false);
  658. }
  659. },
  660. });
  661. },
  662. loadHotNews() {
  663. if (this.isLoadingExplore) return;
  664. this.isLoadingExplore = true;
  665. uni.request({
  666. url: this.$apiHost + "/Article/getlist",
  667. data: {
  668. uuid: getApp().globalData.uuid,
  669. skey: getApp().globalData.skey,
  670. type: "hot",
  671. },
  672. header: {
  673. "content-type": "application/json",
  674. sign: getApp().globalData.headerSign,
  675. },
  676. success: (res) => {
  677. console.log("热点新闻数据:", res.data);
  678. if (res.data.success == "yes" && res.data.list && res.data.list.length > 0) {
  679. this.hotNewsList = res.data.list;
  680. this.hotTopics = this.hotNewsList.map((item, index) => ({
  681. id: item.id,
  682. title: item.title || "热门话题",
  683. num_like: item.num_like || 0,
  684. isHot: index % 2 === 0,
  685. }));
  686. }
  687. },
  688. complete: () => {
  689. this.isLoadingExplore = false;
  690. },
  691. fail: (e) => {
  692. console.log("请求热点新闻失败:", e);
  693. this.isLoadingExplore = false;
  694. },
  695. });
  696. },
  697. // 修改新闻列表加载方法
  698. loadNewsList() {
  699. if (this.isLoadingNews) return;
  700. this.isLoadingNews = true;
  701. // 保存当前列表数据
  702. const currentList = [...this.newsList];
  703. uni.request({
  704. url: this.$apiHost + "/Article/getlist",
  705. data: {
  706. uuid: getApp().globalData.uuid,
  707. skey: getApp().globalData.skey,
  708. type: "list",
  709. offset: this.newsOffset,
  710. },
  711. header: {
  712. "content-type": "application/json",
  713. sign: getApp().globalData.headerSign,
  714. },
  715. success: (res) => {
  716. console.log("新闻列表数据:", res.data);
  717. if (res.data.success == "yes" && res.data.list && res.data.list.length > 0) {
  718. if (this.newsOffset === 0) {
  719. this.newsList = res.data.list;
  720. } else {
  721. this.newsList = currentList.concat(res.data.list);
  722. }
  723. this.newsOffset += res.data.list.length;
  724. console.log(this.newsOffset, "新闻列表数据");
  725. this.hasMoreNews = res.data.list.length >= 20;
  726. } else {
  727. this.hasMoreNews = false;
  728. }
  729. this.$nextTick(() => {
  730. if (this.$refs.paging) {
  731. this.$refs.paging.complete(this.newsList);
  732. }
  733. });
  734. },
  735. complete: () => {
  736. this.isLoadingNews = false;
  737. },
  738. fail: (e) => {
  739. console.log("请求新闻列表失败:", e);
  740. this.isLoadingNews = false;
  741. if (this.$refs.paging) {
  742. this.$refs.paging.complete(false);
  743. }
  744. },
  745. });
  746. },
  747. handleTopicPageChange(e) {
  748. this.currentTopicPage = e.detail.current;
  749. },
  750. formatItem(item) {
  751. console.log("item:", item);
  752. let img = "";
  753. if (item.images) {
  754. img = item.images.split("|")[0];
  755. }
  756. // 处理接口返回的数据,使其适配card组件
  757. return {
  758. id: item.id,
  759. allowEdit: false,
  760. nickname: item.nickname,
  761. avator: item.avator,
  762. num_like: item.num_like,
  763. num_view: item.num_view,
  764. image: img || item.img_url || item.image, // 优先使用images字段
  765. w: item.width,
  766. h: item.height,
  767. title: item.title || "",
  768. desc: item.desc || "",
  769. userID: item.userID || 0,
  770. backgroundColor: "#f6f6f6",
  771. };
  772. },
  773. downloadAndProcessImage(imageUrl, width = 10, height = 10) {
  774. return new Promise((resolve, reject) => {
  775. uni.downloadFile({
  776. url: imageUrl,
  777. success: (downloadResult) => {
  778. if (downloadResult.statusCode === 200) {
  779. const tempFilePath = downloadResult.tempFilePath;
  780. const ctx = uni.createCanvasContext("myCanvas", this);
  781. ctx.drawImage(tempFilePath, 0, 0, width, height);
  782. ctx.draw(false, () => {
  783. uni.canvasGetImageData({
  784. canvasId: "myCanvas",
  785. x: 0,
  786. y: 0,
  787. width: width,
  788. height: height,
  789. success: (res) => {
  790. const data = res.data;
  791. let r = 0,
  792. g = 0,
  793. b = 0;
  794. for (let i = 0; i < data.length; i += 4) {
  795. r += data[i];
  796. g += data[i + 1];
  797. b += data[i + 2];
  798. }
  799. const count = width * height;
  800. r = Math.floor(r / count);
  801. g = Math.floor(g / count);
  802. b = Math.floor(b / count);
  803. resolve({
  804. r,
  805. g,
  806. b,
  807. });
  808. },
  809. fail: (err) => {
  810. reject(err);
  811. },
  812. });
  813. });
  814. } else {
  815. reject(new Error("下载图像失败"));
  816. }
  817. },
  818. fail: (err) => {
  819. reject(err);
  820. },
  821. });
  822. });
  823. },
  824. goToArticleDetail(id) {
  825. if (!id) {
  826. uni.showToast({
  827. title: "文章ID不存在",
  828. icon: "none",
  829. });
  830. return;
  831. }
  832. // uni.$emit("check_login", () => {
  833. uni.navigateTo({
  834. url: "/pages/index/articleDetail?id=" + id,
  835. });
  836. // });
  837. },
  838. goWork(item) {
  839. console.log("skeylogin", "xxx");
  840. uni.$emit("check_login", () => {
  841. uni.navigateTo({
  842. url: "/pages/index/workDetail?id=" + item.id,
  843. });
  844. });
  845. },
  846. goToMake() {
  847. console.log("skeylogin", "xxx2");
  848. uni.$emit("check_login", () => {
  849. uni.navigateTo({
  850. // 生成个人形象
  851. // url: "/pages/make/make",
  852. url: "/pages/make/fabuArticle?id=-1",
  853. });
  854. });
  855. },
  856. goPage(page) {
  857. uni.$emit("check_login", () => {
  858. uni.navigateTo({
  859. url: page,
  860. });
  861. });
  862. },
  863. // 修改下拉刷新方法
  864. onRefresh() {
  865. console.log('下拉刷新开始');
  866. // 重置所有数据
  867. this.followList = [];
  868. this.recommendList = [];
  869. this.newsList = [];
  870. this.hotTopics = [];
  871. // 重置偏移量
  872. this.followOffset = 0;
  873. this.recommendOffset = 0;
  874. this.newsOffset = 0;
  875. // 重置加载状态
  876. this.hasMoreFollow = true;
  877. this.hasMoreRecommend = true;
  878. this.hasMoreNews = true;
  879. // 根据当前标签页加载数据
  880. this.loadTabData(this.currentTab);
  881. },
  882. // 下拉刷新恢复
  883. onRefresherRestore() {
  884. console.log('下拉刷新恢复');
  885. },
  886. // 触底加载更多时的回调
  887. onLoadingMore() {
  888. // 如果不是第一次加载,且没有更多数据时显示提示
  889. if (!this.isFirstLoad) {
  890. switch (this.currentTab) {
  891. case 0:
  892. if (this.followList.length === 0) {
  893. uni.showToast({
  894. title: '暂无更多关注内容',
  895. icon: 'none',
  896. duration: 2000
  897. });
  898. }
  899. break;
  900. case 1:
  901. if (this.recommendList.length === 0) {
  902. uni.showToast({
  903. title: '暂无更多推荐内容',
  904. icon: 'none',
  905. duration: 2000
  906. });
  907. }
  908. break;
  909. case 2:
  910. if (this.newsList.length === 0) {
  911. uni.showToast({
  912. title: '暂无更多新闻内容',
  913. icon: 'none',
  914. duration: 2000
  915. });
  916. }
  917. break;
  918. }
  919. }
  920. },
  921. },
  922. };
  923. </script>
  924. <style lang="scss">
  925. @import "index.scss";
  926. // 添加过渡效果样式
  927. .fade-enter-active,
  928. .fade-leave-active {
  929. transition: opacity 0.3s;
  930. }
  931. .fade-enter,
  932. .fade-leave-to {
  933. opacity: 0;
  934. }
  935. // 确保列表项有最小高度,避免闪烁
  936. .list-item {
  937. min-height: 200rpx;
  938. background: #fff;
  939. margin-bottom: 20rpx;
  940. border-radius: 12rpx;
  941. overflow: hidden;
  942. }
  943. </style>
  944. <style>
  945. @import "@/style/qweather-icons.css";
  946. </style>