Files
dvcp_v2_webapp/packages/3.0.0/AppMeetingChinaunion/components/meetingDetail.vue
yanran200730 69aca8781d 26996
2022-01-24 14:27:45 +08:00

719 lines
23 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>
<div class="addThreeMeeting">
<ai-detail>
<ai-title slot="title" title="三会一课详请" isShowBack @onBackClick="$parent.goBack()" isShowBottomBorder/>
<template #content>
<ai-card title="会议详情">
<template #content>
<el-form size="small" label-suffix="" label-width="100px">
<ai-title :title="obj.meetingAgenda" isShowBottomBorder/>
<el-form-item label="会议分类">
<span v-for="(i,index) in dict.getDict('meetingClassification')" :key="index">
<span v-for="(b,indexs) in obj.meetingClassification" :key="indexs"
v-if="i.dictValue == b">
{{ i.dictName }}
<span v-if="indexs < (obj.meetingClassification.length - 1) ">,</span>
</span>
</span>
</el-form-item>
<el-form-item label="举办方式">{{ obj.isOnline == 1 ? '线上举办' : '线下举办' }}</el-form-item>
<el-form-item label="会议地点" v-if="obj.isOnline==0">{{ obj.meetingAddress || '-' }}</el-form-item>
<el-form-item label="会议说明">
<div v-html="obj.meetingDescription"/>
</el-form-item>
<el-row type="flex" justify="space-between">
<el-form-item label="开始时间">{{ obj.startTime || '-' }}</el-form-item>
<el-form-item label="结束时间">{{ obj.endTime || '-' }}</el-form-item>
</el-row>
<el-form-item label="签到方式">{{ dict.getLabel('addSignMethod', obj.signMethod || '-') }}</el-form-item>
<el-form-item label="签到时间">
<span class="value" v-if="obj.signMethod == 1">
会议开始时间前
<span style="color:#5088FF">{{ obj.meetingBefore }}</span>
分钟至会议开始时间后
<span style="color:#5088FF">{{ obj.meetingAfter }}</span> 分钟可进行签到
<div>可签到时间为 <span style="color:#5088FF">({{ signStart }} ~ {{ signEnd }})</span></div>
</span>
<span class="value" v-else>-</span>
</el-form-item>
<el-form-item label="提醒方式">
<span class="value"
v-if="obj.reminderMethod && obj.reminderMethod.length && obj.reminderMethod[0] !== ''">
<span v-for="(i,index) in dict.getDict('feminderMethod')" :key="index">
<span v-for="(b,indexs) in obj.reminderMethod" :key="indexs" v-if="i.dictValue == b">
{{ i.dictName }}
<span v-if="indexs < (obj.reminderMethod.length - 1) ">,</span>
</span>
</span>
</span>
<span class="value" v-else>-</span></el-form-item>
<ai-title title="附件" isShowBottomBorder>
<template #rightBtn>
<el-button type="text" icon="iconfont iconDownload" @click="downLoadAll">下载全部</el-button>
</template>
</ai-title>
<el-form-item label-width="0">
<div v-if="obj.annex.length">
<div class="flie" v-for="(item, index) in obj.annex" :key="index"
@click="downFile(item)">
<p>
<svg aria-hidden="true" style="width:24px;height:24px;">
<use xlink:href="#iconAppendix_UNdownload"></use>
</svg>
<span>{{ item.name }}</span>
</p>
<span style="color:#999;">{{ (item.size / 1024).toFixed(2) + "KB" }}
<span class="iconfont iconDownload" style="color:#5088FF"></span>
</span>
</div>
</div>
<div class="no-data" style="height:160px;width:100%;" v-else></div>
</el-form-item>
<ai-title title="人员信息" isShowBottomBorder/>
<el-form-item label="与会组织">{{ arrLabel(obj.appThreeMeetingOrganizationList, 'name') }}</el-form-item>
<el-form-item label="主持人">{{ arrLabel(obj.hostList, 'userName') }}</el-form-item>
<el-form-item label="记录人">{{ arrLabel(obj.recorderList, 'userName') }}</el-form-item>
<el-form-item label="签到负责人">{{ arrLabel(obj.chargeOfSignInList, 'userName') }}</el-form-item>
<el-form-item label="参与人">{{ arrLabel(obj.participantList, 'userName') }}</el-form-item>
</el-form>
</template>
</ai-card>
<ai-card title="会议纪要">
<template #content>
<el-form ref="ruleForm" size="small" label-suffix="" label-width="120px">
<ai-title title="会议纪要详情" isShowBottomBorder>
<template #rightBtn>
<template v-if="editable">
<el-button type="text" @click="cancelSummary()">取消</el-button>
<el-button type="text" @click="confirmSummary">保存</el-button>
</template>
<el-button v-else type="text" icon="iconfont iconEdit" @click="editForm">修改
</el-button>
</template>
</ai-title>
<el-form-item label="纪要负责人">{{ obj.recorderName || '-' }}</el-form-item>
<el-form-item label="上次编辑时间">{{ summaryObj.createTime|formatTime }}</el-form-item>
<template v-if="!editable">
<el-form-item label="纪要内容">
<div class="content" v-html="summaryObj.content ||'暂无内容'"/>
</el-form-item>
<el-form-item label="图片">
<span class="value" v-viewer>
<img v-for="(item, index) in summaryObj.images" :key="index" :src="item.url"
style="width: 84px;height:84px;margin: 0 16px 8px 0;">
</span></el-form-item>
</template>
<template v-if="editable">
<el-form-item label="纪要内容:">
<el-input
style="width: 90%;"
type="textarea"
:rows="16"
placeholder="请输入内容"
v-model="summaryObj.content">
</el-input>
</el-form-item>
<el-form-item label="图片:">
<ai-uploader :instance="instance" v-model="summaryObj.images" :limit="50"/>
</el-form-item>
</template>
</el-form>
</template>
</ai-card>
<ai-card title="人员签到">
<template #content>
<el-form>
<ai-title title="人员列表" isShowBottomBorder>
<!-- <template #rightBtn v-if="obj.signMethod==1">-->
<!-- <el-button type="text" icon="iconfont iconEwm" @click="showSignPhoto=true">获取签到码-->
<!-- </el-button>-->
<!-- </template>-->
</ai-title>
<div class="detail-info">
<div class="detail-left detail-info-p84">
<ai-wrapper style="margin-top: 20px;">
<ai-info-item label="签到负责人" isLine>
<span class="value" v-if="obj.chargeOfSignInList && obj.chargeOfSignInList.length">
<span v-for="(item,index) in obj.chargeOfSignInList" :key="item+index">{{ item.userName }}
<span v-if="index < obj.chargeOfSignInList.length-1"></span>
</span>
</span>
<span class="value" v-else>-</span>
</ai-info-item>
</ai-wrapper>
</div>
</div>
<ai-search-bar>
<template #left>
<el-select size="small" v-model="search.status" placeholder="状态" clearable @change="getSignInfo">
<el-option v-for="(op,j) in dict.getDict('OneThreeSignStatus')" :key="j" :label="op.dictName"
:value="op.dictValue"/>
</el-select>
</template>
<template #right>
<el-input size="small" placeholder="姓名" v-model="search.meetingUserName"
prefix-icon="iconfont iconSearch" clearable @keyup.enter.native="getSignInfo"
@clear="clear"></el-input>
</template>
</ai-search-bar>
<ai-table
:tableData="tableData"
:col-configs="colConfigs"
:isShowPagination="false"
border
@getList="getSignInfo">
<el-table-column label="操作" slot="options" align="center" width="150">
<template slot-scope="{row}">
<span class="opt" @click="doSign('2',row)" v-if="row.status==0">代签</span>
<span class="opt" style="margin-left: 16px;" @click="doSign('3',row)"
v-if="row.status==0">请假</span>
<span class="opt" @click="doSign('0',row)" v-if="['1','2','3'].includes(row.status)">撤消状态</span>
</template>
</el-table-column>
</ai-table>
</el-form>
</template>
</ai-card>
<ai-card v-if="obj.isVote == 1" title="投票统计">
<template #content>
<el-form>
<ai-title title="投票统计" isShowBottomBorder/>
<el-form-item label="投票主题">{{ obj.voteTopic }}</el-form-item>
<el-form-item label="投票形式">{{ dict.getLabel('ThreeMeetingAnonymous', obj.anonymous) }}</el-form-item>
<el-form-item label="截止时间">{{ obj.voteDeadline }}</el-form-item>
<ai-echart :ops="voteOps" :data="voteStaData"/>
<template v-if="obj.anonymous==1">
<ai-title title="投票详情" isShowBottomBorder/>
<ai-table :tableData="obj.participantList" :col-configs="voteConfigs" :isShowPagination="false"
border :dict="dict" @getList="getDetailInfo"/>
</template>
</el-form>
</template>
</ai-card>
</template>
</ai-detail>
<div class="signPhoto" v-show="showSignPhoto" @click="showSignPhoto=false"/>
<div class="signPhotoImg" v-show="showSignPhoto" @click="showSignPhoto=false">
<img :src="obj.signPhoto" alt="">
<span>点击鼠标右键另存至本地</span>
</div>
<ai-dialog
title="请假/代签"
:visible.sync="dialog"
:destroyOnClose="true"
@onConfirm="updateState"
width="520px">
<el-form ref="ruleForm" label-width="90px">
<el-form-item label="情况说明:">
<el-input type="textarea" v-model="description" placeholder="请输入..." :rows="4"/>
</el-form-item>
</el-form>
</ai-dialog>
</div>
</template>
<script>
import Vue from 'vue'
import {mapState} from "vuex";
import moment from 'dayjs';
import Viewer from 'v-viewer'
Vue.use(Viewer)
export default {
name: "meetingDetail",
props: {
instance: Function,
dict: Object,
permissions: Function,
detail: Object,
},
computed: {
...mapState(["user"]),
colConfigs() {
const self = this;
return [
{
prop: 'meetingUserName',
align: 'center',
label: '姓名',
},
{
prop: 'signTime',
align: 'center',
label: '签到时间',
width: 180,
},
{
prop: 'doUserName',
align: 'center',
label: '审批人/代签人'
},
{
prop: 'description',
align: 'left',
label: '情况说明'
},
{
prop: 'status',
align: 'center',
label: '状态',
render(h, {row}) {
return h('span', {
style: {
color: self.color[row.status]
}
}, self.$dict.getLabel('OneThreeSignStatus', row.status))
}
},
{slot: 'options', label: '操作'}
]
},
voteConfigs() {
return [
{label: "人员姓名", prop: "userName", align: 'center'},
{label: "投票选项", prop: "myVote", dict: "ThreeMeetingVoteItem", formart: v => v ? (v === '1' ? '同意' : '不同意') : '-' },
{label: "投票时间", prop: "voteTime"},
]
},
voteOps() {
return {
legend: {
itemWidth: 8, itemHeight: 8, itemGap: 20, orient: 'vertical',
top: 56, left: 240, formatter: name => {
let v1 = this.voteStaData.find(e => e['投票'] == name)?.v1 || 0
return `{row|${name}}{v|${v1}}`
},
textStyle: {
rich: {
row: {fontSize: 14, color: '#666', width: 40},
v: {width: 140, align: 'right'},
}
}
},
color: ['#4B87FE', '#fa4'],
daemon: {
center: [80, 80],
radius: [30, 70],
type: 'pie',
label: {position: 'inner', formatter: '{d}%', textStyle: {color: '#fff'}},
}
}
},
voteStaData() {
return [
{'投票': '同意', v1: this.obj.upVote || 0},
{'投票': '不同意', v1: this.obj.downVote || 0},
]
},
color() {
return ["#FF4466", "#2EA222", "#2266FF", "#FF8822", "#333333"]
},
},
data() {
return {
editable: false,
obj: {
meetingAgenda: "",
meetingClassification: [],
reminderMethod: [],
annex: [],
appThreeMeetingOrganizationList: [],
hostList: [],
recorderList: [],
chargeOfSignInList: [],
participantList: [],
images: []
},
summaryObj: {
content: "",
images: "",
meetingId: "",
},
fileList: [],
signStart: "",
signEnd: "",
areaId: "",
dialogVisible: false,
showConfirmBtn: false,
tableData: [],
search: {
status: "",
meetingUserName: "",
},
showSignPhoto: false,
edit: false,
sumEditDia: false,
textarea: "",
dialog: false,
description: "",
id: "",
status: "",
};
},
methods: {
clear() {
this.search.postStatus = "";
this.search.meetingUserName = "";
this.getSignInfo();
},
editAudioDia() {
this.sumEditDia = true;
},
doSign(status, {id}) {
this.status = status;
this.id = id;
if (status == '0') {
this.$confirm('是否撤销当前状态?').then(() => {
this.updateState();
});
} else {
this.description = "";
this.dialog = true;
}
},
//会议签到时间计算
countTime(total) {
let now = new Date(total)
let y = now.getFullYear();
let m = now.getMonth() + 1;
m = m < 10 ? ('0' + m) : m;
let da = now.getDate();
da = da < 10 ? ('0' + da) : da;
let h = now.getHours();
h = h < 10 ? ('0' + h) : h;
let minute = now.getMinutes();
minute = minute < 10 ? ('0' + minute) : minute;
let seconds = now.getSeconds();
seconds = seconds < 10 ? ('0' + seconds) : seconds;
return y + '-' + m + '-' + da + ' ' + h + ':' + minute + ":" + seconds;
},
delFile(index) {
this.fileList.splice(index, 1);
if (!this.showConfirmBtn && this.detail.id) {//非编辑删除文件
this.$message.success("文件删除成功!");
}
},
downFile(item) {
window.open(item.url);
},
updateState() {
this.instance.post(`/app/appthreemeetinguser/sign?id=${this.id}&status=${this.status}&description=${this.description}`).then((res) => {
if (res?.code == 0) {
const msg = this.status == 0 ? "撤销成功!" :
this.status == 2 ? "代签成功!" : "请假成功!";
this.$message.success(msg);
this.dialog = false;
this.getSignInfo();
}
})
},
//编辑取消/修改
editForm() {
this.editable = true;
},
cancelEditBtn() {
this.editable = false;
this.showConfirmBtn = false;
this.getDetailInfo();
},
navClick(id) {
if (id == 0) {
this.getDetailInfo()
} else if (id == 1) {
this.getSummary()
} else if (id == 2) {
this.getSignInfo()
}
this.$forceUpdate()
},
//获取会议详请
getDetailInfo() {
this.detail.id&& this.instance.post(`/app/appthreemeetinginfo/queryDetailById?id=${this.detail.id}`).then(res => {
if (res?.data) {
res.data.annex = JSON.parse(res.data.annex);
res.data.meetingClassification = res.data.meetingClassification.split(',');
this.obj = res.data;
}
});
},
//下载全部附件
downLoadAll() {
this.instance.post(`/app/appthreemeetinginfo/downLoadAllFileForDetail`, null, {
responseType: "blob",
params: {
id: this.detail.id
}
}).then(res => {
if (res?.type == "application/json") {
let reader = new FileReader(), _ = this
reader.readAsText(res, "utf-8")
reader.onload = e => {
if (e.target.readyState === 2) {
let ret = JSON.parse(e.target.result)
_.$message.error(ret.msg)
}
}
} else {
const link = document.createElement("a");
let blob = new Blob([res], {type: "application/vnd.ms-excel"});
link.style.display = "none";
link.href = URL.createObjectURL(blob);
let num = "";
for (let i = 0; i < 10; i++) {
num += Math.ceil(Math.random() * 10);
}
link.setAttribute("download", "三会一课附件" + ".zip");
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
})
},
//获取会议纪要信息
getSummary() {
this.instance.post(`/app/appthreemeetinginfoexpand/queryDetailById?id=${this.detail.id}`).then(res => {
if (res && res.data) {
res.data.images = JSON.parse(res.data.images);
this.summaryObj = res.data;
}
})
},
//获取人员签到
getSignInfo() {
this.instance.post(`/app/appthreemeetinguser/listForSign`, null, {
params: {
meetingId: this.detail.id,
...this.search,
size: 10000
}
}).then((res) => {
if (res && res.data) {
this.tableData = res.data.records;
}
})
},
cancelSummary() {
this.editable = false;
this.getSummary();
},
confirmSummary() {
let imgs = this.summaryObj.images && this.summaryObj.images.map(e => {
return {
url: e.url
}
})
this.instance.post(`/app/appthreemeetinginfoexpand/addOrUpdate`, {
meetingId: this.detail.id,
content: this.summaryObj.content,
images: JSON.stringify(imgs)
}).then(res => {
if (res && res.data) {
this.$message.success("保存成功");
this.getSummary()
this.editable = false;
}
});
},
arrLabel(arr, key) {
return arr?.map(e => e?.[key] || e)?.join(" / ") || "-"
}
},
created() {
this.areaId = this.user.info.areaId;
this.dict.load('ThreeMeetingAnonymous', 'ThreeMeetingVoteItem', "meetingClassification", "topicClassification", "feminderMethod", "addSignMethod", "postStatus", "OneThreeSignStatus").then(() => {
this.getDetailInfo()
this.getSignInfo()
});
},
watch: {
obj: {
handler(newVal) {
if (newVal.startTime && newVal.meetingBefore) {
let d = new Date(newVal.startTime);
let time = d.getTime();
let min = (Number(newVal.meetingBefore)) * 60000
let total = time - min;
this.signStart = this.countTime(total);
}
if (newVal.startTime && newVal.meetingAfter) {
let d = new Date(newVal.startTime);
let time = d.getTime();
let min = (Number(newVal.meetingAfter)) * 60000
let total = time + min;
this.signEnd = this.countTime(total);
}
},
deep: true
}
},
filters: {
formatTime(time) {
return time ? moment(time).format("YYYY-MM-DD HH:mm") : "-";
}
}
};
</script>
<style scoped lang="scss">
.addThreeMeeting {
height: 100%;
::v-deep .el-form {
.ailist-title {
padding: 0;
margin-bottom: 8px;
}
.el-form-item {
margin-bottom: 16px;
.el-date-editor {
width: 100%;
}
}
}
::v-deep.ai-detail__content--wrapper {
.el-form {
width: 1000px;
margin: 0 auto;
}
}
.audio {
display: flex;
margin-bottom: 8px;
}
::v-deep .el-dialog__body {
padding-top: 16px !important;
}
::v-deep .iconfont {
color: #2266FF;
cursor: pointer;
}
.content {
height: 400px;
background-color: #F5F5F5;
border-radius: 3px;
border: 1px solid #D0D4DC;
box-sizing: border-box;
padding: 14px;
font-size: 14px;
color: #333333;
line-height: 19px;
}
.signPhoto {
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
background: #000000;
opacity: 0.2;
z-index: 100;
display: flex;
align-items: center;
justify-content: center;
}
.signPhotoImg {
position: absolute;
left: 0;
top: 0;
margin-left: calc((100% - 280px) / 2);
margin-top: 160px;
z-index: 200;
display: flex;
flex-direction: column;
align-items: center;
img {
width: 320px;
height: 320px;
}
span {
font-size: 14px;
color: #000000;
line-height: 19px;
margin-top: 24px;
}
}
.flie {
width: 100%;
height: 40px;
line-height: 40px;
padding: 0 8px;
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 14px;
color: rgba(51, 51, 51, 1);
background: rgba(255, 255, 255, 1);
border-radius: 4px;
border: 1px solid rgba(208, 212, 220, 1);
margin-bottom: 16px;
cursor: pointer;
p {
display: flex;
justify-content: flex-start;
align-items: center;
}
.iconDelete {
color: #8899bb;
margin-left: 4px;
font-size: 16px;
}
}
::v-deep .el-form-item__label {
color: #999;
}
.flie:hover {
background-color: #f3f6f9;
border: none;
}
.flie:hover .iconDelete {
color: #ff4466;
}
.tips {
box-sizing: border-box;
padding: 0 106px;
font-size: 12px;
color: #999999;
line-height: 16px;
}
.opt {
font-size: 14px;
color: #5088FF;
cursor: pointer;
}
.wid100 {
width: 100%;
}
::v-deep .AiEchart {
height: 160px;
}
}
</style>