From 8ea3a7b25cc0fce9588f7fe64afba7e0d4b54d68 Mon Sep 17 00:00:00 2001
From: tone <3341154833@qq.com>
Date: Sat, 31 Aug 2024 13:38:22 +0800
Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84=E5=8D=9A=E5=AE=A2=E8=AF=84?=
=?UTF-8?q?=E8=AE=BA=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Server/src/APIs/BlogComment.ts | 46 +++++++++++++++
Server/src/Plugs/Middleware/MountIP.ts | 11 ++++
Server/src/Plugs/Middleware/MountUserAgent.ts | 11 ++++
Server/src/Server/Server.ts | 2 +
.../components/Blog/BlogContentToolBar.vue | 56 +++++++++++++------
5 files changed, 110 insertions(+), 16 deletions(-)
create mode 100644 Server/src/APIs/BlogComment.ts
create mode 100644 Server/src/Plugs/Middleware/MountIP.ts
create mode 100644 Server/src/Plugs/Middleware/MountUserAgent.ts
diff --git a/Server/src/APIs/BlogComment.ts b/Server/src/APIs/BlogComment.ts
new file mode 100644
index 0000000..2a41797
--- /dev/null
+++ b/Server/src/APIs/BlogComment.ts
@@ -0,0 +1,46 @@
+import { API } from "../Plugs/API/API";
+import ServerStdResponse from "../ServerStdResponse";
+import MySQLConnection from '../Plugs/MySQLConnection'
+import MountUserAgent from "../Plugs/Middleware/mountUserAgent";
+import axios from "axios";
+import MountIP from "../Plugs/Middleware/mountIP";
+
+
+// 提交博客评论
+class BlogComment extends API {
+ constructor() {
+ super('POST', '/blogComment', MountUserAgent, MountIP);
+ }
+
+ public async onRequset(data: any, res: any) {
+ let { bloguuid, content, name, _userAgent, _ip } = data;
+ if (!bloguuid || bloguuid.length != 32 || typeof content != 'string' || typeof name != 'string'
+ || content.trim() == '' || name.trim() == '') {
+ return res.json(ServerStdResponse.INVALID_PARAMS);
+ }
+
+ // 处理数据
+ content = content.trim();
+ name = name.trim();
+ _ip = (_ip as string).replace('::ffff:', '');
+ // 获取IPAddress
+ let ip_address = '未知'
+ try {
+ let ipAddressRes = await axios.get(`http://ip-api.com/json/${_ip}?lang=zh-CN`);
+ if (ipAddressRes.data && ipAddressRes.data.status == 'success') {
+ ip_address = ipAddressRes.data.country == '中国' ? ipAddressRes.data.city : ipAddressRes.data.country;
+ }
+ } catch (error) {
+ this.logger.warn('获取IP属地失败', error);
+ }
+
+ let blogLikeRes = await MySQLConnection.execute('INSERT INTO blog_comment (uuid, content, name, ip, ip_address, user_agent, time) VALUES (?,?,?,?,?,?,?)', [bloguuid, content.trim(), name.trim(), _ip, ip_address, _userAgent, Date.now()]);
+ if (!blogLikeRes || blogLikeRes.affectedRows != 1) {
+ this.logger.error('发布博客评论时,数据库发生错误');
+ return res.json(ServerStdResponse.SERVER_ERROR);
+ }
+ return res.json(ServerStdResponse.OK);
+ }
+}
+
+export default BlogComment;
\ No newline at end of file
diff --git a/Server/src/Plugs/Middleware/MountIP.ts b/Server/src/Plugs/Middleware/MountIP.ts
new file mode 100644
index 0000000..9040031
--- /dev/null
+++ b/Server/src/Plugs/Middleware/MountIP.ts
@@ -0,0 +1,11 @@
+import { Request, Response, NextFunction } from "express"
+import Logger from "../Logger";
+const logger = new Logger('MountIP')
+
+let MountIP = (req: Request, res: Response, next: NextFunction) => {
+ req.body._ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress || req.ip;
+ logger.info(`[${req.method}][${req.url.split('?')[0]}] IP解析成功:${req.body._ip}`);
+ next();
+}
+
+export default MountIP;
\ No newline at end of file
diff --git a/Server/src/Plugs/Middleware/MountUserAgent.ts b/Server/src/Plugs/Middleware/MountUserAgent.ts
new file mode 100644
index 0000000..3507e41
--- /dev/null
+++ b/Server/src/Plugs/Middleware/MountUserAgent.ts
@@ -0,0 +1,11 @@
+import { Request, Response, NextFunction } from "express"
+import Logger from "../Logger";
+const logger = new Logger('MountUserAgent')
+
+let MountUserAgent = (req: Request, res: Response, next: NextFunction) => {
+ req.body._userAgent = req.headers['user-agent'];
+ logger.info(`[${req.method}][${req.url.split('?')[0]}] 用户代理解析成功:${req.body._userAgent}`);
+ next();
+}
+
+export default MountUserAgent;
\ No newline at end of file
diff --git a/Server/src/Server/Server.ts b/Server/src/Server/Server.ts
index 0777dec..878f505 100644
--- a/Server/src/Server/Server.ts
+++ b/Server/src/Server/Server.ts
@@ -11,6 +11,7 @@ import GetResourceList from "../APIs/GetResourceList";
import GetBlogList from "../APIs/GetBlogList";
import GetBlogContent from "../APIs/GetBlogContent";
import BlogLike from "../APIs/BlogLike";
+import BlogComment from "../APIs/BlogComment";
import GetCaptcha from "../APIs/GetCaptcha";
import CheckCaptcha from "../APIs/CheckCaptcha";
@@ -30,6 +31,7 @@ class Server {
this.apiLoader.add(GetBlogList);
this.apiLoader.add(GetBlogContent);
this.apiLoader.add(BlogLike);
+ this.apiLoader.add(BlogComment);
this.apiLoader.add(GetCaptcha);
this.apiLoader.add(CheckCaptcha);
diff --git a/tonecn/src/components/Blog/BlogContentToolBar.vue b/tonecn/src/components/Blog/BlogContentToolBar.vue
index 49f38ed..54fcc5c 100644
--- a/tonecn/src/components/Blog/BlogContentToolBar.vue
+++ b/tonecn/src/components/Blog/BlogContentToolBar.vue
@@ -4,13 +4,14 @@ import { ElMessage } from 'element-plus';
import { ref, onMounted, onUnmounted } from 'vue';
import { useRoute } from 'vue-router';
import { request } from '@/lib/request';
+import RotationVerification from '../Common/RotationVerification.vue';
const route = useRoute()
const bloguuid = route.params.uuid;
const inputComment = ref('')
-const inputCommentName = ref('')
-const commentDialogVisible = ref(false)
+let inputCommentName = '';
const toolBarVisible = ref(true);
const isLiked = ref(false)
+const isCaptchaViewShow = ref(false)
let lastScrollTop = 0;
const handleScrollMove = () => {
const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
@@ -45,6 +46,40 @@ onUnmounted(async () => {
window.removeEventListener('scroll', handleScrollMove)
})
+const commentHandle = () => {
+ if (inputComment.value == '' || inputComment.value.trim() == '') {
+ return ElMessage.warning('请先填写留言内容哟~')
+ }
+ ElMessageBox.prompt('请输入留言昵称(可留空)', 'Tip', {
+ confirmButtonText: '提交',
+ cancelButtonText: '取消',
+ }).then(({ value }) => {
+ inputCommentName = value ? value : '';
+ isCaptchaViewShow.value = true;
+ }).catch(() => {
+ ElMessage.info('已取消')
+ })
+}
+const submitComment = async () => {
+ isCaptchaViewShow.value = false;
+ ElMessage.info('正在提交,请稍后')
+ try {
+ let commentRes = await request.post('blogComment', {
+ bloguuid: bloguuid,
+ content: inputComment.value.trim(),
+ name: inputCommentName.trim() == '' ? '匿名' : inputCommentName.trim()
+ })
+ if (commentRes.code == 0) {
+ return ElMessage.success('评论成功~');
+ } else {
+ throw new Error(commentRes.message);
+ }
+ } catch (error) {
+ console.error('评论失败', error)
+ ElMessage.error('遇到了一些问题,稍后再来试试吧~')
+ }
+}
+
@@ -52,25 +87,14 @@ onUnmounted(async () => {
-
+
-
-
-
每篇文章最多可发布3条评论,确认要现在发布吗?
-
另外,您可选择留下昵称:
-
-
-
-
-
-
+ { isCaptchaViewShow = false; ElMessage.warning('验证失败') }" @success="submitComment" />