index.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505
  1. <template>
  2. <div class="search-pages">
  3. <div v-if="httpObj.searchKeyword && type == 1" class="breadcrumb flex-row-center">
  4. <div class="breadcrumb-bos flex-row-start">
  5. <div class="home" @click="onPath('/index')">首页</div>
  6. <div class="nav-list">
  7. <el-icon style="margin: 0 4px">
  8. <ArrowRight />
  9. </el-icon>
  10. <div class="like">搜索结果</div>
  11. </div>
  12. <el-icon style="margin: 0 4px">
  13. <ArrowRight />
  14. </el-icon>
  15. <div>{{ httpObj.searchKeyword || '' }}</div>
  16. </div>
  17. </div>
  18. <div v-else style="height: 15px"></div>
  19. <!-- 筛选 -->
  20. <div class="search-head">
  21. <div class="head-bos">
  22. <div class="head-title">分类:</div>
  23. <div class="head-box">
  24. <div
  25. @click="onHead(item, type == 1 ? 'topCategoryId' : type == 2 ? 'middleCategoryId' : 'bottomCategoryId')"
  26. class="classify-list"
  27. v-for="(item, index) in classifyList"
  28. :key="index"
  29. :class="{
  30. hig:
  31. type == 1 ? item.id == httpObj.topCategoryId : type == 2 ? item.id == httpObj.middleCategoryId : item.id == httpObj.bottomCategoryId
  32. }"
  33. >
  34. {{ item.label }}
  35. </div>
  36. </div>
  37. </div>
  38. <div class="head-bos" v-if="type == 1">
  39. <div class="head-title">品牌:</div>
  40. <div class="head-box">
  41. <el-select v-model="httpObj.brandId" filterable remote :remote-method="remoteMethod" placeholder="请输入名牌名称" style="width: 240px">
  42. <el-option v-for="item in brandList" :key="item.id" :label="item.brandName" :value="item.id" />
  43. </el-select>
  44. </div>
  45. </div>
  46. <div class="head-bos" v-else>
  47. <div class="head-title">品牌:</div>
  48. <div class="head-box">
  49. <div
  50. @click="onHead(item, 'brandId')"
  51. class="classify-list"
  52. v-for="(item, index) in brandList"
  53. :key="index"
  54. :class="item.id == httpObj.brandId ? 'hig' : ''"
  55. >
  56. {{ item.brandName }}
  57. </div>
  58. </div>
  59. </div>
  60. <div class="head-bos">
  61. <div class="head-title">价格:</div>
  62. <div class="head-box">
  63. <div
  64. @click="onHead(item, 'priceRange')"
  65. class="classify-list"
  66. v-for="(item, index) in priceList"
  67. :key="index"
  68. :class="item.id == httpObj.priceRange ? 'hig' : ''"
  69. >
  70. {{ item.label }}
  71. </div>
  72. </div>
  73. </div>
  74. <div class="head-bos">
  75. <div class="head-sort flex-row-center" @click="onSort(1)" :class="sortField1 != '' ? 'hig' : ''">
  76. <div>智能匹配</div>
  77. <div class="sort-box">
  78. <el-icon :color="sortField1 == 'Asc' ? '#E7000B' : '#333333'" class="icon1" :size="12">
  79. <CaretTop />
  80. </el-icon>
  81. <el-icon :color="sortField1 == 'Desc' ? '#E7000B' : '#333333'" class="icon2" :size="12">
  82. <CaretBottom />
  83. </el-icon>
  84. </div>
  85. </div>
  86. <div class="head-sort flex-row-center" @click="onSort(2)" :class="sortField2 != '' ? 'hig' : ''">
  87. <div>库存排序</div>
  88. <div class="sort-box">
  89. <el-icon :color="sortField2 == 'Asc' ? '#E7000B' : '#333333'" class="icon1" :size="12">
  90. <CaretTop />
  91. </el-icon>
  92. <el-icon :color="sortField2 == 'Desc' ? '#E7000B' : '#333333'" class="icon2" :size="12">
  93. <CaretBottom />
  94. </el-icon>
  95. </div>
  96. </div>
  97. <div class="head-sort flex-row-center" @click="onSort(3)" :class="sortField3 != '' ? 'hig' : ''">
  98. <div>价格排序</div>
  99. <div class="sort-box">
  100. <el-icon :color="sortField3 == 'Asc' ? '#E7000B' : '#333333'" class="icon1" :size="12">
  101. <CaretTop />
  102. </el-icon>
  103. <el-icon :color="sortField3 == 'Desc' ? '#E7000B' : '#333333'" class="icon2" :size="12">
  104. <CaretBottom />
  105. </el-icon>
  106. </div>
  107. </div>
  108. <el-checkbox-group v-model="checkList" style="margin-top: 15px" @change="getList">
  109. <el-checkbox label="可定制" value="isCustomize" />
  110. </el-checkbox-group>
  111. </div>
  112. </div>
  113. <!-- 游标分页控制 -->
  114. <pagination
  115. v-show="dataList.length > 0"
  116. v-model:page="httpObj.pageNum"
  117. v-model:limit="httpObj.pageSize"
  118. v-model:way="way"
  119. :cursor-mode="true"
  120. :has-more="hasMore"
  121. @pagination="getList"
  122. />
  123. <!-- 商品 -->
  124. <div class="expert-bos">
  125. <div v-for="(item, index) in dataList" :key="index" class="expert-list" @click="onPath('/item?id=' + item.id)">
  126. <img :src="item.productImage" alt="" />
  127. <div class="itemName ellipsis">{{ item.itemName || '' }}</div>
  128. <div class="price">
  129. <span class="memberPrice">¥{{ item.memberPrice }}</span>
  130. <span class="marketPrice">¥{{ item.marketPrice }}</span>
  131. </div>
  132. </div>
  133. <div class="empty-bos" v-if="dataList.length === 0">
  134. <el-empty description="暂无数据" />
  135. </div>
  136. </div>
  137. <!-- 游标分页控制 -->
  138. <pagination
  139. v-show="dataList.length > 0"
  140. v-model:page="httpObj.pageNum"
  141. v-model:limit="httpObj.pageSize"
  142. v-model:way="way"
  143. :cursor-mode="true"
  144. :has-more="hasMore"
  145. @pagination="getList"
  146. />
  147. </div>
  148. </template>
  149. <script setup lang="ts">
  150. import { getPcProductPage, getBrandPage, getBrandByCategoryList } from '@/api/search/index';
  151. import { getProductCategoryTree } from '@/api/home/index';
  152. import { onPath } from '@/utils/siteConfig';
  153. import Pagination from '@/components/Pagination/index.vue';
  154. import { get } from 'http';
  155. const route = useRoute();
  156. const type = ref<any>(1);
  157. const dataList = ref<any>([]);
  158. const checkList = ref<any>([]);
  159. const classifyList = ref<any>([]);
  160. const brandList = ref<any>([]);
  161. const categoryName = ref<any>('');
  162. const hasMore = ref(true); // 是否还有更多数据
  163. const way = ref<any>(1);
  164. const httpObj = ref<any>({
  165. itemName: '',
  166. topCategoryId: '',
  167. middleCategoryId: '',
  168. bottomCategoryId: '',
  169. brandId: '',
  170. priceRange: '',
  171. sortField: '',
  172. sortOrder: '',
  173. isCustomize: '',
  174. pageSize: 20,
  175. pageNum: 1
  176. });
  177. const priceList = ref<any>([
  178. { label: '全部', id: '' },
  179. { label: '1-100', id: 1 },
  180. { label: '100-500', id: 2 },
  181. { label: '500-1000', id: 3 },
  182. { label: '1000以上', id: 4 }
  183. ]);
  184. const sortField1 = ref<any>('');
  185. const sortField2 = ref<any>('');
  186. const sortField3 = ref<any>('');
  187. const getList = () => {
  188. if (sortField1.value) {
  189. httpObj.value.sortField = '1';
  190. httpObj.value.sortOrder = sortField1.value;
  191. }
  192. if (sortField2.value) {
  193. httpObj.value.sortField = httpObj.value.sortField + (httpObj.value.sortField ? ',2' : '2');
  194. httpObj.value.sortOrder = httpObj.value.sortOrder + (httpObj.value.sortOrder ? ',' + sortField2.value : sortField2.value);
  195. }
  196. if (sortField3.value) {
  197. httpObj.value.sortField = httpObj.value.sortField + (httpObj.value.sortField ? ',3' : '3');
  198. httpObj.value.sortOrder = httpObj.value.sortOrder + (httpObj.value.sortOrder ? ',' + sortField3.value : sortField3.value);
  199. }
  200. if (checkList.value.length > 0) {
  201. httpObj.value.isCustomize = 1;
  202. } else {
  203. httpObj.value.isCustomize = '';
  204. }
  205. getPcProductPage(httpObj.value).then((res) => {
  206. if (res.code == 200) {
  207. dataList.value = res.rows ? res.rows : [];
  208. // 判断是否还有更多数据
  209. hasMore.value = dataList.value.length === httpObj.value.pageSize;
  210. }
  211. });
  212. };
  213. // 获取分类
  214. const getClassify = () => {
  215. getProductCategoryTree({}).then((res) => {
  216. if (res.code == 200) {
  217. if (type.value == 2 && httpObj.value.middleCategoryId) {
  218. res.data.forEach((item1: any) => {
  219. item1.children.unshift({
  220. label: '全部',
  221. id: ''
  222. });
  223. item1.children.forEach((item2: any) => {
  224. if (item2.id == httpObj.value.middleCategoryId) {
  225. httpObj.value.topCategoryId = item1.id;
  226. classifyList.value = item1.children;
  227. }
  228. });
  229. });
  230. getList();
  231. //获取当前分类下得品牌
  232. getBrand2();
  233. } else if (type.value == 3 && httpObj.value.bottomCategoryId) {
  234. res.data.forEach((item1: any) => {
  235. item1.children.forEach((item2: any) => {
  236. if (item2.children && item2.children.length > 0) {
  237. item2.children.unshift({
  238. label: '全部',
  239. id: ''
  240. });
  241. item2.children.forEach((item3: any) => {
  242. if (item3.id == httpObj.value.bottomCategoryId) {
  243. httpObj.value.topCategoryId = item1.id;
  244. httpObj.value.middleCategoryId = item2.id;
  245. classifyList.value = item2.children;
  246. }
  247. });
  248. }
  249. });
  250. });
  251. getList();
  252. //获取当前分类下得品牌
  253. getBrand2();
  254. } else {
  255. res.data.unshift({
  256. label: '全部',
  257. id: ''
  258. });
  259. classifyList.value = res.data;
  260. }
  261. }
  262. });
  263. };
  264. const onHead = (item: any, type: string) => {
  265. httpObj.value[type] = item.id;
  266. getList();
  267. };
  268. //查询品牌
  269. const getBrand1 = () => {
  270. getBrandPage({
  271. categoryName: categoryName.value,
  272. categoryId: httpObj.value.topCategoryId,
  273. pageSize: 100,
  274. pageNum: 1
  275. }).then((res) => {
  276. if (res.code == 200) {
  277. brandList.value = res.rows;
  278. }
  279. });
  280. };
  281. //查询分类下得品牌
  282. const getBrand2 = () => {
  283. getBrandByCategoryList({
  284. categoryId: httpObj.value.topCategoryId,
  285. pageSize: 100,
  286. pageNum: 1
  287. }).then((res) => {
  288. if (res.code == 200) {
  289. res.rows.unshift({
  290. brandName: '全部',
  291. id: ''
  292. });
  293. brandList.value = res.rows;
  294. }
  295. });
  296. };
  297. //筛选品牌
  298. const remoteMethod = (res: any) => {
  299. if (res) {
  300. categoryName.value = res;
  301. } else {
  302. categoryName.value = '';
  303. }
  304. getBrand1();
  305. };
  306. // 筛选条件
  307. const onSort = (type: number) => {
  308. if (type == 1) {
  309. if (sortField1.value == '' || sortField1.value == 'Desc') {
  310. sortField1.value = 'Asc';
  311. } else if (sortField1.value == 'Asc') {
  312. sortField1.value = 'Desc';
  313. }
  314. }
  315. if (type == 2) {
  316. if (sortField2.value == '' || sortField2.value == 'Desc') {
  317. sortField2.value = 'Asc';
  318. } else if (sortField2.value == 'Asc') {
  319. sortField2.value = 'Desc';
  320. }
  321. }
  322. if (type == 3) {
  323. if (sortField3.value == '' || sortField3.value == 'Desc') {
  324. sortField3.value = 'Asc';
  325. } else if (sortField3.value == 'Asc') {
  326. sortField3.value = 'Desc';
  327. }
  328. }
  329. getList();
  330. };
  331. // 核心修复:统一初始化函数
  332. const initData = () => {
  333. httpObj.value.searchKeyword = '';
  334. httpObj.value.topCategoryId = '';
  335. type.value = route.query.type;
  336. if (route.query.input) {
  337. httpObj.value.searchKeyword = route.query.input;
  338. }
  339. if (type.value == 1) {
  340. getBrand1();
  341. if (route.query.topCategoryId) {
  342. httpObj.value.topCategoryId = route.query.topCategoryId;
  343. }
  344. getList();
  345. }
  346. if (type.value == 2 && route.query.middleCategoryId) {
  347. httpObj.value.middleCategoryId = route.query.middleCategoryId;
  348. }
  349. if (type.value == 3 && route.query.bottomCategoryId) {
  350. httpObj.value.bottomCategoryId = route.query.bottomCategoryId;
  351. }
  352. getClassify();
  353. };
  354. watch(route, () => {
  355. initData();
  356. });
  357. onMounted(() => {
  358. initData();
  359. });
  360. </script>
  361. <style lang="scss" scoped>
  362. .search-pages {
  363. width: 1200px;
  364. margin: 0px auto 0 auto;
  365. // 筛选
  366. .search-head {
  367. width: 1200px;
  368. background: #ffffff;
  369. border-radius: 10px;
  370. padding: 0 15px 15px 15px;
  371. font-size: 14px;
  372. color: #101828;
  373. .head-bos {
  374. display: flex;
  375. .head-title {
  376. width: 70px;
  377. padding-top: 15px;
  378. }
  379. .head-box {
  380. display: flex;
  381. flex-wrap: wrap;
  382. flex: 1;
  383. width: 0;
  384. gap: 10px 15px;
  385. border-bottom: 1px solid #e5e7eb;
  386. padding: 15px 0;
  387. .classify-list {
  388. cursor: pointer;
  389. &.hig {
  390. color: var(--el-color-primary);
  391. }
  392. }
  393. }
  394. .head-sort {
  395. margin: 15px 15px 0 0;
  396. width: 108px;
  397. height: 32px;
  398. border: 1px solid #e5e7eb;
  399. border-radius: 2px 2px 2px 2px;
  400. cursor: pointer;
  401. &.hig {
  402. border: 1px solid var(--el-color-primary);
  403. }
  404. .sort-box {
  405. margin-left: 10px;
  406. position: relative;
  407. height: 32px;
  408. .icon1 {
  409. position: absolute;
  410. top: 6px;
  411. }
  412. .icon2 {
  413. position: absolute;
  414. bottom: 6px;
  415. }
  416. }
  417. }
  418. }
  419. }
  420. // 商品
  421. // 行家精选
  422. .expert-bos {
  423. width: 1200px;
  424. display: flex;
  425. flex-wrap: wrap;
  426. margin-top: 12px;
  427. gap: 20px 12.5px;
  428. .expert-list {
  429. width: 230px;
  430. height: 306px;
  431. background: #ffffff;
  432. padding: 20px;
  433. cursor: pointer;
  434. img {
  435. width: 100%;
  436. height: 190px;
  437. }
  438. .itemName {
  439. font-weight: 400;
  440. font-size: 14px;
  441. color: #101828;
  442. margin: 27px 0 2px 0;
  443. }
  444. .price {
  445. .memberPrice {
  446. color: var(--el-color-primary);
  447. font-size: 16px;
  448. color: #e7000b;
  449. }
  450. .marketPrice {
  451. font-size: 12px;
  452. color: #99a1af;
  453. line-height: 20px;
  454. text-decoration-line: line-through;
  455. text-transform: none;
  456. margin-left: 6px;
  457. }
  458. }
  459. }
  460. .empty-bos {
  461. width: 100%;
  462. background-color: #ffffff;
  463. border-radius: 10px;
  464. margin-bottom: 20px;
  465. }
  466. }
  467. //面包屑
  468. .breadcrumb {
  469. width: 100%;
  470. height: 44px;
  471. padding-left: 20px;
  472. .breadcrumb-bos {
  473. width: 1200px;
  474. font-size: 14px;
  475. color: #101828;
  476. .nav-list {
  477. height: 44px;
  478. display: flex;
  479. align-items: center;
  480. }
  481. .home {
  482. cursor: pointer;
  483. &:hover {
  484. color: var(--el-color-primary);
  485. }
  486. }
  487. }
  488. }
  489. }
  490. </style>