index.vue 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840
  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 ref="paging" v-model="dataList" @query="queryList" :style="{ height: windowHeight - 80 + 'px' }"
  15. :show-scrollbar="false">
  16. <template #top >
  17. <page-navbar>
  18. <template #navCenter>
  19. <view class="top" style=" display: flex;">
  20. <view class="topBox">
  21. <text style="margin-left: 10rpx; font-size: 44rpx;font-weight: 600;"> 杭州 </text>
  22. <image src="@/static/home/home-bom.png"
  23. style="width: 36rpx; height: 36rpx;margin-left: 15rpx;margin-right: 30rpx;"></image>
  24. </view>
  25. <view class="weather">
  26. <p>多云🌤️20℃</p>
  27. <p>星期五</p>
  28. </view>
  29. </view>
  30. <view class="search">
  31. <uv-input placeholder="“潮玩大作战” 派对季重磅开启!" border="none"
  32. :custom-style="{ background: '#fff', paddingLeft: '25rpx' }" shape="circle">
  33. <image src="@/static/icon/fiery.png" style="width: 22rpx; height: 30rpx"></image>
  34. <template #suffix>
  35. <view class="input-box">
  36. <image src="@/static/icon/search.png" style="width: 32rpx; height: 32rpx">
  37. </image>
  38. </view>
  39. </template>
  40. </uv-input>
  41. </view>
  42. </template>
  43. </page-navbar>
  44. </template>
  45. <z-paging-cell class="benner-box">
  46. <sortble :default-sorts="['uvSwiper', 'classModel', 'uvSwiperCard']">
  47. <template #uvSwiper>
  48. <uv-swiper :list="bannerList" :autoplay="true" circular :interval="5000" indicator
  49. indicator-mode="dot" height="200" radius="0"></uv-swiper>
  50. </template>
  51. <template #classModel>
  52. <view class="classModel">
  53. <image src="@/static/home/benner-iconBom.png" class="benner-iconBom" mode=""></image>
  54. <image src="@/static/home/benner-icontop.png" class="benner-icontop" mode=""></image>
  55. <view class="benner-box benner-left-box">
  56. <view class="text1">
  57. 获取奖励
  58. </view>
  59. <view class="btn">
  60. 立即前往
  61. </view>
  62. </view>
  63. <view class="benner-box benner-right-box" ref="classModel1"
  64. @click="goPage('/pages/my/job')">
  65. <view class="guard">
  66. <view class="text">
  67. 潮玩IP
  68. </view>
  69. </view>
  70. <view class="match">
  71. <view class="text">
  72. 社交
  73. </view>
  74. </view>
  75. </view>
  76. <!-- <view class="classModel-bg classModel-bg1" ref="classModel1"
  77. @click="goPage('/pages/my/job')">
  78. <image class="classModel-img" src="@/static/zhHans-text-icon/text-2.png" mode="">
  79. </image>
  80. </view>
  81. <view class="classModel-bg classModel-bg2" ref="classModel2">
  82. <image class="classModel-img" src="@/static/zhHans-text-icon/text-3.png" mode="">
  83. </image>
  84. </view>
  85. <view class="classModel-bg" ref="classModel3">
  86. <image class="classModel-img" src="@/static/zhHans-text-icon/text-4.png" mode="">
  87. </image>
  88. </view> -->
  89. </view>
  90. </template>
  91. </sortble>
  92. </z-paging-cell>
  93. <z-paging-cell>
  94. <view class="tab-nav">
  95. <view v-for="(tab, index) in tabs" :key="index"
  96. :class="['tab-item', currentTab === index ? 'active' : '']" @click="switchTab(index)">
  97. {{ tab }}
  98. <view class="indicator-triangle">
  99. </view>
  100. </view>
  101. </view>
  102. <view v-if="currentTab === 2" class="hot-topics">
  103. <view class="hot-topics-header">
  104. <!-- <text class="hot-topics-title">热搜资讯!</text> -->
  105. <image class="hot-topics-title" src="@/static/home/hot-topics-title.png" mode=""></image>
  106. </view>
  107. <swiper class="hot-topics-swiper" :current="currentTopicPage" @change="handleTopicPageChange">
  108. <swiper-item v-for="(page, pageIndex) in topicPages" :key="pageIndex">
  109. <view class="hot-topics-list">
  110. <view v-for="(topic, index) in page" :key="index" class="topic-item"
  111. @click="goToArticleDetail(topic.id)">
  112. <view class="hot-topics-left">
  113. <image v-if="(pageIndex * 4 + index) ==0" src="@/static/icon/icon-first.png" class="topic-index topic-index-img" mode=""></image>
  114. <image v-else-if="(pageIndex * 4 + index) ==1" src="@/static/icon/icon-second.png" class="topic-index topic-index-img" mode=""></image>
  115. <image v-else-if="(pageIndex * 4 + index) ==2" src="@/static/icon/icon-third.png" class="topic-index topic-index-img" mode=""></image>
  116. <text v-else class="topic-index">{{ pageIndex * 4 + index + 1 }}</text>
  117. <view class="topic-content toe">
  118. {{ topic.title }}
  119. </view>
  120. <image v-if="topic.isHot" src="@/static/icon/icon-hot.png" class="hot-tag" mode=""></image>
  121. </view>
  122. <text class="topic-participants">{{ topic.num_like }}人正在热议</text>
  123. <!-- <text class="topic-index">{{ pageIndex * 5 + index + 1 }}</text>
  124. <view class="topic-content">
  125. <view class="topic-title-row">
  126. <text class="topic-title">{{ topic.title }}</text>
  127. <text v-if="topic.isHot" class="hot-tag">HOT</text>
  128. </view>
  129. <text class="topic-participants">{{ topic.num_like }}人正在热议</text>
  130. </view> -->
  131. </view>
  132. </view>
  133. </swiper-item>
  134. </swiper>
  135. <view class="indicator-dots">
  136. <view v-for="i in 2" :key="i" :class="['dot', currentTopicPage === i - 1 ? 'active' : '']">
  137. </view>
  138. </view>
  139. </view>
  140. <!-- 根据当前标签显示不同样式的列表 -->
  141. <!-- 关注列表 - 类似my.vue -->
  142. <view v-show="currentTab === 0" class="follow-list">
  143. <block v-if="followList.length > 0">
  144. <!-- <view class="works-list">
  145. <view class="work-item" v-for="(item, index) in followList" :key="index"
  146. @click="goWork(item)">
  147. <image class="work-image" :src="item.images || item.img_url" mode="aspectFill"></image>
  148. <view class="work-title">{{
  149. item.title || "作品" + index
  150. }}</view>
  151. </view>
  152. </view> -->
  153. <w-waterfall :data="followList">
  154. <template v-slot:content="{ item, width }">
  155. <card :item="formatItem(item)" :width="width" :custom-style="{ background: '#fff' }"
  156. textColor="#000"></card>
  157. </template>
  158. </w-waterfall>
  159. </block>
  160. <view class="no-data" v-else-if="!isLoadingFollow">
  161. <text>暂无关注数据</text>
  162. </view>
  163. </view>
  164. <!-- 推荐列表 - 瀑布流样式 -->
  165. <w-waterfall v-show="currentTab === 1 && recommendList.length > 0" :data="recommendList">
  166. <template v-slot:content="{ item, width }">
  167. <card :item="formatItem(item)" :width="width" :custom-style="{ background: '#fff' }"
  168. textColor="#000"></card>
  169. </template>
  170. </w-waterfall>
  171. <!-- 探索列表 - 热点新闻已经有现成的热搜资讯组件,只需添加新闻列表 -->
  172. <view v-show="currentTab === 2 && newsList.length > 0" class="news-list">
  173. <!-- <view class="news-grid">
  174. <view class="news-item" v-for="(item, index) in newsList" :key="index"
  175. @click="goToArticleDetail(item.id)">
  176. <image class="news-image" :src="item.img_url || item.images" mode="aspectFill"></image>
  177. <view class="news-title">{{ item.title || "新闻标题" }}</view>
  178. <view class="news-footer">
  179. <view class="news-author">{{ item.author || "作者" }}</view>
  180. <view class="news-views">
  181. <image src="/static/icon/icon-4.png" class="view-icon"></image>
  182. <text>{{ item.num_view || "0" }}</text>
  183. </view>
  184. </view>
  185. </view>
  186. </view> -->
  187. <w-waterfall v-show="currentTab === 2 && newsList.length > 0" :data="newsList">
  188. <template v-slot:content="{ item, width }">
  189. <card :item="formatItem(item)" :width="width" :custom-style="{ background: '#fff' }"
  190. textColor="#000"></card>
  191. </template>
  192. </w-waterfall>
  193. </view>
  194. <view class="no-data" v-if=" currentTab === 1 && recommendList.length === 0 && !isLoadingRecommend ">
  195. <text>暂无推荐数据</text>
  196. </view>
  197. <view class="no-data" v-if="currentTab === 2 && newsList.length === 0 && !isLoadingNews">
  198. <text>暂无新闻数据</text>
  199. </view>
  200. </z-paging-cell>
  201. <view class="blankHeight"></view>
  202. </z-paging>
  203. <tabbar-vue :tabbars="tabbars" :currentIndex="0" ref="tabbar"></tabbar-vue>
  204. <!-- 添加浮动按钮 -->
  205. <view v-if="currentTab === 2" class="float-btn" @click="goToMake">
  206. <image src="/static/icon/icon_add_black.png" class="float-btn-icon"></image>
  207. </view>
  208. <novice-guidance :step="step"></novice-guidance>
  209. </view>
  210. </template>
  211. <script>
  212. import sortble from "@/components/sortble/sortble.vue";
  213. import tabbarVue from "@/components/tabbar/tabbar.vue";
  214. import pageNavbar from "@/components/page-navbar/page-navbar.vue";
  215. import wWaterfall from "@/components/w-waterfall/w-waterfall.vue";
  216. import tabbar from "@/mixins/tabbar";
  217. import card from "@/components/card/card.vue";
  218. // import noviceGuidance from "@/components/novice-guidance/index.vue";
  219. export default {
  220. components: {
  221. sortble,
  222. tabbarVue,
  223. pageNavbar,
  224. wWaterfall,
  225. // noviceGuidance
  226. },
  227. mixins: [tabbar],
  228. data() {
  229. return {
  230. step: {
  231. name: "workbenchSet5",
  232. guideList: [{
  233. el: ".step1",
  234. tips: "这里是第一步的介绍~",
  235. next: "下一步",
  236. },
  237. {
  238. el: ".step2",
  239. tips: "这里是第二步的介绍~",
  240. next: "下一步",
  241. },
  242. {
  243. el: ".step3",
  244. tips: "这里是第三步的介绍~",
  245. next: "下一步",
  246. },
  247. {
  248. el: ".step4",
  249. tips: "这里是第四步的介绍~",
  250. next: "下一步",
  251. },
  252. {
  253. el: ".step5",
  254. tips: "这里是第五步的介绍~",
  255. next: "下一步",
  256. },
  257. {
  258. el: ".step6",
  259. tips: "这里是第六步的介绍~",
  260. next: "下一步",
  261. },
  262. {
  263. el: ".step7",
  264. tips: "最后一步啦~",
  265. next: "完成",
  266. },
  267. ],
  268. },
  269. windowHeight: uni.getWindowInfo().windowHeight,
  270. bannerList: [
  271. "../../static/dome/home-swper.png",
  272. "../../static/dome/home-swper.png",
  273. "../../static/dome/home-swper.png",
  274. ],
  275. cardList: [{
  276. img: "/static/img/img-1.png",
  277. bgimg: "/static/image/bg-2.png",
  278. },
  279. {
  280. img: "/static/img/img-3.png",
  281. bgimg: "/static/image/bg-3.png",
  282. },
  283. {
  284. img: "/static/img/img-2.png",
  285. bgimg: "/static/image/bg-1.png",
  286. },
  287. ],
  288. list: [], // 瀑布流全部数据
  289. dataList: [],
  290. tabs: ["关注", "推荐", "探索"],
  291. currentTab: 1,
  292. currentTopicPage: 0,
  293. followList: [], // 关注列表数据
  294. recommendList: [], // 推荐列表数据
  295. exploreList: [], // 探索列表数据
  296. hotNewsList: [], // 热点新闻数据
  297. newsList: [], // 新闻列表数据
  298. followOffset: 0, // 关注列表偏移量
  299. recommendOffset: 0, // 推荐列表偏移量
  300. exploreOffset: 0, // 探索列表偏移量
  301. newsOffset: 0, // 新闻列表偏移量
  302. hasMoreFollow: true, // 是否有更多关注列表数据
  303. hasMoreRecommend: true, // 是否有更多推荐列表数据
  304. hasMoreExplore: true, // 是否有更多探索列表数据
  305. hasMoreNews: true, // 是否有更多新闻列表数据
  306. isLoadingFollow: false, // 是否正在加载关注列表
  307. isLoadingRecommend: false, // 是否正在加载推荐列表
  308. isLoadingExplore: false, // 是否正在加载探索列表
  309. isLoadingNews: false, // 是否正在加载新闻列表
  310. hotTopics: [],
  311. };
  312. },
  313. computed: {
  314. currentList() {
  315. switch (this.currentTab) {
  316. case 0:
  317. return this.followList;
  318. case 1:
  319. return this.recommendList; // 使用专门的推荐列表
  320. case 2:
  321. return this.exploreList;
  322. default:
  323. return [];
  324. }
  325. },
  326. topicPages() {
  327. const pages = [];
  328. for (let i = 0; i < this.hotTopics.length; i += 4) {
  329. pages.push(this.hotTopics.slice(i, i + 4));
  330. }
  331. return pages;
  332. },
  333. },
  334. onLoad() {
  335. let that = this;
  336. // 不在onLoad中直接加载数据,避免与z-paging组件重复请求
  337. // 让z-paging组件通过queryList方法控制数据加载
  338. },
  339. // 上拉加载更多
  340. onReachBottom() {
  341. this.loadMoreData();
  342. },
  343. // 下拉刷新数据
  344. methods: {
  345. queryList() {
  346. // 根据当前标签刷新数据
  347. switch (this.currentTab) {
  348. case 0:
  349. // 重置关注列表
  350. this.followList = [];
  351. this.followOffset = 0;
  352. this.hasMoreFollow = true;
  353. this.loadFollowList();
  354. break;
  355. case 1:
  356. // 重置推荐列表
  357. this.recommendList = [];
  358. this.recommendOffset = 0;
  359. this.hasMoreRecommend = true;
  360. this.loadRecommendList();
  361. break;
  362. case 2:
  363. // 重置热点新闻和新闻列表
  364. this.hotNewsList = [];
  365. this.newsList = [];
  366. this.newsOffset = 0;
  367. this.hasMoreNews = true;
  368. // 加载热点新闻和新闻列表
  369. this.loadHotNews();
  370. this.loadNewsList();
  371. break;
  372. }
  373. },
  374. async init() {
  375. const {
  376. data
  377. } = await this.getData();
  378. this.list.push.apply(this.list, data);
  379. },
  380. // 模拟的后端数据
  381. getData() {
  382. return new Promise((resolve) => {
  383. const imgs = [{
  384. url: "https://e.zhichao.art/AI_images/a_1112_10.png",
  385. },
  386. {
  387. url: "https://e.zhichao.art/AI_images/a_1112_108.png",
  388. },
  389. {
  390. url: "https://e.zhichao.art/AI_images/a_1112_113.png",
  391. },
  392. {
  393. url: "https://e.zhichao.art/AI_images/a_1112_13.png",
  394. },
  395. {
  396. url: "https://e.zhichao.art/AI_images/a_1112_137.png",
  397. },
  398. {
  399. url: "https://e.zhichao.art/AI_images/a_1112_141.png",
  400. },
  401. {
  402. url: "https://e.zhichao.art/AI_images/a_1114__562.png",
  403. },
  404. {
  405. url: "https://e.zhichao.art/AI_images/a_1114__568.png",
  406. },
  407. {
  408. url: "https://e.zhichao.art/AI_images/a_1114__569.png",
  409. },
  410. {
  411. url: "https://e.zhichao.art/AI_images/a_1114__570.png",
  412. },
  413. {
  414. url: "https://e.zhichao.art/AI_images/a_1114__571.png",
  415. },
  416. {
  417. url: "https://e.zhichao.art/AI_images/a_1114__575.png",
  418. },
  419. ];
  420. let list = [];
  421. const doFn = (i) => {
  422. const randomIndex = Math.floor(Math.random() * 10);
  423. return {
  424. allowEdit: i == 0,
  425. image: imgs[randomIndex].url,
  426. w: imgs[randomIndex].width,
  427. h: imgs[randomIndex].height,
  428. title: i % 2 == 0 ? `玛丽` : `凌音`,
  429. desc: i % 2 == 0 ?
  430. `欢迎使用uv-ui,uni-app生态专用的UI框架` : `开发者编写一套代码, 可发布到iOS、Android、H5、以及各种小程序`,
  431. };
  432. };
  433. // 模拟异步
  434. setTimeout(() => {
  435. for (let i = 0; i < 20; i++) {
  436. list.push(doFn(i));
  437. }
  438. resolve({
  439. data: list,
  440. });
  441. }, 200);
  442. });
  443. },
  444. switchTab(index) {
  445. this.currentTab = index;
  446. // Check if the target tab's list is already populated
  447. if (this.currentList.length > 0) {
  448. // If the list is already populated, do not fetch data again
  449. return;
  450. }
  451. // If the list is not populated, load the corresponding data
  452. this.loadTabData(index);
  453. },
  454. loadTabData(index) {
  455. switch (index) {
  456. case 0:
  457. if (!this.followList.length) {
  458. this.loadFollowList();
  459. }
  460. break;
  461. case 1:
  462. if (!this.recommendList.length) {
  463. this.loadRecommendList();
  464. }
  465. break;
  466. case 2:
  467. if (!this.hotNewsList.length) {
  468. this.loadHotNews();
  469. }
  470. if (!this.newsList.length) {
  471. this.loadNewsList();
  472. }
  473. break;
  474. }
  475. },
  476. loadFollowList() {
  477. if (this.isLoadingFollow) return;
  478. this.isLoadingFollow = true;
  479. uni.request({
  480. url: this.$apiHost + "/Work/getlist",
  481. data: {
  482. uuid: getApp().globalData.uuid,
  483. skey: getApp().globalData.skey,
  484. type: "attention", // 关注列表
  485. offset: this.followOffset,
  486. },
  487. header: {
  488. "content-type": "application/json",
  489. sign: getApp().globalData.headerSign,
  490. },
  491. success: (res) => {
  492. console.log("关注列表数据:", res.data);
  493. // 确保在任何情况下都完成加载
  494. if (
  495. res.data.success == "yes" &&
  496. res.data.list &&
  497. res.data.list.length > 0
  498. ) {
  499. // 只有当列表有数据时才追加
  500. this.followList = [...this.followList, ...res.data.list];
  501. this.followOffset += res.data.list.length;
  502. if (res.data.list.length < 20) {
  503. this.hasMoreFollow = false;
  504. }
  505. } else {
  506. // 如果列表为空,确保标记没有更多数据
  507. this.hasMoreFollow = false;
  508. }
  509. // 无论是否有数据,都需要通知z-paging组件完成刷新
  510. if (this.$refs.paging) {
  511. this.$refs.paging.complete(this.followList);
  512. }
  513. },
  514. complete: () => {
  515. this.isLoadingFollow = false;
  516. },
  517. fail: (e) => {
  518. console.log("请求关注列表失败:", e);
  519. this.isLoadingFollow = false;
  520. // 加载失败时也要通知组件完成
  521. if (this.$refs.paging) {
  522. this.$refs.paging.complete(false);
  523. }
  524. },
  525. });
  526. },
  527. loadRecommendList() {
  528. if (this.isLoadingRecommend) return;
  529. this.isLoadingRecommend = true;
  530. uni.request({
  531. url: this.$apiHost + "/Work/getlist",
  532. data: {
  533. uuid: getApp().globalData.uuid,
  534. skey: getApp().globalData.skey,
  535. type: "recommend", // 推荐列表
  536. offset: this.recommendOffset,
  537. },
  538. header: {
  539. "content-type": "application/json",
  540. sign: getApp().globalData.headerSign,
  541. },
  542. success: (res) => {
  543. console.log("推荐列表数据:", res.data);
  544. if (
  545. res.data.success == "yes" &&
  546. res.data.list &&
  547. res.data.list.length > 0
  548. ) {
  549. this.recommendList = [...this.recommendList, ...res.data.list];
  550. this.recommendOffset += res.data.list.length;
  551. if (res.data.list.length < 20) {
  552. this.hasMoreRecommend = false;
  553. }
  554. } else {
  555. this.hasMoreRecommend = false;
  556. }
  557. // 无论是否有数据,都需要通知z-paging组件完成刷新
  558. if (this.$refs.paging) {
  559. this.$refs.paging.complete(this.recommendList);
  560. }
  561. },
  562. complete: () => {
  563. this.isLoadingRecommend = false;
  564. },
  565. fail: (e) => {
  566. console.log("请求推荐列表失败:", e);
  567. this.isLoadingRecommend = false;
  568. // 加载失败时也要通知组件完成
  569. if (this.$refs.paging) {
  570. this.$refs.paging.complete(false);
  571. }
  572. },
  573. });
  574. },
  575. loadHotNews() {
  576. if (this.isLoadingExplore) return;
  577. this.isLoadingExplore = true;
  578. uni.request({
  579. url: this.$apiHost + "/Article/getlist",
  580. data: {
  581. uuid: getApp().globalData.uuid,
  582. skey: getApp().globalData.skey,
  583. type: "hot", // 热点新闻
  584. },
  585. header: {
  586. "content-type": "application/json",
  587. sign: getApp().globalData.headerSign,
  588. },
  589. success: (res) => {
  590. console.log("热点新闻数据:", res.data);
  591. if (
  592. res.data.success == "yes" &&
  593. res.data.list &&
  594. res.data.list.length > 0
  595. ) {
  596. this.hotNewsList = res.data.list;
  597. // 如果有热点新闻数据,更新热搜资讯
  598. if (this.hotNewsList.length > 0) {
  599. // 将API返回的热点新闻转换为热搜资讯格式
  600. this.hotTopics = this.hotNewsList.map((item, index) => {
  601. return {
  602. id: item.id,
  603. title: item.title || "热门话题",
  604. num_like: item.num_like || 0,
  605. isHot: index % 2 === 0, // 偶数索引的设为热点
  606. };
  607. });
  608. }
  609. }
  610. },
  611. complete: () => {
  612. this.isLoadingExplore = false;
  613. },
  614. fail: (e) => {
  615. console.log("请求热点新闻失败:", e);
  616. this.isLoadingExplore = false;
  617. },
  618. });
  619. },
  620. loadNewsList() {
  621. if (this.isLoadingNews) return;
  622. this.isLoadingNews = true;
  623. uni.request({
  624. url: this.$apiHost + "/Article/getlist",
  625. data: {
  626. uuid: getApp().globalData.uuid,
  627. skey: getApp().globalData.skey,
  628. type: "list", // 新闻列表
  629. offset: this.newsOffset,
  630. },
  631. header: {
  632. "content-type": "application/json",
  633. sign: getApp().globalData.headerSign,
  634. },
  635. success: (res) => {
  636. console.log("新闻列表数据:", res.data);
  637. if (
  638. res.data.success == "yes" &&
  639. res.data.list &&
  640. res.data.list.length > 0
  641. ) {
  642. this.newsList = [...this.newsList, ...res.data.list];
  643. this.newsOffset += res.data.list.length;
  644. if (res.data.list.length < 20) {
  645. this.hasMoreNews = false;
  646. }
  647. } else {
  648. this.hasMoreNews = false;
  649. }
  650. // 无论是否有数据,都需要通知z-paging组件完成刷新
  651. if (this.$refs.paging) {
  652. this.$refs.paging.complete(this.newsList);
  653. }
  654. },
  655. complete: () => {
  656. this.isLoadingNews = false;
  657. },
  658. fail: (e) => {
  659. console.log("请求新闻列表失败:", e);
  660. this.isLoadingNews = false;
  661. // 加载失败时也要通知组件完成
  662. if (this.$refs.paging) {
  663. this.$refs.paging.complete(false);
  664. }
  665. },
  666. });
  667. },
  668. loadMoreData() {
  669. // 根据当前标签加载更多数据
  670. switch (this.currentTab) {
  671. case 0:
  672. if (this.hasMoreFollow && !this.isLoadingFollow) {
  673. this.loadFollowList();
  674. }
  675. break;
  676. case 1:
  677. if (this.hasMoreRecommend && !this.isLoadingRecommend) {
  678. this.loadRecommendList();
  679. }
  680. break;
  681. case 2:
  682. if (this.hasMoreNews && !this.isLoadingNews) {
  683. this.loadNewsList();
  684. }
  685. break;
  686. }
  687. },
  688. handleTopicPageChange(e) {
  689. this.currentTopicPage = e.detail.current;
  690. },
  691. formatItem(item) {
  692. this.downloadAndProcessImage(item.images)
  693. .then((color) => {
  694. console.log(`平均颜色: R=${color.r}, G=${color.g}, B=${color.b}`);
  695. })
  696. .catch((error) => {
  697. console.error("获取图像失败:", error);
  698. });
  699. // 处理接口返回的数据,使其适配card组件
  700. return {
  701. id: item.id,
  702. allowEdit: false,
  703. author: item.author,
  704. num_like: item.num_like,
  705. num_view: item.num_view,
  706. image: item.images || item.img_url || item.image, // 优先使用images字段
  707. w: item.width,
  708. h: item.height,
  709. title: item.title || "",
  710. desc: item.desc || "",
  711. backgroundColor: "#f6f6f6",
  712. };
  713. },
  714. downloadAndProcessImage(imageUrl, width = 10, height = 10) {
  715. return new Promise((resolve, reject) => {
  716. uni.downloadFile({
  717. url: imageUrl,
  718. success: (downloadResult) => {
  719. if (downloadResult.statusCode === 200) {
  720. const tempFilePath = downloadResult.tempFilePath;
  721. const ctx = uni.createCanvasContext('myCanvas', this);
  722. ctx.drawImage(tempFilePath, 0, 0, width, height);
  723. ctx.draw(false, () => {
  724. uni.canvasGetImageData({
  725. canvasId: 'myCanvas',
  726. x: 0,
  727. y: 0,
  728. width: width,
  729. height: height,
  730. success: (res) => {
  731. const data = res.data;
  732. let r = 0,
  733. g = 0,
  734. b = 0;
  735. for (let i = 0; i < data.length; i +=
  736. 4) {
  737. r += data[i];
  738. g += data[i + 1];
  739. b += data[i + 2];
  740. }
  741. const count = width * height;
  742. r = Math.floor(r / count);
  743. g = Math.floor(g / count);
  744. b = Math.floor(b / count);
  745. resolve({
  746. r,
  747. g,
  748. b
  749. });
  750. },
  751. fail: (err) => {
  752. reject(err);
  753. }
  754. });
  755. });
  756. } else {
  757. reject(new Error('下载图像失败'));
  758. }
  759. },
  760. fail: (err) => {
  761. reject(err);
  762. }
  763. });
  764. });
  765. },
  766. goToArticleDetail(id) {
  767. if (!id) {
  768. uni.showToast({
  769. title: "文章ID不存在",
  770. icon: "none",
  771. });
  772. return;
  773. }
  774. uni.$emit("check_login", () => {
  775. uni.navigateTo({
  776. url: "/pages/index/articleDetail?id=" + id,
  777. });
  778. });
  779. },
  780. goWork(item) {
  781. console.log("skeylogin", "xxx");
  782. uni.$emit("check_login", () => {
  783. uni.navigateTo({
  784. url: "/pages/index/workDetail?id=" + item.id,
  785. });
  786. });
  787. },
  788. goToMake() {
  789. console.log("skeylogin", "xxx2");
  790. uni.$emit("check_login", () => {
  791. uni.navigateTo({
  792. url: "/pages/make/make",
  793. });
  794. });
  795. },
  796. goPage(page) {
  797. uni.$emit("check_login", () => {
  798. uni.navigateTo({
  799. url: page,
  800. });
  801. });
  802. },
  803. },
  804. };
  805. </script>
  806. <style lang="scss">
  807. @import "index.scss";
  808. </style>