main.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636
  1. // 載入共用 template
  2. $('#navbar').load('../../template/navbar.html');
  3. $('#footer').load('../../template/footer.html');
  4. $('#btn-box').load('../../template/button.html');
  5. $('#topCarousel').load('../../template/top_carousel.html');
  6. let assignOrder = ""; // 當前排序
  7. // new, hot, recommend 排序 (預設推薦)
  8. $(".search-btn-filter button").click(function () {
  9. // 切換選取狀態
  10. $('.search-btn-filter').find('.active').removeClass('active');
  11. $(this).addClass('active');
  12. assignOrder = $(this).attr('id');
  13. dataSearch();
  14. });
  15. let page = 1; // 當前頁數
  16. let pageSize = 18; // 每頁數量
  17. let isFirstLoad = true; // 初始載入
  18. let assignTab = "caseTab"; // 指定類別 (預設為空間靈感)
  19. // 列表篩選
  20. async function dataSearch(type = "") {
  21. let url;
  22. $('#dataSpinner').show();
  23. $('#dataList').hide();
  24. switch (assignTab) {
  25. case "caseTab":
  26. url = `https://m3.hhh.com.tw:18673/case_search?page=${page}&page_size=${pageSize}`;
  27. break;
  28. case "designerTab":
  29. url = `https://m3.hhh.com.tw:18673/designer_search?page=${page}&page_size=${pageSize}`;
  30. break;
  31. case "videoTab":
  32. url = `https://m3.hhh.com.tw:18673/video_search?page=${page}&page_size=${pageSize}`;
  33. break;
  34. case "columnTab":
  35. url = `https://m3.hhh.com.tw:18673/column_search?page=${page}&page_size=${pageSize}`;
  36. break;
  37. case "builderTab":
  38. url = `https://m3.hhh.com.tw:18673/builder_search?page=${page}&page_size=${pageSize}`;
  39. break;
  40. default:
  41. break;
  42. }
  43. let input = $(".keywords").val();
  44. if (input !== "") {
  45. let isExist = filterList.some((item) => item.id === "keyword"); // 判斷是否已存在關鍵字
  46. const newItem = {
  47. id: "keyword",
  48. text: "關鍵字",
  49. value: input
  50. };
  51. if (!isExist) {
  52. filterList.push(newItem);
  53. createFilterHtml(newItem);
  54. } else {
  55. // 移除原本關鍵字
  56. $('.budget p.me-1').each(function () {
  57. if ($(this).text().includes('關鍵字')) {
  58. $(this).closest('.me-3').remove();
  59. }
  60. });
  61. if (filterList.length === 0) {
  62. $('#removeResultBtn').hide();
  63. }
  64. filterList = filterList.filter(item => item.text !== "關鍵字");
  65. filterList.push(newItem);
  66. createFilterHtml(newItem);
  67. }
  68. // $(".keywords").val("");
  69. }
  70. if (filterList.length) {
  71. filterList.map(item => {
  72. if (item.id === "fee") {
  73. // 裝修預算
  74. switch (item.value) {
  75. case "100萬以下":
  76. url += `&${item.id}=1`;
  77. break;
  78. case "101~200萬":
  79. url += `&${item.id}=2`;
  80. break;
  81. case "201~300萬":
  82. url += `&${item.id}=3`;
  83. break;
  84. case "301萬以上":
  85. url += `&${item.id}=4`;
  86. break;
  87. default:
  88. break;
  89. }
  90. } else if (item.id === "area") {
  91. // 房屋坪數
  92. switch (item.value) {
  93. case "20坪以下":
  94. url += `&${item.id}=1`;
  95. break;
  96. case "21-30坪":
  97. url += `&${item.id}=2`;
  98. break;
  99. case "31-50坪":
  100. url += `&${item.id}=3`;
  101. break;
  102. case "51坪以上":
  103. url += `&${item.id}=4`;
  104. break;
  105. default:
  106. break;
  107. }
  108. } else if (item.id === 'budget') {
  109. switch (item.value) {
  110. case "100萬以下":
  111. url += `&${item.id}=1`;
  112. break;
  113. case "100~200萬":
  114. url += `&${item.id}=2`;
  115. break;
  116. case "200~300萬":
  117. url += `&${item.id}=3`;
  118. break;
  119. case "300~400萬":
  120. url += `&${item.id}=4`;
  121. break;
  122. case "400~500萬":
  123. url += `&${item.id}=5`;
  124. break;
  125. case "500萬以上":
  126. url += `&${item.id}=6`;
  127. break;
  128. default:
  129. break;
  130. }
  131. } else {
  132. url += `&${item.id}=${item.value}`;
  133. }
  134. });
  135. }
  136. // 排序
  137. if (assignOrder === "") {
  138. // 預設
  139. if (assignTab === "designerTab") {
  140. url += "&order_by=recommend";
  141. } else {
  142. url += "&order_by=new";
  143. }
  144. } else {
  145. url += `&order_by=${assignOrder}`;
  146. }
  147. try {
  148. let isExist = filterList.some((item) => item.id === "keyword"); // 判斷是否已存在關鍵字
  149. if (isExist) {
  150. getAllSearchCount(); // 重新取得總筆數
  151. }
  152. const response = await axios.get(url);
  153. let totalCount = response.data.total_count;
  154. let totalPages = Math.ceil(totalCount / pageSize);
  155. if (totalPages) {
  156. $('.filter-list .pagination').show();
  157. setPagination(totalPages); // 分頁處理
  158. } else {
  159. $('.filter-list .pagination').hide();
  160. }
  161. let resultHtml = '';
  162. switch (assignTab) {
  163. case "caseTab":
  164. if (response.data.cases.length) {
  165. response.data.cases.forEach((item) => {
  166. let tagList = item.CaseTag.split(',');
  167. let tagsHtml = '';
  168. tagList.forEach((tag) => {
  169. if (tag !== "") {
  170. tagsHtml += `<span class="tag-item" data-tag="${tag}">${tag}</span>`;
  171. }
  172. });
  173. resultHtml += `
  174. <div class="col-md-4 mb-4">
  175. <a href="${item.DesignerLink}">
  176. <div class="card lists-card">
  177. <img src="${item.CaseCoverImg}" class="cover-img" alt="${item.DesignerName} ${item.DesignerTitle}">
  178. <div class="card-body d-flex flex-column">
  179. <div class="d-flex align-items-center">
  180. <div class="person-img me-3 me-md-2 me-lg-3" style="background-image: url('${item.DesignerCoverImg}');"></div>
  181. <section>
  182. <h5 class="text-muted mb-2">${item.DesignerTitle}</h5>
  183. <h6 class="mb-0 text-dark">
  184. <span class="font-weight-bold">
  185. ${item.DesignerName}
  186. </span>
  187. 設計師
  188. </h6>
  189. </section>
  190. </div>
  191. <p class="mt-3 text-dark title">${item.CaseTitle}</p>
  192. <div class="tags-container my-3 me-auto">${tagsHtml}</div>
  193. <small class="d-block ms-auto mt-auto date-item">上架日期 ${item.CaseSdate}</small>
  194. </div>
  195. </div>
  196. </a>
  197. </div>`;
  198. });
  199. } else {
  200. resultHtml += "<p class='text-center mt-5'>找不到符合的資料,請重新搜尋。</p>"
  201. }
  202. let caseCount = response.data.total_count.toLocaleString();
  203. setTimeout(() => {
  204. $("#caseCount").html(`(${caseCount})`);
  205. }, 100)
  206. break;
  207. case "designerTab":
  208. if (response.data.designers.length) {
  209. response.data.designers.forEach((item) => {
  210. resultHtml += `
  211. <div class="col-md-4 mb-4">
  212. <a href="${item.DesignerLink}">
  213. <div class="card lists-card">
  214. <img src="${item.CaseCoverImg}" class="cover-img" alt="${item.DesignerName} ${item.DesignerTitle}">
  215. <div class="card-body d-flex align-items-center">
  216. <div class="person-img me-3 me-md-2 me-lg-3" style="background-image: url('${item.DesignerCoverImg}');"></div>
  217. <section>
  218. <h5 class="text-muted mb-2">${item.DesignerTitle}</h5>
  219. <h6 class="mb-0 text-dark">
  220. <span class="font-weight-bold">
  221. ${item.DesignerName}
  222. </span>
  223. 設計師
  224. </h6>
  225. </section>
  226. </div>
  227. </div>
  228. </a>
  229. </div>`;
  230. });
  231. } else {
  232. resultHtml += "<p class='text-center mt-5'>找不到符合的資料,請重新搜尋。</p>"
  233. }
  234. let designerCount = response.data.total_count.toLocaleString();
  235. setTimeout(() => {
  236. $("#designerCount").html(`(${designerCount})`);
  237. }, 100)
  238. break;
  239. case "videoTab":
  240. if (response.data.videos.length) {
  241. response.data.videos.forEach((item) => {
  242. let tagsHtml = '';
  243. item.VideoTag.forEach((tag) => {
  244. if (tag !== "") {
  245. tagsHtml += `<span class="tag-item" data-tag="${tag}">${tag}</span>`;
  246. }
  247. });
  248. resultHtml += `
  249. <div class="col-md-4 mb-4">
  250. <a href="${item.DesignerLink}">
  251. <div class="card lists-card">
  252. <img src="${item.VideoCoverImg}" class="video-cover-img" alt="${item.DesignerName} ${item.DesignerTitle}">
  253. <div class="card-body d-flex flex-column align-items-center">
  254. <section class="d-flex align-items-center w-100">
  255. <div class="person-img me-3 me-md-2 me-lg-3" style="background-image: url('${item.DesignerCoverImg}');"></div>
  256. <h5 class="text-muted mb-2">${item.DesignerTitle}</h5>
  257. </section>
  258. <h3 class="my-3 video-title">${item.VideoTitle}</h3>
  259. <div class="tags-container mt-2 me-auto">${tagsHtml}</div>
  260. </div>
  261. </div>
  262. </a>
  263. </div>`;
  264. });
  265. } else {
  266. resultHtml += "<p class='text-center mt-5'>找不到符合的資料,請重新搜尋。</p>"
  267. }
  268. let videoCount = response.data.total_count.toLocaleString();
  269. setTimeout(() => {
  270. $("#videoCount").html(`(${videoCount})`);
  271. }, 100)
  272. break;
  273. case "columnTab":
  274. if (response.data.columns.length) {
  275. // 取得當前日期並計算三天前的日期
  276. const currentDate = new Date();
  277. const threeDaysAgo = new Date();
  278. threeDaysAgo.setDate(currentDate.getDate() - 3);
  279. response.data.columns.forEach((item, index) => {
  280. // 將 ColumnDate 轉換成日期物件
  281. const columnDate = new Date(item.ColumnDate);
  282. // 判斷 ColumnDate 是否在三天內
  283. const isNew = columnDate >= threeDaysAgo && columnDate <= currentDate;
  284. const newItemClass = isNew ? '' : 'd-none'; // 非三天內則隱藏 New 標籤
  285. let tagList = item.ColumnTag.split(',');
  286. let tagsHtml = '';
  287. tagList.forEach((tag) => {
  288. if (tag !== "") {
  289. tagsHtml += `<span class="tag-item" data-tag="${tag}">${tag}</span>`;
  290. }
  291. });
  292. resultHtml += `
  293. <div class="col-md-4 mb-4">
  294. <a href="${item.ColumnLink}">
  295. <div class="card lists-card h-auto">
  296. <img src="${item.ColumnCoverImg}" class="cover-img" alt="${item.ColumnTitle}">
  297. <div class="card-body d-flex flex-column">
  298. <h5 class="text-dark title">${item.ColumnTitle}</h5>
  299. <div class="tags-container columns-tag mt-3 me-auto">${tagsHtml}</div>
  300. </div>
  301. <span class="new-item ${newItemClass}">NEW</span>
  302. </div>
  303. </a>
  304. </div>`;
  305. });
  306. $('#dataList').append(resultHtml);
  307. } else {
  308. resultHtml += "<p class='text-center mt-5'>找不到符合的資料,請重新搜尋。</p>"
  309. }
  310. let columnCount = response.data.total_count.toLocaleString();
  311. setTimeout(() => {
  312. $("#columnCount").html(`(${columnCount})`);
  313. }, 100)
  314. break;
  315. case "builderTab":
  316. if (response.data.videos.length) {
  317. response.data.videos.forEach((item) => {
  318. resultHtml += `
  319. <div class="col-md-4 mb-4">
  320. <a href="${item.DesignerLink}">
  321. <div class="card lists-card">
  322. <div class="position-relative">
  323. <img src="../../img/icon/play.svg" class="play-img${item.Is_video === '0' ? ' d-none' : ''}" alt="play-img">
  324. <img src="${item.BuilderCoverImg}" class="cover-img" alt="${item.BuilderTitle}">
  325. </div>
  326. <div class="card-body p-4">
  327. <section>
  328. <h5 class="text-dark">${item.BuilderTitle}</h5>
  329. <p class="text-dark my-3">${item.BuilderDescr}</p>
  330. <h6 class="mb-0 text-muted fw-normal">
  331. ${item.BuilderAddress}
  332. </h6>
  333. </section>
  334. </div>
  335. </div>
  336. </a>
  337. </div>`;
  338. });
  339. } else {
  340. resultHtml += "<p class='text-center mt-5'>找不到符合的資料,請重新搜尋。</p>"
  341. }
  342. let builderCount = response.data.total_count.toLocaleString();
  343. setTimeout(() => {
  344. $("#builderCount").html(`(${builderCount})`);
  345. }, 100)
  346. break;
  347. default:
  348. break;
  349. }
  350. // if (response.data.videos.length) {
  351. // response.data.videos.forEach((item) => {
  352. // resultHtml += `
  353. // <div class="col-md-4 mb-4">
  354. // <a href="${item.DesignerLink}">
  355. // <div class="card lists-card">
  356. // <div class="position-relative">
  357. // <img src="../../img/icon/play.svg" class="play-img${item.Is_video === '0' ? ' d-none' : ''}" alt="play-img">
  358. // <img src="${item.BuilderCoverImg}" class="cover-img" alt="${item.BuilderTitle}">
  359. // </div>
  360. // <div class="card-body p-4">
  361. // <section>
  362. // <h5 class="text-dark">${item.BuilderTitle}</h5>
  363. // <p class="text-dark my-3">${item.BuilderDescr}</p>
  364. // <h6 class="mb-0 text-muted fw-normal">
  365. // ${item.BuilderAddress}
  366. // </h6>
  367. // </section>
  368. // </div>
  369. // </div>
  370. // </a>
  371. // </div>`;
  372. // });
  373. // } else {
  374. // resultHtml += "<p class='text-center mt-5'>找不到符合的資料,請重新搜尋。</p>"
  375. // }
  376. $('#dataList').html(resultHtml);
  377. setTimeout(() => {
  378. setTotalCount();
  379. $('#dataList').show();
  380. $('#dataSpinner').hide();
  381. }, 100)
  382. // 更新初始載入狀態
  383. if (isFirstLoad) {
  384. isFirstLoad = false;
  385. }
  386. } catch (error) {
  387. console.log("error", error);
  388. }
  389. }
  390. dataSearch();
  391. // 取得全部符合筆數
  392. async function getAllSearchCount() {
  393. let url = "https://m3.hhh.com.tw:18673/all_search_count";
  394. if (filterList.length) {
  395. let input;
  396. // 取得關鍵字
  397. filterList.find((item) => {
  398. if (item.id === "keyword") {
  399. input = item.value;
  400. if (input !== "") {
  401. url += `?keyword=${input}`
  402. }
  403. }
  404. });
  405. }
  406. try {
  407. const response = await axios.get(url);
  408. $("#caseCount").text(`(${response.data.case_count.toLocaleString()})`)
  409. $("#designerCount").text(`(${response.data.designer_count.toLocaleString()})`)
  410. $("#videoCount").text(`(${response.data.video_count.toLocaleString()})`)
  411. $("#columnCount").text(`(${response.data.column_count.toLocaleString()})`)
  412. $("#builderCount").text(`(${response.data.builder_count.toLocaleString()})`)
  413. // 數量加總
  414. let total = response.data.designer_count + response.data.column_count + response.data.case_count + response.data.builder_count + response.data.video_count;
  415. $('#totalCount').text(total.toLocaleString());
  416. } catch (error) {
  417. console.log("error", error);
  418. }
  419. }
  420. getAllSearchCount();
  421. // 計算總筆數
  422. function setTotalCount() {
  423. // 將各類別總筆數轉為數字
  424. let caseCount = parseInt($('#caseCount').text().replace(/[(),]/g, ''), 10);
  425. let designerCount = parseInt($('#designerCount').text().replace(/[(),]/g, ''), 10);
  426. let videoCount = parseInt($('#videoCount').text().replace(/[(),]/g, ''), 10);
  427. let columnCount = parseInt($('#columnCount').text().replace(/[(),]/g, ''), 10);
  428. let builderCount = parseInt($('#builderCount').text().replace(/[(),]/g, ''), 10);
  429. // 將各個數字相加
  430. let total = caseCount + designerCount + videoCount + builderCount + columnCount;
  431. $('#totalCount').text(total.toLocaleString());
  432. }
  433. // 切換 Tab
  434. $('.search-tab-list .nav-item').click(function (e) {
  435. // getAllSearchCount(); // 重新取得總筆數
  436. let isExist = filterList.some((item) => item.id === "keyword"); // 判斷是否已存在關鍵字
  437. if (!isExist) {
  438. getAllSearchCount(); // 重新取得總筆數
  439. }
  440. // 使用 closest() 找到最近的 button 元素
  441. let button = $(e.target).closest('button');
  442. assignTab = button.attr('id');
  443. if (assignTab === "designerTab") {
  444. $('.search-btn-filter').find('.active').removeClass('active');
  445. $("#recommend").addClass('active');
  446. $("#recommendItem").show();
  447. } else {
  448. $('.search-btn-filter').find('.active').removeClass('active');
  449. $("#new").addClass('active');
  450. $("#recommendItem").hide();
  451. }
  452. // 需保留關鍵字,其餘條件全部清除
  453. if (isExist) {
  454. filterList = filterList.filter(item => item.text === "關鍵字");
  455. // 刪除關鍵字以外的條件
  456. $('.search-tab-result span.me-3').each(function () {
  457. if (!$(this).find('p').text().includes('關鍵字')) {
  458. $(this).remove();
  459. }
  460. });
  461. } else {
  462. filterList.length = 0; // 清空篩選陣列
  463. $('#removeResultBtn').hide(); // 隱藏全部清除按鈕
  464. $('.search-tab-result').empty(); // 清空篩選條件 dom
  465. }
  466. // 全部清除
  467. $('.keywords').val(''); // 清空搜尋欄位
  468. // 取消選取狀態
  469. $('.filter-list input[type="radio"]').prop('checked', false);
  470. $('.search-tab').removeClass('active');
  471. dataSearch(); // 篩選
  472. });
  473. // 次要類別選單
  474. let subCategory = [
  475. {
  476. title: "編輯精選",
  477. list: ["居家趨勢", "人氣排行", "建築設計", "風格選店", "公益活動", "展演資訊"]
  478. },
  479. {
  480. title: "居家設計",
  481. list: ["小宅規劃", "老屋翻新", "風格營造", "配色佈置", "好宅特輯", "設計提案"]
  482. },
  483. {
  484. title: "裝修前線",
  485. list: ["新聞最前線", "預算分配", "施工流程", "建材知識", "裝潢撇步"]
  486. },
  487. {
  488. title: "生活PLUS",
  489. list: ["居家風水", "家事清潔", "收納技巧", "改造修繕", "退休好幸福"]
  490. },
  491. {
  492. title: "品牌好物",
  493. list: ["家具家飾", "美型家電", "推薦廚衛", "居家好物", "優質建材", "品牌新訊"]
  494. },
  495. {
  496. title: "房市焦點",
  497. list: ["房市新聞", "建案特搜", "買屋賣屋", "房貸稅務", "租房須知"]
  498. }
  499. ];
  500. // 專欄文章分類
  501. $("#pills-column #mainCategory .form-check").click(function (e) {
  502. let btnText = $(e.target).text().replace(/\s+/g, ''); // 取得主分類
  503. // 檢查陣列中是否有次分類
  504. let hasSubCategory = filterList.find(item => item.text === "次分類");
  505. if (hasSubCategory) {
  506. // 如果有則移除包含該 DOM 元素
  507. $('span.budget:contains("次分類")').closest('span.me-3').remove();
  508. filterList = filterList.filter(item => item.text !== "次分類");
  509. }
  510. let subHtml = [];
  511. subCategory.map(item => {
  512. if (item.title === btnText) {
  513. item.list.forEach(item => {
  514. let dom = `
  515. <li onclick="clickSubBtn(event, '${item}')">
  516. <div class="form-check">
  517. <input class="form-check-input" type="radio" name="sub_type">
  518. <label class="form-check-label">
  519. ${item}
  520. </label>
  521. </div>
  522. </li>`;
  523. subHtml.push(dom);
  524. })
  525. $('#subCategory ul').html(subHtml);
  526. }
  527. })
  528. $("#subCategory").show();
  529. })
  530. function clickSubBtn(e, item) {
  531. let currentElement = $(e.currentTarget);
  532. currentElement.find('.form-check-input').prop('checked', true);
  533. // 取得 radio 按鈕的 label
  534. let radioLabel = currentElement.find('.form-check-label').text().trim().replace(/\s+/g, ' '); // 移除換行空白
  535. // 取上一層 search-tab 按鈕文字
  536. let buttonValue = currentElement.closest('.dropdown').find('.search-tab').text().trim();
  537. let buttonId = currentElement.closest('.dropdown').find('.search-tab').attr('id');
  538. updateSelectedOptions(buttonId, buttonValue, radioLabel);
  539. }