Skip to content

Commit

Permalink
[Core] [Dashboard] Add upload avatar (#770)
Browse files Browse the repository at this point in the history
  • Loading branch information
qianmoQ authored May 23, 2024
2 parents bc81923 + b6b6076 commit 7cdb09e
Show file tree
Hide file tree
Showing 12 changed files with 259 additions and 38 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package io.edurt.datacap.common.utils;

import org.apache.commons.lang3.StringUtils;

public class UrlUtils
{
private UrlUtils()
Expand All @@ -14,6 +16,9 @@ private UrlUtils()
*/
public static String fixUrl(String url)
{
return url.replaceAll("/+", "/");
if (StringUtils.isNotEmpty(url)) {
return url.replaceAll("/+", "/");
}
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@ public class AvatarEntity
{
private String type;
private String path;
private String local;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.google.inject.Injector;
import io.edurt.datacap.common.response.CommonResponse;
import io.edurt.datacap.common.utils.CodeUtils;
import io.edurt.datacap.common.utils.SpiUtils;
import io.edurt.datacap.common.utils.UrlUtils;
import io.edurt.datacap.fs.FsRequest;
Expand All @@ -10,7 +11,6 @@
import io.edurt.datacap.service.entity.convert.AvatarEntity;
import io.edurt.datacap.service.enums.UploadMode;
import io.edurt.datacap.service.initializer.InitializerConfigure;
import io.edurt.datacap.service.repository.DashboardRepository;
import io.edurt.datacap.service.security.UserDetailsService;
import io.edurt.datacap.service.service.UploadService;
import lombok.extern.slf4j.Slf4j;
Expand All @@ -28,54 +28,48 @@ public class UploadServiceImpl
{
private final Injector injector;
private final HttpServletRequest request;
private final DashboardRepository dashboard;
private final InitializerConfigure initializer;

public UploadServiceImpl(Injector injector, HttpServletRequest request, DashboardRepository dashboard, InitializerConfigure initializer)
public UploadServiceImpl(Injector injector, HttpServletRequest request, InitializerConfigure initializer)
{
this.injector = injector;
this.request = request;
this.dashboard = dashboard;
this.initializer = initializer;
}

@Override
public CommonResponse upload(UploadBody configure)
{
if (configure.getMode().equals(UploadMode.DASHBOARD)) {
return dashboard.findByCode(configure.getCode())
.map(value -> {
try {
FsRequest fsRequest = getFsRequest(configure.getFile(), configure);
SpiUtils.findFs(injector, initializer.getFsConfigure().getType())
.ifPresent(fs -> {
FsResponse response = fs.writer(fsRequest);
AvatarEntity entity = AvatarEntity.builder()
.path(response.getRemote())
.type(initializer.getFsConfigure().getType())
.build();
if (initializer.getFsConfigure().getType().equals("Local")) {
entity.setPath(getAccess(entity));
}
value.setAvatar(entity);
dashboard.save(value);
});
}
catch (IOException e) {
log.error("Failed to upload file [ {} ]", configure.getCode(), e);
return CommonResponse.failure(e.getMessage());
}
finally {
try {
configure.getFile().getInputStream().close();
configure.setCode(CodeUtils.generateCode(false));
AvatarEntity entity = AvatarEntity.builder()
.type(initializer.getFsConfigure().getType())
.build();
try {
FsRequest fsRequest = getFsRequest(configure.getFile(), configure);
SpiUtils.findFs(injector, initializer.getFsConfigure().getType())
.ifPresent(fs -> {
FsResponse response = fs.writer(fsRequest);
entity.setPath(response.getRemote());
entity.setLocal(response.getRemote());
if (initializer.getFsConfigure().getType().equals("Local")) {
entity.setPath(getAccess(entity));
}
catch (IOException e) {
log.warn("Failed to close input stream", e);
}
return CommonResponse.success(value);
}
})
.orElseGet(() -> CommonResponse.failure(String.format("Dashboard [ %s ] not found", configure.getCode())));
});
}
catch (IOException e) {
log.error("Failed to upload file [ {} ]", configure.getCode(), e);
return CommonResponse.failure(e.getMessage());
}
finally {
try {
configure.getFile().getInputStream().close();
}
catch (IOException e) {
log.warn("Failed to close input stream", e);
}
return CommonResponse.success(entity);
}
}
return CommonResponse.failure(String.format("Mode [ %s ] not supported", configure.getMode()));
}
Expand Down
1 change: 1 addition & 0 deletions core/datacap-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
"vue": "^3.4.21",
"vue-clipboard3": "^2.0.0",
"vue-i18n": "^9.10.1",
"vue-picture-cropper": "^0.7.0",
"vue-router": "^4.3.0",
"vue3-ace-editor": "^2.2.4",
"vue3-calendar-heatmap": "^2.0.5",
Expand Down
3 changes: 3 additions & 0 deletions core/datacap-ui/src/i18n/langs/en/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -666,6 +666,9 @@ export default {
backTo: 'Back',
database: 'Database',
table: 'Table',
clear: 'Clear',
reset: 'Reset',
cropper: 'Cropper',
tip: {
pageNotNetwork: 'Oops! Unable to connect to the network, please check if the network is normal!'
}
Expand Down
3 changes: 3 additions & 0 deletions core/datacap-ui/src/i18n/langs/zhCn/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -666,6 +666,9 @@ export default {
backTo: '返回',
database: '数据库',
table: '表',
clear: '清空',
reset: '重置',
cropper: '裁剪',
tip: {
pageNotNetwork: '哎呀!无法连接到网络,请检查网络是否正常!'
}
Expand Down
7 changes: 7 additions & 0 deletions core/datacap-ui/src/services/upload.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { BaseService } from '@/services/base.ts'
import { HttpUtils } from '@/utils/http.ts'
import { ResponseModel } from '@/model/response.ts'

const DEFAULT_PATH = '/api/v1/upload'

Expand All @@ -9,6 +11,11 @@ class UploadService
{
super(DEFAULT_PATH)
}

upload(configure: any): Promise<ResponseModel>
{
return new HttpUtils().upload(`${ DEFAULT_PATH }`, configure)
}
}

export default new UploadService()
138 changes: 138 additions & 0 deletions core/datacap-ui/src/views/components/cropper/CropperHome.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
<template>
<div>
<Button class="p-0 w-full">
<Input ref="uploadInput" type="file" accept="image/jpg, image/jpeg, image/png, image/gif" @change="selectFile"/>
</Button>
</div>

<div v-if="result.blobURL || pic" class="pt-2 grid place-items-center">
<div>
<img class="max-h-[180px]" :src="result.blobURL ? result.blobURL : pic" alt=""/>
</div>
</div>

<Dialog v-if="isShowModal" :is-visible="isShowModal" :title="$t('common.cropper')" @close="isShowModal = $event">
<div class="p-0">
<VuePictureCropper style="max-height: 400px" :boxStyle="{ width: '100%', height: '100%', backgroundColor: '#f8f8f8', margin: 'auto' }"
:options="{ viewMode: 1, dragMode: 'crop', }" :img="pic" @ready="ready"/>
</div>
<template #footer>
<div class="space-x-2">
<Button class="btn" size="sm" @click="isShowModal = false">
{{ $t('common.cancel') }}
</Button>
<Button class="btn" size="sm" variant="destructive" @click="clear">
{{ $t('common.clear') }}
</Button>
<Button class="btn" size="sm" variant="destructive" @click="reset">
{{ $t('common.reset') }}
</Button>
<Button class="btn primary" size="sm" @click="getResult">
{{ $t('common.cropper') }}
</Button>
</div>
</template>
</Dialog>
</template>

<script lang="ts">
import { defineComponent, reactive, ref } from 'vue'
import VuePictureCropper, { cropper } from 'vue-picture-cropper'
import Button from '@/views/ui/button'
import { Input } from '@/components/ui/input'
import Dialog from '@/views/ui/dialog'
export default defineComponent({
components: {
Dialog,
Input,
VuePictureCropper,
Button
},
props: {
pic: {
type: String
}
},
setup(props, { emit })
{
const isShowModal = ref<boolean>(false)
const uploadInput = ref<HTMLInputElement | null>(null)
const pic = ref<string>(props.pic as string)
const result = reactive({
blobURL: ''
})
function selectFile(e: Event)
{
pic.value = ''
result.blobURL = ''
const { files } = e.target as HTMLInputElement
if (!files || !files.length) {
return
}
const file = files[0]
const reader = new FileReader()
reader.readAsDataURL(file)
reader.onload = () => {
pic.value = String(reader.result)
isShowModal.value = true
if (!uploadInput.value) {
return
}
uploadInput.value.value = ''
}
}
async function getResult()
{
if (!cropper) {
return
}
const blob: Blob | null = await cropper.getBlob()
if (!blob) {
return
}
result.blobURL = URL.createObjectURL(blob)
isShowModal.value = false
const file = await cropper.getFile()
emit('update:value', file)
}
function clear()
{
if (!cropper) {
return
}
cropper.clear()
}
function reset()
{
if (!cropper) {
return
}
cropper.reset()
}
function ready()
{
console.log('Cropper is ready.')
}
return {
uploadInput,
pic,
result,
isShowModal,
selectFile,
getResult,
clear,
reset,
ready
}
}
})
</script>
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,13 @@
<Textarea v-model="formState.description"/>
</FormItem>
</FormField>
<FormField name="avatar">
<FormItem class="space-y-2">
<FormLabel>{{ $t('common.avatar') }}</FormLabel>
<FormMessage/>
<CropperHome :pic="formState?.avatar?.path" @update:value="handlerCropper"/>
</FormItem>
</FormField>
</div>
<template #footer>
<div class="space-x-5">
Expand Down Expand Up @@ -83,10 +90,13 @@ import { Input } from '@/components/ui/input'
import { FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from '@/components/ui/form'
import { cloneDeep } from 'lodash'
import { Textarea } from '@/components/ui/textarea'
import CropperHome from '@/views/components/cropper/CropperHome.vue'
import UploadService from '@/services/upload'
export default defineComponent({
name: 'DashboardEditor',
components: {
CropperHome,
Textarea,
Input,
ChartContainer,
Expand Down Expand Up @@ -151,6 +161,26 @@ export default defineComponent({
{
this.configureVisible = opened
},
handlerCropper(value: any)
{
const configure = {
code: this.formState?.code,
mode: 'DASHBOARD',
file: value
}
UploadService.upload(configure)
.then(response => {
if (response.status) {
if (this.formState) {
this.formState.avatar = response.data
}
ToastUtils.success(this.$t('common.successfully'))
}
else {
ToastUtils.error(response.message)
}
})
},
handlerSave()
{
if (this.formState) {
Expand Down
Loading

0 comments on commit 7cdb09e

Please sign in to comment.