commit
be4c3376dd
@ -61,8 +61,8 @@ public class MessageServiceImpl
|
|||||||
@Override
|
@Override
|
||||||
public PageDataVO<MessageVO> page(MessageQuery query, PageQuery pageQuery) {
|
public PageDataVO<MessageVO> page(MessageQuery query, PageQuery pageQuery) {
|
||||||
QueryWrapper<MessageDO> queryWrapper = QueryHelper.build(query);
|
QueryWrapper<MessageDO> queryWrapper = QueryHelper.build(query);
|
||||||
queryWrapper.apply(null != query.getUid(), "msgUser.user_id={0}", query.getUid());
|
queryWrapper.apply(null != query.getUid(), "msgUser.user_id={0}", query.getUid())
|
||||||
queryWrapper.apply(null != query.getReadStatus(), "msgUser.read_status={0}", query.getReadStatus());
|
.apply(null != query.getReadStatus(), "msgUser.read_status={0}", query.getReadStatus());
|
||||||
IPage<MessageVO> page = baseMapper.selectVoPage(pageQuery.toPage(), queryWrapper);
|
IPage<MessageVO> page = baseMapper.selectVoPage(pageQuery.toPage(), queryWrapper);
|
||||||
page.getRecords().forEach(this::fill);
|
page.getRecords().forEach(this::fill);
|
||||||
return PageDataVO.build(page);
|
return PageDataVO.build(page);
|
||||||
@ -71,8 +71,8 @@ public class MessageServiceImpl
|
|||||||
@Override
|
@Override
|
||||||
public List<MessageVO> list(MessageQuery query, SortQuery sortQuery) {
|
public List<MessageVO> list(MessageQuery query, SortQuery sortQuery) {
|
||||||
QueryWrapper<MessageDO> queryWrapper = QueryHelper.build(query);
|
QueryWrapper<MessageDO> queryWrapper = QueryHelper.build(query);
|
||||||
queryWrapper.apply("msgUser.user_id={0}", LoginHelper.getUserId());
|
queryWrapper.apply("msgUser.user_id={0}", LoginHelper.getUserId()).apply(null != query.getReadStatus(),
|
||||||
queryWrapper.apply(null != query.getReadStatus(), "msgUser.read_status={0}", query.getReadStatus());
|
"msgUser.read_status={0}", query.getReadStatus());
|
||||||
// 设置排序
|
// 设置排序
|
||||||
this.sort(queryWrapper, sortQuery);
|
this.sort(queryWrapper, sortQuery);
|
||||||
return baseMapper.selectVoList(queryWrapper);
|
return baseMapper.selectVoList(queryWrapper);
|
||||||
@ -99,8 +99,8 @@ public class MessageServiceImpl
|
|||||||
messageUserService.add(messageId, userIdList);
|
messageUserService.add(messageId, userIdList);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
|
||||||
@Override
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public void delete(List<Long> ids) {
|
public void delete(List<Long> ids) {
|
||||||
super.delete(ids);
|
super.delete(ids);
|
||||||
messageUserService.delete(ids);
|
messageUserService.delete(ids);
|
||||||
|
@ -46,6 +46,7 @@
|
|||||||
"query-string": "^8.1.0",
|
"query-string": "^8.1.0",
|
||||||
"sortablejs": "^1.15.0",
|
"sortablejs": "^1.15.0",
|
||||||
"vue": "^3.3.4",
|
"vue": "^3.3.4",
|
||||||
|
"vue-cropper": "^1.0.9",
|
||||||
"vue-echarts": "^6.6.1",
|
"vue-echarts": "^6.6.1",
|
||||||
"vue-i18n": "^9.5.0",
|
"vue-i18n": "^9.5.0",
|
||||||
"vue-json-pretty": "^2.2.4",
|
"vue-json-pretty": "^2.2.4",
|
||||||
|
3
continew-admin-ui/pnpm-lock.yaml
generated
3
continew-admin-ui/pnpm-lock.yaml
generated
@ -58,6 +58,9 @@ dependencies:
|
|||||||
vue:
|
vue:
|
||||||
specifier: ^3.3.4
|
specifier: ^3.3.4
|
||||||
version: 3.3.4
|
version: 3.3.4
|
||||||
|
vue-cropper:
|
||||||
|
specifier: ^1.0.9
|
||||||
|
version: 1.0.9
|
||||||
vue-echarts:
|
vue-echarts:
|
||||||
specifier: ^6.6.1
|
specifier: ^6.6.1
|
||||||
version: 6.6.1(echarts@5.4.3)(vue@3.3.4)
|
version: 6.6.1(echarts@5.4.3)(vue@3.3.4)
|
||||||
|
@ -12,6 +12,20 @@ export interface AvatarRes {
|
|||||||
avatar: string;
|
avatar: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface cropperOptions {
|
||||||
|
autoCrop: boolean; // 是否默认生成截图框
|
||||||
|
autoCropWidth: number; // 默认生成截图框宽度
|
||||||
|
autoCropHeight: number; // 默认生成截图框高度
|
||||||
|
canMove: boolean; // 上传图片是否可以移动 (默认:true)
|
||||||
|
centerBox: boolean; // 截图框是否被限制在图片里面 (默认:false)
|
||||||
|
full: boolean; // 是否输出原图比例的截图 选true生成的图片会非常大 (默认:false)
|
||||||
|
fixed: boolean; // 是否开启截图框宽高固定比例 (默认:false)
|
||||||
|
fixedBox: boolean; // 固定截图框大小 不允许改变
|
||||||
|
img: string | ArrayBuffer | null; // 裁剪图片的地址
|
||||||
|
outputSize: number; // 裁剪生成图片的质量 (默认:1)
|
||||||
|
outputType: string; // 默认生成截图为PNG格式
|
||||||
|
}
|
||||||
|
|
||||||
export function uploadAvatar(data: FormData) {
|
export function uploadAvatar(data: FormData) {
|
||||||
return axios.post<AvatarRes>(`${BASE_URL}/avatar`, data);
|
return axios.post<AvatarRes>(`${BASE_URL}/avatar`, data);
|
||||||
}
|
}
|
||||||
|
@ -7,8 +7,7 @@
|
|||||||
:show-file-list="false"
|
:show-file-list="false"
|
||||||
list-type="picture-card"
|
list-type="picture-card"
|
||||||
:show-upload-button="true"
|
:show-upload-button="true"
|
||||||
:custom-request="handleUpload"
|
:on-before-upload="handleBeforeUpload"
|
||||||
@change="handleAvatarChange"
|
|
||||||
>
|
>
|
||||||
<template #upload-button>
|
<template #upload-button>
|
||||||
<a-avatar :size="100" class="info-avatar">
|
<a-avatar :size="100" class="info-avatar">
|
||||||
@ -22,6 +21,56 @@
|
|||||||
</template>
|
</template>
|
||||||
</a-upload>
|
</a-upload>
|
||||||
|
|
||||||
|
<div class="main">
|
||||||
|
<a-modal
|
||||||
|
:visible="cropperVisible"
|
||||||
|
width="40%"
|
||||||
|
:footer="false"
|
||||||
|
unmount-on-close
|
||||||
|
render-to-body
|
||||||
|
@cancel="handleCropperCancel"
|
||||||
|
>
|
||||||
|
<a-row>
|
||||||
|
<a-col :span="14">
|
||||||
|
<div style="width: 370px; height: 370px">
|
||||||
|
<!-- 头像裁剪框 -->
|
||||||
|
<vue-cropper
|
||||||
|
ref="cropper"
|
||||||
|
:info="true"
|
||||||
|
:img="options.img"
|
||||||
|
:full="options.full"
|
||||||
|
:fixed="options.fixed"
|
||||||
|
:fixed-box="options.fixedBox"
|
||||||
|
:can-move="options.canMove"
|
||||||
|
:center-box="options.centerBox"
|
||||||
|
:auto-crop="options.autoCrop"
|
||||||
|
:auto-crop-width="options.autoCropWidth"
|
||||||
|
:auto-crop-height="options.autoCropHeight"
|
||||||
|
:output-type="options.outputType"
|
||||||
|
:output-size="options.outputSize"
|
||||||
|
@realTime="realTime"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="6">
|
||||||
|
<!-- 实时预览 -->
|
||||||
|
<div :style="previewStyle">
|
||||||
|
<div :style="previews.div">
|
||||||
|
<img :src="previews.url" :style="previews.img" alt="" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
<br />
|
||||||
|
<a-space>
|
||||||
|
<a-button type="primary" @click="handleUpload">提交</a-button>
|
||||||
|
<a-button type="outline" @click="handleCropperCancel"
|
||||||
|
>取消</a-button
|
||||||
|
>
|
||||||
|
</a-space>
|
||||||
|
</a-modal>
|
||||||
|
</div>
|
||||||
|
|
||||||
<a-descriptions
|
<a-descriptions
|
||||||
:column="2"
|
:column="2"
|
||||||
:label-style="{
|
:label-style="{
|
||||||
@ -70,15 +119,22 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { getCurrentInstance, ref } from 'vue';
|
import { reactive, ref, getCurrentInstance } from 'vue';
|
||||||
import { FileItem, RequestOption } from '@arco-design/web-vue';
|
import { FileItem } from '@arco-design/web-vue';
|
||||||
import { uploadAvatar } from '@/api/system/user-center';
|
import { uploadAvatar, cropperOptions } from '@/api/system/user-center';
|
||||||
import { useUserStore } from '@/store';
|
|
||||||
import getAvatar from '@/utils/avatar';
|
import getAvatar from '@/utils/avatar';
|
||||||
|
import { useUserStore } from '@/store';
|
||||||
|
import { VueCropper } from 'vue-cropper';
|
||||||
|
import 'vue-cropper/dist/index.css';
|
||||||
|
|
||||||
|
const fileRef = ref(reactive({ name: 'avatar.png' }));
|
||||||
|
const previews: any = ref({});
|
||||||
|
const previewStyle: any = ref({});
|
||||||
|
const cropperVisible = ref(false);
|
||||||
|
const cropper = ref();
|
||||||
const { proxy } = getCurrentInstance() as any;
|
const { proxy } = getCurrentInstance() as any;
|
||||||
|
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
|
|
||||||
const avatar = {
|
const avatar = {
|
||||||
uid: '-2',
|
uid: '-2',
|
||||||
name: 'avatar.png',
|
name: 'avatar.png',
|
||||||
@ -86,52 +142,75 @@
|
|||||||
};
|
};
|
||||||
const avatarList = ref<FileItem[]>([avatar]);
|
const avatarList = ref<FileItem[]>([avatar]);
|
||||||
|
|
||||||
|
const options: cropperOptions = reactive({
|
||||||
|
autoCrop: true,
|
||||||
|
autoCropWidth: 200,
|
||||||
|
autoCropHeight: 200,
|
||||||
|
canMove: true,
|
||||||
|
centerBox: true,
|
||||||
|
full: false,
|
||||||
|
fixed: false,
|
||||||
|
fixedBox: false,
|
||||||
|
img: '',
|
||||||
|
outputSize: 1,
|
||||||
|
outputType: 'png',
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 上传头像
|
* 上传前弹出裁剪框
|
||||||
*
|
*
|
||||||
* @param options 选项
|
* @param file 头像
|
||||||
*/
|
*/
|
||||||
const handleUpload = (options: RequestOption) => {
|
const handleBeforeUpload = (file: File): boolean => {
|
||||||
const controller = new AbortController();
|
fileRef.value = file;
|
||||||
(async function requestWrap() {
|
const reader = new FileReader();
|
||||||
const {
|
reader.readAsDataURL(file);
|
||||||
onProgress,
|
reader.onload = () => {
|
||||||
onError,
|
options.img = reader.result;
|
||||||
onSuccess,
|
|
||||||
fileItem,
|
|
||||||
name = 'avatarFile',
|
|
||||||
} = options;
|
|
||||||
onProgress(20);
|
|
||||||
const formData = new FormData();
|
|
||||||
formData.append(name as string, fileItem.file as Blob);
|
|
||||||
uploadAvatar(formData)
|
|
||||||
.then((res) => {
|
|
||||||
onSuccess(res);
|
|
||||||
userStore.avatar = res.data.avatar;
|
|
||||||
proxy.$message.success(res.msg);
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
onError(error);
|
|
||||||
});
|
|
||||||
})();
|
|
||||||
return {
|
|
||||||
abort() {
|
|
||||||
controller.abort();
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
cropperVisible.value = true;
|
||||||
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 切换头像
|
* 关闭裁剪框
|
||||||
*
|
|
||||||
* @param fileItemList 文件列表
|
|
||||||
* @param currentFile 当前文件
|
|
||||||
*/
|
*/
|
||||||
const handleAvatarChange = (
|
const handleCropperCancel = () => {
|
||||||
fileItemList: FileItem[],
|
fileRef.value = { name: '' };
|
||||||
currentFile: FileItem
|
options.img = '';
|
||||||
) => {
|
cropperVisible.value = false;
|
||||||
avatarList.value = [currentFile];
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上传头像
|
||||||
|
*/
|
||||||
|
const handleUpload = () => {
|
||||||
|
cropper.value.getCropBlob((data: string | Blob) => {
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('avatarFile', data, fileRef.value?.name);
|
||||||
|
uploadAvatar(formData).then((res) => {
|
||||||
|
userStore.avatar = res.data.avatar;
|
||||||
|
avatarList.value[0].url = getAvatar(res.data.avatar, undefined);
|
||||||
|
proxy.$message.success(res.msg);
|
||||||
|
handleCropperCancel();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 实时预览
|
||||||
|
* @param data data
|
||||||
|
*/
|
||||||
|
const realTime = (data: any) => {
|
||||||
|
previewStyle.value = {
|
||||||
|
width: `${data.w}px`,
|
||||||
|
height: `${data.h}px`,
|
||||||
|
overflow: 'hidden',
|
||||||
|
margin: '0',
|
||||||
|
zoom: 0.8,
|
||||||
|
borderRadius: '50%',
|
||||||
|
};
|
||||||
|
previews.value = data;
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -152,4 +231,8 @@
|
|||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.main {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
Loading…
Reference in New Issue
Block a user