guide.vue 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  1. <template>
  2. <div class="solve">
  3. <div class="solve-head">
  4. <div class="head-bos">
  5. <div class="nav-bos flex-row-start">
  6. <div
  7. @click="onNav(item)"
  8. v-for="(item, index) in navList"
  9. :key="index"
  10. class="nav-list"
  11. :class="item.id == httpObj.tweetCategory ? 'hig' : ''"
  12. >
  13. {{ item.categoryName }}
  14. </div>
  15. </div>
  16. <div class="filter-bos">
  17. <div v-for="(item1, index1) in filterListy" :key="index1" class="filter-list flex-row-start">
  18. <div class="filter-title">{{ item1.title }}</div>
  19. <div
  20. @click="onFilter(item1, item2)"
  21. v-for="(item2, index2) in item1.list"
  22. :key="index2"
  23. class="filter-item"
  24. :class="item1.id == item2.id ? 'hig' : ''"
  25. >
  26. {{ item2.title }}
  27. </div>
  28. </div>
  29. </div>
  30. </div>
  31. </div>
  32. <!-- 数据 -->
  33. <div class="data-bos">
  34. <div v-for="(item, index) in dataList" :key="index" class="data-list" @click="onPath('/plan_info/guide?id=' + item.id)">
  35. <el-image class="data-img" :src="item.coverImage" fit="cover" />
  36. <div class="data-box flex-column-between">
  37. <div>
  38. <div class="title ellipsis">{{ item.title }}</div>
  39. <div class="info ellipsis">{{ item.releaseTime }}</div>
  40. </div>
  41. <div class="text flex-row-start">
  42. <div>了解详情</div>
  43. <el-icon color="#e7000b" size="14" style="margin: 0 0 0 10px">
  44. <ArrowRight />
  45. </el-icon>
  46. </div>
  47. </div>
  48. </div>
  49. <div class="flex-row-center w100%" v-if="dataList.length === 0">
  50. <el-empty description="暂无数据" />
  51. </div>
  52. </div>
  53. <!-- 游标分页控制 -->
  54. <div class="table-pagination flex-row-between">
  55. <div></div>
  56. <TablePagination v-model:page="httpObj.pageNum" v-model:page-size="httpObj.pageSize" :total="total" @change="getList" />
  57. </div>
  58. </div>
  59. </template>
  60. <script setup lang="ts">
  61. import { onPath } from '@/utils/siteConfig';
  62. import {
  63. getPurchaseGuideList,
  64. getPurchaseCategoryList,
  65. getAdaptSceneList,
  66. getCustomerIndustry,
  67. getPriceRangeList,
  68. getCustomerTag
  69. } from '@/api/plan/index';
  70. import Pagination from '@/components/Pagination/index.vue';
  71. const httpObj = ref<any>({
  72. tweetCategory: '',
  73. adaptNo: '',
  74. adaptIndustry: '',
  75. price: '',
  76. lable: '',
  77. pageSize: 10,
  78. pageNum: 1
  79. });
  80. const dataList = ref<any>([]);
  81. const hasMore = ref(true); // 是否还有更多数据
  82. const total = ref(0);
  83. const navList = ref<any>([
  84. { title: '专题分类' },
  85. { title: '大中型企业采购' },
  86. { title: '政府&公共采购' },
  87. { title: '营销福利' },
  88. { title: '商用工程' },
  89. { title: '中小型企业采购' }
  90. ]);
  91. const filterListy = ref<any>([
  92. {
  93. title: '适配场景',
  94. key: 'adaptNo',
  95. id: '',
  96. list: [
  97. {
  98. id: '',
  99. title: '全部'
  100. }
  101. ]
  102. },
  103. {
  104. title: '适配行业',
  105. key: 'adaptIndustry',
  106. id: '',
  107. list: [
  108. {
  109. id: '',
  110. title: '全部'
  111. }
  112. ]
  113. },
  114. {
  115. title: '价格区间',
  116. key: 'price',
  117. id: '',
  118. list: [
  119. {
  120. id: '',
  121. title: '全部'
  122. }
  123. ]
  124. },
  125. {
  126. title: '推荐标签',
  127. key: 'lable',
  128. id: '',
  129. list: [
  130. {
  131. id: '',
  132. title: '全部'
  133. }
  134. ]
  135. }
  136. ]);
  137. onMounted(() => {
  138. // 采购分类列表
  139. getPurchaseCategoryList({}).then((res) => {
  140. if (res.code == 200) {
  141. res.data.unshift({
  142. id: '',
  143. categoryName: '全部'
  144. });
  145. navList.value = res.data;
  146. httpObj.value.tweetCategory = '';
  147. }
  148. });
  149. // 适配场景列表
  150. getAdaptSceneList({}).then((res) => {
  151. if (res.code == 200) {
  152. res.data.forEach((item: any) => {
  153. item.title = item.sceneName;
  154. filterListy.value[0].list.push(item);
  155. });
  156. }
  157. });
  158. //适配行业
  159. getCustomerIndustry({}).then((res) => {
  160. if (res.code == 200) {
  161. res.data.forEach((item: any) => {
  162. item.title = item.industryCategoryName;
  163. filterListy.value[1].list.push(item);
  164. });
  165. }
  166. });
  167. // 获取价格区间列表
  168. getPriceRangeList({}).then((res) => {
  169. if (res.code == 200) {
  170. res.data.forEach((item: any) => {
  171. item.title = item.minPrice + '-' + item.maxPrice;
  172. item.id = item.minPrice + '-' + item.maxPrice;
  173. filterListy.value[2].list.push(item);
  174. });
  175. }
  176. });
  177. // 推荐标签
  178. getCustomerTag({}).then((res) => {
  179. if (res.code == 200) {
  180. res.data.forEach((item: any) => {
  181. item.title = item.tagName;
  182. filterListy.value[3].list.push(item);
  183. });
  184. }
  185. });
  186. getList();
  187. });
  188. const getList = () => {
  189. getPurchaseGuideList(httpObj.value).then((res) => {
  190. if (res.code == 200) {
  191. dataList.value = res.rows;
  192. total.value = res.total;
  193. }
  194. });
  195. };
  196. const onNav = (item: any) => {
  197. httpObj.value.tweetCategory = item.id;
  198. getList();
  199. };
  200. const onFilter = (item1: any, item2: any) => {
  201. item1.id = item2.id;
  202. httpObj.value[item1.key] = item2.id;
  203. getList();
  204. };
  205. const handleSizeChange = (val: number) => {
  206. console.log(`${val} items per page`);
  207. };
  208. const handleCurrentChange = (val: number) => {
  209. console.log(`current page: ${val}`);
  210. };
  211. </script>
  212. <style lang="scss" scoped>
  213. // 定义响应式容器 Mixin
  214. @mixin responsive-container {
  215. width: 100%;
  216. min-width: 1200px;
  217. max-width: 1500px;
  218. margin: 0 auto;
  219. box-sizing: border-box;
  220. }
  221. .solve {
  222. width: 100%;
  223. .solve-head {
  224. width: 100%;
  225. background: #ffffff;
  226. .head-bos {
  227. width: 100%;
  228. min-width: 1200px;
  229. max-width: 1500px;
  230. margin: 0 auto;
  231. padding-bottom: 20px;
  232. }
  233. }
  234. .nav-bos {
  235. border-bottom: 1px solid #e5e7eb;
  236. width: 100%;
  237. min-width: 1200px;
  238. max-width: 1500px;
  239. .nav-list {
  240. height: 32px;
  241. padding: 0 12px;
  242. background: #f7f8fa;
  243. border-radius: 2px 2px 2px 2px;
  244. font-size: 14px;
  245. color: #4e5969;
  246. margin-right: 8px;
  247. margin-bottom: 10px; // 换行时的间距
  248. line-height: 32px;
  249. cursor: pointer;
  250. &.hig {
  251. background: #ffe8e8;
  252. color: #e7000b;
  253. }
  254. &:hover {
  255. color: #e7000b;
  256. }
  257. }
  258. }
  259. .filter-bos {
  260. .filter-list {
  261. margin-top: 20px;
  262. .filter-title {
  263. font-size: 14px;
  264. color: #101828;
  265. margin-right: 40px;
  266. }
  267. .filter-item {
  268. font-size: 14px;
  269. color: #364153;
  270. margin-right: 30px;
  271. cursor: pointer;
  272. &.hig {
  273. color: #e7000b;
  274. }
  275. &:hover {
  276. color: var(--el-color-primary);
  277. }
  278. &:last-child {
  279. margin-right: 0;
  280. }
  281. }
  282. }
  283. }
  284. // 数据列表
  285. .data-bos {
  286. @include responsive-container;
  287. display: flex;
  288. gap: 20px;
  289. flex-wrap: wrap;
  290. padding: 22px 0 40px 0;
  291. justify-content: space-between; // 均匀分布
  292. .data-list {
  293. // 计算宽度:每行3个。 (100% - 2个间隙 * 20px) / 3
  294. width: calc((100% - 40px) / 3);
  295. height: 302px;
  296. background: #ffffff;
  297. border-radius: 5px;
  298. overflow: hidden;
  299. cursor: pointer;
  300. transition:
  301. transform 0.2s ease,
  302. box-shadow 0.2s ease;
  303. display: flex;
  304. flex-direction: column;
  305. &:hover {
  306. transform: translateY(-2px);
  307. box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
  308. .title {
  309. color: #e7000b !important;
  310. }
  311. }
  312. .data-img {
  313. width: 100%;
  314. height: 200px;
  315. object-fit: cover; // 保持图片比例填充
  316. }
  317. .data-box {
  318. flex: 1; // 占据剩余高度
  319. width: 100%;
  320. padding: 12px 20px;
  321. box-sizing: border-box;
  322. display: flex;
  323. flex-direction: column;
  324. justify-content: space-between;
  325. .title {
  326. font-weight: 600;
  327. font-size: 14px;
  328. color: #101828;
  329. line-height: 1.4;
  330. }
  331. .info {
  332. font-size: 12px;
  333. color: #364153;
  334. margin-top: 4px;
  335. line-height: 1.4;
  336. // 限制显示两行,超出省略
  337. display: -webkit-box;
  338. -webkit-line-clamp: 2;
  339. -webkit-box-orient: vertical;
  340. overflow: hidden;
  341. }
  342. .text {
  343. font-size: 14px;
  344. color: #e7000b;
  345. margin-top: auto; // 推到底部
  346. }
  347. }
  348. }
  349. }
  350. .table-pagination {
  351. @include responsive-container;
  352. padding-bottom: 30px;
  353. }
  354. }
  355. </style>