This commit is contained in:
@jyuhsin
2025-08-29 17:52:16 +08:00
parent a08ae49f03
commit 06a8e2fda4
90 changed files with 2475 additions and 147 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -15,7 +15,7 @@
append-to-body
>
<div class="qrcode-container" style="text-align: center;">
<qrcode :value="url" :options="{ width: 126 }" class="signature-qrcode"></qrcode>
<qrcode v-if="url" :value="url" :options="{ width: width }" class="signature-qrcode"></qrcode>
</div>
<template #footer>
<el-button @click="dialogVisible = false">关闭</el-button>
@@ -26,7 +26,7 @@
<!-- 内联模式 -->
<template v-else-if="mode === 'inline'">
<div class="qrcode-inline-container">
<qrcode :value="url" :options="{ width: 126 }" class="signature-qrcode"></qrcode>
<qrcode v-if="url" :value="url" :options="{ width: width }" class="signature-qrcode"></qrcode>
</div>
</template>
</div>
@@ -41,7 +41,7 @@ module.exports = {
// 二维码内容
url: {
type: String,
required: true
required: true,
},
// 显示模式:dialog(默认)或 inline
mode: {
@@ -53,6 +53,10 @@ module.exports = {
value: {
type: Boolean,
default: false
},
width: {
type: Number,
default: 200
}
},
@@ -60,6 +60,8 @@
<!--Sortable-->
<script src="${base!}/assets/platform/plugins/sortablejs/sortable.min.js"></script>
<script src="${base!}/assets/platform/plugins/vuedraggable/vuedraggable.umd.min.js"></script>
<!--vue-count-to-->
<script src="${base!}/assets/platform/plugins/vue-count-to/vue-count-to.min.js"></script>
<!--vxe-->
<link rel="stylesheet" href="${base!}/assets/platform/plugins/vxe/vxe-pc-ui.css" />
<link rel="stylesheet" href="${base!}/assets/platform/plugins/vxe/vxe-table.css" />
@@ -179,7 +179,7 @@ layout("/layouts/platform.html"){
async initData() {
this.$set(this.formData, "applyStartYear", new Date().getFullYear() - 1 + "")
this.$set(this.formData, "applyEndYear", new Date().getFullYear() + "")
const id = GetQueryString("id")
const id = GetQueryString("bizId")
if (id) {
const resp = await this.$axios.post("/platform/club/evaluate/apply/info", { id })
if (resp.code === 0) {
@@ -0,0 +1,70 @@
const meetingInfo = {
template: /*language=HTML*/ `
<div>
<el-descriptions :column="3" border>
<el-descriptions-item label="会议名称">{{ viewData.name }}</el-descriptions-item>
<el-descriptions-item label="会议地点">{{ viewData.address }}</el-descriptions-item>
<el-descriptions-item label="会议类型">{{ viewData.typeName }}</el-descriptions-item>
<el-descriptions-item label="会议描述" :span="3">
<div v-html="viewData.description"></div>
</el-descriptions-item>
<el-descriptions-item label="场次信息" :span="3">
<el-table v-if="viewData.timePeriods && viewData.timePeriods.length > 0"
:data="viewData.timePeriods" max-height="300" size="mini">
<el-table-column prop="periodName" label="场次名称"></el-table-column>
<el-table-column prop="startTime" label="开始时间"></el-table-column>
<el-table-column prop="endTime" label="结束时间"></el-table-column>
<el-table-column prop="canLeave" label="是否可以请假">
<template slot-scope="{ row }">
<span v-if="row.canLeave">是</span>
<span v-else>否</span>
</template>
</el-table-column>
</el-table>
<span v-else>暂无场次信息</span>
</el-descriptions-item>
<el-descriptions-item label="会议参与人员" :span="3">
<el-table v-if="viewData.users && viewData.users.length > 0"
:data="viewData.users" max-height="300" size="mini">
<el-table-column fixed prop="loginName" label="工号" width="150"></el-table-column>
<el-table-column prop="userName" label="姓名" width="120"></el-table-column>
<el-table-column prop="sex" label="性别" width="50"></el-table-column>
<el-table-column prop="userState" label="在职状态" width="120"></el-table-column>
<el-table-column prop="personType" label="人员类型" width="120"></el-table-column>
<el-table-column prop="preparedBy" label="人事编制" width="120"></el-table-column>
<el-table-column prop="mobile" label="手机" width="120"></el-table-column>
<el-table-column prop="unitName" label="所属单位" show-overflow-tooltip></el-table-column>
<el-table-column prop="unionName" label="所属工会" show-overflow-tooltip></el-table-column>
</el-table>
<span v-else>暂无会议参与人员信息</span>
</el-descriptions-item>
</el-descriptions>
</div>
`,
store,
data() {
return {
viewData: {},
}
},
methods: {
onOpen(row) {
this.$axios.post('/platform/meeting/manage/info', {id: row.id}).then((res) => {
if (res.code === 0) {
this.viewData = res.data
}
})
},
},
style: /*language=CSS*/ `
.el-descriptions-item__label {
width: 200px;
min-width: 200px;
max-width: 200px;
}
.el-tabs__header {
margin: 0;
}
`
}
@@ -0,0 +1,392 @@
const basicForm = {
template: /*language=HTML*/ `
<div>
<el-steps :active="activeName" finish-status="success" simple>
<el-step title="会议基本信息"></el-step>
<el-step title="场次信息"></el-step>
<el-step title="会议参与人员"></el-step>
</el-steps>
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="110px" label-position="left" class="mt20">
<div v-show="activeName === 0">
<el-form-item label="会议名称" prop="name">
<el-input type="text" v-model="formData.name" maxlength="50"
placeholder="请输入会议名称"></el-input>
</el-form-item>
<el-form-item label="会议地点" prop="address">
<el-input type="text" v-model="formData.address" maxlength="100"
placeholder="请输入会议地点"></el-input>
</el-form-item>
<el-form-item label="会议类型" prop="typeId">
<el-select v-model="formData.typeId" style="width: 100%" placeholder="请选择会议类型" filterable clearable>
<el-option v-for="item in typeOptions"
:value="item.id"
:key="item.id"
:label="item.name"
></el-option>
</el-select>
</el-form-item>
<el-form-item v-if="typeOptions.find(o => o.id === formData.typeId)?.designId === 'JDHHY'" label="所属教代会" prop="teacherCongressSessionId">
<el-select v-model="formData.teacherCongressSessionId" style="width: 100%" placeholder="请选择所属教代会" filterable clearable>
<el-option v-for="item in teacherCongressOptions"
:value="item.id"
:key="item.id"
:label="item.fullName"
></el-option>
</el-select>
</el-form-item>
<el-form-item v-if="typeOptions.find(o => o.id === formData.typeId)?.designId === 'GDHHY'" label="所属工代会" prop="workerCongressSessionId">
<el-select v-model="formData.workerCongressSessionId" style="width: 100%" placeholder="请选择所属工代会" filterable clearable>
<el-option v-for="item in workerCongressOptions"
:value="item.id"
:key="item.id"
:label="item.fullName"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="会议描述" prop="description">
<text-editor v-model="formData.description"></text-editor>
</el-form-item>
</div>
<div v-show="activeName === 1">
<el-form-item label="场次信息">
<el-table :data="formData.timePeriods" style="width: 100%" size="small">
<el-table-column label="场次名称" prop="periodName">
<template slot-scope="{ row }">
<el-input maxlength="20" v-model="row.periodName" placeholder="请输入场次名称" size="small"></el-input>
</template>
</el-table-column>
<el-table-column label="开始时间" prop="startTime">
<template slot-scope="{ row }">
<el-date-picker
size="small"
placeholder="请选择开始时间"
type="datetime"
v-model="row.startTime"
format="yyyy-MM-dd HH:mm"
value-format="yyyy-MM-dd HH:mm">
</el-date-picker>
</template>
</el-table-column>
<el-table-column label="结束时间" prop="endTime">
<template slot-scope="{ row }">
<el-date-picker
size="small"
placeholder="请选择结束时间"
type="datetime"
v-model="row.endTime"
format="yyyy-MM-dd HH:mm"
value-format="yyyy-MM-dd HH:mm">
</el-date-picker>
</template>
</el-table-column>
<el-table-column label="是否可以请假" prop="canLeave">
<template slot-scope="{ row }">
<el-radio-group v-model="row.canLeave" size="small">
<el-radio-button :label="true">是</el-radio-button>
<el-radio-button :label="false">否</el-radio-button>
</el-radio-group>
</template>
</el-table-column>
<el-table-column width="80">
<template slot="header" slot-scope="{ row }">
<el-button size="mini" type="primary" icon="el-icon-plus"
@click="formData.timePeriods.push({ canLeave: false })"></el-button>
</template>
<template slot-scope="scope">
<el-button :disabled="formData.timePeriods.length <= 1"
@click="formData.timePeriods.splice(scope.$index, 1)"
icon="el-icon-delete"
size="mini"
type="danger"></el-button>
</template>
</el-table-column>
</el-table>
</el-form-item>
</div>
<div v-show="activeName === 2">
<el-form-item label="参与人员信息">
<el-row class="mb10">
<el-button icon="el-icon-search" @click="openSelect" size="small">选择用户</el-button>
<el-button icon="el-icon-delete" @click="clearSelect" type="danger" size="small">清空用户</el-button>
</el-row>
<el-table :data="userTableData" style="width: 100%" size="mini" max-height="300">
<el-table-column fixed prop="loginName" label="工号" width="150"></el-table-column>
<el-table-column prop="userName" label="姓名" width="120"></el-table-column>
<el-table-column prop="sex" label="性别" width="50"></el-table-column>
<el-table-column prop="userState" label="在职状态" width="120"></el-table-column>
<el-table-column prop="personType" label="人员类型" width="120"></el-table-column>
<el-table-column prop="preparedBy" label="人事编制" width="120"></el-table-column>
<el-table-column prop="mobile" label="手机" width="120"></el-table-column>
<el-table-column prop="unitName" label="所属单位" show-overflow-tooltip></el-table-column>
<el-table-column prop="unionName" label="所属工会" show-overflow-tooltip></el-table-column>
<el-table-column label="操作">
<template slot-scope="scope">
<el-button @click="userTableData.splice(scope.$index, 1)"
icon="el-icon-delete"
size="mini"
type="danger"></el-button>
</template>
</el-table-column>
</el-table>
<p style="color: var(--color-primary)">总计:{{userTableData.length}}人</p>
</el-form-item>
</div>
</el-form>
<el-row class="mt10" justify="end" type="flex">
<el-button @click="$emit('refresh')">取消</el-button>
<el-button v-if="activeName === 1" type="primary" @click="activeName = 0">上一步</el-button>
<el-button v-if="activeName === 2" type="primary" @click="activeName = 1">上一步</el-button>
<el-button v-if="activeName === 0" type="primary" @click="next()">下一步</el-button>
<el-button v-if="activeName === 1" type="primary" @click="activeName = 2">下一步</el-button>
<el-button @click="onSave" type="primary">保存</el-button>
<el-button @click="onSubmit" type="primary">提交</el-button>
</el-row>
<el-dialog title="选择用户" :visible.sync="selectDialogVisible" width="70%" append-to-body>
<div class="btn-group tool-button">
<el-input placeholder="请输入内容" v-model="pageForm.searchKeyword" @keyup.enter.native="doSearch" style="width: 260px">
<el-select v-model="pageForm.searchName" slot="prepend" placeholder="查询类型" style="width: 80px">
<el-option label="工号" value="u.loginName"></el-option>
<el-option label="姓名" value="u.userName"></el-option>
<el-option label="手机" value="u.mobile"></el-option>
</el-select>
</el-input>
<el-select v-model="pageForm.sex" placeholder="请选择性别" clearable>
<el-option label="男" value="男"></el-option>
<el-option label="女" value="女"></el-option>
</el-select>
<el-select v-model="pageForm.unionId" @change="flushUnits" @clear="flushUnits" placeholder="请选择所属工会" filterable clearable>
<el-option v-for="item in unionList" :key="item.id" :label="item.name" :value="item.id"></el-option>
</el-select>
<el-select v-model="pageForm.unitId" placeholder="请选择所属单位" filterable clearable>
<el-option v-for="item in unitList" :key="item.id" :label="item.name" :value="item.id"></el-option>
</el-select>
<el-select v-model="pageForm.roleId" placeholder="请选择角色" filterable clearable>
<el-option v-for="item in roleList" :key="item.id" :label="item.name" :value="item.id"></el-option>
</el-select>
<el-button icon="el-icon-search" @click="doSearch" type="primary"></el-button>
</div>
<div class="left-span-label mt20">人员列表</div>
<el-table
:data="tableData"
@selection-change="handleSelectionChange"
row-key="id"
ref="tableRef"
>
<el-table-column type="selection" reserve-selection width="60"></el-table-column>
<el-table-column fixed prop="loginName" label="工号" width="150"></el-table-column>
<el-table-column prop="userName" label="姓名" width="120"></el-table-column>
<el-table-column prop="sex" label="性别" width="50"></el-table-column>
<el-table-column prop="userState" label="在职状态" width="120"></el-table-column>
<el-table-column prop="personType" label="人员类型" width="120"></el-table-column>
<el-table-column prop="preparedBy" label="人事编制" width="120"></el-table-column>
<el-table-column prop="mobile" label="手机" width="120"></el-table-column>
<el-table-column prop="unitName" label="所属单位" show-overflow-tooltip></el-table-column>
<el-table-column prop="unionName" label="所属工会" show-overflow-tooltip></el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
<span slot="footer" class="dialog-footer">
<el-button @click="selectDialogVisible = false">取 消</el-button>
<el-button type="primary" @click="doSelect">确 定</el-button>
</span>
</el-dialog>
</div>
`,
props: {
unionList: {
type: Array,
required: true
},
unitList: {
type: Array,
required: true
}
},
mixins: [initTableMixins],
data() {
return {
activeName: 0,
formData: {
timePeriods: [{ canLeave: false }],
},
formRules: {
name: [{required: true, message: '必填', trigger: ['blur', 'change']}],
address: [{required: true, message: '必填', trigger: ['blur', 'change']}],
typeId: [{required: true, message: '必填', trigger: ['blur', 'change']}],
teacherCongressSessionId: [{required: true, message: '必填', trigger: ['blur', 'change']}],
workerCongressSessionId: [{required: true, message: '必填', trigger: ['blur', 'change']}],
},
typeOptions: [],
userTableData: [],
selectDialogVisible: false,
roleList: [],
selectUsers: [],
pageForm: {
searchName: 'u.userName',
},
teacherCongressOptions: [],
workerCongressOptions: [],
}
},
methods: {
next() {
const type = this.typeOptions.find(o => o.id === this.formData.typeId)
if(type.designId === 'JDHHY' && !this.formData.teacherCongressSessionId) {
this.$message.warning('请选择所属教代会')
return
}
if(type.designId === 'GDHHY' && !this.formData.workerCongressSessionId) {
this.$message.warning('请选择所属工代会')
return
}
this.activeName = 1
},
flushUnits() {
this.$set(this.pageForm, "unitId", null)
this.unitList = []
if (this.pageForm.unionId) {
this.$businessTool.listUnit(this.pageForm.unionId).then((data) => {
this.unitList = data
})
}
this.doSearch()
},
handleSelectionChange(val) {
this.selectUsers = val
},
doSelect() {
const tableLoginNames = this.userTableData.map(v => v.loginName)
for (const o of this.selectUsers) {
if(!tableLoginNames.includes(o.loginName)){
this.userTableData.push(o)
}
}
if(this.$refs.tableRef){
this.$refs.tableRef.clearSelection()
}
this.selectDialogVisible = false
},
async getRoleList() {
const resp = await this.$axios.post("/platform/sys/msg/getRoleList")
return resp.data
},
openSelect() {
this.selectDialogVisible = true
this.pageData()
},
clearSelect() {
this.userTableData = []
if(this.$refs.tableRef){
this.$refs.tableRef.clearSelection()
}
},
onOpen(row) {
if(row && row.id) {
this.$axios.post('/platform/meeting/manage/info', { id: row.id }).then(res => {
this.formData = res.data
this.userTableData = this.formData.users
})
}
},
onSave() {
this.$confirm("您确定要保存吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post('/platform/meeting/manage/submit', {
data: JSON.stringify(this.formData),
users: JSON.stringify(this.userTableData)
}).then(res => {
if (res.code === 0) {
this.$message.success(res.msg)
this.$emit('refresh')
} else {
this.$message.warning(res.msg)
}
})
})
},
onSubmit() {
this.$refs.formRef.validate((valid) => {
if (valid) {
if(this.formData.timePeriods.length === 0) {
this.$message.warning("请至少添加一条场次信息")
return
}
for (let i = 0; i < this.formData.timePeriods.length; i++) {
const item = this.formData.timePeriods[i]
if(!item.periodName) {
this.$message.warning("第" + (i + 1) + "条场次信息中,场次名称必填")
return
}
if(!item.startTime) {
this.$message.warning("第" + (i + 1) + "条场次信息中,开始时间必填")
return
}
if(!item.endTime) {
this.$message.warning("第" + (i + 1) + "条场次信息中,结束时间必填")
return
}
}
if (this.userTableData.length === 0) {
this.$message.warning("请选择会议参与人员")
return
}
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(async () => {
const resp = await this.$axios.post("/platform/meeting/manage/submit", {
data: JSON.stringify(this.formData),
users: JSON.stringify(this.userTableData)
})
if (resp.code === 0) {
this.$message.success(resp.msg)
this.$emit('refresh')
} else {
this.$message.warning(resp.msg)
}
})
}
})
},
queryMeetingType() {
this.$axios.post("/platform/meeting/type/queryMeetingType")
.then((res) => {
this.typeOptions = res.data
})
},
pageData() {
this.$axios.post("/platform/meeting/manage/userPageData", this.pageForm).then((res) => {
if (res.code === 0) {
this.tableData = res.data.list
this.pageForm.totalCount = res.data.totalCount
}
})
},
queryTeacherCongress() {
this.$axios.post("/platform/meeting/manage/queryTeacherCongress")
.then((res) => {
this.teacherCongressOptions = res.data
})
},
queryWorkerCongress() {
this.$axios.post("/platform/meeting/manage/queryWorkerCongress")
.then((res) => {
this.workerCongressOptions = res.data
})
},
},
async created() {
this.queryMeetingType()
this.queryTeacherCongress()
this.queryWorkerCongress()
this.roleList = await this.getRoleList()
},
style: /*language=CSS*/ `
`
}
@@ -0,0 +1,154 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style>
</style>
<div id="app" v-cloak>
<guava ref="guava">
<template>
<el-card shadow="never">
<search @search="doSearch">
<search-item label="年度:">
<el-date-picker
v-model="pageForm.year"
type="year"
value-format="yyyy"
placeholder="请选择年度"
@change="doSearch"
style="width: 100%"
></el-date-picker>
</search-item>
<search-item label="名称/地点:">
<el-input placeholder="请输入名称或地点查询" clearable v-model="pageForm.searchKeyword"
@keyup.enter.native="doSearch">
</el-input>
</search-item>
</search>
</el-card>
<el-card shadow="never" class="mt20">
<table-tool label="会议列表">
<el-button type="primary" size="small" @click="onAdd">
<i class="ti-plus"></i>
新增会议
</el-button>
</table-tool>
<el-table :data="tableData" @sort-change="pageOrder" :size="tableSize">
<el-table-column label="序号" type="index" :index="indexMethod" width="60"></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:key="column.prop"
:width="column.width"
:sortable="column.sortable"
align="center"
header-align="center"
show-overflow-tooltip
v-for="column in tableColumns"
>
<template v-slot="{ row }" v-if="column.prop === 'createdAt'">
<span>{{ $moment(row.createdAt).format('YYYY-MM-DD') }}</span>
</template>
</el-table-column>
<el-table-column label="操作" width="230">
<template v-slot="{ row }">
<el-button @click="onView(row)" size="mini" type="primary">查看</el-button>
<el-button @click="onEdit(row)" size="mini" type="primary">编辑</el-button>
<el-button @click="onDelete(row)" size="mini" type="danger">删除</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</template>
<template #edit>
<basic-form ref="basicFormRef" @refresh="refresh" :union-list="unionList" :unit-list="unitList"></basic-form>
</template>
<template #view>
<meeting-info ref="infoRef"></meeting-info>
</template>
</guava>
</div>
<script>
<!--#include('../common/meetingInfo.js'){}#-->
<!--#include('basicForm.js'){}#-->
const vue = new Vue({
el: "#app",
mixins: [initTableMixins],
components: {
"basic-form": basicForm,
"meeting-info": meetingInfo,
},
data() {
return {
tableColumns: [
{prop: 'name', label: '会议名称'},
{prop: 'typeName', label: '会议类型'},
{prop: 'address', label: '会议地点'},
{prop: 'createdAt', label: '创建时间'},
],
unionList: [],
unitList: [],
}
},
methods: {
refresh() {
this.doSearch()
this.$refs.guava.index()
},
onAdd() {
this.$refs.guava.edit(() => {
this.$refs.basicFormRef.onOpen()
})
},
onView(row) {
this.$refs.guava.view(() => {
this.$refs.infoRef.onOpen(row)
})
},
onEdit(row) {
this.$refs.guava.edit(() => {
this.$refs.basicFormRef.onOpen(row)
})
},
onDelete(row) {
this.$confirm("您确定要删除吗, 是否继续?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
})
.then(() => {
this.$axios.post("/platform/meeting/manage/delete", { id: row.id }).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.pageData()
}
})
})
.catch(() => {})
},
pageData() {
this.$axios.post(loc() + "/pageData", this.pageForm).then((res) => {
if (res.code === 0) {
this.tableData = res.data.list
this.pageForm.totalCount = res.data.totalCount
}
})
},
},
async created() {
this.unitList = await this.$businessTool.listUnit()
this.unionList = await this.$businessTool.listUnion()
this.pageData()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,328 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style>
.qrcode {
min-width: 240px;
text-align: center;
display: flex;
flex-direction: column;
}
.real-data {
display: flex;
flex-wrap: wrap;
}
.real-data .data-card {
border-radius: 10px;
width: calc((100% - 80px) / 4);
min-width: 100px;
background-image: linear-gradient(141deg, #9fb8ad 0%, #1fc8db 51%, #2cb5e8 75%);
margin: 10px 0 10px 20px;
padding: 10px;
color: #ffffff;
display: flex;
flex-direction: column;
position: relative;
}
.real-data .data-card .data-card-title {
font-size: 20px;
max-width: 100%;
text-overflow: ellipsis;
word-break: keep-all;
white-space: nowrap;
overflow: hidden;
flex: 1;
position: absolute;
}
.real-data .data-card .data-card-num {
font-size: 90px;
flex: auto;
display: flex;
justify-content: center;
align-items: center;
}
.real-data .data-card .flow-border {
position: absolute;
display: block;
}
.timePeriod_card {
border-top: 5px solid #106898;
border-left: 1px solid #ebeef5;
border-bottom: 1px solid #ebeef5;
border-right: 1px solid #ebeef5;
}
.timePeriod_card .el-form-item {
margin-bottom: 0 !important;
}
img {
height: 100% !important;
width: 100%;
}
.operation {
position: fixed;
width: 100%;
height: 100%;
left: 0;
top: 0;
z-index: 1111;
}
</style>
<div id="app" v-cloak>
<guava ref="guava">
<template>
<el-card shadow="never">
<search @search="doSearch">
<search-item label="年度:">
<el-date-picker
v-model="pageForm.year"
type="year"
value-format="yyyy"
placeholder="请选择年度"
@change="doSearch"
style="width: 100%"
></el-date-picker>
</search-item>
<search-item label="名称/地点:">
<el-input placeholder="请输入名称或地点查询" clearable v-model="pageForm.searchKeyword"
@keyup.enter.native="doSearch">
</el-input>
</search-item>
<search-item label="会议类型:">
<el-select v-model="pageForm.type" @change="doSearch" style="width: 100%"
placeholder="请选择慰问类型" filterable clearable>
<el-option v-for="item in typeOptions"
:value="item.id"
:key="item.id"
:label="item.name"
></el-option>
</el-select>
</search-item>
</search>
</el-card>
<el-card shadow="never" class="mt20">
<table-tool label="会议列表"></table-tool>
<el-table :data="tableData" @sort-change="pageOrder" :size="tableSize" ref="meetingTable">
<el-table-column type="expand">
<template slot-scope="scope">
<el-row :gutter="20" justify="start" style="flex-wrap: wrap" type="flex"
v-if="scope.row.timePeriods && scope.row.timePeriods.length > 0">
<el-col :xl="5" v-for="tp,index in scope.row.timePeriods" :key="index">
<el-card class="mb10 timePeriod_card" shadow="hover">
<el-form label-width="80px">
<el-form-item label="名称">{{tp.periodName}}</el-form-item>
<el-form-item label="会议时间">{{tp.startTime}}</el-form-item>
<el-form-item label="结束时间">{{tp.endTime}}</el-form-item>
</el-form>
<el-row justify="space-around" style="border-top: 1px solid #ebeef5;padding: 10px 0 0 0" type="flex">
<el-button @click="exportSignature(tp.id)" size="medium" type="text">
导出签字表
</el-button>
<el-button @click="openOnline(tp.id,scope.row.id)" size="medium" type="text">
扫描二维码
</el-button>
</el-row>
</el-card>
</el-col>
</el-row>
<el-row v-else>
<el-empty description="没有时间段"></el-empty>
</el-row>
</template>
</el-table-column>
<el-table-column label="序号" type="index" :index="indexMethod" width="60"></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:key="column.prop"
:width="column.width"
:sortable="column.sortable"
align="center"
header-align="center"
show-overflow-tooltip
v-for="column in tableColumns"
>
<template v-slot="{ row }" v-if="column.prop === 'createdAt'">
<span>{{ $moment(row.createdAt).format('YYYY-MM-DD') }}</span>
</template>
</el-table-column>
<el-table-column label="操作" width="230">
<template v-slot="{ row }">
<el-button @click="onView(row)" size="mini" type="primary">查看</el-button>
<el-button @click="toggleRowTimePeriod(row)" size="mini" type="primary">展开</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</template>
<template #edit>
<div style="min-width: 500px;height: 100%;position: relative">
<el-row type="flex">
<el-col :span="4" class="qrcode">
<qr-code-plus :url="qrCodeUrl" ref="qrCodePlusRef" mode="inline"></qr-code-plus>
</el-col>
<el-col :span="20" class="real-data">
<template v-for="rd of realTimeData">
<div class="data-card">
<div class="data-card-title">
{{rd.label}}
</div>
<div class="data-card-num">
<count-to :end-val="rd.value" :start-val="getLastValue(rd.key)"></count-to>
</div>
</div>
</template>
</el-col>
</el-row>
<el-table :data="userData" :max-height="signTableHeight" class="mt20" ref="signTable">
<el-table-column label="姓名" prop="username"></el-table-column>
<el-table-column label="工号" prop="loginname"></el-table-column>
<el-table-column label="性别" prop="sex"></el-table-column>
<el-table-column label="单位" prop="unitname"></el-table-column>
<el-table-column label="签到时间" prop="signInDateTime"></el-table-column>
<el-table-column label="签到名次">
<template slot-scope="scope">
{{userData.length - scope.$index}}
</template>
</el-table-column>
</el-table>
</div>
</template>
<template #view>
<meeting-info ref="infoRef"></meeting-info>
</template>
</guava>
</div>
<script>
<!--#include('../common/meetingInfo.js'){}#-->
let pollingInterval = null
const intervalTime = 3500
const vue = new Vue({
el: "#app",
mixins: [initTableMixins],
components: {
"meeting-info": meetingInfo,
},
data() {
return {
tableColumns: [
{prop: 'name', label: '会议名称'},
{prop: 'typeName', label: '会议类型'},
{prop: 'address', label: '会议地点'},
{prop: 'createdAt', label: '创建时间'},
],
typeOptions: [],
meetingId: '',
timePeriodId: '',
qrCodeUrl: '',
lastTimeData: [],
realTimeData: [],
userData: [],
signTableHeight: 600
}
},
methods: {
toggleRowTimePeriod(row) {
this.$refs['meetingTable'].toggleRowExpansion(row)
},
exportSignature(timePeriodId) {
this.$downLoad(loc() + '/exportSignature/' + timePeriodId)
},
openOnline(timePeriodId, meetingId) {
this.meetingId = meetingId
this.timePeriodId = timePeriodId
this.$refs.guava.edit(() => {
this.calcSignTableHeight()
this.generateQrCodeUrl(timePeriodId, meetingId)
this.stopInterval()
pollingInterval = this.startPolling(this.getRealTimeData)
})
},
calcSignTableHeight() {
this.$nextTick(() => {
setTimeout(() => {
const offsetTop = this.$refs.signTable.$el.offsetTop
const th = window.innerHeight - 54 - 40 - offsetTop
this.$set(this, 'signTableHeight', th)
})
})
},
async generateQrCodeUrl(tpId, meetingId) {
const resp = await this.$axios.post(loc() + '/generateQrCodeUrl', {tpId, meetingId})
if (resp.code === 0) {
this.qrCodeUrl = resp.data
} else {
this.$message.warning(resp.msg)
}
},
async getRealTimeData() {
this.lastTimeData = clone(this.realTimeData)
const resp = await this.$axios.post(loc() + '/getRealTimeData/' + this.timePeriodId)
if (resp.code === 0) {
this.lastTimeData = clone(this.realTimeData)
this.$set(this, 'realTimeData', resp.data.countData)
let ud = clone(this.userData)
ud.unshift(...resp.data.userData)
let uMap = new Map()
for (let u of ud) {
if (!uMap.has(u.loginname)) {
uMap.set(u.loginname, u)
}
}
this.$set(this, 'userData', [...uMap.values()])
}
},
startPolling(func) {
this.lastTimeData = []
this.realTimeData = []
this.userData = []
func()
return setInterval(func, intervalTime)
},
stopInterval() {
if (pollingInterval) {
clearInterval(pollingInterval)
}
},
getLastValue(key) {
if (this.lastTimeData && this.lastTimeData.length > 0) {
return this.lastTimeData.find(v => v.key === key).value
} else {
return 0
}
},
onView(row) {
this.$refs.guava.view(() => {
this.$refs.infoRef.onOpen(row)
})
},
pageData() {
this.$axios.post(loc() + "/pageData", this.pageForm).then((res) => {
if (res.code === 0) {
this.tableData = res.data.list
this.pageForm.totalCount = res.data.totalCount
}
})
},
queryMeetingType() {
this.$axios.post('/platform/meeting/type/queryMeetingType')
.then((resp) => {
this.typeOptions = resp.data
})
},
},
async created() {
this.queryMeetingType()
this.pageData()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,82 @@
const basicForm = {
template: /*language=HTML*/ `
<div>
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="110px" label-position="left">
<el-form-item label="类型编码" prop="code">
<el-input type="text" v-model="formData.code" maxlength="50"
placeholder="请输入类型编码"></el-input>
</el-form-item>
<el-form-item label="类型名称" prop="name">
<el-input type="text" v-model="formData.name" maxlength="50"
placeholder="请输入类型名称"></el-input>
</el-form-item>
<el-form-item label="所属流程" prop="designId">
<el-select v-model="formData.designId" placeholder="请选择所属流程" filterable clearable style="width: 100%">
<el-option v-for="item in designOptions" :key="item.name" :value="item.name" :label="item.displayName"></el-option>
</el-select>
</el-form-item>
<el-form-item label="是否启用" prop="enable">
<el-switch
v-model="formData.enable"
active-color="#13ce66"
inactive-color="#ff4949">
</el-switch>
</el-form-item>
</el-form>
<el-row class="mt10" justify="end" type="flex">
<el-button @click="$emit('refresh')">取消</el-button>
<el-button @click="onSubmit" type="primary">提交</el-button>
</el-row>
</div>
`,
data() {
return {
formData: {
enable: true
},
formRules: {
name: [{required: true, message: '必填', trigger: ['blur', 'change']}],
code: [{required: true, message: '必填', trigger: ['blur', 'change']}],
enable: [{required: true, message: '必填', trigger: ['blur', 'change']}],
designId: [{required: true, message: '必填', trigger: ['blur', 'change']}],
},
designOptions: [],
}
},
methods: {
onOpen(row) {
this.queryDesignList()
if(row && row.id) {
this.formData = clone(row)
}
},
onSubmit() {
this.$refs.formRef.validate((valid) => {
if (valid) {
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(async () => {
const resp = await this.$axios.post("/platform/meeting/type/submit", this.formData)
if (resp.code === 0) {
this.$message.success(resp.msg)
this.$emit('refresh')
} else {
this.$message.warning(resp.msg)
}
})
}
})
},
queryDesignList() {
this.$axios.post("/platform/meeting/type/queryDesignList")
.then((res) => {
this.designOptions = res.data
})
},
},
style: /*language=CSS*/ `
`
}
@@ -0,0 +1,139 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style>
</style>
<div id="app" v-cloak>
<guava ref="guava">
<template>
<el-card shadow="never">
<search @search="doSearch">
<search-item label="名称/编码:">
<el-input placeholder="请输入名称或编码查询" clearable v-model="pageForm.searchKeyword"
@keyup.enter.native="doSearch">
</el-input>
</search-item>
</search>
</el-card>
<el-card shadow="never" class="mt20">
<table-tool label="类型列表">
<el-button type="primary" size="small" @click="onAdd">
<i class="ti-plus"></i>
新增类型
</el-button>
</table-tool>
<el-table :data="tableData" @sort-change="pageOrder" :size="tableSize">
<el-table-column label="序号" type="index" :index="indexMethod" width="60"></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:key="column.prop"
:width="column.width"
:sortable="column.sortable"
align="center"
header-align="center"
show-overflow-tooltip
v-for="column in tableColumns"
>
<template v-slot="{ row }" v-if="column.prop === 'enable'">
<el-switch
@change="switchChange(row)"
v-model="row.enable"
active-color="#13ce66"
inactive-color="#ff4949">
</el-switch>
</template>
</el-table-column>
<el-table-column label="操作" width="230">
<template v-slot="{ row }">
<el-button @click="onEdit(row)" size="mini" type="primary">编辑</el-button>
<el-button @click="onDelete(row)" size="mini" type="danger">删除</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</template>
<template #edit>
<basic-form ref="basicFormRef" @refresh="refresh"></basic-form>
</template>
</guava>
</div>
<script>
<!--#include('basicForm.js'){}#-->
const vue = new Vue({
el: "#app",
mixins: [initTableMixins],
components: {
"basic-form": basicForm,
},
data() {
return {
tableColumns: [
{prop: 'code', label: '类型编码'},
{prop: 'name', label: '类型名称'},
{prop: 'enable', label: '是否启用'},
],
}
},
methods: {
refresh() {
this.doSearch()
this.$refs.guava.index()
},
onAdd() {
this.$refs.guava.edit(() => {
this.$refs.basicFormRef.onOpen()
})
},
onEdit(row) {
this.$refs.guava.edit(() => {
this.$refs.basicFormRef.onOpen(row)
})
},
onDelete(row) {
this.$confirm("您确定要删除吗, 是否继续?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
})
.then(() => {
this.$axios.post("/platform/meeting/type/delete", { id: row.id }).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.pageData()
}
})
})
.catch(() => {})
},
switchChange(row) {
this.$axios.post("/platform/meeting/type/submit", row).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.pageData()
}
})
},
pageData() {
this.$axios.post(loc() + "/pageData", this.pageForm).then((res) => {
if (res.code === 0) {
this.tableData = res.data.list
this.pageForm.totalCount = res.data.totalCount
}
})
},
},
async created() {
this.pageData()
}
})
</script>
<!--#
}
#-->
@@ -265,7 +265,7 @@ const basicForm = {
return true
}
if (this.$auth.hasRoleOr(["BRANCH_UNION_ADMIN", "BRANCH_UNION_CHAIRMAN"])) {
return roles.some(r => r === 'H04')
return roles.some(r => r === 'BRANCH_UNION_ADMIN' || r === 'BRANCH_UNION_CHAIRMAN')
}
},
async getConfig() {