Files
PC-Light-Forum/js/search.js
DESKTOP-RQ919RC\Pc 40d06c180f feat: 添加项目库组件并优化搜索页面样式和功能
新增项目库组件item-project,包含学校、专业、学费等信息的展示
优化搜索页面样式,调整分类项宽度和间距
修复搜索页面滚动定位问题,完善分页和URL参数处理
添加本地开发服务器脚本serve.ps1
更新public.css和public.less样式文件
2025-11-20 19:11:48 +08:00

308 lines
12 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;
import { itemForum } from "../component/item-forum/item-forum.js";
import { itemOffer } from "../component/item-offer/item-offer.js";
import { itemSummary } from "../component/item-summary/item-summary.js";
import { itemVote } from "../component/item-vote/item-vote.js";
import { itemMj } from "../component/item-mj/item-mj.js";
import { itemTenement } from "../component/item-tenement/item-tenement.js";
import { itemProject } from "../component/item-project/item-project.js";
import { headTop } from "../component/head-top/head-top.js";
import { hotTag } from "../component/hot-tag/hot-tag.js";
import { hotSearch } from "../component/hot-search/hot-search.js";
import { slideshowBox } from "../component/slideshow-box/slideshow-box.js";
import { latestList } from "../component/latest-list/latest-list.js";
import { loadBox } from "../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();
console.log("params", params);
// 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();
else page.value = null;
getUserInfoWin();
window.addEventListener("scroll", handleScroll);
});
let isLogin = ref(false);
let realname = ref(0); // 是否已经实名
let userInfoWin = ref({});
let permissions = ref([]);
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 || [];
};
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();
};
let tabList = ref({
all: "全部",
thread: "论坛",
offer: "Offer",
offer_summary: "总结",
interviewexperience: "面经",
vote: "投票",
});
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;
}
console.log("res", res);
});
};
let loading = ref(false);
let page = ref(0);
let maxPage = ref(0);
let count = ref(0);
let list = ref([]);
let pagination = ref([]);
const getList = () => {
if (loading.value || page.value == null) return;
loading.value = true;
const limit = 20;
window.scrollTo(0, 0);
updateUrlParams({ page: page.value });
ajaxGet(`/v2/api/forum/topicLists?type=${tabValue.value == "all" ? "" : tabValue.value}&page=${page.value}&limit=${limit}&keyword=${kw.value}`)
.then((res) => {
if (res.code != 200) {
creationAlertBox("error", res.message);
return;
}
let data = res.data;
data.data.unshift({
id: 20,
program_en: "Master of Laws in Arbitration and Dispute Resolution",
program_zh: "法学硕士(仲裁及争议解决学)",
program_abbr: "LLMARBDR",
program_code: "P41",
award_en: "Master of Laws in Arbitration and Dispute Resolution",
award_zh: "法学硕士(仲裁及争议解决学)",
subject_area_id: 9,
subject_area_name: "Law",
primary_university: "City University of Hong Kong",
primary_university_id: 3,
status: "ACTIVE",
intake_year: 2026,
disciplineid: 9,
distinctive: "毕业生可参与:当事人、辩护人、专家、仲裁员和调解员",
rank: "42",
department: "法律学院",
admissionsproject: "1",
departmentid: 26,
schoolalias: "城大",
schoolname: "香港城市大学",
tags: ["有奖学金", "论文课程", "26fall 提前批", "Top 50", "专业资格认证"],
schoolenname: "City University of Hong Kong",
intake_month: 9,
schoolid: 311,
tuition_fee: null,
uniqid: "tf1yFYMER8-1bY1t5oLbKaNc2FVhOWM0",
type: "programs",
schoollogo: "https://oss.x-php.com/school/J6BSwE-VfCFkCb1SBaR7ec6NYmTA4pRcOalNHJRfNzUxNg~~",
});
list.value = data.data;
if (list.value.length == 0) page.value = null;
count.value = data.count;
loading.value = false;
maxPage.value = Math.ceil(count.value / limit);
pagination.value = calculatePagination(page.value, maxPage.value);
let url = `/search/${kw.value}`;
const hostname = location.hostname;
const localHostReg = /^(localhost|127\.0\.0\.1|\[::1\])$/;
if (localHostReg.test(hostname)) url = `/search.html`;
updateUrlLastPath(url);
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 = () => {
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);
return { 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");