refactor(component): 重构组件模板结构,移除重复代码 feat(component): 添加可选props支持外部数据传入 style(css): 优化样式布局和响应式设计 fix(js): 修复URL路径处理逻辑和滚动加载问题 feat(search): 新增搜索页推荐内容和空状态处理 chore: 添加新图标资源文件
444 lines
17 KiB
JavaScript
444 lines
17 KiB
JavaScript
const forumBaseURL = "https://api.gter.net";
|
||
axios.defaults.withCredentials = true;
|
||
axios.defaults.emulateJSON = true;
|
||
|
||
const withVer = (p) => `${p}?v=${window.__ASSET_VERSION__}`;
|
||
|
||
const getScriptParameter = (paramName) => {
|
||
const currentScript = document.currentScript;
|
||
if (currentScript && currentScript.src) {
|
||
const url = new URL(currentScript.src, window.location.origin);
|
||
return url.searchParams.get(paramName);
|
||
}
|
||
return null;
|
||
};
|
||
|
||
// 判断是否已经创建了v参数
|
||
const vParam = getScriptParameter("v");
|
||
|
||
// 导出ajax函数
|
||
const ajax = (url, data) => {
|
||
axios.defaults.withCredentials = true;
|
||
axios.defaults.emulateJSON = true;
|
||
|
||
url = url.indexOf("https://") > -1 ? url : forumBaseURL + url;
|
||
if (data) data["v"] = vParam || "v2";
|
||
return new Promise(function (resolve, reject) {
|
||
if (location.hostname == "127.0.0.1") axios.defaults.headers.common["Authorization"] = "n1pstcsmw6m6bcx49z705xhvduqviw29";
|
||
|
||
axios
|
||
.post(url, data, {
|
||
emulateJSON: true,
|
||
withCredentials: true,
|
||
})
|
||
.then(function (res) {
|
||
var data = typeof res.data == "string" ? JSON.parse(res.data) : res.data;
|
||
|
||
if (data.code == 401) {
|
||
// 需要登录
|
||
go_ajax_Login();
|
||
reject();
|
||
}
|
||
resolve(data);
|
||
})
|
||
.catch((err) => {
|
||
reject();
|
||
if (err.response?.status == 401) go_ajax_Login();
|
||
});
|
||
});
|
||
};
|
||
|
||
const ajaxdelete = (url, data) => {
|
||
axios.defaults.withCredentials = true;
|
||
axios.defaults.emulateJSON = true;
|
||
|
||
url = url.indexOf("https://") > -1 ? url : forumBaseURL + url;
|
||
return new Promise(function (resolve, reject) {
|
||
if (data) data["v"] = vParam || "v2";
|
||
axios
|
||
.delete(url, {
|
||
emulateJSON: true,
|
||
withCredentials: true,
|
||
data,
|
||
})
|
||
.then(function (res) {
|
||
var data = typeof res.data == "string" ? JSON.parse(res.data) : res.data;
|
||
|
||
if (data.code == 401) {
|
||
// 需要登录
|
||
go_ajax_Login();
|
||
reject();
|
||
}
|
||
resolve(data);
|
||
})
|
||
.catch((err) => {
|
||
reject();
|
||
if (err.response?.status == 401) go_ajax_Login();
|
||
});
|
||
});
|
||
};
|
||
|
||
// 导出ajaxGet函数
|
||
const ajaxGet = (url) => {
|
||
axios.defaults.withCredentials = true;
|
||
axios.defaults.emulateJSON = true;
|
||
|
||
url = url.indexOf("https://") > -1 ? url : forumBaseURL + url;
|
||
|
||
const paramSymbol = url.includes("?") ? "&" : "?";
|
||
url = `${url}${paramSymbol}v=${vParam || "v2"}`;
|
||
|
||
return new Promise(function (resolve, reject) {
|
||
if (location.hostname == "127.0.0.1") axios.defaults.headers.common["Authorization"] = "n1pstcsmw6m6bcx49z705xhvduqviw29";
|
||
|
||
axios
|
||
.get(
|
||
url,
|
||
{},
|
||
{
|
||
emulateJSON: true,
|
||
withCredentials: true,
|
||
}
|
||
)
|
||
.then(function (res) {
|
||
var data = typeof res.data == "string" ? JSON.parse(res.data) : res.data;
|
||
if (data.code == 401) {
|
||
// 需要登录
|
||
go_ajax_Login();
|
||
reject();
|
||
}
|
||
resolve(data);
|
||
})
|
||
.catch((error) => {
|
||
if (error?.status == 401) go_ajax_Login();
|
||
reject(error);
|
||
});
|
||
});
|
||
};
|
||
|
||
const strtimeago = (dateStr, type = 1) => {
|
||
dateStr = dateStr + ""; // 反之传入的不是字符串
|
||
dateStr = dateStr.replaceAll("-", "/"); // 修改格式
|
||
var minute = 1000 * 60; // 把分,时,天,周,半个月,一个月用毫秒表示
|
||
var hour = minute * 60;
|
||
var day = hour * 24;
|
||
var now = new Date().getTime(); // 获取当前时间毫秒
|
||
let objectTime = new Date(dateStr).getTime();
|
||
var diffValue = now - objectTime; // 时间差
|
||
if (diffValue < 0) return "刚刚";
|
||
|
||
var minC = diffValue / minute; // 计算时间差的分,时,天,周,月
|
||
var hourC = diffValue / hour;
|
||
var dayC = diffValue / day;
|
||
|
||
const diffInMilliseconds = now - objectTime;
|
||
const diffInYears = diffInMilliseconds / (1000 * 60 * 60 * 24 * 365);
|
||
const diffInMonths = diffInYears * 12;
|
||
|
||
let result = "";
|
||
if (dayC >= 7) {
|
||
var datetime = new Date(dateStr);
|
||
var Nyear = datetime.getFullYear();
|
||
var Nmonth = datetime.getMonth() + 1 < 10 ? "0" + (datetime.getMonth() + 1) : datetime.getMonth() + 1;
|
||
var Ndate = datetime.getDate() < 10 ? "0" + datetime.getDate() : datetime.getDate();
|
||
var Nhour = datetime.getHours() < 10 ? "0" + datetime.getHours() : datetime.getHours();
|
||
var Nmin = datetime.getMinutes() < 10 ? "0" + datetime.getMinutes() : datetime.getMinutes();
|
||
if (type == 4) {
|
||
if (new Date().getFullYear() !== Nyear) result = `${Nyear}年${Nmonth}月${Ndate}日`;
|
||
else result = `${Nmonth}月${Ndate}日 ${Nhour}:${Nmin}`;
|
||
}
|
||
if (type == 1) result = Nyear + "-" + Nmonth + "-" + Ndate;
|
||
if (type == 2) {
|
||
result = `${Nmonth}月${Ndate}日 ${Nhour}:${Nmin}`;
|
||
if (new Date().getFullYear() !== Nyear) result = `${Nyear}年${result}`;
|
||
}
|
||
if (type == 3) {
|
||
if (diffInYears >= 1) result = Math.floor(diffInYears) + "年前";
|
||
else if (diffInMonths >= 1) result = Math.floor(diffInMonths) + "个月前";
|
||
else result = parseInt(dayC) + "天前";
|
||
}
|
||
} else if (dayC >= 1) result = parseInt(dayC) + "天前";
|
||
else if (hourC >= 1 && hourC <= 24) result = parseInt(hourC) + "小时前";
|
||
else if (minC >= 1 && minC <= 60) result = parseInt(minC) + "分钟前";
|
||
else result = "刚刚";
|
||
|
||
return result;
|
||
};
|
||
|
||
const timeago = (dateTimeStamp, type = 1) => {
|
||
if (!dateTimeStamp) return "刚刚";
|
||
|
||
// 判断位数
|
||
if (dateTimeStamp.toString().length !== 13) dateTimeStamp = dateTimeStamp * 1000;
|
||
var minute = 1000 * 60; //把分,时,天,周,半个月,一个月用毫秒表示
|
||
var hour = minute * 60;
|
||
var day = hour * 24;
|
||
var now = new Date().getTime(); //获取当前时间毫秒
|
||
var diffValue = now - dateTimeStamp; //时间差
|
||
if (diffValue < 0) return "刚刚";
|
||
|
||
var minC = diffValue / minute; //计算时间差的分,时,天,周,月
|
||
var hourC = diffValue / hour;
|
||
var dayC = diffValue / day;
|
||
|
||
let result = "";
|
||
if (dayC >= 7) {
|
||
var datetime = new Date(dateTimeStamp);
|
||
var Nyear = datetime.getFullYear();
|
||
var Nmonth = datetime.getMonth() + 1 < 10 ? "0" + (datetime.getMonth() + 1) : datetime.getMonth() + 1;
|
||
var Ndate = datetime.getDate() < 10 ? "0" + datetime.getDate() : datetime.getDate();
|
||
var Nhour = datetime.getHours() < 10 ? "0" + datetime.getHours() : datetime.getHours();
|
||
var Nmin = datetime.getMinutes() < 10 ? "0" + datetime.getMinutes() : datetime.getMinutes();
|
||
|
||
if (type == 1) result = Nyear + "-" + Nmonth + "-" + Ndate;
|
||
if (type == 2) {
|
||
result = `${Nmonth}月${Ndate}日 ${Nhour}:${Nmin}`;
|
||
if (new Date().getFullYear() !== Nyear) result = `${Nyear}年${result}`;
|
||
}
|
||
} else if (dayC >= 1) result = parseInt(dayC) + "天前";
|
||
else if (hourC >= 1 && hourC <= 24) result = parseInt(hourC) + "小时前";
|
||
else if (minC >= 1 && minC <= 60) result = parseInt(minC) + "分钟前";
|
||
else result = "刚刚";
|
||
|
||
return result;
|
||
};
|
||
|
||
const managerHide = (token, state, type = "offer") => {
|
||
return new Promise((resolve, reject) => {
|
||
const obj = {
|
||
offer: "Offer",
|
||
offer_summary: "总结",
|
||
interviewexperience: "面经",
|
||
thread: "帖子",
|
||
question: "帖子",
|
||
vote: "投票",
|
||
};
|
||
|
||
const isConfirmed = confirm(`确定要${state == 0 ? "隐藏" : "显示"}该${obj[type]}吗?`);
|
||
if (isConfirmed) {
|
||
ajax(`/v2/api/forum/setTopicHide`, {
|
||
token,
|
||
hidden: Number(state !== 1),
|
||
}).then((res) => {
|
||
const data = res.data;
|
||
creationAlertBox("success", res.message || "");
|
||
resolve(data.hidden);
|
||
});
|
||
}
|
||
});
|
||
};
|
||
|
||
// 推荐
|
||
const managerRecommend = (token, state) => {
|
||
return new Promise((resolve, reject) => {
|
||
const post = () => {
|
||
ajax(`/v2/api/forum/setTopicRecommend`, {
|
||
token,
|
||
recommend: state == 1 ? 0 : 1,
|
||
}).then((res) => {
|
||
const data = res.data;
|
||
creationAlertBox("success", res.message || "");
|
||
resolve(data.recommend);
|
||
});
|
||
};
|
||
|
||
if (state == 1) {
|
||
const isConfirmed = confirm(`确定要取消推荐吗?`);
|
||
if (isConfirmed) post();
|
||
else resolve(state);
|
||
} else post();
|
||
});
|
||
};
|
||
|
||
// 精华
|
||
const managerEssence = (token, state) => {
|
||
return new Promise((resolve, reject) => {
|
||
const post = () => {
|
||
ajax(`/v2/api/forum/setTopicBest`, {
|
||
token,
|
||
best: state == 1 ? 0 : 1,
|
||
}).then((res) => {
|
||
const data = res.data;
|
||
creationAlertBox("success", res.message || "");
|
||
resolve(data.best);
|
||
});
|
||
};
|
||
|
||
if (state == 1) {
|
||
const isConfirmed = confirm(`确定要取消精华吗?`);
|
||
if (isConfirmed) post();
|
||
else resolve(state);
|
||
} else post();
|
||
});
|
||
};
|
||
|
||
// 删除
|
||
const managerDelete = (token) => {
|
||
return new Promise((resolve, reject) => {
|
||
const post = () => {
|
||
ajaxdelete(`/v2/api/forum/deleteTopic`, {
|
||
token,
|
||
}).then((res) => {
|
||
creationAlertBox("success", res.message || "");
|
||
resolve();
|
||
});
|
||
};
|
||
|
||
const isConfirmed = confirm(`确定要删除吗?`);
|
||
if (!isConfirmed) reject();
|
||
else post();
|
||
});
|
||
};
|
||
|
||
const getUrlParams = () => {
|
||
const params = {};
|
||
const queryString = window.location.search.slice(1);
|
||
if (queryString) {
|
||
queryString.split("&").forEach((pair) => {
|
||
const [key, value] = pair.split("=");
|
||
params[decodeURIComponent(key)] = decodeURIComponent(value || "");
|
||
});
|
||
}
|
||
return params;
|
||
};
|
||
|
||
const updateUrlParams = (params, replace = false) => {
|
||
// 解析当前URL
|
||
const url = new URL(window.location.href);
|
||
const searchParams = url.searchParams;
|
||
|
||
// 遍历参数对象,更新URL参数
|
||
Object.entries(params).forEach(([key, value]) => {
|
||
if (value === null || value === undefined) {
|
||
// 删除参数
|
||
searchParams.delete(key);
|
||
} else {
|
||
// 添加或修改参数
|
||
searchParams.set(key, value);
|
||
}
|
||
});
|
||
|
||
// 生成新的URL(保留协议、域名、路径等,只修改参数)
|
||
const newUrl = url.origin + url.pathname + (searchParams.toString() ? `?${searchParams.toString()}` : "");
|
||
|
||
// 修改URL(不刷新页面)
|
||
if (replace) {
|
||
history.replaceState(null, "", newUrl);
|
||
} else {
|
||
history.pushState(null, "", newUrl);
|
||
}
|
||
};
|
||
|
||
// 跳转 url
|
||
const redirectToExternalWebsite = (url, target = "_blank") => {
|
||
const link = document.createElement("a");
|
||
link.href = url;
|
||
link.target = target;
|
||
link.click();
|
||
};
|
||
|
||
// 点击ta的主页
|
||
const goHomePage = (token) => {
|
||
if (!token) return;
|
||
redirectToExternalWebsite(`/u/${token}`);
|
||
};
|
||
|
||
// 点击发送信息
|
||
const goSendMessage = (token) => {
|
||
if (typeof messagePrivateItem == "function") {
|
||
messagePrivateItem({ token });
|
||
return;
|
||
}
|
||
|
||
goHomePage(token);
|
||
};
|
||
|
||
const lang = {
|
||
money: { 1: "3000以下", 2: "3000-4000", 3: "4000-5000", 4: "5000-6500", 5: "6500-8000", 6: "8000-10000", 7: "10000-20000", 8: "20000-30000", 9: "30000-40000", 10: "40000-50000", 11: "50000以上" },
|
||
leaseterm: { 1: "长租", 2: "短租" },
|
||
intermediary: { 1: "中介", 2: "非中介", 3: "房东", 4: "有房招室友", 5: "其他", 6: "求房源" },
|
||
property: { 1: "唐楼", 2: "洋楼", 3: "酒店式公寓", 4: "村屋", 5: "其他", 6: "学生公寓", 7: "house", 8: "屋苑", 9: "酒店" },
|
||
elevator: { 1: "有电梯", 2: "无电梯", "-1": "不限" },
|
||
sunshinearea: { 1: "阳台", 2: "天台", "-1": "无" },
|
||
floor: { 1: "低层", 2: "中层", 3: "高层", 4: "地下", 5: "不要一楼", 6: "不要顶层" },
|
||
tenementtype: { 1: "合租", 2: "整租", 1.5: "独卫套房", 1.1: "房间", 1.2: "床位", 1.3: "客厅", 1.4: "其他", 2.1: "studio", 2.2: "一房", 2.3: "两房", 2.4: "三房", 2.5: "四房以上" },
|
||
gender: { 1: "女性", 2: "男性", 3: "男女皆可" },
|
||
location: { 1: "港岛", 2: "九龙", 3: "新界", 1.1: "上环/中环/金钟", 1.2: "湾仔/铜锣湾", 1.3: "天后/炮台山", 1.4: "北角/则鱼涌", 1.5: "太古/西湾河", 1.6: "筲箕湾/柴湾", 1.7: "西营盘/坚尼地城/石塘咀", 1.8: "薄扶林", 1.9: "赤柱/香港仔", 1.11: "半山/山顶", 1.12: "南区", 2.1: "九龙站/奥运/南昌", 2.2: "尖沙咀/佐敦", 2.3: "长沙湾/深水埗/荔枝角", 2.4: "美孚/荔景", 2.5: "红磡/黄埔", 2.6: "土瓜湾/何文田", 2.7: "九龙城/启德", 2.8: "石夹尾/九龙塘", 2.9: "乐富/黄大仙", 2.11: "钻石山/彩虹", 2.12: "牛头角/九龙湾/观塘", 2.13: "蓝田/油塘", 2.14: "调景岭", 2.15: "油麻地/旺角/太子", 3.1: "葵芳/葵兴", 3.2: "荃湾", 3.3: "将军澳/坑口/宝琳", 3.4: "大埔仔/西贡", 3.5: "康城", 3.6: "大围/沙田", 3.7: "马鞍山", 3.8: "大埔/火炭/太和", 3.9: "粉岭/上水", 3.11: "赤泥坪/大埔尾/樟树滩", 3.12: "元朗/天水围/屯门", 3.13: "青衣", 3.14: "东涌/马湾/愉景湾", 3.15: "长洲" },
|
||
apartmentschool: [
|
||
{ id: 1, name: "港大", sid: 309 },
|
||
{ id: 2, name: "城大", sid: 311 },
|
||
{ id: 3, name: "理工", sid: 312 },
|
||
{ id: 4, name: "浸会", sid: 313 },
|
||
{ id: 5, name: "中大", sid: 308 },
|
||
{ id: 6, name: "教大", sid: 453 },
|
||
{ id: 7, name: "科大", sid: 310 },
|
||
{ id: 8, name: "岭大", sid: 314 },
|
||
{ id: 9, name: "都大", sid: 315 },
|
||
],
|
||
rentalduration: { 1: "1个月", 2: "2个月", 3: "3个月", 4: "4个月", 5: "5个月", 6: "6个月", 7: "7个月", 8: "8个月", 9: "9个月", 10: "10个月", 11: "11个月", 12: "1年", 13: "1年1个月", 14: "1年2个月", 15: "1年3个月", 16: "1年4个月", 17: "1年5个月", 18: "1年6个月", 24: "2年", 36: "3年" },
|
||
};
|
||
|
||
let copyForumUid = (text) => {
|
||
if (navigator.clipboard)
|
||
copyForumUid = () => {
|
||
navigator.clipboard.writeText(text);
|
||
creationAlertBox("success", "复制成功");
|
||
};
|
||
else {
|
||
copyForumUid = () => {
|
||
var tempInput = document.createElement("input");
|
||
tempInput.value = text;
|
||
document.body.appendChild(tempInput);
|
||
tempInput.select();
|
||
document.execCommand("copy");
|
||
document.body.removeChild(tempInput);
|
||
creationAlertBox("success", "复制成功");
|
||
};
|
||
}
|
||
copyForumUid();
|
||
};
|
||
|
||
const updateUrlLastPath = (newLastPath, isReplace = false) => {
|
||
const raw = typeof newLastPath === "string" ? newLastPath : String(newLastPath);
|
||
const basePath = raw.split("?")[0];
|
||
|
||
let finalPathname = "";
|
||
if (basePath.startsWith("/")) {
|
||
finalPathname = basePath;
|
||
} else {
|
||
const oldPathSegments = window.location.pathname.split("/").filter(Boolean);
|
||
const newPathSegments = oldPathSegments.slice(0, -1); // 移除原最后一段
|
||
if (basePath) {
|
||
newPathSegments.push(basePath); // 添加新最后一段
|
||
}
|
||
finalPathname = "/" + newPathSegments.join("/");
|
||
}
|
||
|
||
// 拼接完整URL
|
||
const newSearch = window.location.search;
|
||
const newUrl = window.location.origin + finalPathname + newSearch;
|
||
|
||
// 管理历史栈 + 修改URL
|
||
if (isReplace) {
|
||
history.replaceState(null, document.title, newUrl);
|
||
} else {
|
||
history.pushState(null, document.title, newUrl);
|
||
}
|
||
};
|
||
|
||
const removeQueryQ = (isReplace = false) => {
|
||
const params = new URLSearchParams(window.location.search);
|
||
if (!params.has("q")) return;
|
||
params.delete("q");
|
||
const qs = params.toString();
|
||
const newUrl = window.location.origin + window.location.pathname + (qs ? "?" + qs : "") + window.location.hash;
|
||
if (isReplace) history.replaceState(null, document.title, newUrl);
|
||
else history.pushState(null, document.title, newUrl);
|
||
};
|
||
|
||
// 跳转登录
|
||
const go_ajax_Login = () => {
|
||
if (typeof ajax_login === "function") ajax_login();
|
||
else window.open("https://passport.gter.net/?referer=" + escape(location.href), "_self");
|
||
};
|