Files
PC-Light-Forum/js/search.js
DESKTOP-RQ919RC\Pc 43556292d2 fix(component): 修复组件名称错误和props类型定义
refactor(component): 重构组件模板结构,移除重复代码

feat(component): 添加可选props支持外部数据传入

style(css): 优化样式布局和响应式设计

fix(js): 修复URL路径处理逻辑和滚动加载问题

feat(search): 新增搜索页推荐内容和空状态处理

chore: 添加新图标资源文件
2025-12-22 19:01:00 +08:00

373 lines
15 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const { createApp, ref, onMounted, nextTick, onUnmounted, computed, watch, provide } = Vue;
(async function () {
const { itemForum } = await import(withVer("../component/item-forum/item-forum.js"));
const { itemOffer } = await import(withVer("../component/item-offer/item-offer.js"));
const { itemSummary } = await import(withVer("../component/item-summary/item-summary.js"));
const { itemVote } = await import(withVer("../component/item-vote/item-vote.js"));
const { itemMj } = await import(withVer("../component/item-mj/item-mj.js"));
const { itemTenement } = await import(withVer("../component/item-tenement/item-tenement.js"));
const { itemProject } = await import(withVer("../component/item-project/item-project.js"));
const { headTop } = await import(withVer("../component/head-top/head-top.js"));
const { hotTag } = await import(withVer("../component/hot-tag/hot-tag.js"));
const { hotSearch } = await import(withVer("../component/hot-search/hot-search.js"));
const { slideshowBox } = await import(withVer("../component/slideshow-box/slideshow-box.js"));
const { latestList } = await import(withVer("../component/latest-list/latest-list.js"));
const { loadBox } = await import(withVer("../component/load-box/load-box.js"));
const appSearch = createApp({
setup() {
let kwValue = ref(null);
let typeValue = ref(null);
let kw = ref("");
onMounted(() => {
const params = getUrlParams();
// kw.value = params.kw || "";
// const urlObj = new URL(location.href);
// const pathParts = urlObj.pathname.split("/").filter((part) => part);
// kw.value = decodeURIComponent(pathParts.pop());
kw.value = kwValue.value.innerText;
const tab = typeValue.value.innerText;
if (tab) tabValue.value = tab;
if (params.page) page.value = params.page;
else page.value = 1;
if (kw.value) {
getList();
isNoSearch.value = false;
nextTick(() => {
const preLoader = document.getElementById("pre-loader");
if (preLoader) preLoader.style.display = "none";
});
} else {
page.value = null;
isEmptySearch.value = true;
getRecommendList();
}
getUserInfoWin();
window.addEventListener("scroll", handleScroll);
getTagList();
getSearchList();
document.querySelectorAll(".vuehide").forEach((item) => (item.style.display = "none"));
window.addEventListener("popstate", () => {
const urlObj = new URL(location.href);
const pathParts = urlObj.pathname.split("/").filter((part) => part);
const keyword = pathParts[1] ? decodeURIComponent(pathParts[1]) : ""; // /search/keyword...
if (keyword) {
kw.value = keyword;
page.value = 1;
list.value = [];
getList(true);
} else {
kw.value = "";
page.value = null;
isNoSearch.value = true;
getRecommendList();
nextTick(() => {
document.querySelectorAll(".vuehide").forEach((item) => (item.style.display = "none"));
});
}
});
});
let isLogin = ref(false);
let realname = ref(0); // 是否已经实名
let userInfoWin = ref({});
let permissions = ref([]);
let isme = ref(false);
const getUserInfoWin = () => {
const checkUser = () => {
const user = window.userInfoWin;
if (!user) return;
document.removeEventListener("getUser", checkUser);
realname.value = user.realname;
userInfoWin.value = user;
if (user?.uin > 0 || user?.uid > 0) isLogin.value = true;
permissions.value = user?.authority || [];
// if (user.uid == 500144) isme.value = true;
};
document.addEventListener("getUser", checkUser);
};
const openAttest = () => {
const handleAttestClose = () => {
document.removeEventListener("closeAttest", handleAttestClose);
realname.value = window.userInfoWin?.realname || 0;
};
// 启动认证流程时添加监听
document.addEventListener("closeAttest", handleAttestClose);
loadAttest(2);
};
// 跳转登录
const goLogin = () => {
if (typeof window === "undefined") return;
if (window["userInfoWin"] && Object.keys(window["userInfoWin"]).length !== 0) {
if (window["userInfoWin"]["uid"]) isLogin.value = true;
else ajax_login();
} else ajax_login();
};
provide("isLogin", isLogin);
provide("userInfoWin", userInfoWin);
provide("realname", realname);
provide("openAttest", openAttest);
provide("goLogin", goLogin);
const cutTab = (type) => {
if (tabValue.value == type) return;
page.value = 1;
list.value = [];
count.value = 0;
tabValue.value = type;
pagination.value = [];
updateUrlParams({ type: type == "all" ? null : type });
getList();
};
const fetchPageData = (pathname) => {
console.log("pathname", pathname);
const lastSegment = pathname.split("/").filter(Boolean).pop() || "index";
console.log("当前路径:", pathname, ",最后一段:", lastSegment);
};
let tabList = ref({
all: "全部",
thread: "论坛",
offer: "Offer",
offer_summary: "总结",
interviewexperience: "面经",
vote: "投票",
xg: "港校项目",
});
let tabValue = ref("all");
let uniqid = "";
const init = () => {
ajaxGet(`https://offer.gter.net/miniprogramApi/offer/search`).then((res) => {
if (res.code != 200) {
creationAlertBox("error", res.message);
page.value = 0;
return;
}
});
};
let loading = ref(false);
let page = ref(0);
let maxPage = ref(0);
let count = ref(0);
let total = ref(0);
let list = ref([]);
let pagination = ref([]);
const getList = (isHistoryBack = false) => {
if (loading.value || page.value == null) return;
isNoSearch.value = false;
loading.value = true;
isEmptySearch.value = false;
const limit = 20;
window.scrollTo(0, 0);
if (!isHistoryBack) updateUrlParams({ page: page.value });
let postHead = null;
if (tabValue.value == "xg") {
postHead = ajax(`https://api.gter.net/v1/program/getList`, {
page: page.value,
keyword: kw.value,
});
} else postHead = ajaxGet(`/v2/api/forum/topicLists?type=${tabValue.value == "all" ? "" : tabValue.value}&page=${page.value}&limit=${limit}&keyword=${kw.value}`);
let historySearchList = JSON.parse(localStorage.getItem("history-search")) || [];
historySearchList.unshift(kw.value);
historySearchList = [...new Set(historySearchList)];
if (historySearchList.length > 10) historySearchList = historySearchList.splice(0, 10);
localStorage.setItem("history-search", JSON.stringify(historySearchList));
postHead
.then((res) => {
if (res.code != 200) {
creationAlertBox("error", res.message);
return;
}
let data = res.data;
list.value = data.data;
if (list.value.length == 0) page.value = null;
total.value = data.total || data.count;
count.value = data.count;
loading.value = false;
maxPage.value = Math.ceil(count.value / limit);
pagination.value = calculatePagination(page.value, maxPage.value);
if (location.hostname != '127.0.0.1') updateUrlLastPath(`/search/${kw.value}`, true);
removeQueryQ();
})
.catch((err) => {
err = err?.data;
if (err?.code == 401) goLogin();
loading.value = false;
});
};
const calculatePagination = (currentPage, totalPages, visibleCount = 3) => {
// 处理特殊情况总页数小于等于1时无需显示分页
if (totalPages <= 1) {
return [];
}
const pages = [];
// 始终显示第一页
pages.push(1);
// 计算中间需要显示的页码范围
let startPage = Math.max(2, currentPage - Math.floor(visibleCount / 2));
let endPage = Math.min(totalPages - 1, startPage + visibleCount - 1);
// 调整起始页码,确保显示足够数量的页码
startPage = Math.max(2, endPage - visibleCount + 1);
// 前面的省略号:如果第一页和起始页之间有间隔
if (startPage > 2) {
pages.push("...");
}
// 添加中间的页码
for (let i = startPage; i <= endPage; i++) {
pages.push(i);
}
// 后面的省略号:如果最后一页和结束页之间有间隔
if (endPage < totalPages - 1) {
pages.push("...");
}
// 始终显示最后一页如果总页数大于1
if (totalPages > 1) {
pages.push(totalPages);
}
return pages;
};
const cutPage = (value) => {
if (value == "...") return;
if (value == page.value) return;
page.value = value;
list.value = [];
getList();
};
const prevPage = () => {
page.value -= 1;
list.value = [];
pagination.value = [];
getList();
};
const nextPage = () => {
page.value += 1;
list.value = [];
pagination.value = [];
getList();
};
const startSearch = (value) => {
if (value) kw.value = value;
if (kw.value == "") {
creationAlertBox("error", "请输入搜索关键词");
return;
}
page.value = 1;
list.value = [];
count.value = 0;
pagination.value = [];
getList();
};
const sidebarFixed = ref(false);
const matterFixed = ref(false);
const matterBottom = ref(false);
const handleScroll = () => {
matterHeight.value = -(matterContentRef.value?.offsetHeight - window.innerHeight);
sidebarHeight.value = -(sidebarRef.value?.offsetHeight - window.innerHeight);
if (matterHeight.value > 0) matterHeight.value = 12;
if (sidebarHeight.value > 0) sidebarHeight.value = 12;
};
const matterRef = ref(null);
const sidebarRef = ref(null);
const matterContentRef = ref(null);
let sidebarHeight = ref(0);
let matterHeight = ref(0);
let isEmptySearch = ref(false);
let tagList = ref([]);
const getTagList = () => {
ajaxGet("/v2/api/forum/getHotTags?limit=20").then((res) => {
const data = res.data;
tagList.value = data || [];
});
};
let placeholder = ref("");
let searchList = ref([]);
const getSearchList = () => {
ajaxGet("/v2/api/forum/getHotSearchWords?limit=20").then((res) => {
const data = res.data || [];
searchList.value = data;
if (data.length) placeholder.value = data[Math.floor(Math.random() * data.length)].keyword || "";
});
};
let isNoSearch = ref(true);
let recommendList = ref([]);
// 推荐阅读
const getRecommendList = () => {
if (recommendList.value?.length != 0) return;
ajaxGet("/v2/api/forum/getRecommendRead").then((res) => {
const data = res.data || [];
recommendList.value = data || [];
});
};
return { placeholder, recommendList, isNoSearch, searchList, tagList, isme, isEmptySearch, total, matterHeight, sidebarHeight, matterBottom, matterFixed, matterContentRef, sidebarFixed, matterRef, sidebarRef, loading, typeValue, kwValue, startSearch, kw, maxPage, prevPage, nextPage, tabValue, cutTab, tabList, count, list, page, pagination, cutPage };
},
});
appSearch.component("item-forum", itemForum);
appSearch.component("itemOffer", itemOffer);
appSearch.component("itemSummary", itemSummary);
appSearch.component("itemVote", itemVote);
appSearch.component("itemMj", itemMj);
appSearch.component("itemTenement", itemTenement);
appSearch.component("itemProject", itemProject);
appSearch.component("head-top", headTop);
appSearch.component("hot-tag", hotTag);
appSearch.component("hot-search", hotSearch);
appSearch.component("slideshow-box", slideshowBox);
appSearch.component("latest-list", latestList);
appSearch.component("load-box", loadBox);
appSearch.mount("#search");
})();