index.vue 14 KB

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