feat: 删除评论权限控制

This commit is contained in:
rd
2025-08-08 17:16:48 +08:00
parent 819fb8db8f
commit 34f8d01c1f
3 changed files with 108 additions and 35 deletions

View File

@ -0,0 +1,39 @@
<template>
<a-modal v-model:visible="visible" title="确定删除评论?" width="400px" @close="onClose">
<div class="flex items-center">
<img :src="icon1" width="20" height="20" class="mr-12px" />
<span>删除的评论将从对话中消失但仍在被引用的评论中可见</span>
</div>
<template #footer>
<a-button size="large" @click="onClose">取消</a-button>
<a-button type="primary" class="ml-16px !border-none" size="large" @click="onDelete">删除</a-button>
</template>
</a-modal>
</template>
<script setup>
import { ref } from 'vue';
import icon1 from '@/assets/img/media-account/icon-warn-1.png';
const emits = defineEmits(['delete', 'close']);
const visible = ref(false);
const commentId = ref('');
const onClose = () => {
commentId.value = ''
visible.value = false;
};
const open = (id) => {
commentId.value = id;
visible.value = true;
};
const onDelete = () => {
emits('delete', commentId.value);
onClose();
};
defineExpose({ open });
</script>

View File

@ -1,11 +1,13 @@
<script lang="jsx"> <script lang="jsx">
import { Image, Spin, Button, Input } from '@arco-design/web-vue'; import { Image, Spin, Button, Input, Textarea } from '@arco-design/web-vue';
import TextOverTips from '@/components/text-over-tips'; import TextOverTips from '@/components/text-over-tips';
import SvgIcon from '@/components/svg-icon/index.vue'; import SvgIcon from '@/components/svg-icon/index.vue';
import DeleteCommentModal from './delete-comment-modal.vue';
import { RESULT_LIST, ENUM_OPINION, formatRelativeTime } from '../../constants'; import { RESULT_LIST, ENUM_OPINION, formatRelativeTime } from '../../constants';
import { postShareWorksComments, deleteShareWorksComments } from '@/api/all/generationWorkshop.ts'; import { postShareWorksComments, deleteShareWorksComments } from '@/api/all/generationWorkshop.ts';
import { exactFormatTime } from '@/utils/tools.ts'; import { exactFormatTime } from '@/utils/tools.ts';
import { useUserStore } from '@/stores';
import icon1 from '@/assets/img/creative-generation-workshop/icon-line.png'; import icon1 from '@/assets/img/creative-generation-workshop/icon-line.png';
import icon2 from '@/assets/img/creative-generation-workshop/icon-avatar-default.png'; import icon2 from '@/assets/img/creative-generation-workshop/icon-avatar-default.png';
@ -67,11 +69,13 @@ export default {
emits: ['toggle', 'updateComment', 'deleteComment'], emits: ['toggle', 'updateComment', 'deleteComment'],
setup(props, { emit, expose }) { setup(props, { emit, expose }) {
const route = useRoute(); const route = useRoute();
const userStore = useUserStore();
const isCollapse = ref(false); const isCollapse = ref(false);
const comment = ref(''); const comment = ref('');
const isReplay = ref(false); const isReplay = ref(false);
const commentId = ref(undefined); const commentId = ref(undefined);
const deleteCommentModalRef = ref(null);
const onComment = async () => { const onComment = async () => {
const { code, data } = await postShareWorksComments(props.dataSource.id, route.params.shareCode, { const { code, data } = await postShareWorksComments(props.dataSource.id, route.params.shareCode, {
@ -90,6 +94,29 @@ export default {
comment.value = ''; comment.value = '';
}; };
const renderDeleteBtn = (item) => {
const { userInfo, isLogin } = userStore;
const { commenter_id, id, commenter } = item;
let showBtn = true;
if (isLogin) {
showBtn = commenter.id === userInfo.id;
} else {
showBtn = commenter_id === 1 ? false : !commenter;
}
if (!showBtn) {
return null;
}
return (
<icon-delete
class="ml-12px cursor-pointer color-#55585F hover:color-#6D4CFE"
size={16}
onClick={() => deleteCommentModalRef.value?.open(id)}
/>
);
};
const deleteComment = async (comment_id) => { const deleteComment = async (comment_id) => {
emit('deleteComment', comment_id); emit('deleteComment', comment_id);
@ -115,7 +142,7 @@ export default {
return () => ( return () => (
<section class="py-16px absolute right-16px w-440px h-full overflow-hidden"> <section class="py-16px absolute right-16px w-440px h-full overflow-hidden">
<div class="ai-suggest-box py-24px flex flex-col"> <div class="ai-suggest-box relative py-24px flex flex-col">
<div class="mb-16px w-full flex justify-between px-24px"> <div class="mb-16px w-full flex justify-between px-24px">
<div class="relative w-fit"> <div class="relative w-fit">
<span class="ai-text">AI 智能审核</span> <span class="ai-text">AI 智能审核</span>
@ -200,7 +227,7 @@ export default {
</p> </p>
<div class="comment-list flex flex-col my-16px rounded-8px"> <div class="comment-list flex flex-col my-16px rounded-8px">
{props.dataSource.comments?.map((item) => ( {props.dataSource.comments?.map((item) => (
<div class="comment-item flex px-12px py-8px" key={item.id}> <div class="comment-item flex px-12px py-8px group" key={item.id}>
<Image <Image
src={item.commenter_id === 0 ? icon2 : item.commenter?.head_image} src={item.commenter_id === 0 ? icon2 : item.commenter?.head_image}
width={40} width={40}
@ -219,42 +246,45 @@ export default {
<span class="cts !color-#211F24 mr-8px">{getCommentName(item)}</span> <span class="cts !color-#211F24 mr-8px">{getCommentName(item)}</span>
<span class="cts !color-#939499">{formatRelativeTime(item.created_at)}</span> <span class="cts !color-#939499">{formatRelativeTime(item.created_at)}</span>
</p> </p>
<div class="flex items-center"> <div class="items-center hidden group-hover:flex">
<SvgIcon <SvgIcon
name="svg-comment" name="svg-comment"
size={16} size={16}
class="color-#55585F mr-12px cursor-pointer hover:color-#6D4CFE" class="color-#55585F cursor-pointer hover:color-#6D4CFE"
/>
<icon-delete
class="cursor-pointer color-#55585F hover:color-#6D4CFE"
size={16}
onClick={() => deleteComment(item.id)}
/> />
{renderDeleteBtn(item)}
</div> </div>
</div> </div>
<p class="cts !color-#211F24">{item.content}</p> <p class="cts !color-#211F24">{item.content}</p>
</div> </div>
</div> </div>
))} ))}
</div> </div>
<div>
<Input size="large" placeholder="输入评论" v-model={comment.value} onPressEnter={onComment} />
{comment.value && (
<div class="flex justify-end mt-12px">
<Button type="outline" class="mr-12px rounded-8px" size="medium" onClick={onClearComment}>
取消
</Button>
<Button type="primary" class="rounded-8px" size="medium" onClick={onComment}>
发送
</Button>
</div>
)}
</div>
</div> </div>
</div> </div>
<div class="sticky bottom-0 left-0 w-full z-22 px-24px">
<Textarea
auto-size
class="max-h-220px overflow-y-auto"
size="large"
placeholder="输入评论"
v-model={comment.value}
onPressEnter={onComment}
/>
{comment.value && (
<div class="flex justify-end mt-12px">
<Button type="outline" class="mr-12px rounded-8px" size="medium" onClick={onClearComment}>
取消
</Button>
<Button type="primary" class="rounded-8px" size="medium" onClick={onComment}>
发送
</Button>
</div>
)}
</div>
</div> </div>
<DeleteCommentModal ref={deleteCommentModalRef} onDelete={deleteComment} />
</section> </section>
); );
}, },

View File

@ -27,6 +27,19 @@
-webkit-background-clip: text; -webkit-background-clip: text;
-webkit-text-fill-color: transparent; -webkit-text-fill-color: transparent;
} }
:deep(.arco-textarea-wrapper) {
min-height: 38px;
display: flex;
border-color: transparent !important;
align-items: center;
border-radius: 8px !important;
background-color: #fff;
color: #211f24 !important;
transition: all 0.3s;
&:hover {
border-color: #6d4cfe !important;
}
}
.result-box { .result-box {
background: rgba(255, 255, 255, 0.8); background: rgba(255, 255, 255, 0.8);
backdrop-filter: blur(4px); backdrop-filter: blur(4px);
@ -64,16 +77,7 @@
-webkit-background-clip: text; -webkit-background-clip: text;
-webkit-text-fill-color: transparent; -webkit-text-fill-color: transparent;
} }
:deep(.arco-input-wrapper) {
padding: 8px 16px;
height: 38px;
border-radius: 8px !important;
background-color: rgba(255, 255, 255, 0.8) !important;
color: #211f24 !important;
&:hover {
border-color: #6d4cfe !important;
}
}
.comment-list { .comment-list {
backdrop-filter: blur(4px); backdrop-filter: blur(4px);
.comment-item { .comment-item {