feat(editor): 新增视频上传功能并优化编辑器体验
- 添加视频上传功能,支持提取视频第一帧作为封面 - 优化图片和视频上传的数量限制检查 - 修复编辑器内容为空判断逻辑,增加视频元素检测 - 改进链接插入功能,自动填充选中文本 - 调整表情选择插入方式,使用execCommand实现 - 优化附件提取逻辑,支持视频元素解析 - 添加编辑器点击事件处理,更新选区状态 - 修复样式问题,调整按钮悬停效果
This commit is contained in:
446
js/details.js
446
js/details.js
@@ -8,28 +8,18 @@ import { itemTenement } from "../component/item-tenement/item-tenement.js";
|
||||
import { latestList } from "../component/latest-list/latest-list.js";
|
||||
import { slideshowBox } from "../component/slideshow-box/slideshow-box.js";
|
||||
import { like } from "../component/like/like.js";
|
||||
import { report } from "../component/report/report.js";
|
||||
import { headTop } from "../component/head-top/head-top.js";
|
||||
|
||||
const appSectionIndex = createApp({
|
||||
setup() {
|
||||
|
||||
onMounted(() => {
|
||||
getUserInfoWin();
|
||||
|
||||
setTimeout(() => (permissions.value = window["permissions"] || ["comment.edit", "comment.delete", "offercollege.hide", "offersummary.hide", "mj.hide", "topic:manager", "topic:hide"]), 1000);
|
||||
});
|
||||
|
||||
let isLogin = ref(true);
|
||||
let realname = ref(1); // 是否已经实名
|
||||
let userInfoWin = ref({
|
||||
authority: ["comment.edit", "comment.delete", "offercollege.hide", "offersummary.hide", "mj.hide", "topic:manager", "topic:hide"],
|
||||
avatar: "https://nas.gter.net:9008/avatar/97K4EWIMLrsbGTWXslC2WFVSEKWOikN42jDKLNjtax7HL4xtfMOJSdU9oWFhY2E~/middle?random=1761733169",
|
||||
groupid: 3,
|
||||
nickname: "肖荣豪",
|
||||
realname: 1,
|
||||
token: "01346a38444d71aaadb3adad52b52c39",
|
||||
uid: 500144,
|
||||
uin: 4238049,
|
||||
});
|
||||
let isLogin = ref(false);
|
||||
let realname = ref(0); // 是否已经实名
|
||||
let userInfoWin = ref({});
|
||||
|
||||
let permissions = ref([]);
|
||||
|
||||
@@ -42,6 +32,7 @@ const appSectionIndex = createApp({
|
||||
userInfoWin.value = user;
|
||||
if (user?.uin > 0 || user?.uid > 0) isLogin.value = true;
|
||||
permissions.value = user?.authority || [];
|
||||
ismanager.value = permissions.value.indexOf("topic:manager") >= 0;
|
||||
};
|
||||
document.addEventListener("getUser", checkUser);
|
||||
};
|
||||
@@ -78,28 +69,65 @@ const appSectionIndex = createApp({
|
||||
let timestamp = ref("");
|
||||
let updatedTime = ref("");
|
||||
let token = "";
|
||||
let tokentoken = ref("");
|
||||
let uniqid = "";
|
||||
|
||||
let sectionn = ref([]);
|
||||
let tags = ref([]);
|
||||
|
||||
let uniqidRef = ref(null);
|
||||
|
||||
onMounted(() => {
|
||||
const params = getUrlParams();
|
||||
uniqid = params.uniqid || "";
|
||||
uniqid = uniqidRef.value.innerText;
|
||||
|
||||
init();
|
||||
|
||||
window.addEventListener("scroll", handleScroll);
|
||||
|
||||
checkWConfig();
|
||||
});
|
||||
|
||||
const checkWConfig = () => {
|
||||
const wConfig = JSON.parse(localStorage.getItem("wConfig")) || {};
|
||||
console.log("wConfig", wConfig);
|
||||
|
||||
if (wConfig.time) {
|
||||
const time = new Date(wConfig.time);
|
||||
const now = new Date();
|
||||
if (now - time > 24 * 60 * 60 * 1000) getWConfig();
|
||||
else {
|
||||
const config = wConfig.config || {};
|
||||
maxPicture.value = config.topic_image_count;
|
||||
}
|
||||
} else {
|
||||
getWConfig();
|
||||
}
|
||||
};
|
||||
|
||||
const getWConfig = () => {
|
||||
ajaxGet("/v2/api/config/website").then((res) => {
|
||||
if (res.code == 200) {
|
||||
let data = res["data"] || {};
|
||||
const config = data.config || {};
|
||||
maxPicture.value = config.topic_image_count;
|
||||
|
||||
data.time = new Date().toISOString();
|
||||
localStorage.setItem("wConfig", JSON.stringify(data));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const init = () => {
|
||||
ajaxget(`/v2/api/forum/getTopicDetails?uniqid=${uniqid}`).then((res) => {
|
||||
ajaxGet(`/v2/api/forum/getTopicDetails?uniqid=${uniqid}`).then((res) => {
|
||||
if (res.code != 200) {
|
||||
creationAlertBox("error", res.message || "主题不存在");
|
||||
setTimeout(() => redirectToExternalWebsite(`/`), 3000);
|
||||
return;
|
||||
}
|
||||
const data = res.data;
|
||||
|
||||
console.log(data, "data");
|
||||
let targetInfo = data.info;
|
||||
console.log("data", data);
|
||||
|
||||
if (!targetInfo.hidden) targetInfo.hidden = 0;
|
||||
|
||||
@@ -114,30 +142,129 @@ const appSectionIndex = createApp({
|
||||
authorInfo.value = Array.isArray(data.authorInfo) ? null : data.authorInfo;
|
||||
ismyself.value = data.ismyself || false;
|
||||
|
||||
const sectionNameSet = new Set(targetInfo.sectionn.map((item) => item.name));
|
||||
const newTag = targetInfo.tags.filter((tagName) => !sectionNameSet.has(tagName));
|
||||
|
||||
sectionn.value = targetInfo.sectionn;
|
||||
tags.value = targetInfo.tags;
|
||||
tags.value = newTag;
|
||||
|
||||
timestamp.value = strtimeago(targetInfo.release_at, 4);
|
||||
updatedTime.value = targetInfo.updated_at ? strtimeago(targetInfo.updated_at, 4) : null;
|
||||
|
||||
// targetInfo.content = "[attach]976054[/attach]\n\n[attachimg]1008585[/attachimg]\n[attach]850105[/attach]";
|
||||
// targetInfo.attachments = {
|
||||
// images: [
|
||||
// {
|
||||
// aid: 1008585,
|
||||
// url: "https://o.x-php.com/Zvt57TuJSUvkyhw-xG_Y2l-U_pokcHeD1NFX9ddrB_WbUGy8P79gQxcXHOeQ4soV7NkzNDQyOQ~~",
|
||||
// thumb: "https://o.x-php.com/Zvt57TuJSUvkyhw-xG_Y2l-U_pokcHeD1NFX9ddrB_WbUWy8K_hyVFweFbPD7IZK4sVMAmnF5Vzp9Fkg0jQ0Mjk~",
|
||||
// },
|
||||
// ],
|
||||
// files: [],
|
||||
// videos: [
|
||||
// {
|
||||
// aid: 976054,
|
||||
// posterurl: "https://o.x-php.com/Zvt57TuJSUvkyhw-xG_Y2l-U_pokc36P1NFX9ddrB_WbUWy8K_hyVFweFrPD7IZK4sVMAm3Btwy-9Fkg0jQ0Mjk~",
|
||||
// url: "https://o.x-php.com/Zvt57TuJSUvkyhw-xG7Y2l-c-ZwscHvqqsgFptxhXa6RWi26P-BuTQFFE7SQttkb8LQ0NDI5",
|
||||
// thumb: "https://o.x-php.com/Zvt57TuJSUvkyhw-xG7Y2l-c-ZwscHvqqsgFptxhXa6QWi2uePJ5Bg8VFLPIqoYV7MtbCG2RtAz_-kVNNDQyOQ~~",
|
||||
// },
|
||||
// {
|
||||
// aid: 850105,
|
||||
// posterurl: "https://o.x-php.com/Zvt57TuJSUvkyhw-xG_Y2l-U_pokc32G1NFX9ddrB_WbUWy8K_hyVFweFrPD7IZK4sVMA2eU5Vvl9Fkg0jQ0Mjk~",
|
||||
// url: "https://o.x-php.com/Zvt57TuJSUvkyhw-xG7Y2l-d-5otdXrqqsgFptxhXa6RWi26P-BuTQNAEuHBs9kb8LQ0NDI5",
|
||||
// thumb: "https://o.x-php.com/Zvt57TuJSUvkyhw-xG7Y2l-d-5otdXrqqsgFptxhXa6QWi2uePJ5Bg8VFLPIqoYV7MsICzzBsFj_-kVNNDQyOQ~~",
|
||||
// },
|
||||
// ],
|
||||
// };
|
||||
if (targetInfo.content) targetInfo.content = restoreHtml(targetInfo.content, targetInfo.attachments);
|
||||
|
||||
info.value = targetInfo;
|
||||
|
||||
token = data.token;
|
||||
tokentoken.value = data.token;
|
||||
|
||||
getAuthorInfo();
|
||||
getTopicOperation();
|
||||
if (info.value["anonymous"] == 0) getAuthorInfo();
|
||||
|
||||
getCoinConfig();
|
||||
isLogin.value = data.islogin;
|
||||
|
||||
if (isLogin.value) getTopicOperation();
|
||||
|
||||
getRelatedTopics();
|
||||
|
||||
getComment();
|
||||
getQrcode();
|
||||
});
|
||||
};
|
||||
|
||||
const restoreHtml = (formattedText, attachments, type) => {
|
||||
const imageList = attachments?.images || [];
|
||||
const filesList = attachments?.files || [];
|
||||
const videosList = attachments?.videos || [];
|
||||
|
||||
let html = formattedText;
|
||||
|
||||
// 1. 还原换行符为<br>标签
|
||||
html = html.replace(/\n/g, "<br>");
|
||||
|
||||
// 2. 还原块级标签的换行标记
|
||||
html = html.replace(/<br><div>/g, "<div>");
|
||||
html = html.replace(/<\/div><br>/g, "</div>");
|
||||
|
||||
// 3. 还原标签标记为span.blue
|
||||
html = html.replace(/\[tag\]([^[]+)\[\/tag\]/gi, '<a class="blue" href="/tag/$1" target="_blank">#$1</a> <span class="fill"></span> ');
|
||||
|
||||
// 4. 还原粗体标记为h2标签
|
||||
html = html.replace(/\[b\]([^[]+)\[\/b\]/gi, "<h2>$1</h2>");
|
||||
|
||||
// 5. 统一在单次遍历中按出现顺序替换 attach/attachimg
|
||||
const byAid = new Map();
|
||||
imageList.forEach((e) => byAid.set(Number(e.aid), { type: "image", ...e }));
|
||||
filesList.forEach((e) => byAid.set(Number(e.aid), { type: "file", ...e }));
|
||||
videosList.forEach((e) => byAid.set(Number(e.aid), { type: "video", ...e }));
|
||||
|
||||
html = html.replace(/\[(attachimg|attach)\](\d+)\[\/\1\]/gi, (match, tag, aidStr) => {
|
||||
const aid = Number(aidStr);
|
||||
const item = byAid.get(aid);
|
||||
if (!item) return match;
|
||||
byAid.delete(aid);
|
||||
if (item.type === "image") {
|
||||
return `<img src="${item.url}" data-aid="${aid}"><br/>`;
|
||||
}
|
||||
if (item.type === "file") {
|
||||
return `<div class="flexacenter"><a href="${item.url}" download="${item.filename}">${item.filename}</a>【点击下载附件】</div>`;
|
||||
}
|
||||
return `<video src="${item.url}" width="400" height="400" preload="none" poster="${item.posterurl}" controls></video><br/>`;
|
||||
});
|
||||
|
||||
// 6. 还原填充标签
|
||||
html = html.replace(/(<span class="blue">[^<]+<\/span>)\s+/gi, '$1 <span class="fill"></span> ');
|
||||
|
||||
// 7. 清理多余的<br>标签
|
||||
html = html.replace(/<br><br>/g, "<br>");
|
||||
|
||||
if (type != "comment") {
|
||||
byAid.forEach((item, aid) => {
|
||||
if (item.type === "image") html += `<img src="${item.url}" data-aid="${aid}"><br/>`;
|
||||
else if (item.type === "file") html += `<div class="flexacenter"><a href="${item.url}" download="${item.name || item.filename}">${item.name || item.filename}</a>【点击下载附件】</div><br/>`;
|
||||
else html += `<video src="${item.url}" width="400" height="400" preload="none" poster="${item.posterurl}" controls></video><br/>`;
|
||||
});
|
||||
}
|
||||
|
||||
return html;
|
||||
};
|
||||
|
||||
let QRcode = ref("");
|
||||
const getQrcode = () => {
|
||||
ajaxGet(`/v2/api/forum/getQrcode?token=${token}`).then((res) => {
|
||||
if (res.code != 200) return;
|
||||
const data = res.data || [];
|
||||
QRcode.value = data.url || "";
|
||||
});
|
||||
};
|
||||
|
||||
let count = ref(0);
|
||||
let medal = ref([]);
|
||||
const getAuthorInfo = () => {
|
||||
ajaxget(`/v2/api/forum/getSpaceDetail?uid=${authorInfo.value.uid || 0}&uin=${authorInfo.value.uin || 0}`).then((res) => {
|
||||
ajaxGet(`/v2/api/forum/getSpaceDetail?uid=${authorInfo.value.uid || 0}&uin=${authorInfo.value.uin || 0}`).then((res) => {
|
||||
const data = res.data;
|
||||
const countList = data.count || [];
|
||||
count.value = countList.reduce((sum, item) => {
|
||||
@@ -153,7 +280,7 @@ const appSectionIndex = createApp({
|
||||
|
||||
let recentlyList = ref([]);
|
||||
const getCreationList = (token) => {
|
||||
ajaxget(`/v2/api/forum/getSpaceTopicList?token=${token}&simple=1`).then((res) => {
|
||||
ajaxGet(`/v2/api/forum/getSpaceTopicList?token=${token}&simple=1`).then((res) => {
|
||||
const data = res.data;
|
||||
recentlyList.value = data.data || [];
|
||||
recentlyList.value = recentlyList.value.slice(0, 8);
|
||||
@@ -167,19 +294,30 @@ const appSectionIndex = createApp({
|
||||
ajax(`/v2/api/forum/getTopicOperation`, {
|
||||
token,
|
||||
actions: ["like", "collection"],
|
||||
}).then((res) => {
|
||||
const data = res.data;
|
||||
const like = data.like;
|
||||
const collection = data.collection;
|
||||
})
|
||||
.then((res) => {
|
||||
console.log("res", res);
|
||||
|
||||
islike.value = like.status;
|
||||
iscollect.value = collection.status;
|
||||
});
|
||||
const data = res.data;
|
||||
const like = data.like;
|
||||
const collection = data.collection;
|
||||
|
||||
islike.value = like.status;
|
||||
iscollect.value = collection.status;
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log("err", err);
|
||||
});
|
||||
};
|
||||
|
||||
let isLikeGif = ref(false);
|
||||
|
||||
const likeClick = () => {
|
||||
if (!isLogin.value) {
|
||||
goLogin();
|
||||
return;
|
||||
}
|
||||
|
||||
ajax(`/v2/api/forum/postTopicLike`, {
|
||||
token,
|
||||
}).then((res) => {
|
||||
@@ -217,19 +355,29 @@ const appSectionIndex = createApp({
|
||||
let defaultcoinnum = 0;
|
||||
|
||||
const getCoinConfig = () => {
|
||||
ajaxget(`/v2/api/forum/getCoinConfig`).then((res) => {
|
||||
if (!isLogin.value) {
|
||||
goLogin();
|
||||
return;
|
||||
}
|
||||
|
||||
ajaxGet(`/v2/api/forum/getCoinConfig`).then((res) => {
|
||||
const data = res.data;
|
||||
strategy.value = data.config.strategy.url || 0;
|
||||
mybalance.value = data.mybalance || 0;
|
||||
defaultcoinnum = data.defaultcoinnum || 0;
|
||||
|
||||
// openCoinBox();
|
||||
});
|
||||
};
|
||||
|
||||
let coinsState = ref(false);
|
||||
const openCoinBox = () => {
|
||||
coinsState.value = true;
|
||||
document.body.style.overflow = "hidden";
|
||||
if (!coinListRequest) getCoinRankList();
|
||||
BiComponent.initComponent();
|
||||
|
||||
// getCoinConfig();
|
||||
// coinsState.value = true;
|
||||
// document.body.style.overflow = "hidden";
|
||||
// if (!coinListRequest) getCoinRankList();
|
||||
};
|
||||
|
||||
const closeCoinBox = () => {
|
||||
@@ -270,7 +418,7 @@ const appSectionIndex = createApp({
|
||||
let coinList = ref([]);
|
||||
let coinListRequest = false; // 控制请求次数
|
||||
const getCoinRankList = () => {
|
||||
ajaxget(`/v2/api/forum/getCoinRankList?token=${token}&limit=1000`).then((res) => {
|
||||
ajaxGet(`/v2/api/forum/getCoinRankList?token=${token}&limit=1000`).then((res) => {
|
||||
const data = res.data;
|
||||
coinNubmer.value = data.nubmer;
|
||||
coinList.value = data.data;
|
||||
@@ -281,7 +429,7 @@ const appSectionIndex = createApp({
|
||||
let relatedList = ref([]);
|
||||
let relatedTime = ref("");
|
||||
const getRelatedTopics = () => {
|
||||
ajaxget(`/v2/api/forum/getRelatedTopics?uniqid=${uniqid}&limit=8`).then((res) => {
|
||||
ajaxGet(`/v2/api/forum/getRelatedTopics?uniqid=${uniqid}&limit=8`).then((res) => {
|
||||
const data = res.data;
|
||||
relatedTime.value = data.updated_at || "";
|
||||
relatedList.value = data.list || [];
|
||||
@@ -295,9 +443,10 @@ const appSectionIndex = createApp({
|
||||
let commentTotalCount = ref(0);
|
||||
|
||||
const getComment = () => {
|
||||
if (commentPage.value == 0 || isgetCommentSate) return;
|
||||
console.log("commentPage.value", commentPage.value);
|
||||
if (commentPage.value == 0 || isgetCommentSate || !token) return;
|
||||
isgetCommentSate = true;
|
||||
ajaxget(`/v2/api/forum/getCommentList?token=${token}&page=${commentPage.value}&limit=1500`)
|
||||
ajaxGet(`/v2/api/forum/getCommentList?token=${token}&page=${commentPage.value}&limit=20`)
|
||||
.then((res) => {
|
||||
if (res.code != 200) {
|
||||
creationAlertBox("error", res.message || "");
|
||||
@@ -309,26 +458,31 @@ const appSectionIndex = createApp({
|
||||
element.timestamp = strtimeago(element.created_at, 4);
|
||||
element["picture"] = [];
|
||||
element["isReplyBoxShow"] = 0;
|
||||
|
||||
if (element["content"]) element["content"] = restoreHtml(element["content"], element.attachments, "comment");
|
||||
|
||||
if (element.child.length > 0) {
|
||||
element.child.forEach((el) => {
|
||||
el["picture"] = [];
|
||||
el.timestamp = strtimeago(element.created_at, 4);
|
||||
el["isReplyBoxShow"] = 0;
|
||||
|
||||
if (el["content"]) el["content"] = restoreHtml(el["content"], el.attachments, "comment");
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
if (commentPage.value > 1) {
|
||||
for (let index = 0; index < data.data.length; index++) {
|
||||
if (alreadyCommentIdList.includes(data.data[index].id)) {
|
||||
data.data.splice(index, 1);
|
||||
index--;
|
||||
}
|
||||
}
|
||||
}
|
||||
// if (commentPage.value > 1) {
|
||||
// for (let index = 0; index < data.data.length; index++) {
|
||||
// if (alreadyCommentIdList.includes(data.data[index].id)) {
|
||||
// data.data.splice(index, 1);
|
||||
// index--;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
commentList.value = commentList.value.concat(data.data);
|
||||
commentTotalCount.value = data.count;
|
||||
commentTotalCount.value = data.commentcount;
|
||||
commentPage.value = data.count > commentList.value.length ? commentPage.value + 1 : 0;
|
||||
})
|
||||
.finally(() => {
|
||||
@@ -339,8 +493,8 @@ const appSectionIndex = createApp({
|
||||
let picture = ref([]);
|
||||
|
||||
const openUserInfo = (index, i) => {
|
||||
if (i != undefined && commentList.value[index].child[i].user["uin"] > 0) commentList.value[index].child[i]["avatarState"] = true;
|
||||
if (i == undefined && index != undefined && commentList.value[index].user["uin"] > 0) commentList.value[index]["avatarState"] = true;
|
||||
if (i != undefined && (commentList.value[index].child[i].user["uin"] > 0 || commentList.value[index].child[i].user["uid"] > 0)) commentList.value[index].child[i]["avatarState"] = true;
|
||||
if (i == undefined && index != undefined && (commentList.value[index].user["uin"] > 0 || commentList.value[index].user["uid"] > 0)) commentList.value[index]["avatarState"] = true;
|
||||
};
|
||||
|
||||
const closeUserInfo = (index, i) => {
|
||||
@@ -348,6 +502,8 @@ const appSectionIndex = createApp({
|
||||
else if (index != undefined) commentList.value[index]["avatarState"] = false;
|
||||
};
|
||||
|
||||
let isReplyBoxShow = ref(true);
|
||||
|
||||
// 打开 回答-评论 的子评论
|
||||
const openAnswerCommentsChild = (index, i) => {
|
||||
if (realname.value == 0 && userInfoWin.value?.uin > 0) {
|
||||
@@ -364,6 +520,8 @@ const appSectionIndex = createApp({
|
||||
|
||||
if (i == null) commentList.value[index]["childState"] = true;
|
||||
else commentList.value[index].child[i]["childState"] = true;
|
||||
|
||||
isReplyBoxShow.value = false;
|
||||
};
|
||||
|
||||
// 关闭 回答-评论 的子评论
|
||||
@@ -378,21 +536,24 @@ const appSectionIndex = createApp({
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
isReplyBoxShow.value = true;
|
||||
};
|
||||
|
||||
let dialogSrc = ref("");
|
||||
const handleAnswerText = (e) => {
|
||||
if (e.target.tagName === "IMG") {
|
||||
var src = e.target.getAttribute("src");
|
||||
dialogSrc.value = src;
|
||||
window.addEventListener("keydown", handleKeydown);
|
||||
}
|
||||
};
|
||||
const div = document.createElement("div");
|
||||
div.innerHTML = `<div class="detail-image flexcenter"><img class="detail-img" src="${src}" /></div>`;
|
||||
div.className = "detail-image-mask flexcenter";
|
||||
div.addEventListener("click", () => {
|
||||
document.body.style.overflow = "auto";
|
||||
div.remove();
|
||||
});
|
||||
|
||||
const handleKeydown = (event) => {
|
||||
if (event.key !== "Escape") return;
|
||||
dialogSrc.value = "";
|
||||
window.removeEventListener("keydown", handleKeydown); // 取消监听
|
||||
document.body.appendChild(div);
|
||||
document.body.style.overflow = "hidden";
|
||||
}
|
||||
};
|
||||
|
||||
// 回答-评论 点赞
|
||||
@@ -407,7 +568,7 @@ const appSectionIndex = createApp({
|
||||
return;
|
||||
}
|
||||
|
||||
ajax("https://api.gter.net/v2/api/forum/likeComment", {
|
||||
ajax("/v2/api/forum/likeComment", {
|
||||
token,
|
||||
}).then((res) => {
|
||||
if (res.code != 200) {
|
||||
@@ -471,8 +632,8 @@ const appSectionIndex = createApp({
|
||||
editEmojiState.value = false;
|
||||
};
|
||||
|
||||
const TAHomePage = (uin) => goHomePage(uin);
|
||||
const sendMessage = (uin) => goSendMessage(uin);
|
||||
const TAHomePage = (token) => goHomePage(token);
|
||||
const sendMessage = (token) => goSendMessage(token);
|
||||
|
||||
let emojiData = ref(["😀", "😁", "😆", "😅", "😂", "😉", "😍", "🥰", "😘", "🤥", "😪", "😵💫", "🤓", "🥺", "😋", "😜", "🤪", "😎", "🤩", "🥳", "😔", "🙁", "😭", "😡", "😳", "🤗", "🤔", "🤭", "🤫", "😯", "😵", "🙄", "🥴", "🤢", "🤑", "🤠", "👌", "✌️", "🤟", "🤘", "🤙", "👍", "👎", "✊", "👏", "🤝", "🙏", "💪", "❎️", "✳️", "✴️", "❇️", "#️⃣", "*️⃣", "1️⃣", "2️⃣", "3️⃣", "4️⃣", "5️⃣", "6️⃣", "7️⃣", "8️⃣", "9️⃣", "🔟", "🆗", "🈶", "🉐", "🉑", "🌹", "🥀", "🌸", "🌺", "🌷", "🌲", "☘️", "🍀", "🍁", "🌙", "⭐", "🌍", "☀️", "⭐️", "🌟", "☁️", "🌈", "☂️", "❄️", "☃️", "☄️", "🔥", "💧", "🍎", "🍐", "🍊", "🍉", "🍓", "🍑", "🍔", "🍟", "🍕", "🥪", "🍜", "🍡", "🍨", "🍦", "🎂", "🍰", "🍭", "🍿", "🍩", "🧃", "🍹", "🍒", "🥝", "🥒", "🥦", "🥨", "🌭", "🥘", "🍱", "🍢", "🥮", "🍩", "🍪", "🧁", "🍵", "🍶", "🍻", "🥂", "🧋", "🎉", "🎁", "🧧", "🎃", "🎄", "🧨", "✨️", "🎈", "🎊", "🎋", "🎍", "🎀", "🎖️", "🏆️", "🏅", "💌", "📬", "🚗", "🚕", "🚲", "🛵", "🚀", "🚁", "⛵", "🚢", "🔮", "🧸", "🀄️"]);
|
||||
|
||||
@@ -497,7 +658,7 @@ const appSectionIndex = createApp({
|
||||
if (!isLogin.value) goLogin();
|
||||
};
|
||||
|
||||
const maxPicture = 10;
|
||||
let maxPicture = ref(10);
|
||||
|
||||
const handleFileUpload = (event, index, i) => {
|
||||
closeEmoji();
|
||||
@@ -518,13 +679,11 @@ const appSectionIndex = createApp({
|
||||
else target = picture.value;
|
||||
}
|
||||
|
||||
if (target.length >= maxPicture) {
|
||||
creationAlertBox("error", `最多只能上传 ${maxPicture} 张图片`);
|
||||
if (target.length >= maxPicture.value) {
|
||||
creationAlertBox("error", `最多只能上传 ${maxPicture.value} 张图片`);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("现有图片", target);
|
||||
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e) => {
|
||||
const base64 = e.target.result;
|
||||
@@ -580,7 +739,7 @@ const appSectionIndex = createApp({
|
||||
|
||||
const getUploadConfig = () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
ajax("https://api.gter.net/v1/config/upload?type=comment").then((res) => {
|
||||
ajaxGet("/v2/api/config/upload?type=comment").then((res) => {
|
||||
let data = res.data;
|
||||
uploadConfig = data;
|
||||
resolve();
|
||||
@@ -641,6 +800,8 @@ const appSectionIndex = createApp({
|
||||
images: image,
|
||||
};
|
||||
|
||||
console.log("userInfoWin", userInfoWin.value);
|
||||
|
||||
ajax("/v2/api/forum/postComment", {
|
||||
content,
|
||||
token,
|
||||
@@ -670,6 +831,7 @@ const appSectionIndex = createApp({
|
||||
attachments,
|
||||
picture: [],
|
||||
timestamp,
|
||||
user: { ...userInfoWin.value },
|
||||
};
|
||||
|
||||
commentList.value[index]["child"].push(targetData);
|
||||
@@ -686,6 +848,7 @@ const appSectionIndex = createApp({
|
||||
attachments,
|
||||
picture: [],
|
||||
timestamp,
|
||||
user: { ...userInfoWin.value },
|
||||
};
|
||||
commentList.value[index]["child"].unshift(targetData);
|
||||
commentList.value[index]["childnum"]++;
|
||||
@@ -701,6 +864,7 @@ const appSectionIndex = createApp({
|
||||
attachments,
|
||||
picture: [],
|
||||
timestamp,
|
||||
user: { ...userInfoWin.value },
|
||||
};
|
||||
commentList.value.unshift(targetData);
|
||||
inputTextarea.value = "";
|
||||
@@ -839,8 +1003,8 @@ const appSectionIndex = createApp({
|
||||
else target = picture.value;
|
||||
}
|
||||
|
||||
if (target.length >= maxPicture) {
|
||||
creationAlertBox("error", `最多只能上传 ${maxPicture} 张图片`);
|
||||
if (target.length >= maxPicture.value) {
|
||||
creationAlertBox("error", `最多只能上传 ${maxPicture.value} 张图片`);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -870,6 +1034,39 @@ const appSectionIndex = createApp({
|
||||
}
|
||||
};
|
||||
|
||||
const alsoCommentsData = (index, i) => {
|
||||
if (!isLogin.value) {
|
||||
goLogin();
|
||||
return;
|
||||
}
|
||||
|
||||
const parentid = commentList.value[index]["id"];
|
||||
|
||||
ajax("/v2/api/forum/childrenList", {
|
||||
token,
|
||||
parentid,
|
||||
limit: 2000,
|
||||
page: 1,
|
||||
childlimit: 3,
|
||||
}).then((res) => {
|
||||
if (res.code != 200) {
|
||||
creationAlertBox("error", res.message || "操作成功");
|
||||
return;
|
||||
}
|
||||
let data = res.data;
|
||||
|
||||
data.data.forEach((element, index) => {
|
||||
element.timestamp = strtimeago(element.created_at, 4);
|
||||
element["isReplyBoxShow"] = 0;
|
||||
element["picture"] = [];
|
||||
});
|
||||
|
||||
let merged = [...commentList.value[index]["child"], ...data.data.filter((item2) => !commentList.value[index]["child"].find((item1) => item1.id == item2.id))];
|
||||
|
||||
commentList.value[index]["child"] = merged;
|
||||
});
|
||||
};
|
||||
|
||||
// 自动输入框增高
|
||||
const autoResize = (e) => {
|
||||
e.target.style.height = "auto"; // 重置高度
|
||||
@@ -916,7 +1113,108 @@ const appSectionIndex = createApp({
|
||||
});
|
||||
};
|
||||
|
||||
return { openDiscuss, commentDelete, handleInputPaste, autoResize, editCommentState, selectEditEmoji, closeEditEmoji, openEditEmoji, closeEdit, openEdit, closeEditFileUpload, postEditComment, submitAnswerComments, closePictureUpload, closeFileUpload, picture, editToken, editPicture, editInput, editEmojiState, handleFileUpload, inputTextarea, judgeLogin, handleEditFile, selectEmoji, emojiData, emojiMaskState, emojiState, closeEmoji, openEmoji, closeAnswerCommentsChild, openAnswerCommentsChild, dialogSrc, handleAnswerText, sendMessage, TAHomePage, operateAnswerCommentsLike, closeUserInfo, openUserInfo, permissions, commentList, commentPage, commentTotalCount, picture, userInfoWin, relatedList, relatedTime, coinNubmer, coinList, coinAmount, coinSubmit, strategy, mybalance, coinsState, openCoinBox, closeCoinBox, isLikeGif, likeClick, collectClick, islike, iscollect, recentlyList, medal, count, sectionn, tags, authorInfo, info, timestamp, updatedTime };
|
||||
let show = ref(false);
|
||||
let ismanager = ref(false);
|
||||
const cutShow = () => {
|
||||
show.value = !show.value; // 修改为切换显示状态
|
||||
};
|
||||
|
||||
let reportState = ref(false);
|
||||
let reportToken = ref("");
|
||||
provide("reportState", reportState);
|
||||
|
||||
// 举报
|
||||
const report = (token) => {
|
||||
cutShow();
|
||||
reportState.value = true;
|
||||
reportToken.value = token;
|
||||
};
|
||||
|
||||
// 隐藏
|
||||
const hide = () => {
|
||||
const target = info.value;
|
||||
managerHide(token, target.hidden, "thread").then((value) => {
|
||||
target.hidden = value;
|
||||
info.value = target;
|
||||
cutShow();
|
||||
});
|
||||
};
|
||||
|
||||
// 推荐
|
||||
const recommend = () => {
|
||||
const target = info.value;
|
||||
managerRecommend(token, target.recommend).then((value) => {
|
||||
target.recommend = value;
|
||||
info.value = target;
|
||||
cutShow();
|
||||
});
|
||||
};
|
||||
|
||||
// 精华
|
||||
const essence = () => {
|
||||
const target = info.value;
|
||||
managerEssence(token, target.best).then((value) => {
|
||||
target.best = value;
|
||||
info.value = target;
|
||||
cutShow();
|
||||
});
|
||||
};
|
||||
|
||||
const copyLinkClick = () => {
|
||||
copyForumUid(location.href);
|
||||
};
|
||||
|
||||
const goPersonalHomepage = (token) => {
|
||||
if (!token) return;
|
||||
redirectToExternalWebsite(`/u/${token}`);
|
||||
};
|
||||
|
||||
let searchInput = ref("");
|
||||
let defaultSearchText = ref("屯特");
|
||||
const goSearch = () => {
|
||||
const searchText = searchInput.value || defaultSearchText.value;
|
||||
redirectToExternalWebsite("/search/" + searchText);
|
||||
};
|
||||
|
||||
const edit = () => {
|
||||
redirectToExternalWebsite(`/publish?uniqid=${info.value.uniqid}`);
|
||||
};
|
||||
|
||||
let pitchInputState = ref(false);
|
||||
|
||||
const sidebarFixed = ref(false);
|
||||
|
||||
const handleScroll = () => {
|
||||
matterHeight.value = -(matterRef.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 scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
|
||||
const scrollHeight = document.documentElement.scrollHeight || document.body.scrollHeight;
|
||||
const clientHeight = window.innerHeight;
|
||||
|
||||
// 列表下 滑动到底部 获取新数据
|
||||
if (scrollTop + clientHeight >= scrollHeight - 200) getComment();
|
||||
};
|
||||
|
||||
const matterRef = ref(null);
|
||||
const sidebarRef = ref(null);
|
||||
|
||||
const deleteItem = () => {
|
||||
managerDelete(token)
|
||||
.then(() => redirectToExternalWebsite("/", "_self"))
|
||||
.finally(() => cutShow());
|
||||
};
|
||||
|
||||
let sidebarHeight = ref(0);
|
||||
let matterHeight = ref(0);
|
||||
|
||||
const share = () => {
|
||||
ajax(`/v2/api/forum/postTopicShare`, { token });
|
||||
};
|
||||
|
||||
return { uniqidRef, share, reportToken, isReplyBoxShow, matterHeight, sidebarHeight, deleteItem, maxPicture, sidebarFixed, matterRef, sidebarRef, pitchInputState, ismyself, edit, searchInput, defaultSearchText, goSearch, goPersonalHomepage, QRcode, alsoCommentsData, copyLinkClick, reportState, tokentoken, essence, recommend, hide, report, cutShow, ismanager, show, openDiscuss, commentDelete, handleInputPaste, autoResize, editCommentState, selectEditEmoji, closeEditEmoji, openEditEmoji, closeEdit, openEdit, closeEditFileUpload, postEditComment, submitAnswerComments, closePictureUpload, closeFileUpload, picture, editToken, editPicture, editInput, editEmojiState, handleFileUpload, inputTextarea, judgeLogin, handleEditFile, selectEmoji, emojiData, emojiMaskState, emojiState, closeEmoji, openEmoji, closeAnswerCommentsChild, openAnswerCommentsChild, handleAnswerText, sendMessage, TAHomePage, operateAnswerCommentsLike, closeUserInfo, openUserInfo, permissions, commentList, commentPage, commentTotalCount, picture, userInfoWin, relatedList, relatedTime, coinNubmer, coinList, coinAmount, coinSubmit, strategy, mybalance, coinsState, openCoinBox, closeCoinBox, isLikeGif, likeClick, collectClick, islike, iscollect, recentlyList, medal, count, sectionn, tags, authorInfo, info, timestamp, updatedTime };
|
||||
},
|
||||
});
|
||||
|
||||
@@ -929,5 +1227,7 @@ appSectionIndex.component("itemTenement", itemTenement);
|
||||
appSectionIndex.component("latestList", latestList);
|
||||
appSectionIndex.component("slideshowBox", slideshowBox);
|
||||
appSectionIndex.component("like", like);
|
||||
appSectionIndex.component("report", report);
|
||||
appSectionIndex.component("headTop", headTop);
|
||||
|
||||
appSectionIndex.mount("#details");
|
||||
|
||||
Reference in New Issue
Block a user