提交 1aac5272 authored 作者: pengxiaohui's avatar pengxiaohui

后台接口调试

上级 9ccfdaee
module.exports = {
domain: 'dev.ezijing.com',
url: 'https://live-broadcast2.ezijing.com/api',
// url: 'https://test-microservices-live-api.ezijing.com',
// url: 'https://microservices-live-api.ezijing.com',
webpack: {
externals: {
CKEDITOR: 'window.CKEDITOR',
......@@ -34,5 +36,6 @@ module.exports = {
ProvidePlugin: {},
others: {
loginUrl: 'https://login2.ezijing.com/auth/login/index'
// loginUrl: 'https://login.ezijing.com/auth/login/index'
}
}
......@@ -53,6 +53,21 @@ if ($GLOBAL.isDev === 'development') {
pathRewrite: {
'^/api': '/'
}
},
'/loginApi': {
target: 'https://learn-api2.ezijing.com/api/',
// target: 'https://learn-api.ezijing.com/api/',
selfHandleResponse: false,
secure: false,
changeOrigin: true,
followRedirects: true,
logLevel: 'info',
headers: {
'Referer': $GLOBAL.webConf.url
},
pathRewrite: {
'^/loginApi': '/'
}
}
},
open: true,
......
import httpRequest from '@/utils/axios'
/**
* 操作日志
*/
export function operateLog(params) {
const logMsg = `操作人:${params.user.nickname},操作人id:${params.user.id},操作:${params.type}`
const data = {
detail: logMsg
}
httpRequest.post('/api/admin/live/v2/system/log/write', data).then(res => {
console.log(res)
}).catch(() => {})
}
/**
* 模糊搜索
*/
export function searchUserList(params) {
return httpRequest.get('/api/common/v1/sso-user/search', { params })
}
/**
* 创建腾讯用户
*/
export function createAccount(data) {
return httpRequest.post('/api/live/admin/v2/tencent/user', data)
}
/**
* 获取腾讯用户列表(分页)
*/
export function getAccountList(params) {
return httpRequest.get('/api/live/admin/v2/tencent/users', { params })
}
/**
* 获取腾讯用户列表(不分页)
*/
export function getAllAccountList() {
return httpRequest.get('/api/live/admin/v2/tencent/user/list')
}
/**
* 更新腾讯用户
*/
export function updateAccount(data) {
return httpRequest.put(`/api/live/admin/v2/tencent/user/${data.userid}/update`, data)
}
/**
* 删除腾讯用户
*/
export function deleteAccount(params) {
return httpRequest.delete(`/api/live/admin/v2/tencent/user/${params.userid}/delete`, params)
}
/**
* 创建会议
*/
export function createMeeting(data) {
return httpRequest.post('/api/live/admin/v2/tencent/meeting', data)
}
/**
* 创建会议
*/
export function updateMeeting(data) {
return httpRequest.put(`/api/live/admin/v2/tencent/meeting/${data.meeting_id}/update`, data)
}
/**
* 获取腾讯会议列表
*/
export function getMeetingList(params) {
return httpRequest.get('/api/live/admin/v2/tencent/meetings', { params })
}
/**
* 获取腾讯会议列表(不分页)
*/
export function getNonpagedMeetingList(params) {
return httpRequest.get('/api/live/admin/v2/tencent/meeting/list-by-day', { params })
}
/**
* 获取腾讯会议详情
*/
export function getMeetingDetails(params) {
return httpRequest.get(`/api/live/admin/v2/tencent/meeting/${params.meeting_id}/detail`, { params })
}
/**
* 通过会议code获取腾讯会议详情
*/
export function getMeetingDetailsByCode(params) {
return httpRequest.get(`/api/live/admin/v2/tencent/meeting/${params.meeting_code}/detail-code`, { params })
}
/**
* 取消(删除)会议
*/
export function cancelMeeting(params) {
return httpRequest.post(`/api/live/admin/v2/tencent/meeting/${params.meeting_id}/cancel`, params)
}
/**
* 终止会议
*/
export function stopMeeting(params) {
return httpRequest.post(`/api/live/admin/v2/tencent/meeting/${params.meeting_id}/dimiss`, params)
}
/**
* 获取回放地址
*/
export function getMeetingRecordAddr(params) {
return httpRequest.post(`/api/live/admin/v2/tencent/meeting/${params.meeting_id}/records/address`, params)
}
/**
* 导出参会人员
*/
export function exportParticipants(params) {
return httpRequest({
url: `/api/admin/live/v2/tencent/meeting/${params.meeting_id}/participants/export`,
method: 'get',
params,
responseType: 'blob'
})
}
import httpRequest from '@/utils/axios'
/**
* 操作日志
*/
export function operateLog(params) {
const logMsg = `操作人:${params.user.nickname},操作人id:${params.user.id},操作:${params.type}`
const data = {
detail: logMsg
}
httpRequest.post('/api/live/admin/v2/system/log/write', data).then(res => {
console.log(res)
}).catch(() => {})
}
/**
* 模糊搜索
*/
export function searchUserList(params) {
return httpRequest.get('/api/live/common/v1/sso-user/search', { params })
}
/**
* 获取当前用户的角色
*/
export function getUserRoles() {
return httpRequest.get('/api/live/admin/v2/user/roles')
}
/**
* 创建角色
*/
export function createRole(data) {
return httpRequest.post('/api/live/admin/v2/role', data)
}
/**
* 更新角色
*/
export function updateRole(params) {
return httpRequest.get(`/api/live/admin/v2/role/${params.role_id}/update`, { params })
}
/**
* 获取角色详情
*/
export function getRoleDetails(params) {
return httpRequest.get(`/api/live/admin/v2/role/${params.role_id}/detail`, { params })
}
/**
* 删除
*/
export function deleteRole(params) {
return httpRequest.get(`/api/live/admin/v2/role/${params.role_id}/delete`, { params })
}
/**
* 获取角色列表
*/
export function getRoles(params) {
return httpRequest.get('/api/live/admin/v2/roles', { params })
}
/**
* 分配角色给用户
*/
export function roleToUser(data) {
return httpRequest.post('/api/live/admin/v2/assign/roles-to-user', data)
}
/**
* 获取角色下的用户列表
*/
export function getUserListUnderRole(params) {
return httpRequest.get(`/api/live/admin/v2/role/${params.role_id}/users`, { params })
}
/**
* 从角色中移除用户
*/
export function romoveUserUnderRole(data) {
return httpRequest.post('/api/live/admin/v2/assign/remove-user-form-role', data)
}
/**
* 获取权限列表
*/
export function getPermissions(params) {
return httpRequest.get('/api/live/admin/v2/permissions', { params })
}
/**
* 分配权限给角色
*/
export function permissionToRole(data) {
return httpRequest.post('/api/live/admin/v2/assign/permission-to-role', data)
}
......@@ -25,9 +25,6 @@ import getDays from './getDays'
export default {
props: {
defaultDate: {
validator: (value) => {
return typeof value === 'object' && (value === null || value instanceof Date)
}
},
type: {
type: String,
......@@ -38,8 +35,8 @@ export default {
return {
weekList: ['周', '一', '二', '三', '四', '五', '六'],
dayList: [],
activeDate: [],
monthFirstDate: '',
activeDate: [],
rangeState: {
endDate: null,
selecting: false
......@@ -68,6 +65,23 @@ export default {
}
},
watch: {
type: {
handler: function(nv) {
if (nv) {
this.activeDate = ''
this.rangeState = {
endDate: null,
selecting: false
}
this.rangeStartDate = null
this.rangeEndDate = null
this.rangeDates = []
this.selectFirstDate = null
this.selectLastDate = null
}
},
immediate: true
},
defaultDate: {
handler: function(nv, ov) {
if (!nv) {
......@@ -76,8 +90,9 @@ export default {
this.setMonthFirstDate(_date)
} else {
if (Array.isArray(nv)) {
const d = nv[0]
this.setMonthFirstDate(d)
this.rangeStartDate = nv[0]
this.rangeEndDate = nv[1]
this.setMonthFirstDate(nv[0])
} else if (typeof nv === 'object' && this.type === 'date') {
this.setMonthFirstDate(nv)
this.activeDate = nv
......
<template>
<el-dialog :title="`会议号${details.meeting_code ? ':' + details.meeting_code : ''}`" :visible="dialogVisible" width="520" :close-on-click-modal="false" append-to-body center @close="dialogClose">
<el-form class="dialog-meeting-details" label-width="90px" ref="details">
<el-form-item label="会议主题:">
{{details.subject}}
</el-form-item>
<el-form-item label="会议时间:">
{{details.start_time | timeFormat('{y}-{m}-{d} {h}:{i}')}} - {{details.end_time | timeFormat('{h}:{i}')}}GMT+08:00)
</el-form-item>
<el-form-item label="会议链接:">
{{details.join_url}}
</el-form-item>
<el-form-item label="会议号:">
{{details.meeting_code}}
</el-form-item>
<el-form-item label="会议直播:" v-if="details.enable_live === 1">
{{details.live_config.live_addr}}
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button size="mini" @click="copyText">复制文字</el-button>
<el-button size="mini" @click="copyMeetingLink">复制参会地址</el-button>
<el-button size="mini" v-if="details.enable_live === 1" @click="copyLiveLink">复制直播地址</el-button>
<el-button type="primary" size="mini" @click="joinMeeting">进入会议</el-button>
</span>
</el-dialog>
</template>
<script>
import { dateFormat } from '@/utils/dateAlgs'
export default {
props: {
details: {
type: Object,
default: {}
},
dialogVisible: {
type: Boolean,
default: false
}
},
filters: {
timeFormat(val, fmt) {
fmt = fmt || '{y}年{m}月{d}日'
return dateFormat(val, fmt)
}
},
methods: {
dialogClose() {
this.$emit('update:dialogVisible', false)
},
copyText() {
const text = this.$refs.details.$el.innerText
this.copyFn(text)
},
copyMeetingLink() {
this.copyFn(this.details.join_url)
},
copyLiveLink() {
this.copyFn(this.details.live_config.live_addr)
},
copyFn(val) {
if (!val) return
const dom = document.createElement('textarea')
document.body.appendChild(dom)
dom.value = val
dom.select(); // 选择对象
document.execCommand('Copy');
this.$message({
message: '复制成功!',
type: 'success'
})
document.body.removeChild(dom)
},
joinMeeting() {
window.open(this.details.join_url, '_blank');
}
}
}
</script>
<style scoped>
::v-deep.el-dialog__header{
padding-top:14px;
}
::v-deep.el-dialog__headerbtn{
top:12px;
right:12px;
}
::v-deep.el-dialog__body{
padding:10px 0;
margin:0 20px;
border: 1px solid #DBDBDB;
}
::v-deep.el-dialog__footer{
padding-bottom:16px;
}
::v-deep.el-dialog .el-form-item{
margin:0;
}
</style>
\ No newline at end of file
<template>
<div class="schedule-item" :style="{'min-width': minWidth}">
<template v-for="ev in schedule.events" >
<div :key="ev.startTime.getTime()" class="schedule-event" :style="{ height: getHeight(ev) + 'px', top: getTop(ev) + 'px' }">
<div :key="ev.start_time" class="schedule-event" :style="{ height: getHeight(ev) + 'px', top: getTop(ev) + 'px' }">
<slot name="content" :data="ev">
<div class="schedule-ev-inner">
<h5>{{ev.title}}</h5>
<p>{{ev.startTime | timeFormat}}-{{ev.endTime | timeFormat}}</p>
<p>{{ev.start_time | timeFormat}}-{{ev.end_time | timeFormat}}</p>
</div>
</slot>
<div class="shadow" @click.stop="detailsClick(ev, $event)"></div>
......@@ -81,14 +81,14 @@ export default {
},
methods: {
getTop(ev) {
const timeRange = timeTrans(ev.startTime).getTime() - this.startDotTimestamp
const timeRange = timeTrans(ev.start_time).getTime() - this.startDotTimestamp
const top = timeRange / ((60 * 1000 * this.options.step) / this.timeLineHeight)
ev.top = top + 1
return top + 1
},
getHeight(ev) {
const start = timeTrans(ev.startTime)
let end = timeTrans(ev.endTime)
const start = timeTrans(ev.start_time)
let end = timeTrans(ev.end_time)
if (!isSameDate(start, end)) {
end = new Date(start.getFullYear(), start.getMonth(), start.getDate(), 24, 0, 0)
}
......@@ -102,25 +102,28 @@ export default {
return {
'schedule-event': true,
'status-start': ev.status === 1,
'status-notstarted': ev.status === 3,
'status-notstarted': ev.status === 0,
small: h < 120 && h >= 40,
medium: h >= 120 && h < 200,
large: h >= 200
}
},
detailsClick(ev, e) {
const o = {
ev,
id: this.schedule.id,
x: e.clientX - e.offsetX + 'px',
y: e.clientY - e.offsetY + 'px',
width: e.target.clientWidth + 'px',
height: e.target.clientHeight + 'px'
if (!this.options.readonly) {
const o = {
ev,
id: this.schedule.id,
x: e.clientX - e.offsetX + 'px',
y: e.clientY - e.offsetY + 'px',
width: e.target.clientWidth + 'px',
height: e.target.clientHeight + 'px'
}
this.$emit('details', o)
}
this.$emit('details', o)
},
newSchedule(dot, e) {
if (!this.options.disabledNew) {
if (!this.options.readonly) {
dot.accountId = this.schedule.userid || ''
dot.x = e.clientX - e.offsetX + 'px'
dot.y = e.clientY - e.offsetY + 'px'
dot.width = e.target.clientWidth + 'px'
......
<template>
<div class="schedule">
<div class="multi-schedule-header" ref="scheduleHeader">
<div v-for="(schedule, idx) in scheduleList" :key="idx" :style="{'min-width': minWidth}">{{schedule.title}}</div>
<div v-for="(schedule, idx) in scheduleList" :key="idx" :style="{'min-width': minWidth}">{{schedule.name}}</div>
</div>
<el-scrollbar ref="scheduleScroll" style="height: calc(100% - 50px)">
<div class="schedule-container">
......
<template>
<el-form label-width="140px">
<el-form-item label="会议主题:">
{{details.subject}}
</el-form-item>
<el-form-item label="会议时间:">
{{details.start_time | dateFormat}} - {{details.end_time | dateFormat('{h}:{i}')}}GMT+08:00)
</el-form-item>
<el-form-item label="会议链接:">
{{details.join_url}}
</el-form-item>
<el-form-item label="会议号:">
{{details.meeting_code}}
</el-form-item>
<el-form-item label="会议直播:" v-if="details.enable_live === 1">
{{details.live_config.live_addr}}
</el-form-item>
<el-form-item label="手机拨号入会:" v-if="false">
<p>+8675536550000,,526430840#(中国大陆)</p>
<p>+85230018898,,526430840#(中国香港)</p>
</el-form-item>
<el-form-item label="根据您的位置拨号:" v-if="false">
<p>+8675536550000(中国大陆)</p>
<p>++85230018898(中国香港)</p>
</el-form-item>
</el-form>
</template>
<script>
import { dateFormat } from '@/utils/dateAlgs'
export default {
props: {
rowData: {},
details: {}
},
computed: {
hasLive() {
return this.rowData.hasLive || false
}
},
filters: {
dateFormat(value, fmt) {
return dateFormat(value, fmt || '{y}年{m}月{d}日 {h}:{i}')
}
}
}
</script>
<style scoped>
::v-deep.el-form-item{
margin:0;
}
</style>
\ No newline at end of file
<template>
<el-form label-width="140px">
<el-form-item label="会议主题:">
{{details.subject}}
</el-form-item>
<el-form-item label="会议时间:">
{{details.start_time | dateFormat}} - {{details.end_time | dateFormat('{h}:{i}')}}GMT+08:00)
</el-form-item>
<el-form-item label="会议号:">
{{details.meeting_code}}
</el-form-item>
<el-form-item label="会议创建者:">
{{rowData.sso_user.nickname}}
</el-form-item>
<el-form-item label="会议主持人:">
<span v-for="(it, index) in details.hosts" :key="it.userid">{{it.username}}{{index > 0 ? '、' : ''}}</span>
</el-form-item>
<el-form-item label="会议管理员:">
<span v-for="(it, index) in details.managers" :key="it.userid">{{it.nickname}}{{index > 0 ? '、' : ''}}</span>
</el-form-item>
<el-form-item label="会议直播主题:" v-if="details.enable_live === 1">
{{details.live_config.live_subject}}
</el-form-item>
<el-form-item label="会议直播简介:" v-if="details.enable_live === 1">
<p style="line-height:26px;padding:7px 10px 7px 0">{{details.live_config.live_summary}}</p>
</el-form-item>
<el-form-item label="参会成员:" v-if="rowData.status === 2">
<el-button type="text" @click="handleExport">导出excel</el-button>
</el-form-item>
<el-form-item label="回放:" v-if="rowData.status === 2">
<el-button type="text" v-if="hasRecord" @click="handleDownload">下载</el-button>
<el-button type="text" v-else disabled>暂无回放</el-button>
</el-form-item>
</el-form>
</template>
<script>
import { dateFormat } from '@/utils/dateAlgs'
import { exportParticipants, getMeetingRecordAddr } from '@api/common'
export default {
props: {
details: {},
rowData: {},
dialogType: {}
},
computed: {
hasRecord() {
if (this.rowData.record_file_ids && Array.isArray(this.rowData.record_file_ids) && this.rowData.record_file_ids.length > 0) {
return true
} else {
return false
}
},
nowFormat() {
const now = Date.now()
const _format = dateFormat(now, '{y}{m}{d}{h}{i}{s}')
const nowStr = now.toString()
return _format + nowStr.substr(10, 12)
}
},
filters: {
dateFormat(value, fmt) {
return dateFormat(value, fmt || '{y}年{m}月{d}日 {h}:{i}')
}
},
methods: {
handleExport() {
const row = this.rowData
const params = {
meeting_id: row.meeting_id
}
if (row.meeting_type === 1) {
params.sub_meeting_id = row.sub_meeting_id
}
exportParticipants(params).then((res) => {
if (res && res.type === 'text/xlsx') {
const url = URL.createObjectURL(res)
// const elink = document.createElement('a')// 创建一个a标签
// elink.download = `参会人员表_${this.nowFormat}.xlsx`;// 设置a标签的下载属性
// elink.style.display = 'none';// 将a标签设置为隐藏
// elink.href = URL.createObjectURL(blob);// 把之前处理好的地址赋给a标签的href
// document.body.appendChild(elink);// 将a标签添加到body中
// elink.click();// 执行a标签的点击方法
// URL.revokeObjectURL(elink.href) // 下载完成释放URL 对象
// document.body.removeChild(elink)// 移除a标签
this.funDownload(url, `参会人员表_${this.nowFormat}.xlsx`)
}
})
},
async handleDownload() {
const list = await this.fetchMeetingRecordAddr()
if (list && Array.isArray(list)) {
list.forEach(it => {
if (it.download_address) {
// window.open(it.download_address, '_blank')
this.funDownload(it.download_address, it.download_address)
}
})
}
},
funDownload(fileUrl, fileName) {
const elink = document.createElement('a')// 创建一个a标签
elink.download = fileName;// 设置a标签的下载属性
elink.style.display = 'none';// 将a标签设置为隐藏
elink.href = fileUrl;// 把之前处理好的地址赋给a标签的href
document.body.appendChild(elink);// 将a标签添加到body中
elink.click();// 执行a标签的点击方法
URL.revokeObjectURL(elink.href) // 下载完成释放URL 对象
document.body.removeChild(elink)// 移除a标签
},
fetchMeetingRecordAddr() {
const params = {
meeting_id: this.rowData.meeting_id,
record_file_ids: this.rowData.record_file_ids
}
return new Promise((resolve, reject) => {
getMeetingRecordAddr(params).then(res => {
if (res.code === 0 && res.data.files) {
resolve(res.data.files)
} else {
reject(res)
}
}).catch((err) => reject(err))
})
}
}
}
</script>
<style scoped>
::v-deep.el-form-item{
margin:0;
}
</style>
\ No newline at end of file
<template>
<div class="btns">
<template v-if="status === 1">
<el-button type="text" size="small" v-if="operatable" @click="handleJoin">进入会议</el-button>
<el-button type="text" size="small" v-if="operatable && hasLive" @click="handleLive">观看直播</el-button>
<el-button type="text" size="small" v-if="operatable" @click="handleCopy">复制邀请</el-button>
<el-button type="text" size="small" v-if="operatable" @click="handleStop">终止</el-button>
<el-button type="text" size="small" v-if="!operatable" @click="handleDetails">查看</el-button>
</template>
<template v-if="status === 0">
<el-button type="text" size="small" v-if="operatable" @click="handleJoin">进入会议</el-button>
<el-button type="text" size="small" v-if="operatable" @click="handleCopy">复制邀请</el-button>
<el-button type="text" size="small" v-if="operatable" @click="handleUpdate">修改</el-button>
<!-- <el-dropdown v-if="operatable && isCycle">
<span class="dropdown-link">
修改<i class="el-icon-arrow-down el-icon--right"></i>
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item @click="handleUpdate">修改本次会议</el-dropdown-item>
<el-dropdown-item @click="handleUpdate">修改周期会议</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown> -->
<el-button type="text" size="small" v-if="operatable" @click="handleCancel">取消</el-button>
<el-button type="text" size="small" v-if="!operatable" @click="handleDetails">查看</el-button>
</template>
<template v-if="status === 2">
<el-button type="text" size="small" v-if="operatable" @click="handleRecord">看回放</el-button>
<el-button type="text" size="small" @click="handleDetails">查看</el-button>
<el-button type="text" size="small" v-if="operatable" @click="handleDelete">删除</el-button>
</template>
<el-dialog :title="domicTitle" :visible.sync="dialogVisible" width="520px" center>
<div slot="title" class="dialog-header">
<p class="meeting-status" v-show="dialogType === 'details'">会议{{rowData.status | statusFilter}}</p>
<p class="title">{{domicTitle}}</p>
</div>
<dialog-details :rowData="rowData" :details="details" v-show="dialogType === 'details'" />
<dialog-copy-invite :rowData="rowData" :details="details" v-show="dialogType === 'copy'"/>
<div slot="footer" class="dialog-footer">
<el-button type="primary" size="mini" v-show="dialogType === 'copy'" @click="copyLink">复制</el-button>
<el-button @click="dialogVisible = false" size="mini">取 消</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import DialogDetails from './DialogDetails.vue'
import DialogCopyInvite from './DialogCopyInvite'
import { mapGetters } from 'vuex'
import { getMeetingDetails, stopMeeting, cancelMeeting, getMeetingRecordAddr } from '@api/common'
export default {
props: {
rowData: {}
},
data() {
return {
userId: '1234',
roleName: '', // general_admin
dialogVisible: false,
dialogType: 'copy',
details: ''
}
},
computed: {
...mapGetters(['isSuperAdmin', 'user']),
domicTitle() {
let title = ''
switch (this.dialogType) {
case 'copy':
title = '复制邀请'
break
case 'details':
title = '会议详情'
break
}
return title
},
status() {
return this.rowData.status
},
isCycle() {
return this.rowData.meeting_type === 1
},
isMyself() {
return this.rowData.sso_id === this.user.id
},
isGeneralAdmin() {
const admins = this.rowData.manage_ids
let flag = false
for (let i = 0; i < admins.length; i++) {
if (admins[i] === this.user.id) {
flag = true
break
}
}
return flag
},
hasLive() {
return this.rowData.enable_live || false
},
operatable() {
return this.isMyself || this.isSuperAdmin || this.isGeneralAdmin
}
},
filters: {
statusFilter(val) {
let result = ''
switch (val) {
case 0:
result = '未开始'
break
case 1:
result = '进行中'
break
case 2:
result = '已结束'
break
}
return result
}
},
components: { DialogDetails, DialogCopyInvite },
created() {
},
methods: {
handleCopy() {
this.fetchMeetingDetails()
this.dialogVisible = true
this.dialogType = 'copy'
},
handleDetails() {
this.dialogVisible = true
this.dialogType = 'details'
this.fetchMeetingDetails()
},
handleLive() {
window.open(this.live_config.live_addr, '_blank');
},
handleUpdate() {
this.$router.push({ path: '/meeting', query: { type: '2', meeting_id: this.rowData.meeting_id, sub_meeting_id: this.rowData.sub_meeting_id } })
},
handleCancel() {
this.$confirm('此操作将取消这场会议, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消'
}).then(() => {
this.fetchCancelMeeting('cancel')
}).catch(() => {})
},
handleStop() {
this.$confirm('此操作将终止正在进行中的会议, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消'
}).then(() => {
this.fetchStopMeeting()
}).catch(() => {})
},
handleDelete() {
this.$confirm('此操作将删除这场会议, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消'
}).then(() => {
this.fetchCancelMeeting('delete')
}).catch(() => {})
},
handleJoin() {
window.open(this.rowData.join_url, '_blank');
},
copyLink() {
const dom = document.createElement('input')
document.body.appendChild(dom)
dom.value = this.rowData.join_url
dom.select(); // 选择对象
document.execCommand('Copy');
this.$message({
message: '复制成功!',
type: 'success'
})
document.body.removeChild(dom)
},
async handleRecord() {
if (this.rowData.record_file_ids.length === 0) {
this.$message.error('该会议没有回放')
} else {
const list = await this.fetchMeetingRecordAddr()
if (list && Array.isArray(list)) {
if (list.length === 1) {
window.open(list[0].view_address, '_blank')
}
}
}
},
fetchStopMeeting() {
const params = {
meeting_id: this.rowData.meeting_id
}
stopMeeting(params).then(res => {
if (res.code === 0 && res.data.status) {
this.$message.success('会议终止成功')
this.$emit('refresh')
} else {
this.$message.error(res.msg || '会议终止失败')
}
})
},
fetchCancelMeeting(type) {
const params = {
meeting_id: this.rowData.meeting_id
}
const msg = type === 'cancel' ? '会议取消' : '会议删除'
cancelMeeting(params).then(res => {
if (res.code === 0 && res.data.status) {
this.$message.success(msg + '成功')
this.$emit('refresh')
} else {
this.$message.error(res.msg || msg + '失败')
}
})
},
fetchMeetingDetails() {
const row = this.rowData
const params = {
meeting_id: row.meeting_id
}
if (row.meeting_type === 1) {
params.sub_meeting_id = row.sub_meeting_id
}
getMeetingDetails(params).then(res => {
if (res.code === 0 && res.data.id) {
this.details = res.data
}
})
},
fetchMeetingRecordAddr() {
const params = {
meeting_id: this.rowData.meeting_id,
record_file_ids: this.rowData.record_file_ids
}
return new Promise((resolve, reject) => {
getMeetingRecordAddr(params).then(res => {
if (res.code === 0 && res.data.files) {
resolve(res.data.files)
} else {
reject(res)
}
}).catch((err) => reject(err))
})
}
}
}
</script>
<style scoped>
.dropdown-link{
cursor: pointer;
color: #409EFF;
font-size:12px;
}
::v-deep.el-icon-arrow-down {
font-size: 12px;
}
.btns ::v-deep.el-dialog__header{
padding-top:14px;
}
.btns ::v-deep.el-dialog__headerbtn{
top:12px;
right:12px;
}
.btns ::v-deep.el-dialog__body{
padding:10px 0;
margin:0 20px;
border: 1px solid #DBDBDB;
}
.btns ::v-deep.el-dialog__footer{
padding-bottom:16px;
}
.dialog-header .meeting-status{
text-align:left;
}
.dialog-header .title{
font-size:16px;
}
</style>
\ No newline at end of file
......@@ -13,8 +13,11 @@
<i class="el-icon-caret-bottom" />
</div>
<el-dropdown-menu slot="dropdown" class="user-dropdown">
<el-dropdown-item>
<span>{{user.nickname || ''}}, 你好</span>
</el-dropdown-item>
<el-dropdown-item divided @click.native="logout">
<span style="display: block">Log Out</span>
<span style="display: block">退出登录</span>
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
......@@ -34,10 +37,7 @@ export default {
}
},
computed: {
...mapGetters(['sidebar']),
user() {
return this.$store.state.user
},
...mapGetters(['sidebar', 'user']),
avatar() {
return this.user.avatar || defaultAvatar
}
......@@ -51,8 +51,8 @@ export default {
this.$router.push('/meeting')
},
async logout() {
await this.$store.dispatch('user/logout')
this.$router.push(`/login?redirect=${this.$route.fullPath}`)
await this.$store.dispatch('logout')
this.$router.push(`/${this.$route.fullPath}`)
}
}
}
......
......@@ -19,7 +19,7 @@ export default {
<style scoped>
.app-main {
height: calc(100vh - 62px);
height: calc(100vh - 52px);
width: 100%;
position: relative;
overflow: hidden;
......
......@@ -3,16 +3,16 @@
<h5>会议详情</h5>
<p>
<i class="el-icon-tickets"></i>
<span>{{ev.title}}</span>
<span>{{ev.subject}}</span>
</p>
<p>
<i class="el-icon-time"></i>
<span v-if="ev.startTime.getDate() === ev.endTime.getDate()">{{ev.startTime | timeFormat('{m}月{d}日')}} {{ev.startTime | timeFormat('周{a}')}} {{ev.startTime | timeFormat}}-{{ev.endTime | timeFormat}}</span>
<span v-else>{{ev.title}}</span>
<span v-if="isSameDate">{{ev.start_time | timeFormat('{m}月{d}日')}} {{ev.end_time | timeFormat('周{a}')}} {{ev.start_time | timeFormat}}-{{ev.end_time | timeFormat}}</span>
<span v-else>{{ev.start_time | timeFormat('{m}月{d}日 {h}:{i}')}} - {{ev.start_time | timeFormat('{m}月{d}日 {h}:{i}')}}</span>
</p>
<p>
<i class="el-icon-s-custom"></i>
<span>{{ev.creator}}</span>
<span>{{ev.sso_user.nickname}}</span>
</p>
</div>
</template>
......@@ -35,6 +35,9 @@ export default {
computed: {
ev() {
return this.data.ev
},
isSameDate() {
return dateFormat(this.ev.start_time, '{m}-{d}') === dateFormat(this.ev.end_time, '{m}-{d}')
}
},
created() {
......
......@@ -2,8 +2,8 @@
<div class="new">
<h5>新建会议</h5>
<el-form ref="ruleForm" :model="form" :rules="rules" label-width="84px">
<el-form-item label="会议主题" prop="theme">
<el-input v-model="form.theme" size="small" />
<el-form-item label="会议主题" prop="subject">
<el-input v-model="form.subject" size="small" />
</el-form-item>
<el-form-item label="开始时间" required>
<el-col :span="11">
......@@ -32,12 +32,12 @@
</el-col>
</el-form-item>
<el-form-item label="会议直播" style="margin-bottom:12px;">
<el-checkbox v-model="form.isLive" @change="updatePopper">开启会议直播(用于分享给观看直播的用户)</el-checkbox>
<el-checkbox v-model="form.enable_live" @change="updatePopper">开启会议直播(用于分享给观看直播的用户)</el-checkbox>
</el-form-item>
<el-form-item v-if="form.isLive" label="直播主题" :required="form.isLive" prop="liveTheme">
<el-form-item v-if="form.enable_live" label="直播主题" :required="form.enable_live" prop="liveTheme">
<el-input v-model="form.liveTheme" size="small" />
</el-form-item>
<el-form-item v-if="form.isLive" label="直播简介" :required="form.isLive" prop="liveDesc">
<el-form-item v-if="form.enable_live" label="直播简介" :required="form.enable_live" prop="liveDesc">
<el-input type="textarea" v-model="form.liveDesc"></el-input>
</el-form-item>
<el-form-item style="text-align:center;">
......@@ -45,10 +45,14 @@
<el-button type="primary" @click="submitForm('ruleForm')" size="mini">立即创建</el-button>
</el-form-item>
</el-form>
<meeting-success-dialog :dialogVisible.sync="dialogVisible" :details="details"/>
</div>
</template>
<script>
import MeetingSuccessDialog from '@/components/MeetingSuccessDialog/index'
import { timeTrans, dateFormat, getTimestampYMD, getCurHalfHour } from '@/utils/dateAlgs'
import { createMeeting, operateLog, getMeetingDetails } from '@api/common'
import { mapGetters } from 'vuex'
const DAY_TIMESTAMP = 8.64e7
export default {
props: {
......@@ -67,6 +71,8 @@ export default {
const timestamp = Date.parse(value);
if (timestamp < Date.now() - DAY_TIMESTAMP) {
callback(new Error('开始时间必须大于当前时间'));
} else {
callback();
}
}
}
......@@ -76,6 +82,8 @@ export default {
callback(new Error('结束时间必须大于开始时间'));
} else if (this.endTimestamp > this.startTimestamp + DAY_TIMESTAMP) {
callback(new Error('会议时间不能超过24小时'));
} else {
callback();
}
}
}
......@@ -91,31 +99,17 @@ export default {
return {
timerClear: true,
form: {
theme: '',
subject: '',
startDate: this.date,
startTime: getCurHalfHour('start'),
endDate: this.date,
endTime: getCurHalfHour('end'),
timezone: 'beijing',
periodic: false,
repeatRate: 'everyday',
endType: 'endOneday',
periodicEndDate: '',
periodicTimes: 7,
isSecret: false,
secret: '',
openWaitingRoom: false,
joinAdvance: false,
mute: false,
recordVideo: false,
isLive: false,
liveTheme: '',
liveDesc: '',
isLiveSecret: false,
permitComment: false
enable_live: false,
live_subject: '',
live_summary: ''
},
rules: {
theme: [{ required: true, message: '请填写会议主题', trigger: 'blur' }],
subject: [{ required: true, message: '请填写会议主题', trigger: 'blur' }],
startDate: [
{ type: 'date', required: true, message: '请选择开始日期', trigger: 'change' },
{ type: 'date', validator: startDateChecked, trigger: 'change' }
......@@ -126,8 +120,8 @@ export default {
{ required: true, message: '请选择结束时间', trigger: 'change' },
{ validator: endDateChecked, trigger: 'change' }
],
liveTheme: [{ validator: validateErrMsg }],
liveDesc: [{ validator: validateErrMsg }]
live_subject: [{ validator: validateErrMsg }],
live_summary: [{ validator: validateErrMsg }]
},
startDateOptions: {
disabledDate(time) {
......@@ -143,10 +137,13 @@ export default {
start: getCurHalfHour('end'),
step: '00:30',
end: '23:30'
}
},
details: {},
dialogVisible: false
}
},
computed: {
...mapGetters(['user']),
startTimestamp() {
return this.getFullDateTime(this.form.startDate, this.form.startTime).getTime()
},
......@@ -166,6 +163,8 @@ export default {
data: {
handler: function(nv) {
if (nv) {
// console.log(nv)
this.form.subject = ''
this.form.startDate = nv.date
this.startDateChange(nv.date)
this.form.startTime = nv.time
......@@ -176,6 +175,7 @@ export default {
deep: true
}
},
components: { MeetingSuccessDialog },
methods: {
updatePopper() {
this.$emit('refreshPopover', Date.now())
......@@ -219,7 +219,6 @@ export default {
}
},
endDateChange() {
console.log(12344)
this.startTimeChange(this.form.startTime)
},
getFullDateTime(date, timeStr) {
......@@ -252,12 +251,66 @@ export default {
submitForm(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
console.log(valid);
this.fetchCreateMeeting()
}
});
},
more() {
this.$router.push({ path: '/meeting', query: { type: '1' } })
this.$router.push({ path: '/meeting', query: { type: '1', account: this.data.accountId, start: this.startTimestamp, end: this.endTimestamp } })
},
fetchCreateMeeting() {
const form = this.form
const params = {
instanceid: 1,
userid: this.data.accountId,
subject: form.subject,
start_time: dateFormat(this.startTimestamp),
end_time: dateFormat(this.endTimestamp),
meeting_type: 0,
enable_live: form.enable_live,
live_config: {
live_subject: form.live_subject,
live_summary: form.live_summary
},
managers: [this.user.id]
}
const loading = this.$loading({
lock: true,
text: '创建腾讯会议中,请稍后...',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)'
})
createMeeting(params).then(res => {
loading.close()
if (res.code === 0 && res.data.id) {
operateLog({ type: `创建会议,被创建会议meeting_code:${res.data.meeting_code}`, user: this.user })
this.$message.success('创建腾讯会议成功')
this.fetchMeetingDetails({ meeting_type: form.meeting_type, meeting_id: res.data.meeting_id })
this.$emit('refreshData')
}
})
},
fetchMeetingDetails(obj) {
if (obj.type === 1) {
console.log(111)
} else {
const params = {
meeting_id: obj.meeting_id
}
const loading = this.$loading({
lock: true,
text: '获取腾讯会议详情,请稍后...',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)'
})
getMeetingDetails(params).then(res => {
loading.close()
if (res.code === 0 && res.data.id) {
this.details = res.data
this.dialogVisible = true
}
})
}
}
}
}
......
......@@ -2,14 +2,14 @@
<div :class="getClass(ev)">
<div class="status">
{{ev.status | statusFilter}}
<span class="time-range">{{ev.startTime | timeFormat}}-{{ev.endTime | timeFormat}}</span>
<span class="time-range">{{ev.start_time | timeFormat}}-{{ev.end_time | timeFormat}}</span>
</div>
<div class="event-cont">
<div class="title">
<span>{{ev.title}}</span>
<span>{{ev.subject}}</span>
</div>
<div class="creator">
<span><i class="el-icon-s-custom"></i>:{{ev.creator}}</span>
<span><i class="el-icon-s-custom"></i>:{{ev.sso_user.nickname}}</span>
</div>
</div>
</div>
......@@ -35,7 +35,7 @@ export default {
case 2:
result = '已完成'
break
case 3:
case 0:
result = '未开始'
break
}
......@@ -54,7 +54,7 @@ export default {
return {
'schedule-ev-inner test': true,
'status-start': ev.status === 1,
'status-notstarted': ev.status === 3,
'status-notstarted': ev.status === 0,
small: h < 120 && h >= 40,
medium: h >= 120 && h < 200,
large: h >= 200
......
<template>
<div class="day">
<schedule :options="options" :data="scheduleList" :date="defaultDate" @eventClick="edit" @addEvent="add">
<schedule :options="options" :data="scheduleData" :date="defaultDate">
<template slot="content" slot-scope="scope">
<schedule-content :ev="scope.data"></schedule-content>
</template>
......@@ -8,7 +8,7 @@
<details-popover :data="scope.data"/>
</template>
<template slot="new-schedule" slot-scope="scope">
<new-popover :data="scope.data" :date="defaultDate" @refreshPopover="refreshPop"/>
<new-popover :data="scope.data" :date="defaultDate" @refreshPopover="refreshPop" @refreshData="getScheduleData"/>
</template>
</schedule>
</div>
......@@ -18,6 +18,9 @@ import Schedule from '@/components/Schedule'
import ScheduleContent from './components/ScheduleContent'
import DetailsPopover from './components/DetailsPopover'
import NewPopover from './components/NewPopover'
import { getAllAccountList, getNonpagedMeetingList } from '@api/common'
import { dateFormat } from '@/utils/dateAlgs'
import { mapGetters } from 'vuex'
export default {
props: {
defaultDate: {
......@@ -25,6 +28,9 @@ export default {
validator: (value) => {
return typeof value === 'object' && (value === null || value instanceof Date)
}
},
filter: {
type: Object
}
},
data() {
......@@ -45,142 +51,112 @@ export default {
events: [
{
status: 2,
title: '开个周会开个周会开个周会开个周会开个周会开个周会开个周会开个周会开个周会开个周会开个周会开个周会',
title: '开个周会',
startTime: new Date(2021, 3, 13, 8, 30, 0),
endTime: new Date(2021, 3, 13, 9, 0, 0),
creator: '张三丰'
},
{
status: 1,
title: '开个周会开个周会开个周会开个周会开个周会开个周会开个周会开个周会开个周会开个周会开个周会开个周会',
startTime: new Date(2021, 3, 13, 11, 0, 0),
endTime: new Date(2021, 3, 13, 13, 0, 0),
creator: '张三丰'
},
{
status: 3,
title: '开个周会开个周会开个周会',
startTime: new Date(2021, 3, 13, 14, 30, 0),
endTime: new Date(2021, 3, 13, 15, 30, 0),
creator: '张三丰'
}
]
},
scheduleList: [
{
id: 'live-1',
title: '会议室1',
events: [
{
status: 2,
title: '开个周会开个周会开个周会开个周会开个周会开个周会开个周会开个周会开个周会开个周会开个周会开个周会',
startTime: new Date(2021, 3, 13, 8, 30, 0),
endTime: new Date(2021, 3, 13, 9, 0, 0),
creator: '张三丰'
},
{
status: 1,
title: '开个周会开个周会开个周会开个周会开个周会开个周会开个周会开个周会开个周会开个周会开个周会开个周会',
startTime: new Date(2021, 3, 13, 11, 0, 0),
endTime: new Date(2021, 3, 13, 13, 0, 0),
creator: '张三丰'
},
{
status: 3,
title: '开个周会开个周会开个周会',
startTime: new Date(2021, 3, 13, 20, 30, 0),
endTime: new Date(2021, 3, 14, 1, 30, 0),
creator: '张三丰'
}
]
},
{
id: 'live-2',
title: '会议室2',
events: [
{
status: 2,
title: '开个周会开个周会开个周会开个周会开个周会开个周会开个周会开个周会开个周会开个周会开个周会开个周会',
startTime: new Date(2021, 3, 13, 9, 30, 0),
endTime: new Date(2021, 3, 13, 10, 0, 0),
creator: '张三丰'
}
]
},
{
id: 'live-3',
title: '会议室3',
events: [
{
status: 3,
title: '开个周会开个周会开个周会开个周会开个周会开个周会开个周会开个周会开个周会开个周会开个周会开个周会',
startTime: new Date(2021, 3, 13, 16, 30, 0),
endTime: new Date(2021, 3, 13, 18, 0, 0),
creator: '张三丰'
}
]
},
{
id: 'live-4',
title: '会议室4',
events: [
{
status: 3,
title: '开个周会开个周会开个周会开个周会开个周会开个周会开个周会开个周会开个周会开个周会开个周会开个周会',
startTime: new Date(2021, 3, 13, 19, 30, 0),
endTime: new Date(2021, 3, 13, 20, 30, 0),
creator: '张三丰'
}
]
},
{
id: 'live-5',
title: '会议室5',
events: [
{
status: 3,
title: '开个周会开个周会开个周会开个周会开个周会开个周会开个周会开个周会开个周会开个周会开个周会开个周会',
startTime: new Date(2021, 3, 8, 21, 0, 0),
endTime: new Date(2021, 3, 8, 22, 0, 0),
creator: '张三丰'
}
]
}
],
list: [
{
id: 'live-1',
title: '会议室1',
events: []
},
{
id: 'live-2',
title: '会议室2',
events: []
}
]
scheduleData: []
}
},
computed: {
...mapGetters(['user'])
},
components: { Schedule, ScheduleContent, DetailsPopover, NewPopover },
watch: {
defaultDate: {
handler: function(nv, ov) {
if (nv) {
// console.log(nv)
console.log(nv)
this.getScheduleData()
}
},
immediate: true
},
'filter.status': {
handler: function(nv, ov) {
if (nv !== ov) {
this.getScheduleData()
}
},
deep: true
},
'filter.isMine': {
handler: function(nv, ov) {
if (nv !== ov) {
this.getScheduleData()
}
},
deep: true
}
},
methods: {
refreshPop(val) {
this.options.refreshPopoverState = val
},
edit(val) {
console.log(val)
pickMeeingData(aList, mList) {
const data = []
for (let i = 0; i < aList.length; i++) {
const _accont = aList[i]
if (_accont.userid) {
const account = {
userid: _accont.userid,
name: _accont.username,
events: []
}
for (let j = 0; j < mList.length; j++) {
const meeting = mList[j]
if (meeting.userid === _accont.userid) {
account.events.push(meeting)
}
}
data.push(account)
}
}
return data
},
add(val) {
console.log(val)
getScheduleData() {
//
Promise.all([this.fetchAccountList(), this.fetchMeetingList()]).then(res => {
// 组装数据
const scheduleData = this.pickMeeingData(res[0], res[1])
this.scheduleData = scheduleData
}).catch(err => {
console.log(err)
})
},
fetchMeetingList() {
const date = this.defaultDate
const start = dateFormat(date)
const end = dateFormat(new Date(date.getFullYear(), date.getMonth(), date.getDate() + 1))
const params = {
sso_id: this.filter.isMine ? this.user.id : undefined,
status: this.filter.status > 2 ? undefined : this.filter.status,
start_time: start,
end_time: end
}
return new Promise((resolve, reject) => {
getNonpagedMeetingList(params).then((res) => {
if (res.code === 0 && res.data && res.data.list) {
resolve(res.data.list)
} else {
reject(res)
}
}).catch((err) => reject(err))
})
},
fetchAccountList() {
return new Promise((resolve, reject) => {
getAllAccountList().then((res) => {
if (res.code === 0 && res.data.list) {
resolve(res.data.list)
} else {
reject(res)
}
}).catch((err) => reject(err))
})
}
}
}
......
......@@ -9,20 +9,22 @@
<calendar :type="dateType" style="margin-left:-10px;" :defaultDate="defaultDate" @change="calendarChange" />
<div class="bottom">
<div class="title">
直播日历 <el-checkbox style="margin-left:20px;" v-model="mineFilter">我的</el-checkbox>
直播日历 <el-checkbox style="margin-left:20px;" v-model="filter.isMine">我的</el-checkbox>
</div>
<div class="status-filter">
<el-radio-group v-model="statusFilter">
<el-radio :label="3">进行中</el-radio>
<el-radio :label="6">未开始</el-radio>
<el-radio :label="9">已完成</el-radio>
<el-radio-group v-model="filter.status">
<el-radio :label="9999">全部</el-radio>
<el-radio :label="1">进行中</el-radio>
<el-radio :label="0">未开始</el-radio>
<el-radio :label="2">已完成</el-radio>
</el-radio-group>
</div>
</div>
</div>
<div class="right-container">
<div class="top">
<div class="title">2021年04月</div>
<div class="title" v-if="tabActive === 'list'">{{defaultDate[0] | dateFormat}} - {{defaultDate[1] | dateFormat}}</div>
<div class="title" v-if="tabActive === 'day'">{{defaultDate | dateFormat}} {{defaultDate | dateFormat('星期{a}')}} </div>
<el-radio-group v-model="tabActive" size="mini">
<el-radio-button label="list">列表</el-radio-button>
<el-radio-button label="day"></el-radio-button>
......@@ -30,8 +32,8 @@
<el-radio-button label="month"></el-radio-button> -->
</el-radio-group>
</div>
<list v-if="tabActive === 'list'" />
<day v-if="tabActive === 'day'" :defaultDate="defaultDate"/>
<list v-if="tabActive === 'list'" :defaultDate="defaultDate" :filter="filter"/>
<day v-if="tabActive === 'day'" :defaultDate="defaultDate" :filter="filter"/>
</div>
</div>
</div>
......@@ -44,8 +46,10 @@ import { dateFormat } from '@/utils/dateAlgs'
export default {
data () {
return {
mineFilter: false,
statusFilter: '',
filter: {
isMine: false,
status: 9999
},
tabActive: 'list',
defaultDate: null,
dateType: 'date'
......@@ -60,22 +64,7 @@ export default {
},
filters: {
dateFormat (value, fmt) {
return dateFormat(value, fmt)
},
statusFilter(val) {
let result = ''
switch (val) {
case 1:
result = '进行中'
break
case 2:
result = '已完成'
break
case 3:
result = '未开始'
break
}
return result
return dateFormat(value, fmt || '{y}年{m}月{d}日')
}
},
watch: {
......@@ -85,7 +74,7 @@ export default {
this.defaultDate = this.now
this.dateType = 'date'
} else {
this.defaultDate = null
this.defaultDate = [this.now, this.now]
this.dateType = 'daterange'
}
},
......@@ -97,17 +86,7 @@ export default {
this.$router.push('/search')
},
calendarChange(val) {
if (this.dateType === 'date') {
this.defaultDate = val
} else {
console.log(val)
}
},
joinMeeting(data) {
console.log(data)
},
pageChange(val) {
console.log(val)
this.defaultDate = val
}
}
}
......@@ -144,23 +123,30 @@ h5{
margin-bottom:10px;
}
.status-filter ::v-deep.el-radio:first-child .el-radio__input.is-checked .el-radio__inner{
border-color:#636363;
background:#636363;
}
.status-filter ::v-deep.el-radio:nth-child(2) .el-radio__input.is-checked .el-radio__inner{
border-color:#409eff;
background:#409eff;
}
.status-filter ::v-deep.el-radio:last-child .el-radio__input.is-checked .el-radio__inner{
border-color:#BFBFBF;
background:#BFBFBF;
}
.status-filter ::v-deep.el-radio__input.is-checked .el-radio__inner{
.status-filter ::v-deep.el-radio:nth-child(3) .el-radio__input.is-checked .el-radio__inner{
border-color:#52B837;
background:#52B837;
}
.status-filter ::v-deep.el-radio__input + .el-radio__label{
color:#52B837;
.status-filter ::v-deep.el-radio:last-child .el-radio__input.is-checked .el-radio__inner{
border-color:#BFBFBF;
background:#BFBFBF;
}
.status-filter ::v-deep.el-radio:first-child .el-radio__input + .el-radio__label{
color:#636363;
}
.status-filter ::v-deep.el-radio:nth-child(2) .el-radio__input + .el-radio__label{
color:#409eff;
}
.status-filter ::v-deep.el-radio:nth-child(3) .el-radio__input + .el-radio__label{
color:#52B837;
}
.status-filter ::v-deep.el-radio:last-child .el-radio__input + .el-radio__label{
color:#BFBFBF;
}
......
<template>
<el-form label-width="140px">
<el-form-item label="会议主题:">
某某某会议主题
{{details.subject}}
</el-form-item>
<el-form-item label="会议时间:">
2021年11月06日 10:00-11:00(GMT+08:00)
{{details.start_time | dateFormat}} - {{details.end_time | dateFormat('{h}:{i}')}}GMT+08:00)
</el-form-item>
<el-form-item label="会议链接:">
http://meeting.tencent.com/sS42KPDILN
{{details.join_url}}
</el-form-item>
<el-form-item label="会议号:">
526 430 840
{{details.meeting_code}}
</el-form-item>
<el-form-item label="会议直播:" v-if="hasLive">
http://meeting.tencent.com/sS42KPDILN
<el-form-item label="会议直播:" v-if="details.enable_live === 1">
{{details.live_config.live_addr}}
</el-form-item>
<el-form-item label="手机拨号入会:">
<el-form-item label="手机拨号入会:" v-if="false">
<p>+8675536550000,,526430840#(中国大陆)</p>
<p>+85230018898,,526430840#(中国香港)</p>
</el-form-item>
<el-form-item label="根据您的位置拨号:">
<el-form-item label="根据您的位置拨号:" v-if="false">
<p>+8675536550000(中国大陆)</p>
<p>++85230018898(中国香港)</p>
</el-form-item>
</el-form>
</template>
<script>
import { dateFormat } from '@/utils/dateAlgs'
export default {
props: {
rowData: {}
rowData: {},
details: {}
},
computed: {
hasLive() {
return this.rowData.hasLive || false
}
},
filters: {
dateFormat(value, fmt) {
return dateFormat(value, fmt || '{y}年{m}月{d}日 {h}:{i}')
}
}
}
</script>
......
<template>
<el-form label-width="140px">
<el-form-item label="会议主题:">
某某某会议主题
{{details.subject}}
</el-form-item>
<el-form-item label="会议时间:">
2021年11月06日 10:00-11:00(GMT+08:00)
{{details.start_time | dateFormat}} - {{details.end_time | dateFormat('{h}:{i}')}}GMT+08:00)
</el-form-item>
<el-form-item label="会议号:">
526 430 840
{{details.meeting_code}}
</el-form-item>
<el-form-item label="会议创建者:">
张三
{{rowData.sso_user.nickname}}
</el-form-item>
<el-form-item label="会议主持人:">
李四
<span v-for="(it, index) in details.hosts" :key="it.userid">{{it.username}}{{index > 0 ? '、' : ''}}</span>
</el-form-item>
<el-form-item label="会议主持人:">
王五、赵⑥
<el-form-item label="会议管理员:">
<span v-for="(it, index) in details.managers" :key="it.userid">{{it.nickname}}{{index > 0 ? '、' : ''}}</span>
</el-form-item>
<el-form-item label="会议直播主题:">
随便写点啥
<el-form-item label="会议直播主题:" v-if="details.enable_live === 1">
{{details.live_config.live_subject}}
</el-form-item>
<el-form-item label="会议直播简介:">
<p style="line-height:26px;padding:7px 10px 7px 0">随便写点啥随便写点啥随便写点啥随便写点啥随便写点啥随便写点啥随便写点啥随便写点啥随便写点啥随便写点啥</p>
<el-form-item label="会议直播简介:" v-if="details.enable_live === 1">
<p style="line-height:26px;padding:7px 10px 7px 0">{{details.live_config.live_summary}}</p>
</el-form-item>
<el-form-item label="参会成员:">
<el-button type="text">导出excel</el-button>
<el-form-item label="参会成员:" v-if="rowData.status === 2">
<el-button type="text" @click="handleExport">导出excel</el-button>
</el-form-item>
<el-form-item label="回放:">
<el-button type="text">下载</el-button>
<el-form-item label="回放:" v-if="rowData.status === 2">
<el-button type="text" v-if="hasRecord" @click="handleDownload">下载</el-button>
<el-button type="text" v-else disabled>暂无回放</el-button>
</el-form-item>
</el-form>
</template>
<script>
import { dateFormat } from '@/utils/dateAlgs'
import { exportParticipants, getMeetingRecordAddr } from '@api/common'
export default {
props: {
details: {},
rowData: {},
dialogType: {}
},
computed: {
hasLive() {
return this.rowData.hasLive || false
hasRecord() {
if (this.rowData.record_file_ids && Array.isArray(this.rowData.record_file_ids) && this.rowData.record_file_ids.length > 0) {
return true
} else {
return false
}
},
nowFormat() {
const now = Date.now()
const _format = dateFormat(now, '{y}{m}{d}{h}{i}{s}')
const nowStr = now.toString()
return _format + nowStr.substr(10, 12)
}
},
filters: {
dateFormat(value, fmt) {
return dateFormat(value, fmt || '{y}年{m}月{d}日 {h}:{i}')
}
},
methods: {
handleExport() {
const row = this.rowData
const params = {
meeting_id: row.meeting_id
}
if (row.meeting_type === 1) {
params.sub_meeting_id = row.sub_meeting_id
}
exportParticipants(params).then((res) => {
if (res && res.type === 'text/xlsx') {
const url = URL.createObjectURL(res)
// const elink = document.createElement('a')// 创建一个a标签
// elink.download = `参会人员表_${this.nowFormat}.xlsx`;// 设置a标签的下载属性
// elink.style.display = 'none';// 将a标签设置为隐藏
// elink.href = URL.createObjectURL(blob);// 把之前处理好的地址赋给a标签的href
// document.body.appendChild(elink);// 将a标签添加到body中
// elink.click();// 执行a标签的点击方法
// URL.revokeObjectURL(elink.href) // 下载完成释放URL 对象
// document.body.removeChild(elink)// 移除a标签
this.funDownload(url, `参会人员表_${this.nowFormat}.xlsx`)
}
})
},
async handleDownload() {
const list = await this.fetchMeetingRecordAddr()
if (list && Array.isArray(list)) {
list.forEach(it => {
if (it.download_address) {
// window.open(it.download_address, '_blank')
this.funDownload(it.download_address, it.download_address)
}
})
}
},
funDownload(fileUrl, fileName) {
const elink = document.createElement('a')// 创建一个a标签
elink.download = fileName;// 设置a标签的下载属性
elink.style.display = 'none';// 将a标签设置为隐藏
elink.href = fileUrl;// 把之前处理好的地址赋给a标签的href
document.body.appendChild(elink);// 将a标签添加到body中
elink.click();// 执行a标签的点击方法
URL.revokeObjectURL(elink.href) // 下载完成释放URL 对象
document.body.removeChild(elink)// 移除a标签
},
fetchMeetingRecordAddr() {
const params = {
meeting_id: this.rowData.meeting_id,
record_file_ids: this.rowData.record_file_ids
}
return new Promise((resolve, reject) => {
getMeetingRecordAddr(params).then(res => {
if (res.code === 0 && res.data.files) {
resolve(res.data.files)
} else {
reject(res)
}
}).catch((err) => reject(err))
})
}
}
}
......
<template>
<div class="btns">
<template v-if="status === 1">
<el-button type="text" size="small" v-if="operatable">进入会议</el-button>
<el-button type="text" size="small" v-if="operatable && hasLive">观看直播</el-button>
<el-button type="text" size="small" v-if="operatable" @click="dialogVisible = 'copy'">复制邀请</el-button>
<el-button type="text" size="small" v-if="operatable">终止</el-button>
<el-button type="text" size="small" v-if="!operatable" @click="dialogVisible = 'details'">查看</el-button>
<el-button type="text" size="small" v-if="operatable" @click="handleJoin">进入会议</el-button>
<el-button type="text" size="small" v-if="operatable && hasLive" @click="handleLive">观看直播</el-button>
<el-button type="text" size="small" v-if="operatable" @click="handleCopy">复制邀请</el-button>
<el-button type="text" size="small" v-if="operatable" @click="handleStop">终止</el-button>
<el-button type="text" size="small" v-if="!operatable" @click="handleDetails">查看</el-button>
</template>
<template v-if="status === 2">
<el-button type="text" size="small" v-if="operatable">进入会议</el-button>
<el-button type="text" size="small" v-if="operatable">复制邀请</el-button>
<template v-if="status === 0">
<el-button type="text" size="small" v-if="operatable" @click="handleJoin">进入会议</el-button>
<el-button type="text" size="small" v-if="operatable" @click="handleCopy">复制邀请</el-button>
<el-button type="text" size="small" v-if="operatable && !isCycle">修改</el-button>
<el-dropdown v-if="operatable && isCycle">
<span class="dropdown-link">
......@@ -20,23 +20,23 @@
<el-dropdown-item>修改周期会议</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<el-button type="text" size="small" v-if="operatable">取消</el-button>
<el-button type="text" size="small" v-if="!operatable" @click="dialogVisible = 'details'">查看</el-button>
<el-button type="text" size="small" v-if="operatable" @click="handleCancel">取消</el-button>
<el-button type="text" size="small" v-if="!operatable" @click="handleDetails">查看</el-button>
</template>
<template v-if="status === 3">
<el-button type="text" size="small" v-if="operatable">看回放</el-button>
<el-button type="text" size="small" @click="dialogVisible = 'details'">查看</el-button>
<el-button type="text" size="small" v-if="operatable">删除</el-button>
<template v-if="status === 2">
<el-button type="text" size="small" v-if="operatable" @click="handleRecord">看回放</el-button>
<el-button type="text" size="small" @click="handleDetails">查看</el-button>
<el-button type="text" size="small" v-if="operatable" @click="handleDelete">删除</el-button>
</template>
<el-dialog :title="domicTitle" :visible.sync="dialogVisible" width="520px" center>
<div slot="title" class="dialog-header">
<p class="meeting-status" v-show="dialogVisible === 'details'">会议进行中</p>
<p class="meeting-status" v-show="dialogType === 'details'">会议{{rowData.status | statusFilter}}</p>
<p class="title">{{domicTitle}}</p>
</div>
<dialog-details :rowData="rowData" :dialogType="dialogVisible" v-show="dialogVisible === 'details'" />
<dialog-copy-invite :rowData="rowData" v-show="dialogVisible === 'copy'"/>
<dialog-details :rowData="rowData" :details="details" v-show="dialogType === 'details'" />
<dialog-copy-invite :rowData="rowData" :details="details" v-show="dialogType === 'copy'"/>
<div slot="footer" class="dialog-footer">
<el-button type="primary" size="mini" v-show="dialogVisible === 'copy'">复制</el-button>
<el-button type="primary" size="mini" v-show="dialogType === 'copy'" @click="copyLink">复制</el-button>
<el-button @click="dialogVisible = false" size="mini">取 消</el-button>
</div>
</el-dialog>
......@@ -45,6 +45,8 @@
<script>
import DialogDetails from './DialogDetails.vue'
import DialogCopyInvite from './DialogCopyInvite'
import { mapGetters } from 'vuex'
import { getMeetingDetails, stopMeeting, cancelMeeting, getMeetingRecordAddr } from '@api/common'
export default {
props: {
rowData: {}
......@@ -53,13 +55,16 @@ export default {
return {
userId: '1234',
roleName: '', // general_admin
dialogVisible: false
dialogVisible: false,
dialogType: 'copy',
details: ''
}
},
computed: {
...mapGetters(['isSuperAdmin', 'user']),
domicTitle() {
let title = ''
switch (this.dialogVisible) {
switch (this.dialogType) {
case 'copy':
title = '复制邀请'
break
......@@ -73,19 +78,16 @@ export default {
return this.rowData.status
},
isCycle() {
return this.rowData.isCycle
return this.rowData.meeting_type === 1
},
isMyself() {
return this.rowData.creatorId === this.userId
},
isSuperAdmin() {
return this.roleName === 'administrator'
return this.rowData.sso_id === this.user.id
},
isGeneralAdmin() {
const admins = this.rowData.general_admin
const admins = this.rowData.manage_ids
let flag = false
for (let i = 0; i < admins.length; i++) {
if (admins[i].userId === this.userId) {
if (admins[i] === this.user.id) {
flag = true
break
}
......@@ -93,14 +95,153 @@ export default {
return flag
},
hasLive() {
return this.rowData.hasLive || false
return this.rowData.enable_live || false
},
operatable() {
return this.isMyself || this.isSuperAdmin || this.isGeneralAdmin
}
},
filters: {
statusFilter(val) {
let result = ''
switch (val) {
case 0:
result = '未开始'
break
case 1:
result = '进行中'
break
case 2:
result = '已结束'
break
}
return result
}
},
components: { DialogDetails, DialogCopyInvite },
created() {
},
methods: {
handleCopy() {
this.fetchMeetingDetails()
this.dialogVisible = true
this.dialogType = 'copy'
},
handleDetails() {
this.dialogVisible = true
this.dialogType = 'details'
this.fetchMeetingDetails()
},
handleLive() {
window.open(this.live_config.live_addr, '_blank');
},
handleCancel() {
this.$confirm('此操作将取消这场会议, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消'
}).then(() => {
this.fetchCancelMeeting('cancel')
}).catch(() => {})
},
handleStop() {
this.$confirm('此操作将终止正在进行中的会议, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消'
}).then(() => {
this.fetchStopMeeting()
}).catch(() => {})
},
handleDelete() {
this.$confirm('此操作将删除这场会议, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消'
}).then(() => {
this.fetchCancelMeeting('delete')
}).catch(() => {})
},
handleJoin() {
window.open(this.rowData.join_url, '_blank');
},
copyLink() {
const dom = document.createElement('input')
document.body.appendChild(dom)
dom.value = this.rowData.join_url
dom.select(); // 选择对象
document.execCommand('Copy');
this.$message({
message: '复制成功!',
type: 'success'
})
document.body.removeChild(dom)
},
async handleRecord() {
if (this.rowData.record_file_ids.length === 0) {
this.$message.error('该会议没有回放')
} else {
const list = await this.fetchMeetingRecordAddr()
if (list && Array.isArray(list)) {
if (list.length === 1) {
window.open(list[0].view_address, '_blank')
}
}
}
},
fetchStopMeeting() {
const params = {
meeting_id: this.rowData.meeting_id
}
stopMeeting(params).then(res => {
if (res.code === 0 && res.data.status) {
this.$message.success('会议终止成功')
this.$emit('refresh')
} else {
this.$message.error(res.msg || '会议终止失败')
}
})
},
fetchCancelMeeting(type) {
const params = {
meeting_id: this.rowData.meeting_id
}
const msg = type === 'cancel' ? '会议取消' : '会议删除'
cancelMeeting(params).then(res => {
if (res.code === 0 && res.data.status) {
this.$message.success(msg + '成功')
this.$emit('refresh')
} else {
this.$message.error(res.msg || msg + '失败')
}
})
},
fetchMeetingDetails() {
const row = this.rowData
const params = {
meeting_id: row.meeting_id
}
if (row.meeting_type === 1) {
params.sub_meeting_id = row.sub_meeting_id
}
getMeetingDetails(params).then(res => {
if (res.code === 0 && res.data.id) {
this.details = res.data
}
})
},
fetchMeetingRecordAddr() {
const params = {
meeting_id: this.rowData.meeting_id,
record_file_ids: this.rowData.record_file_ids
}
return new Promise((resolve, reject) => {
getMeetingRecordAddr(params).then(res => {
if (res.code === 0 && res.data.files) {
resolve(res.data.files)
} else {
reject(res)
}
}).catch((err) => reject(err))
})
}
}
}
</script>
......
......@@ -3,26 +3,35 @@
<el-table :data="listData" style="width: 100%" height="calc(100% - 32px)">
<el-table-column label="会议时间" min-width="160">
<template slot-scope="scope">
<p style="color:#AEAEAE;">
<span style="font-size:18px;color:#606266;">{{ scope.row.date | dateFormat('{d}')}}</span>
{{ scope.row.date | dateFormat('{m}月')}} {{ scope.row.date | dateFormat('周{a}')}}
<span style="font-size:16px;color:#606266;">{{ scope.row.date | dateFormat('{h}:{i}')}}</span>
<p style="color: #aeaeae">
<span style="font-size: 18px; color: #606266">{{ scope.row.start_time | dateFormat('{d}') }}</span>
{{ scope.row.start_time | dateFormat('{m}月') }} {{ scope.row.start_time | dateFormat('周{a}') }}
<span style="font-size: 16px; color: #606266">{{ scope.row.start_time | dateFormat('{h}:{i}') }}</span>
</p>
<p style="color:#AEAEAE;">
<span style="font-size:18px;color:#606266;">{{ scope.row.endDate | dateFormat('{d}')}}</span>
{{ scope.row.endDate | dateFormat('{m}月')}} {{ scope.row.endDate | dateFormat('周{a}')}}
<span style="font-size:16px;color:#606266;">{{ scope.row.endDate | dateFormat('{h}:{i}')}}</span>
<p style="color: #aeaeae">
<span style="font-size: 18px; color: #606266">{{ scope.row.end_time | dateFormat('{d}') }}</span>
{{ scope.row.end_time | dateFormat('{m}月') }} {{ scope.row.end_time | dateFormat('周{a}') }}
<span style="font-size: 16px; color: #606266">{{ scope.row.end_time | dateFormat('{h}:{i}') }}</span>
</p>
</template>
</el-table-column>
<el-table-column label="会议主题" min-width="180">
<template slot-scope="scope">
<el-popover trigger="hover" placement="top" width="240">
<p>{{ scope.row.title }}</p>
<p>{{ scope.row.subject }}</p>
<div slot="reference" class="name-wrapper">
<p style="display:flex;">
<span style="flex:1;display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden;">{{ scope.row.title }}</span>
<span v-if="scope.row.isCycle" style="color:#409DFF;width:40px;">(周期)</span>
<p style="display: flex">
<span
style="
flex: 1;
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
"
>{{ scope.row.subject }}</span
>
<span v-if="scope.row.meeting_type === 1" style="color: #409dff; width: 40px">(周期)</span>
</p>
</div>
</el-popover>
......@@ -31,204 +40,152 @@
<!-- <el-table-column prop="resource" label="会议来源" width="80"></el-table-column> -->
<el-table-column prop="resource" label="会议状态" width="80">
<template slot-scope="scope">
<p :class="{'status-start': scope.row.status === 1, 'status-notstarted': scope.row.status === 2, 'status-end': scope.row.status === 3}">
<p
:class="{
'status-start': scope.row.status === 1,
'status-notstarted': scope.row.status === 0,
'status-end': scope.row.status === 2
}"
>
<i></i>
<span style="margin-left: 10px">{{ scope.row.status | statusFilter}}</span>
<span style="margin-left: 10px">{{ scope.row.status | statusFilter }}</span>
</p>
</template>
</el-table-column>
<el-table-column prop="creator" label="创建人" width="80"></el-table-column>
<el-table-column label="操作" min-width="240">
<el-table-column prop="sso_user.nickname" label="创建人" min-width="100"></el-table-column>
<el-table-column label="操作" width="220">
<template slot-scope="scope">
<table-handles :rowData="scope.row"/>
<table-handles :rowData="scope.row" @refresh="fetchMeetingList"/>
</template>
</el-table-column>
</el-table>
<el-pagination :current-page.sync="curPage" :page-size="pageSize" layout="total, prev, pager, next" :total="total" @current-change="pageChange" style="float:right;"></el-pagination>
<el-pagination
:current-page.sync="curPage"
:page-size="pageSize"
layout="total, prev, pager, next"
:total="total"
@current-change="pageChange"
style="float: right"
></el-pagination>
</div>
</template>
<script>
import { dateFormat } from '@/utils/dateAlgs'
import TableHandles from './components/TableHandles.vue'
import TableHandles from '@/components/TableHandles/index.vue'
import { getMeetingList } from '@api/common'
import { mapGetters } from 'vuex'
export default {
props: {
defaultDate: {
type: [Array, Object]
},
filter: {
type: Object
}
},
data() {
return {
listData: [
{
date: new Date(2021, 3, 7, 10, 30, 0).getTime(),
endDate: new Date(2021, 3, 8, 8, 0, 0).getTime(),
title: 'CIIS直播课CIIS直播课CIIS直播课CIIS直播课CIIS直播课CIIS直播课CIIS直播课CIIS直播课CIIS直播课CIIS直播课CIIS直播课',
isCycle: false,
resource: '腾讯',
status: 1,
creator: '张三丰',
creatorId: '3211',
hasLive: true,
general_admin: [
{
userId: '1234'
},
{
userId: '1342'
}
]
},
{
date: new Date(2021, 3, 7, 10, 30, 0).getTime(),
endDate: new Date(2021, 3, 8, 8, 0, 0).getTime(),
title: 'CIIS直播课CII课',
isCycle: false,
resource: '腾讯',
status: 1,
creator: '张三三',
creatorId: '3211',
hasLive: true,
general_admin: [
{
userId: '2222'
},
{
userId: '1342'
}
]
},
{
date: new Date(2021, 3, 7, 10, 30, 0).getTime(),
endDate: new Date(2021, 3, 8, 8, 0, 0).getTime(),
title: 'CIIS直播课CII课',
isCycle: false,
resource: '腾讯',
status: 1,
creator: '张三多',
creatorId: '1234',
hasLive: false,
general_admin: [
{
userId: '2222'
},
{
userId: '1342'
}
]
},
{
date: new Date(2021, 10, 7).getTime(),
endDate: new Date(2021, 10, 8).getTime(),
title: '索菲亚直播索菲亚直播索菲亚直播索菲亚直播索菲亚直播索菲亚直播索菲亚直播索菲亚直播索菲亚直播',
isCycle: true,
resource: '腾讯',
status: 2,
creator: '黄飞鸿',
hasLive: false,
general_admin: [
{
userId: '1111'
},
{
userId: '1342'
}
]
},
{
date: new Date(2021, 10, 7).getTime(),
endDate: new Date(2021, 10, 8).getTime(),
title: '索菲亚直播索菲亚直播索菲亚直播索菲亚直播索菲亚直播索菲亚直播索菲亚直播索菲亚直播索菲亚直播',
isCycle: true,
resource: '腾讯',
status: 2,
creator: '黄飞鸿',
general_admin: [
{
userId: '1234'
},
{
userId: '1342'
}
]
},
{
date: new Date(2021, 10, 7).getTime(),
endDate: new Date(2021, 10, 8).getTime(),
title: '索菲亚直播索菲亚直播',
isCycle: false,
resource: '腾讯',
status: 3,
creator: '楚留香',
general_admin: [
{
userId: '1234'
},
{
userId: '1342'
}
]
},
{
date: new Date(2021, 10, 7).getTime(),
endDate: new Date(2021, 10, 8).getTime(),
title: '索菲亚直播索菲亚直播',
isCycle: false,
resource: '腾讯',
status: 3,
creator: '楚留香',
general_admin: [
{
userId: '3421'
},
{
userId: '1342'
}
]
}
],
listData: [],
dateRange: [],
curPage: 1,
pageSize: 20,
total: 200
total: 0
}
},
computed: {
...mapGetters(['user'])
},
filters: {
dateFormat (value, fmt) {
dateFormat(value, fmt) {
return dateFormat(value, fmt)
},
statusFilter(val) {
let result = ''
switch (val) {
case 0:
result = '未开始'
break
case 1:
result = '进行中'
break
case 2:
result = '未开始'
break
case 3:
result = '已完成'
result = '已结束'
break
}
return result
}
},
components: { TableHandles },
watch: {
defaultDate: {
handler: function(nv, ov) {
if (nv) {
this.dateRange = nv
this.fetchMeetingList()
}
},
immediate: true,
deep: true
},
'filter.status': {
handler: function(nv, ov) {
if (nv !== ov) {
this.fetchMeetingList()
}
},
deep: true
},
'filter.isMine': {
handler: function(nv, ov) {
console.log(nv)
if (nv !== ov) {
this.fetchMeetingList()
}
},
deep: true
}
},
created() {
// this.fetchMeetingList()
},
methods: {
joinMeeting(data) {
console.log(data)
pageChange() {
this.fetchMeetingList()
},
pageChange(val) {
console.log(val)
fetchMeetingList() {
const start = dateFormat(this.dateRange[0])
const end = this.dateRange[1]
const endPlus1 = dateFormat(new Date(end.getFullYear(), end.getMonth(), end.getDate() + 1))
const params = {
page: this.curPage,
limit: this.pageSize,
sso_id: this.filter.isMine ? this.user.id : undefined,
status: this.filter.status > 2 ? undefined : this.filter.status,
start_time: start,
end_time: endPlus1
}
getMeetingList(params).then((res) => {
if (res.code === 0 && res.data.data) {
this.listData = res.data.data
this.total = res.data.total
}
})
}
}
}
</script>
<style scoped>
.list{
.list {
padding: 5px 5px 0 10px;
height:calc(100% - 40px);
height: calc(100% - 40px);
}
.status-start{
color:#409eff;
.status-start {
color: #409eff;
}
.status-notstarted{
color:#52B837;
.status-notstarted {
color: #52b837;
}
.status-end{
color:#BFBFBF;
.status-end {
color: #bfbfbf;
}
</style>
\ No newline at end of file
<template>
<div class="create-meeting">
<el-radio-group v-model="tabActive" size="mini" style="margin:14px 0 10px 40px;">
<el-radio-button label="tx">腾讯</el-radio-button>
<el-radio-button label="cc">cc</el-radio-button>
<!-- <el-radio-button label="week"></el-radio-button>
<el-radio-button label="month"></el-radio-button> -->
</el-radio-group>
<tencent-meeting-test />
</div>
</template>
<script>
import TencentMeetingTest from './tencent-meeting-test/index.vue'
export default {
data() {
return {
tabActive: 'tx'
}
},
components: { TencentMeetingTest }
}
</script>
<style scope>
.create-meeting{
height:100%;
}
</style>
\ No newline at end of file
......@@ -10,7 +10,7 @@
</div>
</template>
<script>
import TencentMeeting from './components/tencentMeeting.vue'
import TencentMeeting from './tencent-meeting/index.vue'
export default {
data() {
return {
......
<template>
<el-form ref="ruleForm" :model="form" :rules="rules" label-width="120px">
<!-- <el-form-item label="会议选择" prop="meetingType">
<el-radio-group v-model="form.meetingType">
<el-radio label="tencent">腾讯</el-radio>
</el-radio-group>
</el-form-item> -->
<el-form-item label="会议主题" prop="subject">
<el-input v-model="form.subject" size="small" />
</el-form-item>
<el-form-item label="开始时间" required>
<el-col :span="11">
<el-form-item prop="startDate">
<el-date-picker
v-model="form.startDate"
type="date"
placeholder="选择日期"
style="width: 100%"
size="small"
:clearable="timerClear"
:editable="timerClear"
:picker-options="startDateOptions"
@change="startDateChange"
/>
</el-form-item>
</el-col>
<el-col :span="2" class="line">-</el-col>
<el-col :span="11">
<el-form-item prop="startTime">
<el-time-select
v-model="form.startTime"
style="width: 100%"
:picker-options="startTimeOptions"
placeholder="选择时间"
size="small"
:clearable="timerClear"
:editable="timerClear"
@change="startTimeChange"
/>
</el-form-item>
</el-col>
</el-form-item>
<el-form-item label="结束时间" required>
<el-col :span="11">
<el-form-item prop="endDate">
<el-date-picker
v-model="form.endDate"
type="date"
placeholder="选择日期"
style="width: 100%"
size="small"
:clearable="timerClear"
:editable="timerClear"
:picker-options="endDateOptions"
@change="endDateChange"
/>
</el-form-item>
</el-col>
<el-col :span="2" class="line">-</el-col>
<el-col :span="11">
<el-form-item prop="endTime">
<el-time-select
v-model="form.endTime"
style="width: 100%"
:picker-options="endTimeOptions"
placeholder="选择时间"
size="small"
:clearable="timerClear"
:editable="timerClear"
/>
</el-form-item>
</el-col>
</el-form-item>
<el-form-item label="时区" required>
<el-col :span="11">
<el-select style="width: 100%" v-model="form.timezone" placeholder="选择时区" size="small">
<el-option label="(GMT+8:00)中国标准时间-北京" value="beijing" />
</el-select>
</el-col>
</el-form-item>
<el-form-item label="周期会议">
<el-switch v-model="form.meeting_type" :active-value="1" :inactive-value="0" />
</el-form-item>
<el-form-item label="重复频率" v-if="form.meeting_type" required>
<el-col :span="11">
<el-select
style="width: 100%"
v-model="form.recurring_type"
placeholder="选择重复频率"
size="small"
@change="repaeatRateChange"
>
<el-option label="每天" :value="0" />
<el-option label="每个工作日" :value="1" />
<el-option label="每周" :value="2" />
<el-option label="每两周" :value="3" />
<el-option label="每月" :value="4" />
</el-select>
</el-col>
</el-form-item>
<el-form-item label="结束重复" v-if="form.meeting_type" required>
<el-col :span="11">
<el-select style="width: 100%" v-model="form.until_type" placeholder="选择时区" size="small">
<el-option label="结束于某天" :value="0" />
<el-option label="限制会议次数" :value="1" />
</el-select>
</el-col>
<el-col :span="2" class="line">-</el-col>
<el-col :span="11">
<el-date-picker
v-if="form.until_type === 0"
v-model="getCycleMeetingEndDate"
type="date"
placeholder="选择结束日期"
style="width: 100%"
size="small"
:clearable="timerClear"
:editable="timerClear"
:picker-options="untilDateOptions"
/>
<el-input-number v-else v-model="form.until_count" :min="1" :max="50" size="small"></el-input-number>
</el-col>
</el-form-item>
<!-- <el-form-item label="指定主持人">
<el-col :span="11">
<el-select style="width:100%" v-model="form.moderator" placeholder="选择主持人" size="small">
<el-option :label="user.username" :value="user.id" v-for="user in userList" :key="user.id" />
</el-select>
</el-col>
</el-form-item> -->
<el-form-item label="指定会议管理员">
<el-col :span="11">
<el-select
style="width: 100%"
v-model="form.managers"
placeholder="选择管理员"
size="small"
multiple
filterable
remote
:remote-method="fetchUserList"
:loading="searchUsersloading"
>
<el-option :label="user.nickname" :value="user.id" v-for="user in userList" :key="user.id" />
</el-select>
</el-col>
<el-col :span="13" style="color: #999; height: 40px; position: relative; font-size: 12px; line-height: 18px">
<span style="position: absolute; left: 5px; top: 50%; transform: translateY(-50%)"
>(会议管理员有修改会议,复制、取消会议等所有管理本次会议的权限)</span
>
</el-col>
</el-form-item>
<el-form-item label="会议设置">
<el-checkbox style="width: 120px" v-model="form.hasPwd">开启会议密码</el-checkbox>
<el-input
style="width: 170px"
v-model="form.password"
v-if="form.hasPwd"
placeholder="请输入4-6位数字密码"
type="password"
suffix-icon="el-icon-lock"
size="small"
>
</el-input>
<el-checkbox style="display: block" v-model="form.auto_in_waiting_room">开启等候室</el-checkbox>
<el-checkbox style="display: block" v-model="form.allow_in_before_host"
>准许成员在主持人开始前进入会议</el-checkbox
>
<el-checkbox style="display: block" v-model="form.mute_enable_join">入会自动静音</el-checkbox>
<el-checkbox v-model="form.auto_record" @change="autoRecordChange">自动录制会议</el-checkbox>
<el-radio-group v-model="form.auto_record_type" v-if="form.auto_record">
<el-radio label="local">本地录制</el-radio>
<el-radio label="cloud">云录制</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="会议直播">
<el-checkbox v-model="form.enable_live">开启会议直播(用于分享给观看直播的用户)</el-checkbox>
</el-form-item>
<el-form-item label="直播主题" v-if="form.enable_live" :required="form.enable_live" prop="live_subject">
<el-input v-model="form.live_subject" size="small" />
</el-form-item>
<el-form-item label="直播简介" v-if="form.enable_live" :required="form.enable_live" prop="live_summary">
<el-input type="textarea" v-model="form.live_summary"></el-input>
</el-form-item>
<el-form-item label="直播设置" v-if="form.enable_live" style="margin-bottom: 0">
<el-checkbox style="width: 150px" v-model="form.enable_live_password">开启观看直播密码</el-checkbox>
<el-input
style="width: 170px"
v-model="form.live_password"
v-if="form.enable_live_password"
placeholder="请输入4-6位数字密码"
type="password"
suffix-icon="el-icon-lock"
size="small"
/>
</el-form-item>
<el-form-item label="" v-if="form.enable_live">
<el-checkbox v-model="form.enable_live_im">准许观众讨论</el-checkbox>
</el-form-item>
<el-form-item style="padding-left: 100px">
<el-button type="primary" @click="submitForm('ruleForm')" size="mini">立即创建</el-button>
<el-button @click="resetForm('ruleForm')" size="mini">重置</el-button>
</el-form-item>
</el-form>
</template>
<script>
import { timeTrans, dateFormat, getYMDByDate, getTimestampYMD, getCurHalfHour } from '@/utils/dateAlgs'
import { searchUserList } from '@api/common'
const DAY_TIMESTAMP = 8.64e7
export default {
data() {
const now = new Date()
const nowDate = getYMDByDate(now)
const startDateChecked = (rule, value, callback) => {
if (value) {
console.log(value)
const timestamp = Date.parse(value)
if (timestamp < Date.now() - DAY_TIMESTAMP) {
callback(new Error('开始时间必须大于当前时间'))
} else {
callback()
}
}
}
const endDateChecked = (rule, value, callback) => {
if (value) {
if (this.endTimestamp < this.startTimestamp) {
callback(new Error('结束时间必须大于开始时间'))
} else if (this.endTimestamp > this.startTimestamp + DAY_TIMESTAMP) {
callback(new Error('会议时间不能超过24小时'))
} else {
callback()
}
}
}
const validateErrMsg = (rule, value, callback) => {
// 当开启会议直播时,启用验证,处理callback
if (this.form.isLive) {
const errMsg = rule.field === 'liveTheme' ? '请输入直播主题' : '请输入直播简介'
callback(new Error(errMsg))
} else {
callback()
}
}
return {
timerClear: false,
time: '',
form: {
meetingType: 'tencent',
subject: '',
startDate: nowDate,
startTime: getCurHalfHour('start'),
endDate: nowDate,
endTime: getCurHalfHour('end'),
timezone: 'beijing',
meeting_type: 0,
recurring_rule: {
recurring_type: 0,
until_type: 0,
until_date: '',
until_count: 7
},
recurring_type: 0,
until_type: 0,
until_date: '',
until_count: 7,
hasPwd: false,
password: '',
settings: {
auto_in_waiting_room: false,
allow_in_before_host: true,
auto_record_type: 'cloud',
mute_enable_join: false
},
auto_in_waiting_room: false,
allow_in_before_host: false,
auto_record_type: 'cloud',
mute_enable_join: false,
auto_record: false,
enable_live: false,
live_config: {
live_subject: '',
live_summary: '',
enable_live_password: false,
live_password: '',
enable_live_im: false
},
live_subject: '',
live_summary: '',
enable_live_password: false,
live_password: '',
enable_live_im: false
},
userList: [],
searchUsersloading: false,
rules: {
meetingType: [{ required: true, message: '请选择会议类型', trigger: 'blur' }],
subject: [{ required: true, message: '请填写会议主题', trigger: 'blur' }],
startDate: [
{ type: 'date', required: true, message: '请选择开始日期', trigger: 'change' },
{ type: 'date', validator: startDateChecked, trigger: 'change' }
],
startTime: [{ required: true, message: '请选择开始时间', trigger: 'change' }],
endDate: [{ type: 'date', required: true, message: '请选择结束日期', trigger: 'change' }],
endTime: [
{ required: true, message: '请选择结束时间', trigger: 'change' },
{ validator: endDateChecked, trigger: 'change' }
],
moderator: [{ required: true, message: '请选择主持人', trigger: 'change' }],
liveTheme: [{ validator: validateErrMsg }],
liveDesc: [{ validator: validateErrMsg }]
},
startDateOptions: {
disabledDate(time) {
return time.getTime() < Date.now() - DAY_TIMESTAMP
}
},
startTimeOptions: {
start: getCurHalfHour('start'),
step: '00:30',
end: '23:30'
},
endTimeOptions: {
start: getCurHalfHour('end'),
step: '00:30',
end: '23:30'
},
monthMaxDay: 28,
_untilDateOptions: {
disabledDate: time => {
let flag = false
switch (this.form.recurring_type) {
case 0: {
break
}
case 1: {
if (time.getDay() === 5 || time.getDay() === 6) flag = true
break
}
case 2: {
const startDate = timeTrans(this.form.startDate)
if (startDate.getDay() !== time.getDay() || getTimestampYMD(time) < getTimestampYMD(startDate)) flag = true
break
}
case 3: {
const startDate = timeTrans(this.form.startDate)
const disabledDay = ((getTimestampYMD(time) - getTimestampYMD(startDate)) / (DAY_TIMESTAMP * 7)) % 2 !== 0
if (disabledDay || getTimestampYMD(time) < getTimestampYMD(startDate)) flag = true
break
}
case 4: {
const startDate = timeTrans(this.form.startDate)
const day = startDate.getDate()
const targetDay = time.getDate()
let disabledDay = false
if (day > 28) {
const year = time.getFullYear()
const month = time.getMonth() + 1
const targetMDays = new Date(year, month, 0).getDate()
if (targetDay !== targetMDays) disabledDay = true
} else if (startDate.getDate() !== targetDay) {
disabledDay = true
}
if (disabledDay || getTimestampYMD(time) < getTimestampYMD(startDate)) flag = true
break
}
}
return flag
}
}
}
},
computed: {
endDateOptions() {
const sDate = this.form.startDate
return {
disabledDate(time) {
return (
getTimestampYMD(time) < getTimestampYMD(sDate) ||
getTimestampYMD(time) > getTimestampYMD(sDate) + DAY_TIMESTAMP
)
}
}
},
untilDateOptions() {
const form = this.form
const type = form.recurring_type
const sDate = timeTrans(form.startDate)
// const eDate = timeTrans(form.endDate)
return {
disabledDate: time => {
let flag = false
if (getTimestampYMD(time) < getTimestampYMD(sDate)) {
flag = true
} else {
switch (type) {
case 0: {
break
}
case 1: {
if (time.getDay() === 5 || time.getDay() === 6) flag = true
break
}
case 2: {
if (sDate.getDay() !== time.getDay()) flag = true
break
}
case 3: {
const disabledDay = ((getTimestampYMD(time) - getTimestampYMD(sDate)) / (DAY_TIMESTAMP * 7)) % 2 !== 0
if (disabledDay) flag = true
break
}
case 4: {
const day = sDate.getDate()
const targetDay = time.getDate()
let disabledDay = false
if (day > 28) {
const year = time.getFullYear()
const month = time.getMonth() + 1
const targetMDays = new Date(year, month, 0).getDate()
if (targetDay !== targetMDays) disabledDay = true
} else if (sDate.getDate() !== targetDay) {
disabledDay = true
}
if (disabledDay) flag = true
break
}
}
}
return flag
}
}
}
},
watch: {
getCycleMeetingEndDate: {
handler: function (nv, ov) {
this.form.until_date = Date.parse(nv)
},
immediate: true
}
},
methods: {
startDateChange(val) {
this.form.endDate = val
const _startDate = timeTrans(this.form.startDate)
if (Date.parse(_startDate) > Date.now()) {
this.startTimeOptions = {
start: '00:00',
step: '00:30',
end: '23:30'
}
} else {
this.startTimeOptions = {
start: getCurHalfHour('start'),
step: '00:30',
end: '23:30'
}
}
if (this.showSchedule) {
this.fetchMeetingList()
}
},
startTimeChange(val) {
const { startDate, endDate } = this.form
const fullDate = this.getFullDateTime(startDate, val)
if (this.isSameDate(startDate, endDate)) {
const startTime = getCurHalfHour('end', fullDate)
this.form.endTime = startTime
this.endTimeOptions = {
start: startTime,
step: '00:30',
end: '23:30'
}
} else {
const endTime = getCurHalfHour('start', fullDate)
this.form.endTime = endTime
this.endTimeOptions = {
start: '00:00',
step: '00:30',
end: endTime
}
}
},
endDateChange() {
this.startTimeChange(this.form.startTime)
},
repaeatRateChange(val) {
if (val === 'everyworkday' && this.form.endType === 'endOneday') {
this.form.periodicTimes = 7
}
},
getFullDateTime(date, timeStr) {
const hmArr = timeStr.split(':')
const h = parseInt(hmArr[0])
const s = parseInt(hmArr[1])
return new Date(date.getFullYear(), date.getMonth(), date.getDate(), h, s, 0)
},
isSameDate(start, end) {
return dateFormat(start, '{y}-{m}-{d}') === dateFormat(end, '{y}-{m}-{d}')
},
autoRecordChange(val) {
this.auto_record_type = val ? 'cloud' : 'none'
},
copyText() {
const text = this.$refs.details.$el.innerText
this.copyFn(text)
},
copyMeetingLink() {
this.copyFn(this.details.join_url)
},
copyLiveLink() {
this.copyFn(this.details.live_config.live_addr)
},
copyFn(val) {
if (!val) return
const dom = document.createElement('textarea')
document.body.appendChild(dom)
dom.value = val
dom.select(); // 选择对象
document.execCommand('Copy');
this.$message({
message: '复制成功!',
type: 'success'
})
document.body.removeChild(dom)
},
joinMeeting() {
window.open(this.details.join_url, '_blank');
},
submitForm(formName) {
this.$refs[formName].validate(valid => {
if (valid) {
this.$message.success('验证通过')
} else {
return false
}
})
},
resetForm(formName) {
this.$refs[formName].resetFields()
},
fetchUserList(val) {
if (val) {
const params = {
nickname: val
}
this.searchUsersloading = true
searchUserList(params)
.then(res => {
this.searchUsersloading = false
if (res.data && Array.isArray(res.data.items)) {
this.userList = res.data.items
}
})
.catch(() => {})
}
}
}
}
</script>
<style scoped>
.el-form {
flex: 1;
max-width: 600px;
padding:20px 0 10px;
}
.line {
text-align: center;
}
</style>
\ No newline at end of file
<template>
<component v-bind:is="currentPage"></component>
</template>
<script>
import PageCreate from './page-create'
import PageAccountCreate from './page-account-create'
import PageUpdate from './page-update'
export default {
data () {
return {
currentPage: 'PageCreate'
}
},
components: { PageCreate, PageAccountCreate, PageUpdate },
watch: {
$route: {
handler: function (nv, ov) {
const query = this.$route.query
console.log(query)
if (query.type === '1') {
this.currentPage = 'PageAccountCreate'
} else if (query.type === '2') {
console.log('edit')
this.currentPage = 'PageUpdate'
} else {
this.currentPage = 'PageCreate'
}
},
immediate: true
}
}
}
</script>
\ No newline at end of file
<template>
<div>同一账号下创建</div>
</template>
<script>
export default ({
data () {
return {}
}
})
</script>
<style scoped>
</style>
\ No newline at end of file
<template>
<div class="create">
<div class="inner">
<meeting-form></meeting-form>
</div>
</div>
</template>
<script>
import MeetingForm from './components/MeetingForm'
export default ({
data () {
return {}
},
components: { MeetingForm }
})
</script>
<style scoped>
.create{
overflow-y: auto;
height: calc(100% - 52px);
}
.inner {
background: #fff;
margin: 0 15px;
border-radius: 4px;
padding-bottom:10px;
}
</style>
<template>
<div>修改</div>
</template>
<script>
export default {
data() {
return {
obj: {
timestamp: 1618998029,
nonce: 'rgHMrr7Bg',
signature: 'UG7wBenexQhiuD2wpCwuxkU0jqcj006d',
instanceid: 1,
userid: '6653195831513972736',
subject: 'sewe',
start_time: '2021-04-21 17:30:00',
end_time: '2021-04-21 18:00:00',
password: '',
meeting_type: 1,
recurring_rule: {
recurring_type: 0,
until_type: 1,
until_count: 2
},
settings: {
mute_enable_join: false,
auto_in_waiting_room: false,
allow_in_before_host: true,
auto_record_type: 'none'
},
enable_live: 0,
live_config: {
live_subject: '',
live_summary: '',
enable_live_password: false,
enable_live_im: false
},
managers: ['6775725014348988416'],
meeting_id: '8343776720283269132'
}
}
}
}
</script>
<style scoped>
</style>
\ No newline at end of file
......@@ -2,150 +2,250 @@
<div class="tx-meeting-container">
<div class="inner">
<el-form ref="ruleForm" :model="form" :rules="rules" label-width="120px">
<!-- <el-form-item label="会议选择" prop="meetingType">
<el-radio-group v-model="form.meetingType">
<el-radio label="tencent">腾讯</el-radio>
</el-radio-group>
</el-form-item> -->
<el-form-item label="会议主题" prop="theme">
<el-input v-model="form.theme" size="small" />
<el-form-item label="会议主题" prop="subject">
<el-input v-model="form.subject" size="small" />
</el-form-item>
<el-form-item label="开始时间" required>
<el-col :span="11">
<el-form-item prop="startDate">
<el-date-picker v-model="form.startDate" type="date" placeholder="选择日期" style="width: 100%;" size="small" :clearable="timerClear" :editable="timerClear" :picker-options="startDateOptions" @change="startDateChange" />
<el-date-picker
v-model="form.startDate"
type="date"
placeholder="选择日期"
style="width: 100%"
size="small"
:clearable="timerClear"
:editable="timerClear"
:picker-options="startDateOptions"
@change="startDateChange"
/>
</el-form-item>
</el-col>
<el-col :span="2" class="line">-</el-col>
<el-col :span="11">
<el-form-item prop="startTime">
<el-time-select v-model="form.startTime" style="width:100%;" :picker-options="startTimeOptions" placeholder="选择时间" size="small" :clearable="timerClear" :editable="timerClear" @change="startTimeChange" />
<el-time-select
v-model="form.startTime"
style="width: 100%"
:picker-options="startTimeOptions"
placeholder="选择时间"
size="small"
:clearable="timerClear"
:editable="timerClear"
@change="startTimeChange"
/>
</el-form-item>
</el-col>
</el-form-item>
<el-form-item label="结束时间" required>
<el-col :span="11">
<el-form-item prop="endDate">
<el-date-picker v-model="form.endDate" type="date" placeholder="选择日期" style="width: 100%;" size="small" :clearable="timerClear" :editable="timerClear" :picker-options="endDateOptions" @change="endDateChange" />
<el-date-picker
v-model="form.endDate"
type="date"
placeholder="选择日期"
style="width: 100%"
size="small"
:clearable="timerClear"
:editable="timerClear"
:picker-options="endDateOptions"
@change="endDateChange"
/>
</el-form-item>
</el-col>
<el-col :span="2" class="line">-</el-col>
<el-col :span="11">
<el-form-item prop="endTime">
<el-time-select v-model="form.endTime" style="width:100%;" :picker-options="endTimeOptions" placeholder="选择时间" size="small" :clearable="timerClear" :editable="timerClear"/>
<el-time-select
v-model="form.endTime"
style="width: 100%"
:picker-options="endTimeOptions"
placeholder="选择时间"
size="small"
:clearable="timerClear"
:editable="timerClear"
/>
</el-form-item>
</el-col>
</el-form-item>
<el-form-item label="时区" required>
<el-col :span="11">
<el-select style="width:100%" v-model="form.timezone" placeholder="选择时区" size="small">
<el-select style="width: 100%" v-model="form.timezone" placeholder="选择时区" size="small">
<el-option label="(GMT+8:00)中国标准时间-北京" value="beijing" />
</el-select>
</el-col>
</el-form-item>
<el-form-item label="周期会议">
<el-switch v-model="form.periodic" />
<el-switch v-model="form.meeting_type" :active-value="1" :inactive-value="0" />
</el-form-item>
<el-form-item label="重复频率" v-if="form.periodic" required>
<el-form-item label="重复频率" v-if="form.meeting_type" required>
<el-col :span="11">
<el-select style="width:100%" v-model="form.repeatRate" placeholder="选择重复频率" size="small" @change="repaeatRateChange">
<el-option label="每天" value="everyday" />
<el-option label="每个工作日" value="everyworkday" />
<el-option label="每周" value="everyweek" />
<el-option label="每两周" value="every2weeks" />
<el-option label="每月" value="everymonth" />
</el-select>
<el-select
style="width: 100%"
v-model="form.recurring_type"
placeholder="选择重复频率"
size="small"
@change="repaeatRateChange"
>
<el-option label="每天" :value="0" />
<el-option label="每个工作日" :value="1" />
<el-option label="每周" :value="2" />
<el-option label="每两周" :value="3" />
<el-option label="每月" :value="4" />
</el-select>
</el-col>
</el-form-item>
<el-form-item label="结束重复" v-if="form.periodic" required>
<el-form-item label="结束重复" v-if="form.meeting_type" required>
<el-col :span="11">
<el-select style="width:100%" v-model="form.endType" placeholder="选择时区" size="small">
<el-option label="结束于某天" value="endOneday" />
<el-option label="限制会议次数" value="limitTimes" />
<el-select style="width: 100%" v-model="form.until_type" placeholder="选择时区" size="small">
<el-option label="结束于某天" :value="0" />
<el-option label="限制会议次数" :value="1" />
</el-select>
</el-col>
<el-col :span="2" class="line">-</el-col>
<el-col :span="11">
<el-date-picker v-if="form.endType === 'endOneday'" v-model="getCycleMeetingEndDate" type="date" placeholder="选择结束日期" style="width: 100%;" size="small" :clearable="timerClear" :editable="timerClear" :picker-options="cycleMeetingEndDateOptions" />
<el-input-number v-else v-model="form.periodicTimes" :min="1" :max="50" size="small" @change="handleChange"></el-input-number>
<el-date-picker
v-if="form.until_type === 0"
v-model="getCycleMeetingEndDate"
type="date"
placeholder="选择结束日期"
style="width: 100%"
size="small"
:clearable="timerClear"
:editable="timerClear"
:picker-options="cycleMeetingEndDateOptions"
/>
<el-input-number v-else v-model="form.until_count" :min="1" :max="50" size="small"></el-input-number>
</el-col>
</el-form-item>
<el-form-item label="指定主持人">
<!-- <el-form-item label="指定主持人">
<el-col :span="11">
<el-select style="width:100%" v-model="form.moderator" placeholder="选择主持人" size="small">
<el-option label="张三" value="zhangsan" />
<el-option label="李四" value="lisi" />
<el-option :label="user.username" :value="user.id" v-for="user in userList" :key="user.id" />
</el-select>
</el-col>
</el-form-item>
</el-form-item> -->
<el-form-item label="指定会议管理员">
<el-col :span="11">
<el-select style="width:100%" v-model="form.administrators" placeholder="选择管理员" size="small" multiple>
<el-option label="张三" value="zhangsan" />
<el-option label="李四" value="lisi" />
<el-select
style="width: 100%"
v-model="form.managers"
placeholder="选择管理员"
size="small"
multiple
filterable
remote
:remote-method="fetchUserList"
:loading="searchUsersloading"
>
<el-option :label="user.nickname" :value="user.id" v-for="user in userList" :key="user.id" />
</el-select>
</el-col>
<el-col :span="13" style="color:#999;height:40px;position:relative;font-size:12px;line-height:18px;">
<span style="position:absolute;left:5px;top:50%;transform:translateY(-50%)">(会议管理员有修改会议,复制、取消会议等所有管理本次会议的权限)</span>
<el-col :span="13" style="color: #999; height: 40px; position: relative; font-size: 12px; line-height: 18px">
<span style="position: absolute; left: 5px; top: 50%; transform: translateY(-50%)"
>(会议管理员有修改会议,复制、取消会议等所有管理本次会议的权限)</span
>
</el-col>
</el-form-item>
<el-form-item label="会议设置">
<el-checkbox style="width:120px;" v-model="form.isSecret">开启会议密码</el-checkbox>
<el-input style="width:170px;" v-model="form.secret" v-if="form.isSecret" placeholder="请输入4-6位数字密码" type="password" suffix-icon="el-icon-lock" size="small">
<el-checkbox style="width: 120px" v-model="form.hasPwd">开启会议密码</el-checkbox>
<el-input
style="width: 170px"
v-model="form.password"
v-if="form.hasPwd"
placeholder="请输入4-6位数字密码"
type="password"
suffix-icon="el-icon-lock"
size="small"
>
</el-input>
<el-checkbox style="display:block;" v-model="form.openWaitingRoom">开启等候室</el-checkbox>
<el-checkbox style="display:block;" v-model="form.joinAdvance">准许成员在主持人开始前进入会议</el-checkbox>
<el-checkbox style="display:block;" v-model="form.mute">入会自动静音</el-checkbox>
<el-checkbox style="display:block;" v-model="form.recordVideo">自动录制会议</el-checkbox>
<el-checkbox style="display: block" v-model="form.auto_in_waiting_room">开启等候室</el-checkbox>
<el-checkbox style="display: block" v-model="form.allow_in_before_host"
>准许成员在主持人开始前进入会议</el-checkbox
>
<el-checkbox style="display: block" v-model="form.mute_enable_join">入会自动静音</el-checkbox>
<el-checkbox v-model="form.auto_record" @change="autoRecordChange">自动录制会议</el-checkbox>
<el-radio-group v-model="form.auto_record_type" v-if="form.auto_record">
<el-radio label="local">本地录制</el-radio>
<el-radio label="cloud">云录制</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="会议直播">
<el-checkbox v-model="form.isLive">开启会议直播(用于分享给观看直播的用户)</el-checkbox>
<el-checkbox v-model="form.enable_live">开启会议直播(用于分享给观看直播的用户)</el-checkbox>
</el-form-item>
<el-form-item label="直播主题" v-if="form.isLive" :required="form.isLive" prop="liveTheme">
<el-input v-model="form.liveTheme" size="small" />
<el-form-item label="直播主题" v-if="form.enable_live" :required="form.enable_live" prop="live_subject">
<el-input v-model="form.live_subject" size="small" />
</el-form-item>
<el-form-item label="直播简介" v-if="form.isLive" :required="form.isLive" prop="liveDesc">
<el-input type="textarea" v-model="form.liveDesc"></el-input>
<el-form-item label="直播简介" v-if="form.enable_live" :required="form.enable_live" prop="live_summary">
<el-input type="textarea" v-model="form.live_summary"></el-input>
</el-form-item>
<el-form-item label="直播设置" v-if="form.isLive" >
<el-checkbox style="display:block;" v-model="form.isLiveSecret">开启观看直播密码</el-checkbox>
<el-checkbox v-model="form.permitComment">准许观众讨论</el-checkbox>
<el-form-item label="直播设置" v-if="form.enable_live" style="margin-bottom: 0">
<el-checkbox style="width: 150px" v-model="form.enable_live_password">开启观看直播密码</el-checkbox>
<el-input
style="width: 170px"
v-model="form.live_password"
v-if="form.enable_live_password"
placeholder="请输入4-6位数字密码"
type="password"
suffix-icon="el-icon-lock"
size="small"
/>
</el-form-item>
<el-form-item style="padding-left:100px;">
<el-button type="primary" @click="submitForm('ruleForm')" size="mini">立即创建</el-button>
<el-form-item label="" v-if="form.enable_live">
<el-checkbox v-model="form.enable_live_im">准许观众讨论</el-checkbox>
</el-form-item>
<el-form-item style="padding-left: 100px">
<el-button type="primary" @click="submitForm('ruleForm')" size="mini">{{isUpdate ? '修改会议' : '立即创建'}}</el-button>
<el-button @click="resetForm('ruleForm')" size="mini">重置</el-button>
</el-form-item>
</el-form>
<div class="right-container" v-if="showSchedule">
<div class="title">{{form.startDate | timeFormat}} {{form.startDate | timeFormat('星期{a}')}}</div>
<div class="title">{{ form.startDate | timeFormat }} {{ form.startDate | timeFormat('星期{a}') }}</div>
<schedule :options="options" :data="schedule" :date="form.startDate" />
<div class="pre-time-range" :style="{top: getTop, height: getHeight}"></div>
<div class="pre-time-range" :style="{ top: getTop, height: getHeight }"></div>
</div>
</div>
<meeting-success-dialog :dialogVisible.sync="dialogVisible" :details="details"/>
</div>
</template>
<script>
import Schedule from '@/components/Schedule'
import { timeTrans, dateFormat, getTimestampYMD, computedDateByRateTimes, computedTimesByRateDate, getCurHalfHour, isSameDate } from '@/utils/dateAlgs'
import MeetingSuccessDialog from '@/components/MeetingSuccessDialog/index'
import {
timeTrans,
dateFormat,
getYMDByDate,
getTimestampYMD,
computedDateByRateTimes,
computedTimesByRateDate,
getCurHalfHour,
isSameDate
} from '@/utils/dateAlgs'
import { searchUserList, createMeeting, operateLog, getMeetingDetails, getNonpagedMeetingList, updateMeeting } from '@api/common'
const DAY_TIMESTAMP = 8.64e7
export default {
data () {
data() {
const now = new Date()
const nowDate = new Date(now.getFullYear(), now.getMonth(), now.getDate())
const nowDate = getYMDByDate(now)
const startDateChecked = (rule, value, callback) => {
if (value) {
const timestamp = Date.parse(value);
console.log(value)
const timestamp = Date.parse(value)
if (timestamp < Date.now() - DAY_TIMESTAMP) {
callback(new Error('开始时间必须大于当前时间'));
callback(new Error('开始时间必须大于当前时间'))
} else {
callback()
}
}
}
const endDateChecked = (rule, value, callback) => {
if (value) {
if (this.endTimestamp < this.startTimestamp) {
callback(new Error('结束时间必须大于开始时间'));
callback(new Error('结束时间必须大于开始时间'))
} else if (this.endTimestamp > this.startTimestamp + DAY_TIMESTAMP) {
callback(new Error('会议时间不能超过24小时'));
callback(new Error('会议时间不能超过24小时'))
} else {
callback()
}
}
}
......@@ -153,50 +253,47 @@ export default {
// 当开启会议直播时,启用验证,处理callback
if (this.form.isLive) {
const errMsg = rule.field === 'liveTheme' ? '请输入直播主题' : '请输入直播简介'
callback(new Error(errMsg));
callback(new Error(errMsg))
} else {
callback();
callback()
}
};
}
return {
tabActive: 'tx',
timerClear: false,
time: '',
form: {
meetingType: 'tencent',
theme: '',
subject: '',
startDate: nowDate,
startTime: getCurHalfHour('start'),
endDate: nowDate,
endTime: getCurHalfHour('end'),
timezone: 'beijing',
periodic: true,
repeatRate: 'everyday',
endType: 'endOneday',
periodicEndDate: '',
periodicTimes: 7,
isSecret: false,
secret: '',
openWaitingRoom: false,
joinAdvance: false,
mute: false,
recordVideo: false,
isLive: false,
liveTheme: '',
liveDesc: '',
isLiveSecret: false,
permitComment: false
meeting_type: 0,
recurring_type: 0,
until_type: 0,
until_date: '',
until_count: 7,
hasPwd: false,
password: '',
auto_in_waiting_room: false,
allow_in_before_host: true,
auto_record_type: 'none',
mute_enable_join: false,
auto_record: false,
enable_live: false,
live_subject: '',
live_summary: '',
enable_live_password: false,
live_password: '',
enable_live_im: false
},
rules: {
meetingType: [{ required: true, message: '请选择会议类型', trigger: 'blur' }],
theme: [{ required: true, message: '请填写会议主题', trigger: 'blur' }],
subject: [{ required: true, message: '请填写会议主题', trigger: 'blur' }],
startDate: [
{ type: 'date', required: true, message: '请选择开始日期', trigger: 'change' },
{ type: 'date', validator: startDateChecked, trigger: 'change' }
],
startTime: [
{ required: true, message: '请选择开始时间', trigger: 'change' }
],
startTime: [{ required: true, message: '请选择开始时间', trigger: 'change' }],
endDate: [{ type: 'date', required: true, message: '请选择结束日期', trigger: 'change' }],
endTime: [
{ required: true, message: '请选择结束时间', trigger: 'change' },
......@@ -208,7 +305,7 @@ export default {
},
startDateOptions: {
disabledDate(time) {
return time.getTime() < Date.now() - DAY_TIMESTAMP;
return time.getTime() < Date.now() - DAY_TIMESTAMP
}
},
startTimeOptions: {
......@@ -223,36 +320,36 @@ export default {
},
monthMaxDay: 28,
cycleMeetingEndDateOptions: {
disabledDate: (time) => {
disabledDate: time => {
let flag = false
switch (this.form.repeatRate) {
case 'everyday': {
switch (this.form.recurring_type) {
case 0: {
break
}
case 'everyworkday': {
case 1: {
if (time.getDay() === 5 || time.getDay() === 6) flag = true
break
}
case 'everyweek': {
case 2: {
const startDate = timeTrans(this.form.startDate)
if (startDate.getDay() !== time.getDay() || getTimestampYMD(time) < getTimestampYMD(startDate)) flag = true
break
}
case 'every2weeks': {
case 3: {
const startDate = timeTrans(this.form.startDate)
const disabledDay = ((getTimestampYMD(time) - getTimestampYMD(startDate)) / (DAY_TIMESTAMP * 7)) % 2 !== 0
if (disabledDay || getTimestampYMD(time) < getTimestampYMD(startDate)) flag = true
break
}
case 'everymonth': {
case 4: {
const startDate = timeTrans(this.form.startDate)
const day = startDate.getDate()
const targetDay = time.getDate()
let disabledDay = false
if (day > 28) {
const year = time.getFullYear();
const month = time.getMonth() + 1;
const targetMDays = new Date(year, month, 0).getDate();
const year = time.getFullYear()
const month = time.getMonth() + 1
const targetMDays = new Date(year, month, 0).getDate()
if (targetDay !== targetMDays) disabledDay = true
} else if (startDate.getDate() !== targetDay) {
disabledDay = true
......@@ -264,6 +361,8 @@ export default {
return flag
}
},
userList: [],
searchUsersloading: false,
showSchedule: false,
options: {
multi: false, // 是否为多日程
......@@ -272,21 +371,27 @@ export default {
step: 60, // 只接收15, 30, 60三种步伐
lineHeight: 40, // init number 时间线间的高度
nowBeforeDisabled: true,
disabledNew: true,
readonly: true,
popoverPos: 'bottom'
},
schedule: {
id: 'live-1',
events: [
]
}
userid: '',
events: []
},
dialogVisible: false,
details: {},
isUpdate: false,
userid: ''
}
},
computed: {
user() {
return this.$store.getters.user
},
getTop() {
const timeRange = this.startTimestamp - this.startDotTimestamp
const top = timeRange / ((60 * 1000 * this.options.step) / this.options.lineHeight)
return (top + 56) + 'px'
return top + 56 + 'px'
},
getHeight() {
const start = timeTrans(this.startTimestamp)
......@@ -296,7 +401,7 @@ export default {
}
const timeRange = end.getTime() - start.getTime()
const h = timeRange / ((60 * 1000 * this.options.step) / this.options.lineHeight)
return (h - 2) + 'px'
return h - 2 + 'px'
},
startDotTimestamp() {
const date = this.form.startDate
......@@ -310,20 +415,23 @@ export default {
return this.getFullDateTime(this.form.endDate, this.form.endTime).getTime()
},
getCycleMeetingEndDate: {
get: function() {
get: function () {
const startDate = this.form.startDate ? this.form.startDate : Date.now()
return computedDateByRateTimes(startDate, this.form.periodicTimes, this.form.repeatRate)
return computedDateByRateTimes(startDate, this.form.until_count, this.form.recurring_type)
},
set: function (newValue) {
const times = computedTimesByRateDate(this.form.startDate, newValue, this.form.repeatRate)
this.form.periodicTimes = times
const times = computedTimesByRateDate(this.form.startDate, newValue, this.form.recurring_type)
this.form.until_count = times
}
},
endDateOptions() {
const _startDate = this.form.startDate;
const _startDate = this.form.startDate
return {
disabledDate(time) {
return getTimestampYMD(time) < getTimestampYMD(_startDate) || getTimestampYMD(time) > getTimestampYMD(_startDate) + DAY_TIMESTAMP;
return (
getTimestampYMD(time) < getTimestampYMD(_startDate) ||
getTimestampYMD(time) > getTimestampYMD(_startDate) + DAY_TIMESTAMP
)
}
}
}
......@@ -334,27 +442,47 @@ export default {
return dateFormat(val, fmt)
}
},
components: { Schedule },
components: { Schedule, MeetingSuccessDialog },
created() {
const type = this.$route.query.type
switch (type) {
case '1':
this.showSchedule = true
}
console.log(this.$route.query)
// this.getUserList()
},
watch: {
getCycleMeetingEndDate: {
handler: function(nv, ov) {
this.form.periodicEndDate = Date.parse(nv)
handler: function (nv, ov) {
this.form.until_date = Date.parse(nv)
},
immediate: true
},
$route: {
handler: function (nv, ov) {
const query = this.$route.query
console.log(query)
if (query.type === '1') {
this.showSchedule = true
this.form.startDate = getYMDByDate(query.start)
this.form.startTime = dateFormat(query.start, '{h}:{i}')
this.form.endDate = getYMDByDate(query.end)
this.form.endTime = dateFormat(query.end, '{h}:{i}')
this.schedule.userid = query.account
this.fetchMeetingList()
} else if (query.type === '2') {
const params = {
meeting_id: query.meeting_id,
sub_meeting_id: query.sub_meeting_id
}
this.isUpdate = true
this.getDetailsData(params)
} else {
this.showSchedule = false
}
},
immediate: true
}
},
methods: {
startDateChange(val) {
this.form.endDate = val;
const _startDate = timeTrans(this.form.startDate);
this.form.endDate = val
const _startDate = timeTrans(this.form.startDate)
if (Date.parse(_startDate) > Date.now()) {
this.startTimeOptions = {
start: '00:00',
......@@ -368,6 +496,9 @@ export default {
end: '23:30'
}
}
if (this.showSchedule) {
this.fetchMeetingList()
}
},
startTimeChange(val) {
const { startDate, endDate } = this.form
......@@ -382,7 +513,7 @@ export default {
}
} else {
const endTime = getCurHalfHour('start', fullDate)
this.form.endTime = endTime;
this.form.endTime = endTime
this.endTimeOptions = {
start: '00:00',
step: '00:30',
......@@ -395,78 +526,305 @@ export default {
},
repaeatRateChange(val) {
if (val === 'everyworkday' && this.form.endType === 'endOneday') {
this.form.periodicTimes = 7;
this.form.periodicTimes = 7
}
},
getFullDateTime(date, timeStr) {
const hmArr = timeStr.split(':');
const h = parseInt(hmArr[0]);
const s = parseInt(hmArr[1]);
const hmArr = timeStr.split(':')
const h = parseInt(hmArr[0])
const s = parseInt(hmArr[1])
return new Date(date.getFullYear(), date.getMonth(), date.getDate(), h, s, 0)
},
isSameDate(start, end) {
return dateFormat(start, '{y}-{m}-{d}') === dateFormat(end, '{y}-{m}-{d}')
},
autoRecordChange(val) {
this.auto_record_type = val ? 'cloud' : 'none'
},
copyText() {
const text = this.$refs.details.$el.innerText
this.copyFn(text)
},
copyMeetingLink() {
this.copyFn(this.details.join_url)
},
copyLiveLink() {
this.copyFn(this.details.live_config.live_addr)
},
copyFn(val) {
if (!val) return
const dom = document.createElement('textarea')
document.body.appendChild(dom)
dom.value = val
dom.select(); // 选择对象
document.execCommand('Copy');
this.$message({
message: '复制成功!',
type: 'success'
})
document.body.removeChild(dom)
},
joinMeeting() {
window.open(this.details.join_url, '_blank');
},
submitForm(formName) {
this.$refs[formName].validate((valid) => {
this.$refs[formName].validate(valid => {
if (valid) {
console.log(valid);
if (this.isUpdate) {
this.fetchUpdateMeeting()
} else {
this.fetchCreateMeeting()
}
} else {
console.log('error submit!!');
return false;
return false
}
});
})
},
resetForm(formName) {
this.$refs[formName].resetFields();
this.$refs[formName].resetFields()
},
handleChange(val) {
console.log(val)
async getDetailsData(params) {
const details = await this.fetchMeetingDetails(params)
this.details = details
const start = timeTrans(details.start_time)
const end = timeTrans(details.end_time)
this.userid = details.userid
this.form.subject = details.subject
this.form.startDate = getYMDByDate(start)
this.form.startTime = dateFormat(start, '{h}:{i}')
this.form.endDate = getYMDByDate(end)
this.form.endTime = dateFormat(end, '{h}:{i}')
this.form.meeting_type = details.meeting_type
if (details.meeting_type === 1) {
const recurringRule = details.recurring_rule
this.form.recurring_type = recurringRule.recurring_type
this.form.until_type = recurringRule.until_type
if (recurringRule.until_type === 0) {
this.form.until_date = timeTrans(recurringRule.until_date)
} else {
this.form.until_count = recurringRule.until_count
}
}
if (details.password) {
this.form.password = details.password
this.hasPwd = true
}
const setting = details.settings
this.form.auto_in_waiting_room = setting.auto_in_waiting_room
this.form.allow_in_before_host = setting.allow_in_before_host
this.form.auto_record_type = setting.auto_record_type
if (setting.auto_record_type !== 'none') {
this.form.auto_record = true
}
this.form.mute_enable_join = setting.mute_enable_join
this.form.enable_live = details.enable_live
if (details.enable_live === 1) {
const liveConfig = details.live_config
this.form.live_subject = liveConfig.live_subject
this.form.live_summary = liveConfig.live_summary
this.form.enable_live_password = liveConfig.enable_live_password
this.form.live_password = liveConfig.live_password
this.form.enable_live_im = liveConfig.enable_live_im
}
},
async showMeetingDetails(obj) {
const loading = this.$loading({
lock: true,
text: '获取腾讯会议详情,请稍后...',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)'
});
const params = {
meeting_id: obj.meeting_id,
sub_meeting_id: obj.sub_meetings[0].sub_meeting_id
}
const details = await this.fetchMeetingDetails(params)
loading.close()
this.details = details
this.dialogVisible = true
},
fetchMeetingList() {
const date = this.form.startDate
const start = dateFormat(date)
const end = dateFormat(new Date(date.getFullYear(), date.getMonth(), date.getDate() + 1))
const params = {
userid: this.schedule.userid,
start_time: start,
end_time: end
}
getNonpagedMeetingList(params).then((res) => {
if (res.code === 0 && res.data && res.data.list) {
console.log(res.data.list)
this.schedule.events = res.data.list
} else {
}
}).catch()
},
fetchUserList(val) {
if (val) {
const params = {
nickname: val
}
this.searchUsersloading = true
searchUserList(params)
.then(res => {
this.searchUsersloading = false
if (res.data && Array.isArray(res.data.items)) {
this.userList = res.data.items
}
})
.catch(() => {})
}
},
getSubmitParams() {
const form = this.form
const params = {
instanceid: 1,
userid: this.showSchedule ? this.schedule.userid : undefined,
subject: form.subject,
start_time: dateFormat(this.startTimestamp),
end_time: dateFormat(this.endTimestamp),
password: form.password,
meeting_type: form.meeting_type,
recurring_rule: {
recurring_type: form.recurring_type,
until_type: form.until_type,
until_date: form.until_type ? undefined : parseInt(form.until_date / 1000),
until_count: form.until_type ? form.until_count : undefined
},
settings: {
mute_enable_join: form.mute_enable_join,
auto_in_waiting_room: form.auto_in_waiting_room,
allow_in_before_host: form.allow_in_before_host,
auto_record_type: form.auto_record ? form.auto_record_type : 'none'
},
enable_live: form.enable_live,
live_config: {
live_subject: form.live_subject,
live_summary: form.live_summary,
enable_live_password: form.enable_live_password,
live_password: form.enable_live_password ? form.live_password : undefined,
enable_live_im: form.enable_live_im
},
managers: form.managers.length > 0 ? form.managers : [this.user.id]
}
return params
},
fetchUpdateMeeting() {
const params = this.getSubmitParams()
params.meeting_id = this.$route.query.meeting_id
params.userid = this.userid
const loading = this.$loading({
lock: true,
text: '修改腾讯会议中,请稍后...',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)'
})
console.log(params)
updateMeeting(params).then(res => {
loading.close()
if (res.code === 0 && res.data.status) {
operateLog({ type: `修改会议,被修改会议meeting_code:${res.data.meeting_code}`, user: this.user })
this.$message.success('修改腾讯会议成功')
this.dialogVisible = true
} else {
this.$message.error(res.message || res.msg || '创建腾讯会议失败')
}
})
},
fetchCreateMeeting() {
const params = this.getSubmitParams()
const loading = this.$loading({
lock: true,
text: '创建腾讯会议中,请稍后...',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)'
})
createMeeting(params).then(res => {
loading.close()
if (res.code === 0 && res.data.id) {
operateLog({ type: `创建会议,被创建会议meeting_code:${res.data.meeting_code}`, user: this.user })
this.$message.success('创建腾讯会议成功')
this.showMeetingDetails(res.data)
} else {
this.$message.error(res.message || res.msg || '创建腾讯会议失败')
}
})
},
fetchMeetingDetails(params) {
return new Promise((resolve, reject) => {
getMeetingDetails(params).then(res => {
if (res.code === 0 && res.data.id) {
resolve(res.data)
} else {
reject(res)
}
}).catch((err) => reject(err))
})
}
}
}
</script>
<style scoped>
.tx-meeting-container{
overflow-y:auto;
height:calc(100% - 52px);
.tx-meeting-container {
overflow-y: auto;
height: calc(100% - 52px);
}
.inner{
display:flex;
background:#fff;
margin:0 15px;
border-radius:4px;
.inner {
display: flex;
background: #fff;
margin: 0 15px;
border-radius: 4px;
padding-bottom:10px;
}
.el-form{
.el-form {
flex: 1;
max-width:600px;
padding-bottom:30px;
max-width: 600px;
padding:20px 0 10px;
}
.line{
text-align:center;
.line {
text-align: center;
}
.right-container{
position:relative;
width:45%;
box-sizing:border-box;
.right-container {
position: relative;
width: 45%;
box-sizing: border-box;
padding-left: 20px;
}
.right-container .title{
position:absolute;
left:0;
top:0;
width:100%;
line-height:50px;
font-size:16px;
text-align:center;
.right-container .title {
position: absolute;
left: 0;
top: 0;
width: 100%;
line-height: 50px;
font-size: 16px;
text-align: center;
}
.pre-time-range{
position:absolute;
left:70px;
width:calc(100% - 70px);
background:#52b837;
.pre-time-range {
position: absolute;
left: 70px;
width: calc(100% - 70px);
background: #52b837;
}
.right-container .el-scrollbar ::v-deep.el-scrollbar__wrap{
.right-container .el-scrollbar ::v-deep.el-scrollbar__wrap {
/* overflow:hidden; */
}
.tx-meeting-container ::v-deep.el-dialog__header{
padding-top:14px;
}
.tx-meeting-container ::v-deep.el-dialog__headerbtn{
top:12px;
right:12px;
}
.tx-meeting-container ::v-deep.el-dialog__body{
padding:10px 0;
margin:0 20px;
border: 1px solid #DBDBDB;
}
.tx-meeting-container ::v-deep.el-dialog__footer{
padding-bottom:16px;
}
.tx-meeting-container ::v-deep.el-dialog .el-form-item{
margin:0;
}
</style>
......@@ -10,23 +10,22 @@
</el-col>
<el-col :span="8">
<label>会议主题</label>
<el-input placeholder="请输入会议主题" v-model="filter.meetingTitle" size="mini" clearable></el-input>
<el-input placeholder="请输入会议主题" v-model="filter.subject" size="mini" clearable></el-input>
</el-col>
<el-col :span="8">
<label>会议状态</label>
<el-select v-model="filter.status" placeholder="请选择" size="mini" clearable>
<el-option label="进行中" value="1" />
<el-option label="未开始" value="2" />
<el-option label="已完成" value="3" />
<el-option label="进行中" :value="1" />
<el-option label="未开始" :value="0" />
<el-option label="已完成" :value="2" />
</el-select>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<label>会议类型</label>
<el-select v-model="filter.meetingType" placeholder="请选择" size="mini" clearable>
<el-option label="腾讯" value="1" />
<el-option label="cc" value="2" />
<label>会议创建人</label>
<el-select v-model="filter.userid" placeholder="搜索用户" size="mini" filterable remote :remote-method="fetchUserList" :loading="searchUsersloading">
<el-option :label="user.nickname" :value="user.id" v-for="user in userList" :key="user.id" />
</el-select>
</el-col>
<el-col :span="11">
......@@ -34,61 +33,67 @@
<el-date-picker v-model="filter.timeRange" type="datetimerange" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" size="mini" clearable></el-date-picker>
</el-col>
<el-col :span="5">
<el-button type="primary" icon="el-icon-search" size="mini">查询</el-button>
<el-button type="primary" icon="el-icon-search" size="mini" @click="fetchMeetingList">查询</el-button>
<el-button icon="el-icon-refresh-left" size="mini" @click="reset">重置</el-button>
</el-col>
</el-row>
</div>
<el-table :data="listData" style="width: 100%" height="calc(100% - 116px)">
<el-table-column label="会议时间" min-width="180">
<el-table-column label="会议时间" min-width="160">
<template slot-scope="scope">
<p style="color:#AEAEAE;">
<span style="font-size:18px;color:#606266;">{{ scope.row.date | dateFormat('{d}')}}</span>
{{ scope.row.date | dateFormat('{m}月')}} {{ scope.row.date | dateFormat('周{a}')}}
<span style="font-size:16px;color:#606266;">{{ scope.row.date | dateFormat('{h}:{i}')}}</span>
<p style="color: #aeaeae">
<span style="font-size: 18px; color: #606266">{{ scope.row.start_time | dateFormat('{d}') }}</span>
{{ scope.row.start_time | dateFormat('{m}月') }} {{ scope.row.start_time | dateFormat('周{a}') }}
<span style="font-size: 16px; color: #606266">{{ scope.row.start_time | dateFormat('{h}:{i}') }}</span>
</p>
<p style="color:#AEAEAE;">
<span style="font-size:18px;color:#606266;">{{ scope.row.endDate | dateFormat('{d}')}}</span>
{{ scope.row.endDate | dateFormat('{m}月')}} {{ scope.row.endDate | dateFormat('周{a}')}}
<span style="font-size:16px;color:#606266;">{{ scope.row.endDate | dateFormat('{h}:{i}')}}</span>
<p style="color: #aeaeae">
<span style="font-size: 18px; color: #606266">{{ scope.row.end_time | dateFormat('{d}') }}</span>
{{ scope.row.end_time | dateFormat('{m}月') }} {{ scope.row.end_time | dateFormat('周{a}') }}
<span style="font-size: 16px; color: #606266">{{ scope.row.end_time | dateFormat('{h}:{i}') }}</span>
</p>
</template>
</el-table-column>
<el-table-column label="会议主题" min-width="170">
<el-table-column label="会议主题" min-width="180">
<template slot-scope="scope">
<el-popover trigger="hover" placement="top" width="240">
<p>{{ scope.row.title }}</p>
<p>{{ scope.row.subject }}</p>
<div slot="reference" class="name-wrapper">
<p style="display:flex;">
<span style="flex:1;display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden;">{{ scope.row.title }}</span>
<span v-if="scope.row.isCycle" style="color:#409DFF;width:40px;">(周期)</span>
<p style="display: flex">
<span
style="
flex: 1;
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
"
>{{ scope.row.subject }}</span
>
<span v-if="scope.row.meeting_type === 1" style="color: #409dff; width: 40px">(周期)</span>
</p>
</div>
</el-popover>
</template>
</el-table-column>
<el-table-column prop="resource" label="会议来源" min-width="80"></el-table-column>
<!-- <el-table-column prop="resource" label="会议来源" width="80"></el-table-column> -->
<el-table-column prop="resource" label="会议状态" min-width="80">
<template slot-scope="scope">
<p :class="{'status-start': scope.row.status === 1, 'status-notstarted': scope.row.status === 2, 'status-end': scope.row.status === 3}">
<p
:class="{
'status-start': scope.row.status === 1,
'status-notstarted': scope.row.status === 0,
'status-end': scope.row.status === 2
}"
>
<i></i>
<span style="margin-left: 10px">{{ scope.row.status | statusFilter}}</span>
<span style="margin-left: 10px">{{ scope.row.status | statusFilter }}</span>
</p>
</template>
</el-table-column>
<el-table-column prop="creator" label="创建人" min-width="80"></el-table-column>
<el-table-column label="操作" min-width="240">
<el-table-column prop="sso_user.nickname" label="创建人" min-width="100"></el-table-column>
<el-table-column label="操作" width="240">
<template slot-scope="scope">
<p>
<el-button @click="joinMeeting(scope.row)" type="text" size="small">进入会议</el-button>
<el-button type="text" size="small">观看会议直播</el-button>
<el-button type="text" size="small">复制邀请</el-button>
</p>
<el-button type="text" size="small">查看</el-button>
<el-button type="text" size="small">修改</el-button>
<el-button type="text" size="small">取消</el-button>
<el-button type="text" size="small">终止</el-button>
<el-button type="text" size="small">删除</el-button>
<table-handles :rowData="scope.row" @refresh="fetchMeetingList"/>
</template>
</el-table-column>
</el-table>
......@@ -97,51 +102,31 @@
</div>
</template>
<script>
import TableHandles from '@/components/TableHandles/index.vue'
import { dateFormat } from '@/utils/dateAlgs'
import { searchUserList, getMeetingList } from '@api/common'
import { mapGetters } from 'vuex'
export default {
data() {
return {
filter: {
meetingId: '',
meetingTitle: '',
subject: '',
status: '',
meetingType: '',
userid: '',
timeRange: ''
},
listData: [
{
date: new Date(2021, 3, 7, 10, 30, 0).getTime(),
endDate: new Date(2021, 3, 8, 8, 0, 0).getTime(),
title: 'CIIS直播课CIIS直播课CIIS直播课CIIS直播课CIIS直播课CIIS直播课CIIS直播课CIIS直播课CIIS直播课CIIS直播课CIIS直播课',
isCycle: false,
resource: '腾讯',
status: 1,
creator: '张三丰'
},
{
date: new Date(2021, 10, 7).getTime(),
endDate: new Date(2021, 10, 8).getTime(),
title: '索菲亚直播索菲亚直播索菲亚直播索菲亚直播索菲亚直播索菲亚直播索菲亚直播索菲亚直播索菲亚直播',
isCycle: true,
resource: '腾讯',
status: 2,
creator: '黄飞鸿'
},
{
date: new Date(2021, 10, 7).getTime(),
endDate: new Date(2021, 10, 8).getTime(),
title: '索菲亚直播索菲亚直播',
isCycle: false,
resource: '腾讯',
status: 3,
creator: '楚留香'
}
],
searchUsersloading: false,
userList: [],
listData: [],
curPage: 1,
pageSize: 20,
total: 200
}
},
computed: {
...mapGetters(['user'])
},
filters: {
dateFormat (value, fmt) {
return dateFormat(value, fmt)
......@@ -155,23 +140,63 @@ export default {
case 2:
result = '已完成'
break
case 3:
case 0:
result = '未开始'
break
}
return result
}
},
components: { TableHandles },
created() {
this.fetchMeetingList()
},
methods: {
reset() {
// this.filter
Object.keys(this.filter).map(key => { this.filter[key] = '' })
this.fetchMeetingList()
},
pageChange() {
this.fetchMeetingList()
},
joinMeeting(data) {
console.log(data)
fetchMeetingList() {
const filter = this.filter
let start, endPlus1
if (filter.length > 0) {
start = dateFormat(filter.timeRange[0])
const end = filter.timeRange[1]
endPlus1 = dateFormat(new Date(end.getFullYear(), end.getMonth(), end.getDate() + 1))
}
const params = {
page: this.curPage,
limit: this.pageSize,
sso_id: filter.userid ? filter.userid : undefined,
status: filter.status ? filter.status : undefined,
meeting_id: filter.meetingId ? filter.meetingId : undefined,
subject: filter.subject ? filter.subject : undefined,
start_time: start,
end_time: endPlus1
}
getMeetingList(params).then((res) => {
if (res.code === 0 && res.data.data) {
this.listData = res.data.data
this.total = res.data.total
}
})
},
pageChange(val) {
console.log(val)
fetchUserList(val) {
if (val) {
const params = {
nickname: val
}
this.searchUsersloading = true;
searchUserList(params).then((res) => {
this.searchUsersloading = false;
if (res.data && Array.isArray(res.data.items)) {
this.userList = res.data.items
}
}).catch(() => {})
}
}
}
}
......
<template>
<div class="account">
<h5>账号管理 <el-button style="float:right;margin:12px 30px 0 0" size="mini" type="primary" plain @click="dialogVisible = 'add'">添加账号</el-button></h5>
<h5>账号管理 <el-button style="float:right;margin:12px 30px 0 0" size="mini" type="primary" plain @click="handleAdd" v-if="isSuperAdmin">添加账号</el-button></h5>
<div class="inner">
<el-table :data="listData" style="width: 100%" height="calc(100% - 32px)">
<el-table-column prop="id" label="ID" min-width="120"></el-table-column>
<el-table-column prop="name" label="名称" min-width="120"></el-table-column>
<el-table-column prop="mobile" label="手机号码" min-width="120"></el-table-column>
<el-table-column prop="email" label="邮箱" min-width="120"></el-table-column>
<el-table-column label="操作" min-width="140">
<el-table-column prop="userid" label="ID" min-width="120"></el-table-column>
<el-table-column prop="username" label="名称" min-width="120"></el-table-column>
<el-table-column prop="phone" label="手机号码" min-width="120"></el-table-column>
<el-table-column prop="email" label="邮箱" min-width="140"></el-table-column>
<el-table-column label="操作" min-width="60">
<template slot-scope="scope">
<el-button type="text" size="small" @click="edit(scope.row)">编辑</el-button>
<el-button type="text" size="small" @click="dialogVisible = 'delete'">删除</el-button>
<el-button type="text" size="small" @click="handleEdit(scope.row)">编辑</el-button>
<el-button type="text" size="small" @click="handleDelete(scope.row.userid)" v-if="isSuperAdmin">删除</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination :current-page.sync="curPage" :page-size="pageSize" layout="total, prev, pager, next" :total="total" @current-change="pageChange" style="float:right;"></el-pagination>
<el-dialog :title="domicTitle" :visible.sync="dialogVisible" width="30%" center>
<el-form :model="form" :rules="rules" ref="ruleForm" label-width="70px" class="demo-ruleForm" v-show="dialogVisible === 'add' || dialogVisible === 'edit'">
<el-form-item label="ID" prop="id">
<el-input v-model="form.id"></el-input>
<el-form-item label="ID" prop="userid" v-if="dialogVisible === 'edit'">
<el-input v-model="form.userid" size="small" disabled></el-input>
</el-form-item>
<el-form-item label="名称" prop="name">
<el-input v-model="form.name"></el-input>
<el-form-item label="ID" prop="userid" v-else>
<el-select style="width:100%" v-model="form.userid" placeholder="搜索用户" size="small" filterable remote :remote-method="fetchUserList" :loading="searchUsersloading">
<el-option :label="user.nickname" :value="user.id" v-for="user in userList" :key="user.id" />
</el-select>
</el-form-item>
<el-form-item label="手机号" prop="mobile">
<el-input v-model="form.mobile"></el-input>
<el-form-item label="名称" prop="username">
<el-input v-model="form.username" size="small"></el-input>
</el-form-item>
<el-form-item label="手机号" prop="phone">
<el-input v-model="form.phone" size="small"></el-input>
</el-form-item>
<el-form-item label="邮箱" prop="email">
<el-input v-model="form.email"></el-input>
<el-input v-model="form.email" size="small"></el-input>
</el-form-item>
</el-form>
<p v-show="dialogVisible === 'delete'">确认删除此账号吗?</p>
<p v-show="dialogVisible === 'delete'">删除此账号,与其相关的会议将被同时删除,确认删除此账号吗?</p>
<span slot="footer" class="dialog-footer">
<el-button type="primary" @click="addAccount" size="mini">确 定</el-button>
<el-button type="primary" @click="handleBtn" size="mini">确 定</el-button>
<el-button @click="dialogVisible = null" size="mini">取 消</el-button>
</span>
</el-dialog>
......@@ -40,6 +45,9 @@
</div>
</template>
<script>
import { getAccountList, searchUserList, createAccount, updateAccount, deleteAccount, operateLog } from '@api/common'
import { mapGetters } from 'vuex'
import _ from 'lodash'
export default {
data () {
const MOBILE_REG = /^1(3[0-9]|4[01456879]|5[0-35-9]|6[2567]|7[0-8]|8[0-9]|9[0-35-9])\d{8}$/
......@@ -48,6 +56,8 @@ export default {
if (value) {
if (!MOBILE_REG.test(value)) {
callback(new Error('手机号格式错误'));
} else {
callback()
}
}
}
......@@ -55,44 +65,27 @@ export default {
if (value) {
if (!EMAIL_REG.test(value)) {
callback(new Error('邮箱格式错误'));
} else {
callback()
}
}
}
return {
listData: [
{
id: '1234567890',
name: '张三',
mobile: '13111112222',
email: '1243@qq.com'
},
{
id: '1234567891',
name: '张三',
mobile: '13111112222',
email: '1243@qq.com'
},
{
id: '1234567892',
name: '张三',
mobile: '13111112222',
email: '1243@qq.com'
}
],
listData: [],
curPage: 1,
pageSize: 20,
total: 200,
total: 0,
dialogVisible: null,
form: {
id: '',
name: '',
mobile: '',
userid: '',
username: '',
phone: '',
email: ''
},
rules: {
id: [{ required: true, message: '请输入ID', trigger: 'blur' }],
name: [{ required: true, message: '请输入名称', trigger: 'blur' }],
mobile: [
userid: [{ required: true, message: '请输入ID', trigger: 'blur' }],
username: [{ required: true, message: '请输入名称', trigger: 'blur' }],
phone: [
{ required: true, message: '请输入手机号', trigger: 'blur' },
{ validator: checkMobile, trigger: 'blur' }
],
......@@ -100,10 +93,14 @@ export default {
{ required: true, message: '请输入邮箱', trigger: 'blur' },
{ validator: checkEmail, trigger: 'blur' }
]
}
},
searchUsersloading: false,
userList: [],
deleteId: ''
}
},
computed: {
...mapGetters(['isSuperAdmin']),
domicTitle() {
let title = '新增'
switch (this.dialogVisible) {
......@@ -117,20 +114,117 @@ export default {
return title + '账号'
}
},
created() {
this.fetchAccountList()
console.log(this.isSuperAdmin)
},
methods: {
pageChange(val) {
console.log(val)
},
edit(data) {
this.form = data
handleEdit(data) {
this.form = _.cloneDeep(data)
this.dialogVisible = 'edit'
},
addAccount() {
this.$refs.ruleForm.validate((valid) => {
if (valid) {
console.log('submit!');
handleAdd() {
for (const key in this.form) {
this.form[key] = ''
}
this.dialogVisible = 'add'
},
handleDelete(id) {
this.dialogVisible = 'delete'
this.deleteId = id
},
pageChange() {
this.fetchRoleList()
},
handleBtn() {
if (this.dialogVisible === 'delete') {
this.fetchDeleteAccount()
} else {
this.$refs.ruleForm.validate((valid) => {
if (valid) {
this.dialogVisible === 'add' ? this.fetchCreateAccount() : this.fetchUpdateAccount()
}
});
}
this.dialogVisible = false
},
fetchUserList(val) {
if (val) {
const params = {
nickname: val
}
this.searchUsersloading = true;
searchUserList(params).then((res) => {
this.searchUsersloading = false;
if (res.data && Array.isArray(res.data.items)) {
this.userList = res.data.items
}
}).catch(() => {})
}
},
fetchAccountList() {
const params = {
page: this.curPage,
limit: this.pageSize
}
getAccountList(params).then((res) => {
if (res.code === 0 && res.data.data) {
this.listData = res.data.data
this.total = res.data.total
}
})
},
fetchCreateAccount() {
const form = this.form
const params = {
userid: form.userid,
username: form.username,
phone: form.phone,
email: form.email,
type: 1
}
createAccount(params).then((res) => {
if (res.code === 0 && res.data.id) {
this.$message.success('创建账户成功')
this.fetchAccountList()
operateLog({ type: `创建腾讯账号,被创建账户userid:${form.userid}`, user: this.user })
} else {
this.$message.error(res.message || '创建账户失败')
}
})
},
fetchUpdateAccount() {
const form = this.form
const params = {
userid: form.userid,
username: form.username,
phone: form.phone,
email: form.email
}
updateAccount(params).then((res) => {
if (res.code === 0 && res.data.status === true) {
this.$message.success('更新账户成功')
this.fetchAccountList()
operateLog({ type: `更新腾讯账号,被更新账户userid:${form.userid}`, user: this.user })
} else {
this.$message.error(res.message || '更新账户失败')
}
})
},
fetchDeleteAccount() {
const params = {
userid: this.deleteId
}
deleteAccount(params).then((res) => {
if (res.code === 0 && res.data.status === true) {
this.$message.success('删除账户成功')
this.fetchAccountList()
operateLog({ type: `删除腾讯账号,被删除账户userid:${this.deleteId}`, user: this.user })
this.deleteId = ''
} else {
this.$message.error(res.message || '删除账户失败')
}
});
})
}
}
}
......
<template>
<div class="account">
<h5>角色管理</h5>
<h5>
角色管理
<el-button style="float: right; margin: 12px 30px 0 0" size="mini" type="primary" plain @click="handleAdd"
>添加角色</el-button
>
</h5>
<div class="inner">
<el-table :data="listData" style="width: 100%" height="calc(100% - 32px)">
<el-table-column prop="name" label="角色" min-width="140" v-if="!isSuperAdmin"></el-table-column>
<el-table-column prop="display_name" label="角色名称" min-width="120"></el-table-column>
<el-table-column prop="description" label="角色描述" min-width="120"></el-table-column>
<el-table-column prop="updated_at" label="创建时间" min-width="120"></el-table-column>
<el-table-column label="操作" min-width="140">
<template slot-scope="scope">
<el-button type="text" size="small" @click="handleUsers(scope.row)">分配用户</el-button>
<el-button type="text" size="small" @click="handlePermission(scope.row)">设置权限</el-button>
<el-button type="text" size="small" @click="handleEdit(scope.row)">编辑</el-button>
<el-button type="text" size="small" @click="handleDelete(scope.row.userid)">删除</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination :current-page.sync="curPage" :page-size="pageSize" layout="total, prev, pager, next" :total="total" @current-change="pageChange" style="float:right;"></el-pagination>
</div>
</div>
</template>
<script>
import { getRoles } from '@api/system'
import { mapGetters } from 'vuex'
export default {
data () {
return {}
data() {
return {
listData: [
{
id: 2,
name: 'general_admin',
display_name: '普通管理员',
description: '拥有超级管理员下的最高权限',
created_at: '2021-04-01 09:38:25',
updated_at: '2021-04-01 09:38:25'
},
{
id: 1,
name: 'administrator',
display_name: '超级管理员',
description: '拥有所有的权限',
created_at: '2021-04-01 09:29:41',
updated_at: '2021-04-01 09:29:41'
}
],
curPage: 1,
pageSize: 20,
total: 0
}
},
computed: {
...mapGetters(['isSuperAdmin'])
},
created() {
this.fetchRoleList()
},
methods: {
handleUsers(val) {
this.$router.push({ path: '/system/roleToUser', query: { id: val.id } })
},
handlePermission(val) {
console.log(val)
},
handleEdit(val) {
console.log(val)
},
handleDelete(val) {
console.log(val)
},
pageChange() {
this.fetchRoleList()
},
fetchRoleList() {
const params = {
page: this.curPage,
limit: this.pageSize
}
getRoles(params).then((res) => {
if (res.code === 0 && res.data.data) {
this.listData = res.data.data
this.total = res.data.total
}
})
}
}
}
</script>
<style scoped>
.account{
height:100%;
.account {
height: 100%;
}
h5{
h5 {
font-size: 16px;
font-family: PingFangSC-Regular, PingFang SC;
color:#333;
color: #333;
font-weight: 400;
line-height:50px;
text-indent:40px;
line-height: 50px;
text-indent: 40px;
}
.inner{
.inner {
height: calc(100% - 50px - 10px);
display:flex;
background: #FFFFFF;
background: #ffffff;
border-radius: 10px;
margin:0 16px;
box-sizing:border-box;
padding:14px 14px 6px;
margin: 0 16px;
box-sizing: border-box;
padding: 14px 14px 6px;
}
</style>
\ No newline at end of file
<template>
<div class="account">
<h5>
角色管理 / 分配用户
<el-button style="float: right; margin: 12px 30px 0 0" size="mini" type="primary" plain @click="handleAdd"
>角色下增加用户</el-button
>
</h5>
<div class="inner">
<el-table :data="listData" style="width: 100%" height="calc(100% - 32px)">
<!-- <el-table-column prop="name" label="角色" min-width="140"></el-table-column> -->
<el-table-column prop="user_info.nickname" label="用户昵称" min-width="120"></el-table-column>
<el-table-column prop="user_info.id" label="用户ID" min-width="120"></el-table-column>
<el-table-column prop="user_info.mobile" label="手机号" min-width="120"></el-table-column>
<el-table-column prop="user_info.email" label="邮箱" min-width="120"></el-table-column>
<el-table-column label="操作" min-width="140">
<template slot-scope="scope">
<el-button type="text" size="small" @click="handleDelete(scope.row.userid)">从角色下删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
</div>
</template>
<script>
export default {
data() {
return {
listData: [
{
created_at: '2021-04-01 10:45:38',
updated_at: '2021-04-01 10:45:38',
user_info: {
id: '6653195831513972736',
username: 'ZJ6653195831513972736',
email: 'wangyizheng@ezijing.com',
mobile: '18435134258',
wechat_unionid: 'oJ6hPszybKN83GkWbvaY33q4oeIo',
nickname: 'sdagads',
country_code: '86',
id_number: null,
user_id: '6653195831513972736',
gender: '0',
province: null,
city: null,
county: null,
company_name: null,
position: null,
personal_signature: null,
phone: null,
qq: null,
wechat: null,
weibo: null,
tencent_weibo: null,
org: null,
real_name: 'sdagads',
highest_degree: null,
major: null,
birthday: null,
channel_code: null,
created_time: '2020-04-07 15:44:57',
updated_time: '2020-08-26 17:12:10',
status: '0',
avatar: null,
realname: 'sdagads'
}
}
]
}
},
methods: {
handleAdd() {},
handleUsers(val) {
console.log(val)
},
handlePermission(val) {
console.log(val)
},
handleEdit(val) {
console.log(val)
},
handleDelete(val) {
console.log(val)
}
}
}
</script>
<style scoped>
.account {
height: 100%;
}
h5 {
font-size: 16px;
font-family: PingFangSC-Regular, PingFang SC;
color: #333;
font-weight: 400;
line-height: 50px;
text-indent: 40px;
}
.inner {
height: calc(100% - 50px - 10px);
display: flex;
background: #ffffff;
border-radius: 10px;
margin: 0 16px;
box-sizing: border-box;
padding: 14px 14px 6px;
}
</style>
\ No newline at end of file
......@@ -18,6 +18,18 @@ export default [
}
]
},
{
path: '/meeting-test',
component: Layout,
children: [
{
path: '',
component: () => import('@/pages/meeting/index-test.vue'),
name: 'MeetingCreate',
meta: { title: '创建直播', affix: true }
}
]
},
{
path: '/calendar',
component: Layout,
......@@ -43,6 +55,12 @@ export default [
component: () => import('@/pages/system/role/index'),
meta: { title: '角色管理', icon: 'el-icon-s-check' }
},
{
path: 'roleToUser',
name: 'RoleToUser',
component: () => import('@/pages/system/role/roleToUser/index'),
meta: { title: '管理角色用户', icon: '' }
},
{
path: 'account',
name: 'Account',
......
const getters = {
token: state => state.user.token,
user: state => state.user.user,
roles: state => state.user.roles,
isSuperAdmin: state => state.user.isSuperAdmin,
sidebar: state => state.app.sidebar
}
export default getters
......@@ -4,7 +4,6 @@ import app from './modules/app'
import user from './modules/user'
import getters from './getters'
// import { getUser, logout } from '@/api/account'
Vue.use(Vuex)
const store = new Vuex.Store({
......@@ -17,58 +16,3 @@ const store = new Vuex.Store({
})
export default store
/* const store = new Vuex.Store({
state: {
user: {},
isLogin: false
},
mutations: {
setUser(state, user) {
state.user = user
},
setIsLogin(state, isLogin) {
state.isLogin = isLogin
},
TOGGLE_SIDEBAR: state => {
if (state.sidebar.opened) {
Cookies.set('sidebarStatus', 1)
} else {
Cookies.set('sidebarStatus', 0)
}
state.sidebar.opened = !state.sidebar.opened
state.sidebar.withoutAnimation = false
}
},
actions: {
getUser({ commit }) {
getUser().then(response => {
commit('setUser', response)
})
},
// 退出登录
logout({ commit }) {
return logout().then(response => {
commit('setUser', {})
commit('setIsLogin', false)
return response
})
},
// 检测登录状态
async checkLogin({ commit }) {
const isLogin = await getUser()
.then(response => {
commit('setUser', response)
return true
})
.catch(() => {
commit('setUser', {})
return false
})
commit('setIsLogin', isLogin)
return isLogin
}
}
})
export default store
*/
import { getUser, logout } from '@/api/account'
import { getUserRoles } from '@/api/system'
const user = {
state: {
user: {},
isLogin: false
roles: [],
isLogin: false,
isSuperAdmin: false
},
mutations: {
......@@ -11,6 +14,12 @@ const user = {
},
setIsLogin(state, isLogin) {
state.isLogin = isLogin
},
setRoles(state, roles) {
state.roles = roles
},
setSuperAdmin(state, isSuperAdmin) {
state.isSuperAdmin = isSuperAdmin
}
},
......@@ -20,6 +29,19 @@ const user = {
commit('setUser', response)
})
},
setUserRoles({ commit }) {
getUserRoles().then(res => {
const roles = res.data.roles
let isSuperAdmin = false
if (roles && Array.isArray(roles)) {
roles.forEach(it => {
if (it.name === 'administrator') isSuperAdmin = true
})
commit('setRoles', roles)
commit('setSuperAdmin', isSuperAdmin)
}
})
},
// 退出登录
logout({ commit }) {
return logout().then(response => {
......
import axios from 'axios'
import qs from 'qs'
import { Message } from 'element-ui'
import { getNonce } from '@/utils/utils'
import router from '@/router'
const httpRequest = axios.create({
timeout: 60000,
withCredentials: true,
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
headers: { 'Content-Type': 'application/json' }
})
// 请求拦截
httpRequest.interceptors.request.use(
function(config) {
const defaultParams = {
timestamp: parseInt(Date.now() / 1000),
nonce: getNonce(9),
signature: 'UG7wBenexQhiuD2wpCwuxkU0jqcj006d'
}
let params = config.params || config.data
params = Object.assign({}, defaultParams, params)
if (['post', 'put', 'delete'].includes(config.method)) {
config.data = params
} else {
config.params = params
}
if (config.headers['Content-Type'] === 'application/x-www-form-urlencoded') {
config.data = qs.stringify(config.data)
}
......@@ -25,8 +38,9 @@ httpRequest.interceptors.request.use(
httpRequest.interceptors.response.use(
function(response) {
const { data } = response
if (data.code) {
Message.error(data.msg || data.message)
if (data.code === 1 && data.msg === '请先登录') {
// Message.error(data.msg || data.message)
window.location.href = `${webConf.others.loginUrl}?rd=${encodeURIComponent(window.location.href)}`
return Promise.reject(data)
}
return data
......
......@@ -11,6 +11,7 @@ export default class BeforeEnter {
next(`/login?redirect_uri=${encodeURIComponent(window.location.href)}`)
return
}
store.dispatch('setUserRoles')
next()
}
}
......@@ -28,19 +28,7 @@ export function timeTrans(time) {
}
return date
}
/**
* 获取随机字符串
* @returns {String}
*/
export function nounceStr() {
const chars = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
let str = ''
for (let i = 0; i < 16; i++) {
const idx = parseInt(36 * Math.random())
str += chars[idx]
}
return str
}
/**
* 获取一天内从某小时至某小时结束的时间点
* @param {number} start
......@@ -117,9 +105,17 @@ export function getCurHalfHourDate(type, date) {
* @param {(Object|string|number)} date
* @returns {Date Object}
*/
export function getTimestampYMD(date) {
export function getYMDByDate(date) {
date = timeTrans(date)
return new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime()
return new Date(date.getFullYear(), date.getMonth(), date.getDate())
}
/**
* 将日期转换为年月日整时
* @param {(Object|string|number)} date
* @returns {Date Object}
*/
export function getTimestampYMD(date) {
return getYMDByDate(date).getTime()
}
/**
* 获取从起始日之后的N个月范围的日期
......@@ -218,27 +214,27 @@ export function computedDateByRateTimes(startDate, times, repeatRate) {
let endTime
startDate = timeTrans(startDate)
switch (repeatRate) {
case 'everyday': {
case 0: {
rangeTimeStamp = (times - 1) * dayTimeStamp
endTime = Date.parse(startDate) + rangeTimeStamp
break
}
case 'everyworkday': {
case 1: {
const dateArr = recentWeekdays(times, startDate)
endTime = dateArr[dateArr.length - 1]
break
}
case 'everyweek': {
case 2: {
rangeTimeStamp = (times - 1) * 7 * dayTimeStamp
endTime = Date.parse(startDate) + rangeTimeStamp
break
}
case 'every2weeks': {
case 3: {
rangeTimeStamp = (times - 1) * 14 * dayTimeStamp
endTime = Date.parse(startDate) + rangeTimeStamp
break
}
case 'everymonth': {
case 4: {
endTime = getDateByMouths(startDate, times)
break
}
......@@ -268,23 +264,23 @@ export function computedTimesByRateDate(startDate, endDate, repeatRate) {
const rangeTimeStamp = getTimestampYMD(endDate) - getTimestampYMD(startDate)
let times = 0
switch (repeatRate) {
case 'everyday': {
case 0: {
times = rangeTimeStamp / dayTimeStamp + 1
break
}
case 'everyworkday': {
case 1: {
times = rangeCount(timeTrans(startDate), timeTrans(endDate))
break
}
case 'everyweek': {
case 2: {
times = rangeTimeStamp / (dayTimeStamp * 7) + 1
break
}
case 'every2weeks': {
case 3: {
times = rangeTimeStamp / (dayTimeStamp * 14) + 1
break
}
case 'everymonth': {
case 4: {
times = getMonthsByDate(startDate, endDate)
break
}
......
/**
* 获取随机字符串
* @param {number} length
* @returns {String}
*/
export function getNonce(length) {
typeof length !== 'number' && (length = 16)
const chars = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'k', 'm', 'n', 'p', 'r', 's', 't', 'w', 'x', 'y', 'z', 2, 3, 4, 5, 6, 7, 8]
const charsLen = chars.length;
let str = ''
for (let i = 0; i < length; i++) {
const idx = parseInt(charsLen * Math.random())
let _char = chars[idx];
if (typeof _char === 'string' && idx % 2) {
_char = _char.toUpperCase()
}
str += _char
}
return str
}
\ No newline at end of file
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论