613 lines
17 KiB
Vue
613 lines
17 KiB
Vue
<template>
|
||
<z-paging
|
||
ref="paging"
|
||
inside-more
|
||
loading-more-no-more-text="咱也是有底线的!"
|
||
:auto-show-back-to-top="true"
|
||
v-model="dataList"
|
||
@query="queryList"
|
||
>
|
||
<template #top>
|
||
<dNav></dNav>
|
||
<view class="box" >
|
||
<view class="title">肝胆相照临床病例库肝胆相照临床病例库肝胆相照临床病例库</view>
|
||
<view class="content">
|
||
<view class="info">
|
||
<up--image :src="headImg" mode="widthFix" class="headImg" width="46rpx" height="46rpx"
|
||
radius="50%"></up--image>
|
||
<view class="name">陈医生 · 北京某三甲医院</view>
|
||
</view>
|
||
<view class="deal">
|
||
<view class="left">
|
||
<view class="eyebox">
|
||
<up-icon name="eye" color="#6B7280" size="28rpx"></up-icon>
|
||
<view class="num">1</view>
|
||
</view>
|
||
<view class="collect">
|
||
<up-icon name="heart" color="#6B7280" size="28rpx"></up-icon>
|
||
<view class="num">1</view>
|
||
</view>
|
||
</view>
|
||
<view class="time">
|
||
<up-icon name="clock" color="#6B7280" size="28rpx"></up-icon>
|
||
<view class="num">1</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view class="bar"></view>
|
||
|
||
|
||
<!-- 评论框 -->
|
||
<up-popup :zIndex="11" :overlayStyle="{ zIndex: 10 }" :closeOnClickOverlay="false" :show="showCommentDialog" :round="10" closeable mode="bottom" @close="close" @open="open">
|
||
<view class="poptitle"></view>
|
||
<view class="wraper">
|
||
<up--textarea height="200" v-model="comment" placeholder="请输入评论内容"></up--textarea>
|
||
</view>
|
||
<view class="imgbox">
|
||
<view class="imgunit">
|
||
<up--image :src="shangImg" radius="6" width="150rpx" height="150rpx" @click="previewImg"></up--image>
|
||
<view class="close">
|
||
<up-icon name="close-circle" color="#666" size="16" ></up-icon>
|
||
</view>
|
||
|
||
</view>
|
||
</view>
|
||
<view class="sendbox">
|
||
<view class="left"><up--image :src="uploadImg" mode="widthFix" width="40rpx" height="77rpx" @click="chooseImg"></up--image></view>
|
||
<view class="btn">发送</view>
|
||
</view>
|
||
</up-popup>
|
||
<canvas
|
||
v-if="showCanvas"
|
||
type="2d"
|
||
id="watermarkCanvas"
|
||
style="width:200px;
|
||
height:200px;position: fixed; top: -9999px;"
|
||
/>
|
||
</view>
|
||
</template>
|
||
<template #bottom>
|
||
<view class="bottom">
|
||
<view class="iptbox">
|
||
<up--image :src="chatImg" mode="widthFix" width="46rpx" radius="50%"></up--image>
|
||
<up-input @focus="open" type="text" placeholderClass="placeholderClass" placeholder="对病例发表您的看法" class="ipt" />
|
||
</view>
|
||
<view class="right">
|
||
<up--image :src="collectImg" mode="widthFix" width="38rpx"></up--image>
|
||
<view class="imgboxshang" >
|
||
<up--image :src="shangImg" mode="widthFix" width="169rpx" height="77rpx"></up--image>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
<view class="desc">
|
||
<view class="item" v-for="(item, index) in dataList" :key="index">
|
||
<view class="qq">
|
||
{{index}}
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
</z-paging>
|
||
|
||
|
||
</template>
|
||
|
||
<script setup>
|
||
import {
|
||
ref
|
||
} from 'vue'
|
||
import headImg from "@/static/headImg.png";
|
||
import collectImg from "@/static/collect.png";
|
||
import shangImg from "@/static/shang.png";
|
||
import chatImg from "@/static/chat.png";
|
||
import uploadImg from "@/static/uploadImg.png";
|
||
import list from "@/uni_modules/z-paging/components/z-paging/z-paging";
|
||
import api from "@/api/api";
|
||
import { onLoad } from "@dcloudio/uni-app";
|
||
const paging = ref(null);
|
||
const dataList = ref([]);
|
||
const showCanvas=ref(false)
|
||
const showCommentDialog = ref(false);
|
||
const canvasWidth=ref(0);
|
||
const canvasHeight=ref(0);
|
||
const comment = ref('');
|
||
onLoad(() => {});
|
||
const queryList = (pageNo, pageSize) => {
|
||
const params = {
|
||
pageNo: pageNo,
|
||
pageSize: pageSize,
|
||
type: 1,
|
||
};
|
||
// 此处请求仅为演示,请替换为自己项目中的请求
|
||
api
|
||
.queryList(params)
|
||
.then((res) => {
|
||
// console.log(res)
|
||
// dataList.value=dataList.value.concat(res.data.list)
|
||
// 将请求结果通过complete传给z-paging处理,同时也代表请求结束,这一行必须调用
|
||
paging.value.complete(res.data.list);
|
||
})
|
||
.catch((res) => {
|
||
// 如果请求失败写paging.value.complete(false);
|
||
// 注意,每次都需要在catch中写这句话很麻烦,z-paging提供了方案可以全局统一处理
|
||
// 在底层的网络请求抛出异常时,写uni.$emit('z-paging-error-emit');即可
|
||
paging.value.complete(false);
|
||
});
|
||
};
|
||
const open=()=>{
|
||
showCommentDialog.value = true;
|
||
console.log('open');
|
||
};
|
||
const close=()=>{
|
||
showCommentDialog.value = false
|
||
console.log('close');
|
||
};
|
||
const previewImg=()=>{
|
||
uni.previewImage({
|
||
current: 'https://example.com/image1.jpg',
|
||
urls: ['https://example.com/image1.jpg', 'https://example.com/image2.jpg']
|
||
});
|
||
|
||
};
|
||
const fillTextToImgWx=(base64)=>{
|
||
let maskText="@zjd嗯嗯嗯嗯嗯嗯3评论暂时真实的334"
|
||
|
||
return new Promise((resolve, reject) => {
|
||
wx.createSelectorQuery().select('#watermarkCanvas').fields({
|
||
node: true,
|
||
size: true
|
||
}).exec((res) => {
|
||
const canvas = res[0].node;
|
||
const ctx = canvas.getContext('2d');
|
||
let textMetrics = ctx.measureText(maskText);
|
||
console.log(textMetrics)
|
||
//水印文字宽度
|
||
let { width: textWidth, actualBoundingBoxAscent, actualBoundingBoxDescent } = textMetrics;
|
||
//水印文字高度
|
||
let textHeight = actualBoundingBoxAscent ? (actualBoundingBoxAscent + actualBoundingBoxDescent) : (textMetrics.fontBoundingBoxAscent + textMetrics.fontBoundingBoxDescent);
|
||
let imgHeight,imgWidth;
|
||
let font='';//fontsize"px Arial";
|
||
|
||
let fontColor="#fff"
|
||
let strokeWidth=3;
|
||
uni.getImageInfo({
|
||
src: base64,
|
||
success: (imageRes) => {
|
||
// 设置canvas宽高
|
||
let scale=(imageRes.width/800)*30>12?(imageRes.width/800)*30:12
|
||
font=scale+"px Arial"
|
||
console.log(imageRes)
|
||
canvas.width = imageRes.width
|
||
canvas.height = imageRes.height;
|
||
imgHeight=imageRes.height;
|
||
imgWidth=imageRes.width;
|
||
// 创建目标图片对象
|
||
const image = canvas.createImage();
|
||
image.src='';
|
||
image.src = base64;
|
||
image.onload = () => {
|
||
|
||
// 清除画布
|
||
//ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||
|
||
// 将图片绘制到canvas上
|
||
ctx.drawImage(image, 0, 0, canvas.width, canvas.height)
|
||
let posXmargin =10; //this.data.posXmargin // 自定义离左/右边的距离
|
||
let posYmargin =10;// this.data.posYmargin // 自定义离上/下边的距离
|
||
let randomNumber =3;//Math.floor(Math.random() * (3 + 1));
|
||
console.log('randomNumber:'+randomNumber);
|
||
switch (randomNumber) {
|
||
case 0: //左上角
|
||
let lt_x = posXmargin
|
||
let lt_y = posYmargin + textHeight
|
||
ctx.font = font
|
||
ctx.fillStyle = fontColor
|
||
ctx.storkStyle = "black";
|
||
ctx.strokeWidth= strokeWidth
|
||
ctx.fillStyle = "#fff";
|
||
ctx.fillText(maskText, lt_x, lt_y)
|
||
|
||
//ctx.restore()
|
||
//ctx.save()
|
||
break;
|
||
case 1: //左下角
|
||
let lb_x = posXmargin
|
||
let lb_y = imgHeight- posYmargin
|
||
ctx.font = font
|
||
ctx.fillStyle = fontColor
|
||
ctx.strokeStyle = "black";
|
||
ctx.strokeWidth= strokeWidth
|
||
ctx.fillStyle = "#fff";
|
||
ctx.fillText(maskText, lb_x, lb_y)
|
||
//ctx.restore()
|
||
//ctx.save()
|
||
break;
|
||
|
||
case 2: //右上角
|
||
let rt_x = imgWidth - textWidth*2.9- posXmargin<=0?10:imgWidth - textWidth*2.9- posXmargin
|
||
let rt_y = posYmargin + textHeight*2
|
||
ctx.font = font
|
||
ctx.fillStyle = fontColor
|
||
ctx.strokeStyle = "black";
|
||
ctx.strokeWidth= strokeWidth
|
||
ctx.fillStyle = "#fff";
|
||
ctx.fillText(maskText, rt_x, rt_y)
|
||
ctx.restore()
|
||
ctx.save()
|
||
break;
|
||
case 3: //右下角
|
||
let rb_x = imgWidth - textWidth*2.9- posXmargin<=0?10:imgWidth - textWidth*2.9- posXmargin
|
||
let rb_y = imgHeight - posYmargin
|
||
ctx.font = font
|
||
ctx.fillStyle = fontColor;
|
||
ctx.strokeStyle = "black";
|
||
ctx.strokeWidth= strokeWidth
|
||
ctx.fillStyle = "#fff";
|
||
ctx.fillText(maskText, rb_x, rb_y)
|
||
//ctx.restore()
|
||
//ctx.save()
|
||
break;
|
||
}
|
||
|
||
//ctx.restore()
|
||
// 将canvas转为图片
|
||
//setTimeout(() => {
|
||
wx.canvasToTempFilePath({
|
||
canvas: canvas,
|
||
success: function (res) {
|
||
// 输出生成的带水印的图片临时路径
|
||
resolve(res.tempFilePath)
|
||
wx.previewImage({ urls: [res.tempFilePath] });
|
||
showCanvas.value=false;
|
||
},
|
||
fail: function (res) {
|
||
// reject(res)
|
||
console.error(res);
|
||
}
|
||
});
|
||
|
||
//})
|
||
|
||
|
||
}
|
||
}
|
||
})
|
||
|
||
|
||
})
|
||
})
|
||
}
|
||
const fillTextToImg=(base64)=>{
|
||
const img = new Image();
|
||
img.src = base64;
|
||
img.setAttribute("crossOrigin", "Anonymous");
|
||
return new Promise((resolve, reject) => {
|
||
img.onload = () => {
|
||
const canvas = document.createElement("canvas");
|
||
const ctx = canvas.getContext("2d");
|
||
canvas.width = img.width;
|
||
canvas.height = img.height;
|
||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
|
||
const remFontSize = 30; //canvas.width / 35;
|
||
ctx.font = remFontSize + "px '微软雅黑'";
|
||
ctx.textAlign = "right";
|
||
ctx.strokeStyle = "#000";
|
||
ctx.fillStyle = "#fff";
|
||
const uploadTime = new Date();
|
||
const name = "@zjd";
|
||
const spaceH = remFontSize * 0.1;
|
||
let randomNumber = Math.floor(Math.random() * (3 + 1));
|
||
let position = [
|
||
{
|
||
top: remFontSize,
|
||
left: name.length * 30 || 30,
|
||
},
|
||
{
|
||
top: remFontSize,
|
||
left: canvas.width - remFontSize * 0.1 - spaceH,
|
||
},
|
||
{
|
||
top: canvas.height - remFontSize * 0.5 - spaceH,
|
||
left: name.length * 30 || 30,
|
||
},
|
||
{
|
||
top: canvas.height - remFontSize * 0.5 - spaceH,
|
||
left: canvas.width - remFontSize * 0.1 - spaceH,
|
||
},
|
||
];
|
||
ctx.strokeText(
|
||
name,
|
||
position[randomNumber].left,
|
||
position[randomNumber].top
|
||
);
|
||
ctx.fillText(
|
||
name,
|
||
position[randomNumber].left,
|
||
position[randomNumber].top
|
||
);
|
||
resolve(canvas.toDataURL("image/jpeg"));
|
||
};
|
||
});
|
||
};
|
||
const base64ToFile=(base64Data, filename)=> {
|
||
var arr = base64Data.split(",");
|
||
var type = arr[0].match(/:(.*?);/)[1];
|
||
var fileExt = type.split("/")[1];
|
||
var bstr = atob(arr[1]);
|
||
var n = bstr.length;
|
||
var u8arr = new Uint8Array(n);
|
||
while (n--) {
|
||
u8arr[n] = bstr.charCodeAt(n);
|
||
}
|
||
return new File([u8arr], filename, {
|
||
type: type,
|
||
});
|
||
};
|
||
|
||
|
||
const generateUUID=()=> {
|
||
let d = new Date().getTime();
|
||
if (
|
||
typeof performance !== "undefined" &&
|
||
typeof performance.now === "function"
|
||
) {
|
||
d += performance.now(); // 使用性能测量 API(performance.now())获取更高精度的时间戳
|
||
}
|
||
const uuid = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(
|
||
/[xy]/g,
|
||
function (c) {
|
||
const r = (d + Math.random() * 16) % 16 | 0;
|
||
d = Math.floor(d / 16);
|
||
return (c == "x" ? r : (r & 0x3) | 0x8).toString(16);
|
||
}
|
||
);
|
||
return uuid;
|
||
};
|
||
const readImages=async(localIds)=>{
|
||
console.log(localIds)
|
||
let promiseFun = [];
|
||
for (var i = 0; i < localIds.length; i++) {
|
||
//let localData = await doreadImage(localIds[i]);
|
||
|
||
let img=null;
|
||
/* #ifdef H5 */
|
||
|
||
let imgBase64=await getImageBase64(localIds[i]) ;
|
||
img = await fillTextToImg(imgBase64);
|
||
console.log(img)
|
||
uni.previewImage({ urls: [img]})
|
||
/* #endif */
|
||
/* #ifdef MP-WEIXIN */
|
||
let imgpromise = await fillTextToImgWx(localIds[i]);;
|
||
|
||
console.log(22222);
|
||
//console.log(imgBase64);
|
||
/* #endif */
|
||
|
||
//let imgFile = base64ToFile(img, new Date().getTime() + ".jpg");
|
||
// console.log(imgFile)
|
||
//promiseFun.push(uploadImg(imgFile));
|
||
}
|
||
Promise.all(promiseFun).then((res) => {
|
||
uni.showToast({
|
||
duration: 1000,
|
||
message: "上传成功",
|
||
});
|
||
});
|
||
};
|
||
// 图片转64代
|
||
const getImageBase64=(url)=> {
|
||
return new Promise((resolve, reject) => {
|
||
const xhr = new XMLHttpRequest();
|
||
xhr.open("GET", url, true);
|
||
xhr.responseType = "blob";
|
||
xhr.onload = function () {
|
||
if (this.status == 200) {
|
||
const fileReader = new FileReader();
|
||
fileReader.onloadend = function () {
|
||
|
||
resolve(fileReader.result); // Base64编码的字符串
|
||
};
|
||
fileReader.readAsDataURL(xhr.response); // 将blob转换为base64
|
||
} else {
|
||
reject("Could not fetch the file.");
|
||
}
|
||
};
|
||
xhr.onerror = function () {
|
||
reject("XHR error");
|
||
};
|
||
xhr.send();
|
||
});
|
||
}
|
||
|
||
const chooseImg=()=>{
|
||
showCanvas.value=true;
|
||
uni.chooseImage({
|
||
count: 1, //默认9
|
||
sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有
|
||
sourceType: ['album','camera '], //从相册选择
|
||
success: function (res) {
|
||
console.log(333)
|
||
readImages(res.tempFilePaths);
|
||
}
|
||
});
|
||
|
||
}
|
||
|
||
|
||
|
||
</script>
|
||
|
||
<style lang='scss' scoped>
|
||
.imgboxshang{
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
.imgbox{
|
||
margin:0 30rpx 30rpx;
|
||
.imgunit{
|
||
width:150rpx;
|
||
hight:150rpx;
|
||
position: relative;
|
||
.close{
|
||
position: absolute;
|
||
top:0rpx;
|
||
right:0;
|
||
}
|
||
}
|
||
}
|
||
.poptitle{
|
||
height: 88rpx;
|
||
border-bottom:1rpx solid #e7e7e7;
|
||
}
|
||
.sendbox{
|
||
display: flex;
|
||
justify-content: space-between;
|
||
margin:0 30rpx 30rpx;
|
||
.btn{
|
||
width:120rpx;
|
||
height: 58rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
background: #3cc7c0;
|
||
font-weight: 400;
|
||
font-size: 30rpx;
|
||
color: #fff;
|
||
border-radius:12rpx;
|
||
}
|
||
}
|
||
.wraper{
|
||
margin: 0rpx 12rpx;
|
||
}
|
||
.desc {
|
||
padding-bottom: 80rpx;
|
||
|
||
}
|
||
|
||
.bottom {
|
||
position: fixed;
|
||
display: flex;
|
||
width:100%;
|
||
box-sizing: border-box;
|
||
padding: 40rpx 30rpx;
|
||
align-items: center;
|
||
border-top: 2rpx solid #f9fafb;
|
||
background: #fff;
|
||
bottom: 0;
|
||
|
||
:deep(.u-image) {
|
||
background: none !important;
|
||
}
|
||
|
||
:deep(.placeholderClass) {
|
||
font-size: 30rpx;
|
||
color: #4B5563;
|
||
}
|
||
|
||
.right {
|
||
margin-left: 20rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
background: #fff;
|
||
|
||
.imgbox {
|
||
margin-left: 20rpx;
|
||
}
|
||
}
|
||
|
||
.iptbox {
|
||
flex: 1;
|
||
padding-left: 30rpx;
|
||
background: #F3F4F6;
|
||
border-radius: 38px;
|
||
height: 77rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
|
||
.ipt {
|
||
margin-left: 15rpx;
|
||
}
|
||
|
||
|
||
}
|
||
}
|
||
|
||
.bar {
|
||
width: 100%;
|
||
background: #f9fafb;
|
||
height: 24rpx;
|
||
}
|
||
|
||
.box {
|
||
background: #fff;
|
||
/* height: calc(100vh - 220rpx);
|
||
overflow-y: scroll;
|
||
-webkit-overflow-scrolling: touch; */
|
||
.title {
|
||
position: relative;
|
||
z-index: 1;
|
||
padding: 35rpx 30rpx 0;
|
||
background: #fff;
|
||
margin-top: -40rpx;
|
||
font-weight: 400;
|
||
font-size: 38rpx;
|
||
color: #111827;
|
||
line-height: 54rpx;
|
||
}
|
||
|
||
.info {
|
||
display: flex;
|
||
align-items: center;
|
||
margin-top: 20rpx;
|
||
padding: 0 30rpx;
|
||
font-size: 28rpx;
|
||
color: #4b5563;
|
||
line-height: 38rpx;
|
||
|
||
:deep(.u-image) {
|
||
margin-top: 10rpx;
|
||
}
|
||
|
||
.name {
|
||
margin-left: 15rpx;
|
||
}
|
||
}
|
||
}
|
||
|
||
.deal {
|
||
margin-top: 12rpx;
|
||
padding: 0 30rpx 20rpx;
|
||
display: flex;
|
||
color: #6b7280;
|
||
font-size: 24rpx;
|
||
justify-content: space-between;
|
||
|
||
.left {
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.collect {
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.eyebox {
|
||
width: 160rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.time {
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.num {
|
||
margin-left: 8rpx;
|
||
}
|
||
}
|
||
</style> |