index.vue 31 KB

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