494 lines
14 KiB
Vue
494 lines
14 KiB
Vue
<template>
|
||
<div id="tui-image-editor"></div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { message, Modal } from 'ant-design-vue';
|
||
import { ref, onBeforeUnmount, nextTick } from 'vue';
|
||
import 'tui-image-editor/dist/tui-image-editor.css';
|
||
import 'tui-color-picker/dist/tui-color-picker.css';
|
||
import ImageEditor from 'tui-image-editor/dist/tui-image-editor';
|
||
import { caseplatformCaseApi } from '/@/api/business/case/caseplatform-case-api';
|
||
import { FileUtil } from '/@/utils/fileutil';
|
||
import dayjs from 'dayjs';
|
||
import { SmartLoading } from '/@/components/framework/smart-loading';
|
||
const props = defineProps({
|
||
imgsrc: {
|
||
type: String,
|
||
default: '',
|
||
},
|
||
imgIndex: {
|
||
type: Number,
|
||
default: 0,
|
||
},
|
||
imgType: {
|
||
type: String,
|
||
default: '',
|
||
},
|
||
dpmasId: {
|
||
type: Number,
|
||
default: 0,
|
||
},
|
||
caseId: {
|
||
type: Number,
|
||
default: 0,
|
||
},
|
||
caseObj: {
|
||
type: Object,
|
||
default: () => {},
|
||
},
|
||
});
|
||
const uploadImgSrc = ref('');
|
||
|
||
const emit = defineEmits(['freshDetail']);
|
||
// tui-image-editor语言配置,汉化文字
|
||
const locale_zh = {
|
||
ZoomIn: '放大',
|
||
ZoomOut: '缩小',
|
||
Hand: '手掌',
|
||
History: '历史',
|
||
Resize: '调整宽高',
|
||
Crop: '裁剪',
|
||
DeleteAll: '全部删除',
|
||
Delete: '删除',
|
||
Undo: '撤销',
|
||
Redo: '反撤销',
|
||
Reset: '重置',
|
||
Flip: '镜像',
|
||
Rotate: '旋转',
|
||
Draw: '画',
|
||
Shape: '形状标注',
|
||
Icon: '图标标注',
|
||
Text: '文字标注',
|
||
Mask: '遮罩',
|
||
Filter: '滤镜',
|
||
Bold: '加粗',
|
||
Italic: '斜体',
|
||
Underline: '下划线',
|
||
Left: '左对齐',
|
||
Center: '居中',
|
||
Right: '右对齐',
|
||
Color: '颜色',
|
||
'Text size': '字体大小',
|
||
Custom: '自定义',
|
||
Square: '正方形',
|
||
Apply: '应用',
|
||
Cancel: '取消',
|
||
'Flip X': 'X 轴',
|
||
'Flip Y': 'Y 轴',
|
||
Range: '区间',
|
||
Stroke: '描边',
|
||
Fill: '填充',
|
||
Circle: '圆',
|
||
Triangle: '三角',
|
||
Rectangle: '矩形',
|
||
Free: '曲线',
|
||
Straight: '直线',
|
||
Arrow: '箭头',
|
||
'Arrow-2': '箭头2',
|
||
'Arrow-3': '箭头3',
|
||
'Star-1': '星星1',
|
||
'Star-2': '星星2',
|
||
Polygon: '多边形',
|
||
Location: '定位',
|
||
Heart: '心形',
|
||
Bubble: '气泡',
|
||
'Custom icon': '自定义图标',
|
||
'Load Mask Image': '加载蒙层图片',
|
||
Grayscale: '灰度',
|
||
Blur: '模糊',
|
||
Sharpen: '锐化',
|
||
Emboss: '浮雕',
|
||
'Remove White': '除去白色',
|
||
Distance: '距离',
|
||
Brightness: '亮度',
|
||
Noise: '噪音',
|
||
'Color Filter': '彩色滤镜',
|
||
Sepia: '棕色',
|
||
Sepia2: '棕色2',
|
||
Invert: '负片',
|
||
Pixelate: '像素化',
|
||
Threshold: '阈值',
|
||
Tint: '色调',
|
||
Multiply: '正片叠底',
|
||
Blend: '混合色',
|
||
Width: '宽度',
|
||
Height: '高度',
|
||
'Lock Aspect Ratio': '锁定宽高比例',
|
||
};
|
||
|
||
// 画布组件自定义样式
|
||
const customTheme = {
|
||
'common.bi.image': '', // 左上角logo图片
|
||
'common.bisize.width': '0px',
|
||
'common.bisize.height': '0px',
|
||
'common.backgroundImage': 'none',
|
||
'common.backgroundColor': '#fff',
|
||
'common.border': 'none',
|
||
|
||
// header
|
||
'header.backgroundImage': 'none',
|
||
'header.backgroundColor': '#f3f4f6',
|
||
'header.border': '0px',
|
||
'header.display': 'none',
|
||
|
||
// load button
|
||
'loadButton.backgroundColor': '#fff',
|
||
'loadButton.border': '1px solid #ddd',
|
||
'loadButton.color': '#222',
|
||
'loadButton.fontFamily': 'NotoSans, sans-serif',
|
||
'loadButton.fontSize': '12px',
|
||
'loadButton.display': 'none', // 可以直接隐藏掉
|
||
|
||
// download button
|
||
'downloadButton.backgroundColor': '#fdba3b',
|
||
'downloadButton.border': '1px solid #fdba3b',
|
||
'downloadButton.color': '#fff',
|
||
'downloadButton.fontFamily': 'NotoSans, sans-serif',
|
||
'downloadButton.fontSize': '12px',
|
||
'downloadButton.display': 'none', // 可以直接隐藏掉
|
||
// icons default
|
||
'menu.normalIcon.color': '#fff',
|
||
'menu.activeIcon.color': '#4080ff',
|
||
'menu.disabledIcon.color': '#ccc',
|
||
'menu.hoverIcon.color': '#4080ff',
|
||
'submenu.normalIcon.color': 'rgba(255,255,255,.9)',
|
||
'submenu.activeIcon.color': '#4080ff',
|
||
|
||
'menu.iconSize.width': '16px',
|
||
'menu.iconSize.height': '16px',
|
||
'submenu.iconSize.width': '18px',
|
||
'submenu.iconSize.height': '18px',
|
||
|
||
// submenu primary color
|
||
'submenu.backgroundColor': 'transparent',
|
||
'submenu.partition.color': 'transparent',
|
||
|
||
// submenu labels
|
||
'submenu.normalLabel.color': 'rgba(255,255,255,.5)',
|
||
'submenu.normalLabel.fontWeight': 'lighter',
|
||
'submenu.activeLabel.color': '#fff',
|
||
'submenu.activeLabel.fontWeight': 'lighter',
|
||
|
||
// checkbox style
|
||
'checkbox.border': '1px solid #ccc',
|
||
'checkbox.backgroundColor': '#fff',
|
||
|
||
// rango style
|
||
'range.pointer.color': '#fff',
|
||
'range.bar.color': 'rgba(255,255,255,0.5)',
|
||
'range.subbar.color': '#fff',
|
||
|
||
'range.disabledPointer.color': '#414141',
|
||
'range.disabledBar.color': '#282828',
|
||
'range.disabledSubbar.color': '#414141',
|
||
|
||
'range.value.color': '#fff',
|
||
'range.value.fontWeight': 'lighter',
|
||
'range.value.fontSize': '11px',
|
||
'range.value.border': '1px solid #496fb9',
|
||
'range.value.backgroundColor': '#496fb9',
|
||
'range.title.color': '#fff',
|
||
'range.title.fontWeight': 'lighter',
|
||
|
||
// colorpicker style
|
||
'colorpicker.button.border': '1px solid #fff',
|
||
'colorpicker.title.color': '#fff',
|
||
};
|
||
const instance = ref(null);
|
||
const HandleMainDiagnoseImg = () => {
|
||
let obj = props.caseObj.mainDiagnose;
|
||
obj.mainDiagnoseImg = uploadImgSrc.value;
|
||
|
||
caseplatformCaseApi
|
||
.updateMainDiagnose({
|
||
caseId: props.caseId,
|
||
mainDiagnose: JSON.stringify(obj),
|
||
})
|
||
.then((res) => {
|
||
emit('freshDetail');
|
||
SmartLoading.hide();
|
||
message.success('保存成功');
|
||
})
|
||
.catch((err) => {
|
||
SmartLoading.hide();
|
||
message.error('保存失败');
|
||
});
|
||
};
|
||
const HandleDpmasImg = () => {
|
||
let dpmasList = props.caseObj.dpmas;
|
||
let dpmasIndex = 0;
|
||
for (let i = 0; i < dpmasList.length; i++) {
|
||
if (dpmasList[i].dpmasId == props.dpmasId) {
|
||
dpmasIndex = i;
|
||
break;
|
||
}
|
||
}
|
||
console.log(dpmasList[dpmasIndex].dpmasImg);
|
||
let newImgList = dpmasList[dpmasIndex].dpmasImg.split(',');
|
||
newImgList[props.imgIndex] = uploadImgSrc.value;
|
||
let dpmasImg = '';
|
||
newImgList.forEach((item) => {
|
||
if (dpmasImg) {
|
||
dpmasImg += ',' + item;
|
||
} else {
|
||
dpmasImg = item;
|
||
}
|
||
});
|
||
|
||
caseplatformCaseApi
|
||
.updateDpmas({
|
||
caseId: props.caseId,
|
||
dmpsId: props.dpmasId,
|
||
dpmasImg: dpmasImg,
|
||
})
|
||
.then((res) => {
|
||
emit('freshDetail');
|
||
SmartLoading.hide();
|
||
message.success('保存成功');
|
||
})
|
||
.catch((err) => {
|
||
SmartLoading.hide();
|
||
message.error('保存失败');
|
||
});
|
||
};
|
||
const HandleCheckImg = () => {
|
||
let newImgList=[];
|
||
if(props.imgType=='bio'){
|
||
newImgList = props.caseObj.bioImg.split(',');
|
||
}else if(props.imgType=='coa'){
|
||
newImgList = props.caseObj.coaImg.split(',');
|
||
}else if(props.imgType=='inf'){
|
||
newImgList = props.caseObj.infImg.split(',');
|
||
}
|
||
console.log(newImgList);
|
||
newImgList[props.imgIndex] = uploadImgSrc.value;
|
||
let img = '';
|
||
newImgList.forEach((item) => {
|
||
if (img) {
|
||
img += ',' + item;
|
||
} else {
|
||
img = item;
|
||
}
|
||
});
|
||
let postData={
|
||
caseId: props.caseId,
|
||
}
|
||
if(props.imgType=='bio'){
|
||
postData.bioImg=img;
|
||
|
||
}else if(props.imgType=='coa'){
|
||
postData.coaImg=img;
|
||
}else if(props.imgType=='inf'){
|
||
postData.infImg=img;
|
||
}
|
||
caseplatformCaseApi
|
||
.updateCheck(postData)
|
||
.then((res) => {
|
||
emit('freshDetail');
|
||
SmartLoading.hide();
|
||
message.success('保存成功');
|
||
})
|
||
.catch((err) => {
|
||
SmartLoading.hide();
|
||
message.error('保存失败');
|
||
});
|
||
};
|
||
const getImageFormat = (imageUrl) => {
|
||
console.log(imageUrl);
|
||
var parts = imageUrl.split('.');
|
||
return parts[parts.length - 1];
|
||
};
|
||
const getImg = (file) => {
|
||
return new Promise((resolve, reject) => {
|
||
caseplatformCaseApi.getOssSign(1).then((res) => {
|
||
console.log(res.data);
|
||
let { accessid, dir, policy, signature, host } = res.data;
|
||
let filename = dayjs().format('YYYYMMDDHHmmss') + FileUtil.UUID() + '.' + 'png';
|
||
let formData = new FormData();
|
||
formData.append('OSSAccessKeyId', accessid);
|
||
formData.append('policy', policy);
|
||
formData.append('signature', signature);
|
||
formData.append('key', dir + filename);
|
||
formData.append('file', file, filename);
|
||
formData.append('success_action_status', 200);
|
||
caseplatformCaseApi
|
||
.ossUpload(host, formData)
|
||
.then((res) => {
|
||
console.log(host + dir + filename);
|
||
resolve(host + dir + filename);
|
||
})
|
||
.catch((err) => {
|
||
message.error('上传失败');
|
||
SmartLoading.hide();
|
||
});
|
||
});
|
||
});
|
||
SmartLoading.hide();
|
||
};
|
||
const blobToFile = (blob, name) => {
|
||
return new File([blob], name, { type: blob.type });
|
||
};
|
||
|
||
const save = () => {
|
||
SmartLoading.show();
|
||
instance.value.resetZoom();
|
||
const base64String = instance.value.toDataURL(); // base64 文件
|
||
const data = window.atob(base64String.split(',')[1]);
|
||
const ia = new Uint8Array(data.length);
|
||
for (let i = 0; i < data.length; i++) {
|
||
ia[i] = data.charCodeAt(i);
|
||
}
|
||
const blob = new Blob([ia], { type: 'image/png' }); // blob 文件
|
||
//下面懒得弄组件直接用当前时间弄得文件名,如果后台写了这里可以随便,也可以使用uuid进行生成
|
||
// const file = new File([blob], new Date().getTime() + '.jpeg', { type: blob.type });
|
||
// fileToBase64(file).then((res) => {
|
||
// newSrc.value = res;
|
||
// });
|
||
let file = blobToFile(blob, new Date().getTime() + '.png');
|
||
console.log(file);
|
||
getImg(file)
|
||
.then((res) => {
|
||
uploadImgSrc.value = res;
|
||
if (props.imgType === 'mainDiagnose') {
|
||
HandleMainDiagnoseImg();
|
||
} else if (props.imgType === 'dpmas') {
|
||
HandleDpmasImg();
|
||
} else if (props.imgType === 'bio' || props.imgType === 'coa' || props.imgType === 'inf') {
|
||
HandleCheckImg();
|
||
}
|
||
})
|
||
.catch((err) => {
|
||
SmartLoading.hide();
|
||
});
|
||
};
|
||
|
||
const fileToBase64 = (file) => {
|
||
return new Promise((resolve, reject) => {
|
||
const reader = new FileReader();
|
||
reader.readAsDataURL(file);
|
||
reader.onload = () => resolve(reader.result);
|
||
reader.onerror = (error) => reject(error);
|
||
});
|
||
};
|
||
const init = (src) => {
|
||
// console.log(ImageEditor);
|
||
instance.value = new ImageEditor(document.querySelector('#tui-image-editor'), {
|
||
|
||
includeUI: {
|
||
loadImage: {
|
||
path: src+'?time='+new Date().getTime(),
|
||
name: '编辑图片',
|
||
},
|
||
|
||
menu: ['draw', 'text'], // 底部菜单按钮列表 隐藏镜像flip和遮罩mask
|
||
initMenu: 'draw', // 默认打开的菜单项
|
||
menuBarPosition: 'bottom', // 菜单所在的位置
|
||
locale: locale_zh, // 本地化语言为中文
|
||
theme: customTheme, // 自定义样式
|
||
},
|
||
cssMaxWidth: 1000, // canvas 最大宽度
|
||
cssMaxHeight: 800
|
||
})
|
||
|
||
document.getElementsByClassName('tui-image-editor-main')[0].style.top = '45px'; // 调整图片显示位置
|
||
//document.getElementsByClassName('tie-btn-reset tui-image-editor-item help')[0].style.display = 'none'; // 隐藏顶部重置按钮
|
||
document.getElementsByClassName('tie-text-align-button')[0].style.display = 'none'; // 隐藏文字对齐选项
|
||
|
||
// // 调整图片显示位置
|
||
// document.getElementsByClassName("tui-image-editor-main")[0].style.top = "0px";
|
||
// //隐藏重置按钮
|
||
document.getElementsByClassName('tie-btn-reset tui-image-editor-item help')[0].style.display = 'none';
|
||
//隐藏移动按钮
|
||
document.getElementsByClassName('tie-btn-hand tui-image-editor-item help')[0].style.display = 'none';
|
||
//隐藏历史记录按钮
|
||
document.getElementsByClassName('tie-btn-history tui-image-editor-item help')[0].style.display = 'none';
|
||
//隐藏单个删除按钮
|
||
document.getElementsByClassName('tie-btn-delete tui-image-editor-item')[0].style.display = 'none';
|
||
};
|
||
|
||
onBeforeUnmount(() => {
|
||
if (instance.value) {
|
||
instance.value.destroy();
|
||
instance.value = null;
|
||
}
|
||
});
|
||
defineExpose({ init, save });
|
||
</script>
|
||
|
||
<style>
|
||
.tui-image-editor-help-menu {
|
||
background: skyblue !important;
|
||
}
|
||
.tui-image-editor-container .tui-image-editor-controls {
|
||
display: flex !important;
|
||
align-items: center !important;
|
||
background: transparent;
|
||
height: 40px !important;
|
||
}
|
||
.tui-image-editor-container .color-picker-value {
|
||
width: 20px !important;
|
||
height: 20px !important;
|
||
}
|
||
.tui-image-editor-container.bottom .tui-image-editor-submenu > div {
|
||
padding-bottom: 0 !important;
|
||
}
|
||
.tui-image-editor-container .tui-image-editor-submenu .tui-image-editor-submenu-item li {
|
||
display: flex !important;
|
||
}
|
||
.tui-image-editor-container .tui-image-editor-submenu .tui-image-editor-submenu-item .tui-image-editor-newline {
|
||
display: flex !important;
|
||
align-items: center;
|
||
}
|
||
.tui-image-editor-menu {
|
||
width: 300px !important;
|
||
height: 50px;
|
||
display: flex !important;
|
||
align-items: center !important;
|
||
justify-content: center;
|
||
background: skyblue !important;
|
||
}
|
||
|
||
.tui-image-editor-container .tui-image-editor-menu > .tui-image-editor-item,
|
||
.tui-image-editor-container .tui-image-editor-help-menu > .tui-image-editor-item.active {
|
||
padding: 0 !important;
|
||
width: 25px;
|
||
height: 25px;
|
||
display: flex !important;
|
||
justify-content: center !important;
|
||
align-items: center !important;
|
||
}
|
||
.tui-image-editor-container {
|
||
background: transparent !important;
|
||
}
|
||
.tui-image-editor-submenu-item {
|
||
display: flex !important;
|
||
justify-content: center !important;
|
||
width: 800px !important;
|
||
margin: 0 auto !important;
|
||
align-items: center !important;
|
||
background: skyblue !important;
|
||
}
|
||
.tui-image-editor-container .tui-image-editor-range {
|
||
top: 0 !important;
|
||
}
|
||
.tui-image-editor-container .tui-image-editor-range-value {
|
||
margin-top: 0;
|
||
}
|
||
.editorcon {
|
||
width: 100%;
|
||
height: 100%;
|
||
position: relative;
|
||
}
|
||
.save {
|
||
position: absolute;
|
||
right: 195px;
|
||
top: 14px;
|
||
z-index: 999;
|
||
cursor: pointer;
|
||
color: #fff;
|
||
font-size: 17px;
|
||
opacity: 0.8;
|
||
}
|
||
</style>
|