updated

This commit is contained in:
landaiqing
2024-09-23 00:53:57 +08:00
parent 1539a2d9bb
commit 74dc2b36c8
9 changed files with 229 additions and 53 deletions

1
components.d.ts vendored
View File

@@ -27,6 +27,7 @@ declare module 'vue' {
AMenuDivider: typeof import('ant-design-vue/es')['MenuDivider']
AMenuItem: typeof import('ant-design-vue/es')['MenuItem']
AModal: typeof import('ant-design-vue/es')['Modal']
APagination: typeof import('ant-design-vue/es')['Pagination']
APopover: typeof import('ant-design-vue/es')['Popover']
AQrcode: typeof import('ant-design-vue/es')['QRCode']
ASegmented: typeof import('ant-design-vue/es')['Segmented']

View File

@@ -1,19 +1,61 @@
import {service} from "@/utils/alova/service.ts";
/**
* 上传图片转base64
* @description 评论提交
* @param params
*/
export const uploadToBase64 = (images: any[]) => {
return service.Post('/api/auth/comment/upload_to_base64',
export const commentSubmitApi = (params: any) => {
return service.Post('/api/auth/comment/submit', {
user_id: params.user_id,
content: params.content,
images: params.images,
topic_id: params.topic_id,
author: params.author,
},
{
images,
}, {
headers: {
'Content-Type': 'multipart/form-data'
},
meta: {
ignoreToken: false,
}
},
}
);
};
/**
* @description 回复提交
* @param params
*/
export const replySubmitApi = (params: any) => {
return service.Post('/api/auth/reply/submit', {
user_id: params.user_id,
content: params.content,
images: params.images,
topic_id: params.topic_id,
reply_id: params.reply_id,
reply_user: params.reply_user,
author: params.author,
},
{
meta: {
ignoreToken: false,
},
}
);
};
/**
* @description 评论列表
* @param params
*/
export const commentListApi = (params: any) => {
return service.Post('/api/auth/comment/list', {
page: params.page,
size: params.size,
topic_id: params.topic_id,
},
{
cacheFor: 1000 * 60 * 60 * 24 * 7, // 7天缓存
meta: {
ignoreToken: false,
},
}
);
};

View File

@@ -12,6 +12,7 @@
<AFlex :vertical="true" class="comment-content">
<ATextarea :rows="4" class="comment-text" @focus="onFocusHandler"
v-model:value="commentContent"
@keyup.ctrl.enter="commentSubmitThrottled"
:placeholder="commentTextAreaPlaceholder" allow-clear :showCount="false"/>
<AFlex :vertical="false" align="center" justify="space-between" class="comment-actions"
v-if="showCommentActions">
@@ -34,14 +35,14 @@
<AUpload
:accept="'image/jpg, image/png, image/jpeg, image/gif, image/svg+xml, image/webp'"
name="images"
:max-count="5"
:max-count="3"
:multiple="true"
method="post"
:directory="false"
:show-upload-list="false"
:custom-request="customUploadRequest"
:before-upload="beforeUpload"
:disabled="imageList.length >= 5"
:disabled="imageList.length >= 3"
>
<ABadge :count="imageList.length">
<AButton type="text" size="small" :icon="h(PictureOutlined)"
@@ -57,7 +58,7 @@
</template>
<AAvatar shape="square" size="small">
<template #icon>
<AImage v-if="item" :src="item"/>
<AImage v-if="item" :width="24" :height="24" :src="item"/>
</template>
</AAvatar>
</ABadge>
@@ -66,7 +67,8 @@
</AFlex>
<AFlex :vertical="false" align="center">
<AButton
@click="console.log(commentContent.replace(/\r\n/g, '<br/>').replace(/\n/g, '<br/>').replace(/\s/g, ' '))"
@click="commentSubmitThrottled"
:disabled="commentContent.trim().length === 0"
type="primary" size="middle" class="comment-action-btn">{{ t('comment.sendComment') }}
</AButton>
</AFlex>
@@ -198,19 +200,49 @@
>
<AFlex :vertical="false" align="center">
<AFlex :vertical="false" align="center" class="comment-action-item-reply">
<AButton type="text" size="small" :icon="h(SmileOutlined)" class="comment-action-icon-reply">
<AButton type="text" size="small" :icon="h(SmileOutlined)"
class="comment-action-icon-reply">
{{ t('comment.emoji') }}
</AButton>
</AFlex>
<AFlex :vertical="false" align="center" class="comment-action-item-reply">
<AButton type="text" size="small" :icon="h(PictureOutlined)"
class="comment-action-icon-reply">
{{ t('comment.picture') }}
</AButton>
<AUpload
:accept="'image/jpg, image/png, image/jpeg, image/gif, image/svg+xml, image/webp'"
name="images"
:max-count="3"
:multiple="true"
method="post"
:directory="false"
:show-upload-list="false"
:custom-request="customUploadRequest"
:before-upload="beforeUpload"
:disabled="imageList.length >= 3"
>
<ABadge :count="imageList.length">
<AButton type="text" size="small" :icon="h(PictureOutlined)"
class="comment-action-icon-reply">
{{ t('comment.picture') }}
</AButton>
</ABadge>
</AUpload>
<template v-if="imageList.length > 0">
<ABadge style="margin-left: 10px;" v-for="(item, index) in imageList" :key="index">
<template #count>
<CloseCircleOutlined @click="removeBase64Image(index)" style="color: #f5222d"/>
</template>
<AAvatar shape="square" size="small">
<template #icon>
<AImage v-if="item" :width="24" :height="24" :src="item"/>
</template>
</AAvatar>
</ABadge>
</template>
</AFlex>
</AFlex>
<AFlex :vertical="false" align="center">
<AButton type="primary" size="middle" class="comment-action-btn-reply">
<AButton @click="replySubmitThrottled" type="primary" size="middle"
:disabled="replyContent.trim().length === 0"
class="comment-action-btn-reply">
{{ t('comment.sendComment') }}
</AButton>
</AFlex>
@@ -247,14 +279,16 @@
</span>
<AFlex :vertical="false" justify="space-between" align="center">
<!--评论操作按钮 -->
<AFlex :vertical="false" align="center" justify="space-between" class="reply-action-item-child">
<AFlex :vertical="false" align="center" justify="space-between"
class="reply-action-item-child">
<AFlex :vertical="false" align="center">
<AButton type="text" size="small" :icon="h(LikeOutlined)" class="reply-action-btn-child">
10
</AButton>
</AFlex>
<AFlex :vertical="false" align="center">
<AButton type="text" size="small" :icon="h(DislikeOutlined)" class="reply-action-btn-child">
<AButton type="text" size="small" :icon="h(DislikeOutlined)"
class="reply-action-btn-child">
1
</AButton>
</AFlex>
@@ -281,7 +315,8 @@
</AButton>
<!-- 评论操作按钮 -->
<ADropdown trigger="click">
<AButton type="text" size="small" :icon="h(EllipsisOutlined)" class="reply-action-btn-child"
<AButton type="text" size="small" :icon="h(EllipsisOutlined)"
class="reply-action-btn-child"
@click.prevent>
</AButton>
<template #overlay>
@@ -307,7 +342,8 @@
<AFlex :vertical="false" align="center" class="reply-input-header-child">
<span class="reply-input-title-child">{{ t('comment.reply') + '' }}</span>
<span class="reply-input-author-child">沈建明</span>
<AButton @click="replyInputVisible = false" type="dashed" size="small" :icon="h(CloseOutlined )"
<AButton @click="replyInputVisible = false" type="dashed" size="small"
:icon="h(CloseOutlined )"
class="reply-input-cancel-child">
{{ t('comment.cancelReply') }}
</AButton>
@@ -377,6 +413,9 @@ import {
import EMOJI from "@/constant/emoji.ts";
import imageCompression from "browser-image-compression";
import {message} from "ant-design-vue";
import {useThrottleFn} from "@vueuse/core";
import {commentListApi, commentSubmitApi, replySubmitApi} from "@/api/comment";
import useStore from "@/store";
const {t} = useI18n();
const showCommentActions = ref<boolean>(false);
@@ -385,8 +424,10 @@ const data = reactive([t('comment.latest'), t('comment.hot')]);
const segmentedValue = ref<string>(data[0]);
const replyInputVisible = ref<boolean>(false);
const commentContent = ref<string>("");
const replyContent = ref<string>("");
const fileList = ref<any[]>([]);
const imageList = ref<any[]>([]);
const user = useStore().user;
/**
* 聚焦事件
@@ -444,6 +485,98 @@ async function removeBase64Image(index: number) {
fileList.value.splice(index, 1);
imageList.value.splice(index, 1);
}
/**
* 评论提交 throttled
*/
const commentSubmitThrottled = useThrottleFn(commentSubmit, 1000);
/**
* 评论提交
*/
async function commentSubmit() {
if (commentContent.value.trim() === "") {
message.error("评论内容不能为空");
return;
}
if (imageList.value.length > 3) {
message.error("最多只能上传3张图片");
return;
}
const content = commentContent.value.replace(/\r\n/g, '<br/>').replace(/\n/g, '<br/>').replace(/\s/g, ' ');
const commentParams: object = {
user_id: user.user.uid,
topic_id: "123",
content: content,
images: imageList.value,
author: user.user.uid,
};
const result: any = await commentSubmitApi(commentParams);
if (result.code === 200 && result.success) {
message.success("评论成功");
commentContent.value = "";
fileList.value = [];
imageList.value = [];
} else {
message.error("评论失败");
}
}
/**
* 回复提交 throttled
*/
const replySubmitThrottled = useThrottleFn(replySubmit, 1000);
/**
* 回复提交
*/
async function replySubmit() {
if (commentContent.value.trim() === "") {
message.error("回复内容不能为空");
return;
}
if (imageList.value.length > 3) {
message.error("最多只能上传3张图片");
return;
}
const content = commentContent.value.replace(/\r\n/g, '<br/>').replace(/\n/g, '<br/>').replace(/\s/g, ' ');
const replyParams: object = {
user_id: user.user.uid,
topic_id: "123",
content: content,
images: imageList.value,
author: user.user.uid,
reply_id: "5",
reply_user: user.user.uid,
};
const result: any = await replySubmitApi(replyParams);
if (result.code === 200 && result.success) {
message.success("回复成功");
commentContent.value = "";
fileList.value = [];
imageList.value = [];
} else {
message.error("回复失败");
}
}
/**
* 获取评论列表
*/
async function getCommentList() {
const params = {
topic_id: "123",
page: 1,
size: 10,
};
// 获取评论列表
const result: any = await commentListApi(params);
console.log(result);
}
getCommentList();
</script>
<style src="./index.scss" lang="scss" scoped>

View File

@@ -26,7 +26,7 @@ const {onAuthRequired, onResponseRefreshToken} = createServerTokenAuthentication
// 刷新token
const user = useStore().user;
const res: any = await refreshToken(user.user?.refreshToken);
if (res.code === 0 && res.data) {
if (res.code === 200 && res.data) {
const {access_token, refresh_token, uid} = res.data;
user.user.accessToken = access_token;
user.user.refreshToken = refresh_token;

View File

@@ -257,7 +257,7 @@ async function resetPasswordSubmit() {
.validate()
.then(async () => {
const res: any = await resetPasswordApi(ResetPasswordForm);
if (res.code === 0 && res.success) {
if (res.code === 200 && res.success) {
message.success(t('login.resetPasswordSuccess'));
await router.push('/login');
} else {
@@ -279,7 +279,7 @@ const refreshCaptcha = useDebounceFn(getRotateCaptcha, 3000);
*/
async function getRotateCaptcha() {
const data: any = await getRotatedCaptchaData();
if (data.code === 0 && data.data) {
if (data.code === 200 && data.data) {
const {angle, image, thumb, key} = data.data;
captchaData.angle = angle;
captchaData.image = image;
@@ -296,7 +296,7 @@ async function getRotateCaptcha() {
async function sendMessageByPhone(): Promise<boolean> {
const phone: string = ResetPasswordForm.phone as string;
const res: any = await sendMessage(phone);
if (res.code === 0 && res.success) {
if (res.code === 200 && res.success) {
message.success(t('login.sendCaptchaSuccess'));
return true;
} else {
@@ -317,7 +317,7 @@ async function checkPhoneLoginCaptcha(angle: number) {
});
} else {
const result: any = await checkRotatedCaptcha(angle, captchaData.key);
if (result.code === 0 && result.success) {
if (result.code === 200 && result.success) {
showRotateCaptcha.value = false;
const result: boolean = await sendMessageByPhone();
if (result) {

View File

@@ -44,7 +44,7 @@ const client = useStore().client;
async function getGithubRedirectUrl() {
const clientId: string = await getLocalClientId() as string;
const res: any = await getGithubUrl(clientId);
if (res.code === 0 && res.data) {
if (res.code === 200 && res.data) {
githubRedirectUrl.value = res.data;
}
}
@@ -54,7 +54,7 @@ async function getGithubRedirectUrl() {
*/
async function getGiteeRedirectUrl() {
const res: any = await getGiteeUrl();
if (res.code === 0 && res.data) {
if (res.code === 200 && res.data) {
giteeRedirectUrl.value = res.data;
}
}
@@ -65,7 +65,7 @@ async function getGiteeRedirectUrl() {
async function getQQRedirectUrl() {
const clientId: string = await getLocalClientId() as string;
const res: any = await getQQUrl(clientId);
if (res.code === 0 && res.data) {
if (res.code === 200 && res.data) {
qqRedirectUrl.value = res.data;
}
}
@@ -75,7 +75,7 @@ async function getQQRedirectUrl() {
*/
async function getClientId() {
const res: any = await generateClientId();
if (res.code === 0 && res.data) {
if (res.code === 200 && res.data) {
client.setClientId(res.data);
}
}
@@ -111,7 +111,7 @@ function openGithubUrl() {
const messageHandler = async (e: any) => {
if (typeof e.data === 'string') {
const data: any = JSON.parse(e.data);
if (data.code === 0 && data.data) {
if (data.code === 200 && data.data) {
const user = useStore().user;
const {access_token, refresh_token, uid, expires_at} = data.data;
user.user.accessToken = access_token;
@@ -154,7 +154,7 @@ function openGiteeUrl() {
const messageHandler = async (e: any) => {
if (typeof e.data === 'string') {
const data: any = JSON.parse(e.data);
if (data.code === 0 && data.data) {
if (data.code === 200 && data.data) {
const user = useStore().user;
const {access_token, refresh_token, uid, expires_at} = data.data;
user.user.accessToken = access_token;
@@ -195,7 +195,7 @@ function openQQUrl() {
const messageHandler = async (e: any) => {
if (typeof e.data === 'string') {
const data: any = JSON.parse(e.data);
if (data.code === 0 && data.data) {
if (data.code === 200 && data.data) {
const user = useStore().user;
const {access_token, refresh_token, uid, expires_at} = data.data;
user.user.accessToken = access_token;

View File

@@ -142,7 +142,7 @@
</ACard>
</div>
<AModal v-model:open="showPhoneRotateCaptcha" :footer="null" :closable="false" width="375" :centered="true"
:maskClosable="false" bodyStyle="padding: 0">
:maskClosable="false" :bodyStyle="{padding: 0}">
<!-- 滑动验证码 -->
<gocaptcha-rotate
class="gocaptcha-rotate"
@@ -155,7 +155,7 @@
/>
</AModal>
<AModal v-model:open="showAccountRotateCaptcha" :footer="null" :closable="false" width="375" :centered="true"
:maskClosable="false" bodyStyle="padding: 0">
:maskClosable="false" :bodyStyle="{padding: 0}">
<!-- 滑动验证码 -->
<gocaptcha-rotate
class="gocaptcha-rotate"
@@ -371,7 +371,7 @@ async function phoneLoginSubmit() {
.validate()
.then(async () => {
const res: any = await phoneLoginApi(phoneLoginForm);
if (res.code === 0 && res.success) {
if (res.code === 200 && res.success) {
const userStore = useStore().user;
const {uid, access_token, refresh_token, expires_at} = res.data;
userStore.user.uid = uid;
@@ -403,7 +403,7 @@ const refreshCaptcha = useThrottleFn(getRotateCaptcha, 3000);
*/
async function getRotateCaptcha() {
const data: any = await getRotatedCaptchaData();
if (data.code === 0 && data.data) {
if (data.code === 200 && data.data) {
const {angle, image, thumb, key} = data.data;
captchaData.angle = angle;
captchaData.image = image;
@@ -431,7 +431,7 @@ async function checkPhoneLoginCaptcha(angle: number) {
});
} else {
const result: any = await checkRotatedCaptcha(angle, captchaData.key);
if (result.code === 0 && result.success) {
if (result.code === 200 && result.success) {
showPhoneRotateCaptcha.value = false;
const result: boolean = await sendMessageByPhone();
if (result) {
@@ -466,11 +466,11 @@ async function checkAccountLoginCaptcha(angle: number) {
});
} else {
const result: any = await checkRotatedCaptcha(angle, captchaData.key);
if (result.code === 0 && result.success) {
if (result.code === 200 && result.success) {
showAccountRotateCaptcha.value = false;
loginLoading.value = true;
const res: any = await accountLoginApi(accountLoginForm);
if (res.code === 0 && res.success) {
if (res.code === 200 && res.success) {
const userStore = useStore().user;
const {uid, access_token, refresh_token, expires_at} = res.data;
userStore.user.uid = uid;
@@ -504,7 +504,7 @@ async function checkAccountLoginCaptcha(angle: number) {
async function sendMessageByPhone(): Promise<boolean> {
const phone: string = phoneLoginForm.phone as string;
const res: any = await sendMessage(phone);
if (res.code === 0 && res.success) {
if (res.code === 200 && res.success) {
message.success(t('login.sendCaptchaSuccess'));
return true;
} else {

View File

@@ -77,7 +77,7 @@ const status = ref<string>('loading');
*/
async function getClientId() {
const res: any = await generateClientId();
if (res.code === 0 && res.data) {
if (res.code === 200 && res.data) {
client.setClientId(res.data);
}
}
@@ -93,7 +93,7 @@ async function getQrCode() {
await getQrCode();
} else {
const res: any = await generateQrCode(client.getClientId() || "");
if (res.code === 0 && res.data) {
if (res.code === 200 && res.data) {
status.value = 'active';
qrcode.value = res.data;
await handleListenMessage();
@@ -128,7 +128,7 @@ async function handleListenMessage() {
open();
// 注册消息接收处理函数
on('message', async (data: any) => {
if (data.code === 0 && data.data) {
if (data.code === 200 && data.data) {
const user = useStore().user;
const {access_token, refresh_token, uid, expires_at} = data.data;
user.user.accessToken = access_token;

View File

@@ -45,7 +45,7 @@ const qqRedirectUrl = ref<string>('');
async function getGithubRedirectUrl() {
const clientId: string = await getLocalClientId() as string;
const res: any = await getGithubUrl(clientId);
if (res.code === 0 && res.data) {
if (res.code === 200 && res.data) {
githubRedirectUrl.value = res.data;
}
}
@@ -55,7 +55,7 @@ async function getGithubRedirectUrl() {
*/
async function getGiteeRedirectUrl() {
const res: any = await getGiteeUrl();
if (res.code === 0 && res.data) {
if (res.code === 200 && res.data) {
giteeRedirectUrl.value = res.data;
}
}
@@ -66,7 +66,7 @@ async function getGiteeRedirectUrl() {
async function getQQRedirectUrl() {
const clientId: string = await getLocalClientId() as string;
const res: any = await getQQUrl(clientId);
if (res.code === 0 && res.data) {
if (res.code === 200 && res.data) {
qqRedirectUrl.value = res.data;
}
}
@@ -76,7 +76,7 @@ async function getQQRedirectUrl() {
*/
async function getClientId() {
const res: any = await generateClientId();
if (res.code === 0 && res.data) {
if (res.code === 200 && res.data) {
client.setClientId(res.data);
}
}
@@ -112,7 +112,7 @@ function openGithubUrl() {
const messageHandler = async (e: any) => {
if (typeof e.data === 'string') {
const data: any = JSON.parse(e.data);
if (data.code === 0 && data.data) {
if (data.code === 200 && data.data) {
const user = useStore().user;
const {access_token, refresh_token, uid, expires_at} = data.data;
user.user.accessToken = access_token;
@@ -154,7 +154,7 @@ function openGiteeUrl() {
const messageHandler = async (e: any) => {
if (typeof e.data === 'string') {
const data: any = JSON.parse(e.data);
if (data.code === 0 && data.data) {
if (data.code === 200 && data.data) {
const user = useStore().user;
const {access_token, refresh_token, uid, expires_at} = data.data;
user.user.accessToken = access_token;
@@ -195,7 +195,7 @@ function openQQUrl() {
const messageHandler = async (e: any) => {
if (typeof e.data === 'string') {
const data: any = JSON.parse(e.data);
if (data.code === 0 && data.data) {
if (data.code === 200 && data.data) {
const user = useStore().user;
const {access_token, refresh_token, uid, expires_at} = data.data;
user.user.accessToken = access_token;