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('遇到了一些问题,稍后再来试试吧~') + } +} +