case-data/pages/detail/detail.vue
zoujiandong fc0d7ce817 5.16
2025-05-16 17:16:23 +08:00

613 lines
17 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<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(); // 使用性能测量 APIperformance.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>