353 lines
8.0 KiB
Vue
353 lines
8.0 KiB
Vue
|
|
<template>
|
|||
|
|
<view class="w-process">
|
|||
|
|
<view
|
|||
|
|
:class="{'w-process-node': true, 'w-cmt-node': (node.comment && node.comment.length > 0) || node.signature}"
|
|||
|
|
v-for="(node, index) in (progress || [])" :key="index">
|
|||
|
|
<view class="w-process-item-line"></view>
|
|||
|
|
<view class="w-process-item">
|
|||
|
|
<view class="w-process-item-avatar">
|
|||
|
|
<avatar :size="42" :status="getStatus(node)" :name="node.user.name" :src="getRes(node.user.avatar)"
|
|||
|
|
:showName="false"></avatar>
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
<view class="w-p-text-info">
|
|||
|
|
<view>{{node.name}} <text
|
|||
|
|
v-show="(node.comment && node.comment.length > 0) || node.signature">(添加了评论)</text></view>
|
|||
|
|
<view>{{node.user.name}}</view>
|
|||
|
|
</view>
|
|||
|
|
<text class="w-p-time">
|
|||
|
|
{{ node.isFuture ? '等待中' : getFinishTime(node.finishTime) }}
|
|||
|
|
</text>
|
|||
|
|
</view>
|
|||
|
|
<view class="w-process-node-content">
|
|||
|
|
<view class="w-comments" v-show="(node.comment && node.comment.length > 0) || node.signature">
|
|||
|
|
<view v-if="(node.signature || '') !== ''"
|
|||
|
|
style="display: flex; align-items: flex-start; margin-bottom: 5px;">
|
|||
|
|
<text>签字:</text>
|
|||
|
|
<image mode="aspectFit" :src="node.signature" style="width: 150rpx; height: 100rpx;"></image>
|
|||
|
|
</view>
|
|||
|
|
<view v-for="cmt in node.comment" :key="cmt.id" class="w-comment">
|
|||
|
|
<view>{{cmt.text}}</view>
|
|||
|
|
<template v-if="cmt.attachments.length > 0">
|
|||
|
|
<view>
|
|||
|
|
<image mode="aspectFit" :src="img" v-for="(img, i) in filterImages(cmt.attachments)"
|
|||
|
|
:key="img" @click="previewImg(img, cmt.attachments)"></image>
|
|||
|
|
</view>
|
|||
|
|
<view>
|
|||
|
|
<view class="ellipsis" v-for="(file, i) in filterFiles(cmt.attachments)" :key="file.id">
|
|||
|
|
<view style="color: #4C87F3;" @click="downloadFile(file.url)">{{file.name}}</view>
|
|||
|
|
</view>
|
|||
|
|
<!-- <text v-for="(file, i) in filterFiles(cmt.attachments)" :key="file.id">
|
|||
|
|
<text v-if="typeIsImg(file.name)" style="color: #4C87F3;"
|
|||
|
|
@click="previewImgOne(file)">{{file.name}}</text>
|
|||
|
|
<uni-link v-else :showUnderLine="false" color="#4C87F3" :download="file.name"
|
|||
|
|
:href="file.url" :text="file.name"></uni-link>
|
|||
|
|
</text> -->
|
|||
|
|
</view>
|
|||
|
|
</template>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
<view class="w-process-end w-process-item">
|
|||
|
|
<view :style="{width: 50 / 16 + 'rem', height: 50 / 16 * 0.8 + 'rem'}">
|
|||
|
|
<uni-icons2 :size="30" type="more-filled" color="#8b8b8b" class="w-pr-running"
|
|||
|
|
v-if="result === 'RUNNING'"></uni-icons2>
|
|||
|
|
<uni-icons2 :size="30" type="checkbox-filled" color="#5FB685" class="w-pr-status"
|
|||
|
|
v-else-if="result === 'PASS'"></uni-icons2>
|
|||
|
|
<uni-icons2 :size="30" type="clear" color="#CE5266" class="w-pr-status"
|
|||
|
|
v-else-if="result === 'REFUSE'"></uni-icons2>
|
|||
|
|
<uni-icons2 :size="30" type="close" color="#8b8b8b" class="w-pr-status"
|
|||
|
|
v-else-if="result === 'CANCEL'"></uni-icons2>
|
|||
|
|
</view>
|
|||
|
|
<view>{{status}}</view>
|
|||
|
|
</view>
|
|||
|
|
<view class="fixed" :class="{show:showIframe}" v-if="show" @click="show=false">
|
|||
|
|
<view class="iframeMain" @click.stop="show=true">
|
|||
|
|
<video v-if="getType(iframeUrl) == 'video'" class="iframe" :src="iframeUrl"></video>
|
|||
|
|
<image v-else-if="getType(iframeUrl) == 'image'" class="iframe" :src="iframeUrl" mode="aspectFill"></image>
|
|||
|
|
<iframe v-else class="iframe" ref="iframe" :src="iframeUrl" frameborder="0"></iframe>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
</template>
|
|||
|
|
|
|||
|
|
<script setup>
|
|||
|
|
import Avatar from '@/components/Avatar.vue'
|
|||
|
|
import {
|
|||
|
|
nextTick,
|
|||
|
|
ref
|
|||
|
|
} from 'vue';
|
|||
|
|
import {
|
|||
|
|
getRes,
|
|||
|
|
getFileSize,
|
|||
|
|
isVideoLink,
|
|||
|
|
isImageLink
|
|||
|
|
} from '@/utils/tool.js'
|
|||
|
|
import {
|
|||
|
|
Log
|
|||
|
|
} from '@icon-park/vue-next';
|
|||
|
|
|
|||
|
|
const props = defineProps(['progress', 'status', 'result'])
|
|||
|
|
|
|||
|
|
const imgViews = ref([])
|
|||
|
|
const showIframe = ref(false)
|
|||
|
|
const show = ref(false)
|
|||
|
|
const iframeUrl = ref("")
|
|||
|
|
const iframe = ref()
|
|||
|
|
|
|||
|
|
|
|||
|
|
function getFinishTime(time) {
|
|||
|
|
if (time) {
|
|||
|
|
return time.substring(5, 16)
|
|||
|
|
}
|
|||
|
|
return '处理中'
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function filterImages(attachments) {
|
|||
|
|
return (attachments || []).filter(f => f.isImage).map(f => {
|
|||
|
|
console.log(f.url);
|
|||
|
|
return getRes(f.url)
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function filterFiles(attachments) {
|
|||
|
|
return (attachments || []).filter(f => !f.isImage).map(f => {
|
|||
|
|
return {
|
|||
|
|
...f,
|
|||
|
|
url: getRes(f.url)
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function previewImg(img, attachments) {
|
|||
|
|
console.log(img, attachments);
|
|||
|
|
const imgs = filterImages(attachments)
|
|||
|
|
console.log(imgs);
|
|||
|
|
uni.previewImage({
|
|||
|
|
current: imgs.indexOf(img),
|
|||
|
|
urls: imgs,
|
|||
|
|
longPressActions: true
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function getType(url){
|
|||
|
|
if(isImageLink(url)){
|
|||
|
|
return "image"
|
|||
|
|
}else if(isVideoLink(url)){
|
|||
|
|
return "video"
|
|||
|
|
}else{
|
|||
|
|
return ''
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function downloadFile(url) {
|
|||
|
|
// 下载所有的文件
|
|||
|
|
let name = url.substring(url.lastIndexOf('/') + 1);
|
|||
|
|
console.log(name, "文件名称");
|
|||
|
|
if (isVideoLink(url) || isImageLink(url)) {
|
|||
|
|
// 是图片和视频
|
|||
|
|
show.value = true;
|
|||
|
|
showIframe.value = true;
|
|||
|
|
iframeUrl.value = url;
|
|||
|
|
} else {
|
|||
|
|
show.value = true;
|
|||
|
|
showIframe.value = false;
|
|||
|
|
iframeUrl.value = url;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function previewImgOne(img) {
|
|||
|
|
console.log(img);
|
|||
|
|
downloadFile(img.url, Date.now() + ".jpg")
|
|||
|
|
// uni.previewImage({
|
|||
|
|
// current: 0,
|
|||
|
|
// urls: [img.url],
|
|||
|
|
// longPressActions: true
|
|||
|
|
// })
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function typeIsImg(filename) {
|
|||
|
|
// 获取文件名称是否为图片
|
|||
|
|
const imageExtensions = /\.(jpg|jpeg|png|gif|bmp)$/i;
|
|||
|
|
return imageExtensions.test(filename);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function getStatus(item) {
|
|||
|
|
if (item.isFuture) {
|
|||
|
|
return 'waiting'
|
|||
|
|
} else if (item.finishTime === null) {
|
|||
|
|
return 'pending'
|
|||
|
|
} else if (item.nodeType === 'CC') {
|
|||
|
|
return 'cc'
|
|||
|
|
} else if (item.result === 'agree') {
|
|||
|
|
return 'success'
|
|||
|
|
} else if (item.result === 'refuse') {
|
|||
|
|
return 'error'
|
|||
|
|
} else if (item.result === 'comment') {
|
|||
|
|
return 'comment'
|
|||
|
|
} else if (item.result === 'transfer') {
|
|||
|
|
return 'transfer'
|
|||
|
|
} else if (item.result === 'recall') {
|
|||
|
|
return 'recall'
|
|||
|
|
} else if (item.nodeType === 'cancel') {
|
|||
|
|
return 'cancel'
|
|||
|
|
} else {
|
|||
|
|
return undefined
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
</script>
|
|||
|
|
|
|||
|
|
<style lang="less" scoped>
|
|||
|
|
.fixed {
|
|||
|
|
position: fixed;
|
|||
|
|
z-index: 9999;
|
|||
|
|
left: 0;
|
|||
|
|
top: 0;
|
|||
|
|
right: 0;
|
|||
|
|
bottom: 0;
|
|||
|
|
background-color: rgba(0, 0, 0, .3);
|
|||
|
|
display: none;
|
|||
|
|
|
|||
|
|
&.show {
|
|||
|
|
display: initial;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.iframeMain {
|
|||
|
|
position: absolute;
|
|||
|
|
left: 50%;
|
|||
|
|
top: 50%;
|
|||
|
|
transform: translate(-50%, -50%);
|
|||
|
|
width: 650rpx;
|
|||
|
|
font-size: 0;
|
|||
|
|
|
|||
|
|
.iframe {
|
|||
|
|
width: 100%;
|
|||
|
|
height: 500rpx;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
.w-process {
|
|||
|
|
font-size: 32rpx;
|
|||
|
|
|
|||
|
|
.w-process-node {
|
|||
|
|
position: relative;
|
|||
|
|
padding-bottom: 64rpx;
|
|||
|
|
|
|||
|
|
//连接线
|
|||
|
|
.w-process-item-line {
|
|||
|
|
background-color: #E4E4E4;
|
|||
|
|
position: absolute;
|
|||
|
|
width: 6rpx;
|
|||
|
|
height: 100%;
|
|||
|
|
left: 40rpx;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//节点体
|
|||
|
|
.w-process-node-content {
|
|||
|
|
margin-left: 96rpx;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.w-process-item {
|
|||
|
|
display: flex;
|
|||
|
|
position: relative;
|
|||
|
|
|
|||
|
|
.w-process-item-avatar {
|
|||
|
|
padding: 5px 0;
|
|||
|
|
background-color: white;
|
|||
|
|
border-radius: 50%;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.w-p-text-info {
|
|||
|
|
display: flex;
|
|||
|
|
flex-direction: column;
|
|||
|
|
justify-content: center;
|
|||
|
|
margin-left: 16rpx;
|
|||
|
|
|
|||
|
|
&>view:first-child {
|
|||
|
|
font-size: 29rpx;
|
|||
|
|
color: #8C8C8C;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
&>view {
|
|||
|
|
padding: 3rpx;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.w-p-time {
|
|||
|
|
position: absolute;
|
|||
|
|
color: #8C8C8C;
|
|||
|
|
font-size: 30rpx;
|
|||
|
|
top: 10rpx;
|
|||
|
|
right: 0;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.w-process-end {
|
|||
|
|
display: flex;
|
|||
|
|
align-items: center;
|
|||
|
|
padding: 3rpx;
|
|||
|
|
|
|||
|
|
&>view:first-child {
|
|||
|
|
display: flex;
|
|||
|
|
background-color: white;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.w-pr-running {
|
|||
|
|
width: 80%;
|
|||
|
|
height: 100%;
|
|||
|
|
background-color: #E4E4E4;
|
|||
|
|
border-radius: 50%;
|
|||
|
|
display: flex;
|
|||
|
|
justify-content: center;
|
|||
|
|
align-items: center;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.w-pr-status {
|
|||
|
|
width: 80%;
|
|||
|
|
height: 100%;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.w-comments {
|
|||
|
|
margin-top: 10rpx;
|
|||
|
|
padding: 16rpx;
|
|||
|
|
background-color: #F4F5F7;
|
|||
|
|
border-radius: 0 8px 8px 8px;
|
|||
|
|
|
|||
|
|
.w-comment {
|
|||
|
|
image {
|
|||
|
|
margin: 2px;
|
|||
|
|
width: 112rpx;
|
|||
|
|
height: 112rpx;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
&>view:first-child {
|
|||
|
|
font-size: 29rpx;
|
|||
|
|
color: #515151;
|
|||
|
|
margin-bottom: 6rpx;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.ellipsis {
|
|||
|
|
overflow: hidden;
|
|||
|
|
|
|||
|
|
>view {
|
|||
|
|
white-space: nowrap;
|
|||
|
|
overflow: hidden;
|
|||
|
|
text-overflow: ellipsis;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.w-cmt-node {
|
|||
|
|
padding-bottom: 16rpx !important;
|
|||
|
|
}
|
|||
|
|
</style>
|