378 lines
15 KiB
HTML
378 lines
15 KiB
HTML
<!--#
|
|
layout("/layouts/platform.html"){
|
|
#-->
|
|
|
|
<style>
|
|
.qrcode {
|
|
min-width: 240px;
|
|
text-align: center;
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.real-data {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.real-data .data-card {
|
|
border-radius: 10px;
|
|
width: calc((100% - 80px) / 4);
|
|
min-width: 100px;
|
|
/*height: 150px;*/
|
|
/*min-height: 100px;*/
|
|
/*max-height: 150px;*/
|
|
/*background: #3CB371;*/
|
|
/*background: #000;*/
|
|
background-image: linear-gradient(141deg, #9fb8ad 0%, #1fc8db 51%, #2cb5e8 75%);
|
|
margin: 10px 0 10px 20px;
|
|
padding: 10px;
|
|
color: #ffffff;
|
|
display: flex;
|
|
flex-direction: column;
|
|
position: relative;
|
|
}
|
|
|
|
.real-data .data-card .data-card-title {
|
|
font-size: 20px;
|
|
max-width: 100%;
|
|
text-overflow: ellipsis;
|
|
word-break: keep-all;
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
flex: 1;
|
|
position: absolute;
|
|
}
|
|
|
|
.real-data .data-card .data-card-num {
|
|
font-size: 90px;
|
|
flex: auto;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
}
|
|
|
|
.real-data .data-card .flow-border {
|
|
position: absolute;
|
|
display: block;
|
|
}
|
|
|
|
.timePeriod_card {
|
|
border-top: 5px solid #106898;
|
|
}
|
|
|
|
.timePeriod_card .el-form-item {
|
|
margin-bottom: 0 !important;
|
|
}
|
|
|
|
img {
|
|
height: 100% !important;
|
|
width: 100%;
|
|
}
|
|
|
|
.operation {
|
|
position: fixed;
|
|
width: 100%;
|
|
height: 100%;
|
|
left: 0;
|
|
top: 0;
|
|
z-index: 1111;
|
|
}
|
|
</style>
|
|
|
|
<div id="app" v-cloak>
|
|
<guava ref="guava" v-model="guavaIndex">
|
|
<el-card shadow="never">
|
|
<div class="search">
|
|
<div class="search-item">
|
|
<div class="search-item-label">年度:</div>
|
|
<div class="search-item-option">
|
|
<el-date-picker
|
|
placeholder="选择年份"
|
|
style="width: 100%" type="year"
|
|
v-model="pageForm.year"
|
|
value-format="yyyy">
|
|
</el-date-picker>
|
|
</div>
|
|
</div>
|
|
<div class="search-item">
|
|
<div class="search-item-label">会议名称:</div>
|
|
<div class="search-item-option">
|
|
<el-input clearable
|
|
placeholder="可输入会议名称、地点进行查询"
|
|
v-model="pageForm.searchKeyword"></el-input>
|
|
</div>
|
|
</div>
|
|
<div class="search-item">
|
|
<div class="search-item-label">会议类型:</div>
|
|
<div class="search-item-option">
|
|
<el-select clearable style="width: 100%" v-model="pageForm.typeId">
|
|
<el-option :label="item.meetingTypeName"
|
|
:value="item.id"
|
|
v-for="item in meetingTypeList"></el-option>
|
|
</el-select>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<div class="search-query">
|
|
<el-button @click="doSearch" icon="el-icon-search" type="primary">搜索</el-button>
|
|
</div>
|
|
</div>
|
|
</el-card>
|
|
|
|
<el-card class="mt10" shadow="never">
|
|
<table-tool :app="this" label="会议信息">
|
|
<template #func>
|
|
</template>
|
|
</table-tool>
|
|
<el-table :data="tableData" :size="tableSize" @sort-change="pageOrder"
|
|
align="center"
|
|
header-align="center" ref="meetingTable">
|
|
<el-table-column type="expand">
|
|
<template scope="scope">
|
|
<el-row :gutter="20" justify="start" style="flex-wrap: wrap" type="flex"
|
|
v-if="scope.row.timePeriods && scope.row.timePeriods.length>0">
|
|
<el-col :xl="5" v-for="tp in scope.row.timePeriods">
|
|
<el-card class="mb10 timePeriod_card" shadow="hover">
|
|
<el-form label-width="80px">
|
|
<el-form-item label="名称">{{tp.timePeriodName}}</el-form-item>
|
|
<el-form-item label="会议时间">{{tp.startTime}}</el-form-item>
|
|
<!--<el-form-item label="结束时间">{{tp.endTime}}</el-form-item>-->
|
|
</el-form>
|
|
<el-row justify="space-around"
|
|
style="border-top: 1px solid #ebeef5;padding: 20px 0 0 0"
|
|
type="flex">
|
|
<el-button @click="exportSignature(tp.id)" size="medium" type="text">
|
|
导出签字表
|
|
</el-button>
|
|
<el-button @click="title = tp.timePeriodName; openOnline(tp.id,scope.row.id)"
|
|
size="medium" type="text">
|
|
扫描二维码
|
|
</el-button>
|
|
</el-row>
|
|
</el-card>
|
|
</el-col>
|
|
</el-row>
|
|
<el-row v-else>
|
|
<el-empty description="没有时间段"></el-empty>
|
|
</el-row>
|
|
</template>
|
|
</el-table-column>
|
|
|
|
<el-table-column align="center" header-align="center" label="序号" type="index" width="80">
|
|
<template scope="scope">
|
|
<span>{{ scope.$index + (pageForm.pageNumber - 1) * pageForm.pageSize + 1 }} </span>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column
|
|
:label="column.label"
|
|
:prop="column.prop"
|
|
:sortable="column.sortable"
|
|
:width="column.width"
|
|
align="center"
|
|
header-align="center"
|
|
show-overflow-tooltip
|
|
v-for="column in tableColumns"
|
|
>
|
|
<template scope="{row}" v-if="column.prop=='isCanLeave'">
|
|
<span class="text-muted" v-if="row.isCanLeave==null">未设置</span>
|
|
<span class="text-success" v-if="row.isCanLeave==true">能</span>
|
|
<span class="text-danger" v-if="row.isCanLeave==false">否</span>
|
|
</template>
|
|
</el-table-column>
|
|
|
|
<el-table-column label="操作" width="200px">
|
|
<template scope="{row}">
|
|
<el-button @click="toggleRowTimePeriod(row)" size="mini" type="primary">展开</el-button>
|
|
</template>
|
|
</el-table-column>
|
|
</el-table>
|
|
</el-card>
|
|
|
|
<template #view>
|
|
<div style="min-width: 500px;height: 100%;position: relative">
|
|
<el-row type="flex">
|
|
<el-col :span="4" class="qrcode">
|
|
<div @click="downLoadQrCode" title="点击二维码可下载">
|
|
<qrcode :value="qrCodeUrl" ref="qrCode"
|
|
tag="img"></qrcode>
|
|
</div>
|
|
</el-col>
|
|
<el-col :span="20" class="real-data">
|
|
<template v-for="rd of realTimeData">
|
|
<div class="data-card">
|
|
<div class="data-card-title">
|
|
{{rd.label}}
|
|
</div>
|
|
<div class="data-card-num">
|
|
<count-to :end-val="rd.value"
|
|
:start-val="getLastValue(rd.key)"></count-to>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</el-col>
|
|
</el-row>
|
|
|
|
<!-- <el-row class="mt20">-->
|
|
<el-table :data="userData" :max-height="signTableHeight" class="mt20" ref="signTable">
|
|
<el-table-column label="姓名" prop="username"></el-table-column>
|
|
<el-table-column label="工号" prop="loginname"></el-table-column>
|
|
<el-table-column label="性别" prop="sex"></el-table-column>
|
|
<el-table-column label="单位" prop="unitname"></el-table-column>
|
|
<el-table-column label="签到时间" prop="signInDateTime"></el-table-column>
|
|
<el-table-column label="签到名次">
|
|
<template scope="scope">
|
|
{{userData.length - scope.$index}}
|
|
</template>
|
|
</el-table-column>
|
|
</el-table>
|
|
<!-- </el-row>-->
|
|
</div>
|
|
</template>
|
|
</guava>
|
|
</div>
|
|
|
|
<script>
|
|
<!--# include("/platform/meeting/includeJs/meetingUtil.js"){} #-->
|
|
const meetUtil = new meetingUtil()
|
|
let pollingInterval = null
|
|
const intervalTime = 3500
|
|
window['vue'] = new Vue({
|
|
el: '#app',
|
|
mixins: [initTableMixins],
|
|
data() {
|
|
return {
|
|
title: '',
|
|
tableColumns: [
|
|
{prop: 'meetingName', label: '会议名称', sortable: true},
|
|
{prop: 'meetingTypeName', label: '会议类型', sortable: true},
|
|
{prop: 'startTime', label: '会议时间', sortable: true},
|
|
/*{prop: 'endTime', label: '结束时间', sortable: true},*/
|
|
{prop: 'location', label: '会议地点', sortable: true},
|
|
{prop: 'isCanLeave', label: '能否请假', sortable: true},
|
|
],
|
|
pageForm: {
|
|
year: new Date().getFullYear().toString()
|
|
},
|
|
meetingTypeList: [],
|
|
lastTimeData: [],
|
|
realTimeData: [],
|
|
userData: [],
|
|
meetingId: null,
|
|
timePeriodId: null,
|
|
qrcodeVisible: false,
|
|
qrCodeUrl: null,
|
|
signTableHeight: 600
|
|
}
|
|
},
|
|
watch: {
|
|
guavaIndex(val) {
|
|
if (val === 'index') {
|
|
this.toggleFullScreen()
|
|
}
|
|
}
|
|
},
|
|
methods: {
|
|
//导出签字表
|
|
exportSignature(timePeriodId) {
|
|
window.open(loc() + '/exportSignature/' + timePeriodId)
|
|
},
|
|
//打开在线
|
|
async openOnline(timePeriodId, meetingId) {
|
|
this.meetingId = meetingId
|
|
this.timePeriodId = timePeriodId
|
|
this.$refs.guava.view()
|
|
this.toggleFullScreen()
|
|
this.calcSignTableHeight()
|
|
this.generateQrCodeUrl(timePeriodId, meetingId)
|
|
this.stopInterval()
|
|
pollingInterval = this.startPolling(this.getRealTimeData)
|
|
},
|
|
calcSignTableHeight() {
|
|
this.$nextTick(() => {
|
|
setTimeout(() => {
|
|
console.log(window.innerHeight)
|
|
const offsetTop = this.$refs.signTable.$el.offsetTop
|
|
const th = window.innerHeight - 54 - 40 - offsetTop
|
|
console.log(th)
|
|
this.$set(this, 'signTableHeight', th)
|
|
})
|
|
})
|
|
},
|
|
async generateQrCodeUrl(tpId, meetingId) {
|
|
const resp = await $.get(loc() + '/generateQrCodeUrl', {tpId, meetingId})
|
|
if (resp.code === 0) {
|
|
this.qrCodeUrl = resp.data
|
|
} else {
|
|
this.notifyError(resp.msg)
|
|
}
|
|
},
|
|
async getRealTimeData() {
|
|
this.lastTimeData = clone(this.realTimeData)
|
|
const resp = await $.get(loc() + '/getRealTimeData/' + this.timePeriodId)
|
|
if (resp.code === 0) {
|
|
this.lastTimeData = clone(this.realTimeData)
|
|
this.$set(this, 'realTimeData', resp.data.countData)
|
|
//去重
|
|
let ud = clone(this.userData)
|
|
ud.unshift(...resp.data.userData)
|
|
let uMap = new Map()
|
|
for (let u of ud) {
|
|
if (!uMap.has(u.loginname)) {
|
|
uMap.set(u.loginname, u)
|
|
}
|
|
}
|
|
this.$set(this, 'userData', [...uMap.values()])
|
|
} else {
|
|
|
|
}
|
|
},
|
|
startPolling(func) {
|
|
this.lastTimeData = []
|
|
this.realTimeData = []
|
|
this.userData = []
|
|
func()
|
|
return setInterval(func, intervalTime)
|
|
},
|
|
stopInterval() {
|
|
if (pollingInterval) {
|
|
clearInterval(pollingInterval)
|
|
}
|
|
},
|
|
getLastValue(key) {
|
|
if (this.lastTimeData && this.lastTimeData.length > 0) {
|
|
return this.lastTimeData.find(v => v.key === key).value
|
|
} else {
|
|
return 0
|
|
}
|
|
},
|
|
downLoadQrCode() {
|
|
if (this.$refs['qrCode']) {
|
|
const src = this.$refs['qrCode'].$el.currentSrc
|
|
const aEle = document.createElement('a')
|
|
aEle.setAttribute("download", '签到二维码')
|
|
aEle.setAttribute("href", src)
|
|
aEle.click()
|
|
}
|
|
},
|
|
toggleRowTimePeriod(row) {
|
|
this.$refs['meetingTable'].toggleRowExpansion(row)
|
|
}
|
|
},
|
|
async created() {
|
|
this.meetingTypeList = await meetUtil.getAllMeetingType()
|
|
this.pageData()
|
|
// this.openOnline('2bb2b18a053b4c8ca00e27d30e8f4573')
|
|
},
|
|
beforeDestroy() {
|
|
this.stopInterval()
|
|
}
|
|
})
|
|
|
|
</script>
|
|
|
|
<!--#
|
|
}
|
|
#-->
|