refactor(views): 重构多个视图组件代码结构,优化类型定义和逻辑组织
feat(services): 新增文章分页查询方法,支持按状态筛选文章 style(styles): 调整主布局样式,优化分页组件显示效果 docs(README): 更新API文档,完善服务模块说明和类型定义 fix(components): 修复左侧模块点击属性时使用错误字段名的问题 chore(package): 移除未使用的依赖项,清理项目依赖 perf(layouts): 优化主布局组件性能,拆分功能模块,减少重复计算 test(views): 为分页组件添加基础测试用例 build: 更新构建配置,优化生产环境打包 ci: 调整CI配置,添加类型检查步骤
This commit is contained in:
@@ -131,6 +131,8 @@ import { ElMessage, ElForm } from 'element-plus'
|
||||
import { useGlobalStore } from '@/store/globalStore'
|
||||
import { formatDate } from '@/utils/dateUtils'
|
||||
|
||||
// ============================== 组件初始化 ==============================
|
||||
|
||||
// 定义组件属性
|
||||
const props = defineProps({
|
||||
comments: {
|
||||
@@ -138,65 +140,37 @@ const props = defineProps({
|
||||
default: null
|
||||
}
|
||||
})
|
||||
const globalStore = useGlobalStore()
|
||||
const messageBoardData = ref([]) // 留言板留言(articleid为空的主留言及其回复)
|
||||
const loading = ref(false)
|
||||
const submitting = ref(false)
|
||||
const replyingTo = ref({ id: null, nickname: '', content: '' })
|
||||
const formRef = ref()
|
||||
// 验证码相关状态
|
||||
const captchaHint = ref('')
|
||||
const captchaAnswer = ref('')
|
||||
const showCaptchaHint = ref(false)
|
||||
|
||||
// 全局状态管理
|
||||
const globalStore = useGlobalStore()
|
||||
|
||||
// ============================== 响应式数据 ==============================
|
||||
|
||||
// 留言板数据状态
|
||||
const messageBoardData = ref([]) // 留言板留言(articleid为空的主留言及其回复)
|
||||
const loading = ref(false) // 加载状态
|
||||
const submitting = ref(false) // 提交状态
|
||||
const replyingTo = ref({ id: null, nickname: '', content: '' }) // 正在回复的信息
|
||||
const formRef = ref() // 表单引用
|
||||
|
||||
// 验证码相关状态
|
||||
const captchaHint = ref('') // 验证码提示
|
||||
const captchaAnswer = ref('') // 验证码答案
|
||||
const showCaptchaHint = ref(false) // 是否显示验证码提示
|
||||
|
||||
// 表单数据
|
||||
const form = reactive({
|
||||
parentid: null,
|
||||
replyid: null,
|
||||
articleid: null,
|
||||
content: '',
|
||||
nickname: '',
|
||||
email: '',
|
||||
captcha: ''
|
||||
parentid: null, // 父留言ID
|
||||
replyid: null, // 被回复留言ID
|
||||
articleid: null, // 文章ID
|
||||
content: '', // 评论内容
|
||||
nickname: '', // 昵称
|
||||
email: '', // 邮箱
|
||||
captcha: '' // 验证码
|
||||
})
|
||||
|
||||
// 生成简单验证码
|
||||
const generateCaptcha = () => {
|
||||
// 随机选择数学题或字符验证码
|
||||
const isMathCaptcha = Math.random() > 0.5
|
||||
// ============================== 表单验证规则 ==============================
|
||||
|
||||
if (isMathCaptcha) {
|
||||
// 简单数学题:加法或减法
|
||||
const num1 = Math.floor(Math.random() * 10) + 1
|
||||
const num2 = Math.floor(Math.random() * 10) + 1
|
||||
const operator = Math.random() > 0.5 ? '+' : '-'
|
||||
|
||||
let answer
|
||||
if (operator === '+') {
|
||||
answer = num1 + num2
|
||||
} else {
|
||||
// 确保减法结果为正
|
||||
const larger = Math.max(num1, num2)
|
||||
const smaller = Math.min(num1, num2)
|
||||
captchaHint.value = `${larger} - ${smaller} = ?`
|
||||
captchaAnswer.value = (larger - smaller).toString()
|
||||
return
|
||||
}
|
||||
|
||||
captchaHint.value = `${num1} ${operator} ${num2} = ?`
|
||||
captchaAnswer.value = answer.toString()
|
||||
} else {
|
||||
// 简单字符验证码
|
||||
const chars = 'ABCDEFGHIJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz123456789'
|
||||
let captcha = ''
|
||||
for (let i = 0; i < 4; i++) {
|
||||
captcha += chars.charAt(Math.floor(Math.random() * chars.length))
|
||||
}
|
||||
captchaHint.value = captcha
|
||||
captchaAnswer.value = captcha.toLowerCase()
|
||||
}
|
||||
}
|
||||
|
||||
// 表单验证规则
|
||||
const rules = {
|
||||
content: [
|
||||
{ required: true, message: '请输入评论内容', trigger: 'blur' },
|
||||
@@ -237,42 +211,109 @@ const rules = {
|
||||
]
|
||||
}
|
||||
|
||||
// ============================== 验证码模块 ==============================
|
||||
|
||||
// 获取Gravatar头像URL
|
||||
/**
|
||||
* 生成验证码
|
||||
* 随机选择生成数学题验证码或字符验证码
|
||||
*/
|
||||
const generateCaptcha = () => {
|
||||
// 随机选择数学题或字符验证码
|
||||
const isMathCaptcha = Math.random() > 0.5
|
||||
|
||||
if (isMathCaptcha) {
|
||||
generateMathCaptcha()
|
||||
} else {
|
||||
generateCharCaptcha()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成数学题验证码
|
||||
* 包含简单的加法或减法运算
|
||||
*/
|
||||
const generateMathCaptcha = () => {
|
||||
// 简单数学题:加法或减法
|
||||
const num1 = Math.floor(Math.random() * 10) + 1
|
||||
const num2 = Math.floor(Math.random() * 10) + 1
|
||||
const operator = Math.random() > 0.5 ? '+' : '-'
|
||||
|
||||
if (operator === '+') {
|
||||
const answer = num1 + num2
|
||||
captchaHint.value = `${num1} ${operator} ${num2} = ?`
|
||||
captchaAnswer.value = answer.toString()
|
||||
} else {
|
||||
// 确保减法结果为正
|
||||
const larger = Math.max(num1, num2)
|
||||
const smaller = Math.min(num1, num2)
|
||||
captchaHint.value = `${larger} - ${smaller} = ?`
|
||||
captchaAnswer.value = (larger - smaller).toString()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成字符验证码
|
||||
* 随机生成4位大小写字母和数字的组合
|
||||
*/
|
||||
const generateCharCaptcha = () => {
|
||||
const chars = 'ABCDEFGHIJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz123456789'
|
||||
let captcha = ''
|
||||
for (let i = 0; i < 4; i++) {
|
||||
captcha += chars.charAt(Math.floor(Math.random() * chars.length))
|
||||
}
|
||||
captchaHint.value = captcha
|
||||
captchaAnswer.value = captcha.toLowerCase()
|
||||
}
|
||||
|
||||
// ============================== UI辅助模块 ==============================
|
||||
|
||||
/**
|
||||
* 获取Gravatar头像URL
|
||||
* @param {string} email - 用户邮箱
|
||||
* @returns {string|null} - 头像URL或null
|
||||
*/
|
||||
const getAvatarUrl = (email) => {
|
||||
if (!email) return null;
|
||||
|
||||
// 简单验证邮箱格式
|
||||
const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
|
||||
if (!emailRegex.test(email)) return null;
|
||||
|
||||
// 使用邮箱的MD5哈希(这里简化处理,实际项目中应该使用md5库)
|
||||
// 注意:在实际项目中应该使用正确的MD5哈希函数
|
||||
return `https://www.gravatar.com/avatar/${email}?d=404&s=40`;
|
||||
}
|
||||
|
||||
// 获取名字的首字母
|
||||
/**
|
||||
* 获取名字的首字母
|
||||
* 用于生成字母头像
|
||||
* @param {string} name - 用户昵称
|
||||
* @returns {string} - 首字母或问号
|
||||
*/
|
||||
const getInitialLetter = (name) => {
|
||||
if (!name || typeof name !== 'string') return '?';
|
||||
|
||||
// 移除可能的@回复前缀
|
||||
const cleanName = name.replace(/^.+@\s*/, '');
|
||||
|
||||
// 获取第一个字符
|
||||
const firstChar = cleanName.charAt(0).toUpperCase();
|
||||
|
||||
return firstChar;
|
||||
// 获取第一个字符并转为大写
|
||||
return cleanName.charAt(0).toUpperCase();
|
||||
}
|
||||
|
||||
// 获取首字母头像的样式
|
||||
/**
|
||||
* 获取首字母头像的样式
|
||||
* 根据名字生成一致的颜色
|
||||
* @param {string} name - 用户昵称
|
||||
* @returns {Object} - 包含背景色和文字颜色的样式对象
|
||||
*/
|
||||
const getLetterAvatarStyle = (name) => {
|
||||
// 颜色映射表,根据名字生成一致的颜色
|
||||
// 预定义的颜色数组
|
||||
const colors = [
|
||||
'#4A90E2', '#50E3C2', '#F5A623', '#D0021B', '#9013FE',
|
||||
'#B8E986', '#BD10E0', '#50E3C2', '#417505', '#7ED321',
|
||||
'#BD10E0', '#F8E71C', '#8B572A', '#9B9B9B', '#4A4A4A'
|
||||
];
|
||||
|
||||
// 根据名字生成一个一致的颜色索引
|
||||
// 根据名字生成一致的颜色索引
|
||||
let hash = 0;
|
||||
if (name) {
|
||||
for (let i = 0; i < name.length; i++) {
|
||||
@@ -287,195 +328,258 @@ const getLetterAvatarStyle = (name) => {
|
||||
};
|
||||
}
|
||||
|
||||
// 从后端获取留言列表
|
||||
// ============================== 数据处理模块 ==============================
|
||||
|
||||
/**
|
||||
* 处理留言数据,构建留言与回复的层级结构
|
||||
* @param {Array} messages - 原始留言数据
|
||||
* @returns {Array} - 处理后的留言数据(包含回复数组)
|
||||
*/
|
||||
const processMessageData = (messages) => {
|
||||
// 为主留言添加replies数组
|
||||
const allMessagesWithReplies = messages.map(msg => ({
|
||||
...msg,
|
||||
replies: []
|
||||
}))
|
||||
|
||||
// 分离主留言和回复
|
||||
const mainMessages = []
|
||||
const replies = []
|
||||
|
||||
allMessagesWithReplies.forEach(msg => {
|
||||
if (msg.parentid && msg.parentid > 0) {
|
||||
replies.push(msg)
|
||||
} else {
|
||||
mainMessages.push(msg)
|
||||
}
|
||||
})
|
||||
|
||||
// 将回复添加到对应的主留言中并处理@回复显示
|
||||
processRepliesForMainMessages(mainMessages, replies)
|
||||
|
||||
return mainMessages
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理回复数据,将其添加到对应的主留言中
|
||||
* @param {Array} mainMessages - 主留言数组
|
||||
* @param {Array} replies - 回复数组
|
||||
*/
|
||||
const processRepliesForMainMessages = (mainMessages, replies) => {
|
||||
replies.forEach(reply => {
|
||||
// 找到父留言
|
||||
const parentMsg = mainMessages.find(msg => msg.messageid === reply.parentid)
|
||||
if (parentMsg) {
|
||||
// 处理@回复的显示名称
|
||||
processReplyDisplayName(reply, replies)
|
||||
parentMsg.replies.push(reply)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理回复的显示名称
|
||||
* 如果是回复其他回复,添加@标记
|
||||
* @param {Object} reply - 回复对象
|
||||
* @param {Array} allReplies - 所有回复数组
|
||||
*/
|
||||
const processReplyDisplayName = (reply, allReplies) => {
|
||||
if (reply.replyid) {
|
||||
const repliedMsg = allReplies.find(msg => msg.messageid === reply.replyid)
|
||||
if (repliedMsg) {
|
||||
reply.displayName = `${reply.nickname}@ ${repliedMsg.nickname}`
|
||||
} else {
|
||||
reply.displayName = reply.nickname
|
||||
}
|
||||
} else {
|
||||
reply.displayName = reply.nickname
|
||||
}
|
||||
}
|
||||
|
||||
// ============================== API调用模块 ==============================
|
||||
|
||||
/**
|
||||
* 从后端获取留言列表
|
||||
* 根据articleid决定获取文章留言还是全局留言
|
||||
*/
|
||||
const fetchMessages = async () => {
|
||||
try {
|
||||
loading.value = true
|
||||
let res = null
|
||||
|
||||
// 优先使用props传递的articleid,其次使用globalStore中的数据
|
||||
let articleid = props.comments || null
|
||||
|
||||
if (!articleid) {
|
||||
// 安全获取文章ID,如果globalStore中没有articleInfo则返回null
|
||||
const articleData = globalStore.getValue('articleInfo')
|
||||
articleid = (articleData && typeof articleData === 'object' && 'articleid' in articleData) ? articleData.articleid : null
|
||||
}
|
||||
|
||||
// 获取文章ID(优先使用props,其次使用全局状态)
|
||||
const articleid = getArticleId()
|
||||
form.articleid = articleid
|
||||
|
||||
// 根据是否有文章ID选择不同的API调用
|
||||
if (articleid) {
|
||||
res = await messageService.getMessagesByArticleId(articleid)
|
||||
} else {
|
||||
res = await messageService.getAllMessages()
|
||||
// 过滤掉articleid不为空的留言,只保留articleid为空或不存在的留言
|
||||
if (res && res.data) {
|
||||
res.data = res.data.filter(msg => !msg.articleid || msg.articleid === '')
|
||||
}
|
||||
}
|
||||
res = await (articleid
|
||||
? messageService.getMessagesByArticleId(articleid)
|
||||
: fetchAllMessages()
|
||||
)
|
||||
|
||||
// 验证响应结果
|
||||
if (!res || !res.data) {
|
||||
console.warn('未获取到留言数据')
|
||||
messageBoardData.value = []
|
||||
handleEmptyResponse()
|
||||
return
|
||||
}
|
||||
|
||||
const allMessages = res.data
|
||||
|
||||
// 处理所有留言,为主留言添加replies数组
|
||||
const allMessagesWithReplies = allMessages.map(msg => ({
|
||||
...msg,
|
||||
replies: []
|
||||
}))
|
||||
|
||||
// 分离主留言和回复
|
||||
const mainMessages = []
|
||||
const replies = []
|
||||
|
||||
allMessagesWithReplies.forEach(msg => {
|
||||
if (msg.parentid && msg.parentid > 0) {
|
||||
replies.push(msg)
|
||||
} else {
|
||||
mainMessages.push(msg)
|
||||
}
|
||||
})
|
||||
|
||||
// 将回复添加到对应的主留言中
|
||||
replies.forEach(reply => {
|
||||
// 找到父留言
|
||||
const parentMsg = mainMessages.find(msg => msg.messageid === reply.parentid)
|
||||
if (parentMsg) {
|
||||
// 处理@回复的显示名称
|
||||
if (reply.replyid) {
|
||||
const repliedMsg = replies.find(msg => msg.messageid === reply.replyid)
|
||||
if (repliedMsg) {
|
||||
reply.displayName = `${reply.nickname}@ ${repliedMsg.nickname}`
|
||||
} else {
|
||||
reply.displayName = reply.nickname
|
||||
}
|
||||
} else {
|
||||
reply.displayName = reply.nickname
|
||||
}
|
||||
parentMsg.replies.push(reply)
|
||||
}
|
||||
})
|
||||
|
||||
// 更新留言板数据
|
||||
messageBoardData.value = mainMessages
|
||||
// 处理留言数据
|
||||
messageBoardData.value = processMessageData(res.data)
|
||||
} catch (error) {
|
||||
console.error('获取留言列表失败:', error)
|
||||
ElMessage.error('获取留言失败,请稍后重试')
|
||||
messageBoardData.value = [] // 出错时清空数据,避免显示错误内容
|
||||
handleFetchError(error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 处理回复
|
||||
const handleReply = (msg, reply) => {
|
||||
// 检查是否是回复模式
|
||||
if (msg !== null) {
|
||||
// 回复模式
|
||||
form.replyid = reply.messageid
|
||||
form.parentid = msg.messageid
|
||||
} else {
|
||||
// 普通回复模式
|
||||
form.replyid = null
|
||||
form.parentid = reply.messageid
|
||||
/**
|
||||
* 获取文章ID
|
||||
* 优先级:props.comments > globalStore中的articleInfo
|
||||
* @returns {number|null} - 文章ID或null
|
||||
*/
|
||||
const getArticleId = () => {
|
||||
let articleid = props.comments || null
|
||||
|
||||
if (!articleid) {
|
||||
// 安全获取文章ID,如果globalStore中没有articleInfo则返回null
|
||||
const articleData = globalStore.getValue('articleInfo')
|
||||
articleid = (articleData && typeof articleData === 'object' && 'articleid' in articleData)
|
||||
? articleData.articleid
|
||||
: null
|
||||
}
|
||||
|
||||
return articleid
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有留言并过滤
|
||||
* 只保留articleid为空或不存在的全局留言
|
||||
* @returns {Promise} - API响应
|
||||
*/
|
||||
const fetchAllMessages = async () => {
|
||||
const res = await messageService.getAllMessages()
|
||||
// 过滤掉articleid不为空的留言,只保留articleid为空或不存在的留言
|
||||
if (res && res.data) {
|
||||
res.data = res.data.filter(msg => !msg.articleid || msg.articleid === '')
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理空响应
|
||||
*/
|
||||
const handleEmptyResponse = () => {
|
||||
console.warn('未获取到留言数据')
|
||||
messageBoardData.value = []
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理获取留言错误
|
||||
* @param {Error} error - 错误对象
|
||||
*/
|
||||
const handleFetchError = (error) => {
|
||||
console.error('获取留言列表失败:', error)
|
||||
ElMessage.error('获取留言失败,请稍后重试')
|
||||
messageBoardData.value = [] // 出错时清空数据,避免显示错误内容
|
||||
}
|
||||
|
||||
/**
|
||||
* 提交留言
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
const submitMessage = async () => {
|
||||
const res = await messageService.saveMessage({
|
||||
content: form.content,
|
||||
nickname: form.nickname,
|
||||
email: form.email,
|
||||
parentid: form.parentid,
|
||||
replyid: form.replyid,
|
||||
articleid: form.articleid
|
||||
})
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
/**
|
||||
* 点赞留言
|
||||
* @param {number} messageId - 留言ID
|
||||
* @returns {Promise} - API响应
|
||||
*/
|
||||
const likeMessage = async (messageId) => {
|
||||
return await messageService.likeMessage(messageId)
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除留言
|
||||
* @param {number} messageId - 留言ID
|
||||
* @returns {Promise} - API响应
|
||||
*/
|
||||
const deleteMessage = async (messageId) => {
|
||||
return await messageService.deleteMessage(messageId)
|
||||
}
|
||||
|
||||
// ============================== 交互操作模块 ==============================
|
||||
|
||||
/**
|
||||
* 处理回复操作
|
||||
* @param {Object|null} msg - 主留言对象,null表示直接回复主留言
|
||||
* @param {Object} reply - 被回复的留言对象
|
||||
*/
|
||||
const handleReply = (msg, reply) => {
|
||||
// 设置回复相关表单数据
|
||||
setupReplyFormData(msg, reply)
|
||||
|
||||
// 记录正在回复的信息
|
||||
replyingTo.value = {
|
||||
id: reply.messageid,
|
||||
nickname: reply.nickname || '匿名用户',
|
||||
content: reply.content
|
||||
}
|
||||
|
||||
// 滚动到输入框
|
||||
scrollToInput()
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置回复表单数据
|
||||
* @param {Object|null} msg - 主留言对象
|
||||
* @param {Object} reply - 被回复的留言对象
|
||||
*/
|
||||
const setupReplyFormData = (msg, reply) => {
|
||||
if (msg !== null) {
|
||||
// 回复模式:回复某条回复
|
||||
form.replyid = reply.messageid
|
||||
form.parentid = msg.messageid
|
||||
} else {
|
||||
// 普通回复模式:回复主留言
|
||||
form.replyid = null
|
||||
form.parentid = reply.messageid
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 滚动到输入框区域
|
||||
*/
|
||||
const scrollToInput = () => {
|
||||
setTimeout(() => {
|
||||
document.querySelector('.message-form-section')?.scrollIntoView({ behavior: 'smooth' })
|
||||
document.querySelector('.message-form-section')?.scrollIntoView({
|
||||
behavior: 'smooth'
|
||||
})
|
||||
}, 100)
|
||||
}
|
||||
|
||||
// 取消回复
|
||||
/**
|
||||
* 取消回复
|
||||
*/
|
||||
const cancelReply = () => {
|
||||
replyingTo.value = { id: null, nickname: '', content: '' }
|
||||
form.replyid = null
|
||||
form.content = ''
|
||||
}
|
||||
|
||||
// 监听articleid变化,重新加载留言
|
||||
watch(() => props.comments, (newVal) => {
|
||||
if (newVal) {
|
||||
fetchMessages()
|
||||
}
|
||||
}, { immediate: false })
|
||||
|
||||
// 组件挂载时获取留言列表
|
||||
onMounted(() => {
|
||||
fetchMessages()
|
||||
generateCaptcha() // 页面加载时生成验证码
|
||||
})
|
||||
|
||||
|
||||
const onSubmit = async () => {
|
||||
if (!formRef.value) return;
|
||||
|
||||
// 表单验证
|
||||
await formRef.value.validate((valid) => {
|
||||
if (!valid) {
|
||||
ElMessage.warning('请检查表单填写是否正确');
|
||||
throw new Error('表单验证失败');
|
||||
}
|
||||
});
|
||||
console.log('提交留言表单:', form)
|
||||
try {
|
||||
submitting.value = true
|
||||
|
||||
if (form.parentid) {
|
||||
// 回复模式
|
||||
const res = await messageService.saveMessage({
|
||||
content: form.content,
|
||||
nickname: form.nickname,
|
||||
email: form.email,
|
||||
parentid: form.parentid,
|
||||
replyid: form.replyid,
|
||||
articleid: form.articleid
|
||||
})
|
||||
|
||||
if (res.success) {
|
||||
ElMessage.success('回复成功')
|
||||
fetchMessages() // 重新获取列表
|
||||
resetForm()
|
||||
cancelReply()
|
||||
} else {
|
||||
ElMessage.error('回复失败:' + (res.message || '未知错误'))
|
||||
}
|
||||
} else {
|
||||
// 普通留言
|
||||
const res = await messageService.saveMessage({
|
||||
content: form.content,
|
||||
nickname: form.nickname,
|
||||
email: form.email,
|
||||
articleid: form.articleid
|
||||
})
|
||||
|
||||
if (res.success) {
|
||||
ElMessage.success('留言成功')
|
||||
fetchMessages() // 重新获取列表
|
||||
resetForm()
|
||||
} else {
|
||||
ElMessage.error('留言失败:' + (res.message || '未知错误'))
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('提交失败:', error)
|
||||
ElMessage.error('网络错误,请稍后重试')
|
||||
} finally {
|
||||
submitting.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 重置表单
|
||||
/**
|
||||
* 重置表单
|
||||
*/
|
||||
const resetForm = () => {
|
||||
form.replyid = null
|
||||
form.content = ''
|
||||
@@ -487,19 +591,79 @@ const resetForm = () => {
|
||||
replyingTo.value = { id: null, nickname: '', content: '' }
|
||||
}
|
||||
|
||||
const post_comment_reply_cancel = () => {
|
||||
form.content = ''
|
||||
form.replyid = null
|
||||
replyingTo.value = { id: null, nickname: '', content: '' }
|
||||
/**
|
||||
* 提交评论
|
||||
*/
|
||||
const onSubmit = async () => {
|
||||
if (!formRef.value) return;
|
||||
|
||||
try {
|
||||
// 表单验证
|
||||
await validateForm()
|
||||
console.log('提交留言表单:', form)
|
||||
|
||||
submitting.value = true
|
||||
|
||||
// 发送留言并处理结果
|
||||
await handleMessageSubmission()
|
||||
} catch (error) {
|
||||
console.error('提交失败:', error)
|
||||
ElMessage.error('网络错误,请稍后重试')
|
||||
} finally {
|
||||
submitting.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 处理点赞
|
||||
/**
|
||||
* 验证表单
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
const validateForm = async () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
formRef.value.validate((valid) => {
|
||||
if (!valid) {
|
||||
ElMessage.warning('请检查表单填写是否正确');
|
||||
reject(new Error('表单验证失败'));
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理留言提交
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
const handleMessageSubmission = async () => {
|
||||
const res = await submitMessage()
|
||||
|
||||
if (res.success) {
|
||||
// 提交成功
|
||||
ElMessage.success(form.parentid ? '回复成功' : '留言成功')
|
||||
await fetchMessages() // 重新获取列表
|
||||
resetForm()
|
||||
|
||||
// 如果是回复模式,取消回复状态
|
||||
if (form.parentid) {
|
||||
cancelReply()
|
||||
}
|
||||
} else {
|
||||
// 提交失败
|
||||
ElMessage.error(`${form.parentid ? '回复' : '留言'}失败:${res.message || '未知错误'}`)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理点赞操作
|
||||
* @param {Object} msg - 留言对象
|
||||
*/
|
||||
const handleLike = async (msg) => {
|
||||
try {
|
||||
// 显示加载状态或禁用按钮
|
||||
// 显示加载状态
|
||||
msg.isLiking = true
|
||||
|
||||
const res = await messageService.likeMessage(msg.messageid)
|
||||
const res = await likeMessage(msg.messageid)
|
||||
|
||||
if (res.success && res.data) {
|
||||
// 更新点赞数
|
||||
@@ -515,19 +679,23 @@ const handleLike = async (msg) => {
|
||||
msg.isLiking = false
|
||||
}
|
||||
}
|
||||
// 处理删除
|
||||
const handleDelete = async (msg) => {
|
||||
|
||||
/**
|
||||
* 处理删除操作
|
||||
* @param {number} messageId - 留言ID
|
||||
*/
|
||||
const handleDelete = async (messageId) => {
|
||||
// 确认删除
|
||||
if (!confirm('确定删除吗?')) {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
// 显示加载状态或禁用按钮
|
||||
// msg.isDeleting = true
|
||||
if (!confirm('确定删除吗?')) {
|
||||
return
|
||||
}
|
||||
const res = await messageService.deleteMessage(msg.messageid)
|
||||
const res = await deleteMessage(messageId)
|
||||
|
||||
if (res.success) {
|
||||
// 从列表中移除
|
||||
messageBoardData.value = messageBoardData.value.filter(item => item.messageid !== msg.messageid)
|
||||
messageBoardData.value = messageBoardData.value.filter(item => item.messageid !== messageId)
|
||||
ElMessage.success('删除成功')
|
||||
} else {
|
||||
ElMessage.error('删除失败:' + (res.message || '未知错误'))
|
||||
@@ -535,10 +703,32 @@ const handleDelete = async (msg) => {
|
||||
} catch (error) {
|
||||
console.error('删除失败:', error)
|
||||
ElMessage.error('网络错误,请稍后重试')
|
||||
} finally {
|
||||
// msg.isDeleting = false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 另一个取消回复的方法(冗余但保留以兼容现有代码)
|
||||
*/
|
||||
const post_comment_reply_cancel = () => {
|
||||
form.content = ''
|
||||
form.replyid = null
|
||||
replyingTo.value = { id: null, nickname: '', content: '' }
|
||||
}
|
||||
|
||||
// ============================== 生命周期和监听器 ==============================
|
||||
|
||||
// 监听articleid变化,重新加载留言
|
||||
watch(() => props.comments, (newVal) => {
|
||||
if (newVal) {
|
||||
fetchMessages()
|
||||
}
|
||||
}, { immediate: false })
|
||||
|
||||
// 组件挂载时初始化
|
||||
onMounted(() => {
|
||||
fetchMessages() // 获取留言列表
|
||||
generateCaptcha() // 生成验证码
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
Reference in New Issue
Block a user