first commit

This commit is contained in:
2026-08-26 14:25:17 +08:00
commit 06debfd1fc
10595 changed files with 1836924 additions and 0 deletions
@@ -0,0 +1,96 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app" v-cloak>
<el-card shadow="never">
<el-select v-model="sessionId" placeholder="请选择教代会" style="width: 100%">
<el-option v-for="item in sessionOptions" :label="item.fullName" :value="item.id" :key="item.id"></el-option>
</el-select>
</el-card>
<el-card shadow="never">
<el-row :gutter="20">
<el-col :span="24">
<div id="delegationNumChart"></div>
</el-col>
</el-row>
</el-card>
</div>
<script nonce="${cspNonce!}">
let delegationChart = null
new Vue({
el: "#app",
components: {},
data() {
return {
sessionId: null,
sessionOptions: []
}
},
methods: {
sessionChange() {
this.pageForm.delegationId = null
this.delegationOptions = []
this.renderDelegationChart()
},
listSession() {
this.$axios.post("/platform/teacherCongress/common/listSession").then((res) => {
if (res.code === 0) {
this.sessionOptions = res.data
if (this.sessionOptions.length > 0) {
this.sessionId = this.sessionOptions[0].id
this.renderDelegationChart()
}
}
})
},
renderDelegationChart() {
this.$axios.post("/platform/teacherCongress/dashboard/listDelegationCount", { sessionId: this.sessionId }).then((res) => {
if (res.code === 0) {
if (!delegationChart) {
delegationChart = new G2Plot.Column("delegationNumChart", {
data: res.data,
xField: "name",
yField: "delegateCount",
label: {
position: "middle",
style: {
fill: "#FFFFFF",
opacity: 0.6
}
},
xAxis: {
label: {
autoHide: true,
autoRotate: false
}
},
meta: {
name: {
alias: "类别"
},
num: {
alias: "人数"
}
}
})
delegationChart.render()
} else {
delegationChart.changeData(res.data)
}
}
})
}
},
mounted() {
this.listSession()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,155 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app" v-cloak>
<guava ref="guava">
<template>
<el-card shadow="never">
<search @search="doSearch">
<search-item label="姓名/工号">
<el-input v-model="pageForm.searchKeyword" clearable
placeholder="请输入姓名或工号"
@keyup.enter.native="doSearch"></el-input>
</search-item>
<search-item label="教代会">
<el-select v-model="pageForm.sessionId" clearable filterable
placeholder="请选择教代会" style="width: 100%">
<el-option v-for="item in sessionOptions" :key="item.id"
:label="item.fullName" :value="item.id"></el-option>
</el-select>
</search-item>
<search-item label="所属工会">
<el-select v-model="pageForm.unionId" clearable filterable
placeholder="请选择所属工会" style="width: 100%"
@change="handleUnionChange">
<el-option v-for="item in unionOptions" :key="item.id"
:label="item.name" :value="item.id"></el-option>
</el-select>
</search-item>
<search-item label="所属单位">
<el-select v-model="pageForm.unitId" clearable filterable
placeholder="请选择所属单位" style="width: 100%">
<el-option v-for="item in unitOptions" :key="item.id"
:label="item.name" :value="item.id"></el-option>
</el-select>
</search-item>
</search>
</el-card>
<el-card class="mt10" shadow="never">
<table-tool label="代表变动记录"></table-tool>
<el-table v-loading="tableLoading" :data="tableData"
@sort-change="pageOrder" row-key="id" ref="tableRef"
style="width: 100%">
<el-table-column type="index" :index="indexMethod" label="序号"
align="center" header-align="center" width="70"></el-table-column>
<el-table-column label="姓名" prop="username" sortable="custom"
align="center" header-align="center" min-width="110"></el-table-column>
<el-table-column label="工号" prop="loginname" sortable="custom"
align="center" header-align="center" min-width="110"></el-table-column>
<el-table-column label="原教代会" prop="oldJdhName" sortable="custom"
align="center" header-align="center" min-width="130"
show-overflow-tooltip></el-table-column>
<el-table-column label="新教代会" prop="newJdhName" sortable="custom"
align="center" header-align="center" min-width="130"
show-overflow-tooltip></el-table-column>
<el-table-column label="原单位" prop="oldUnitName" sortable="custom"
align="center" header-align="center" min-width="180"
show-overflow-tooltip></el-table-column>
<el-table-column label="新单位" prop="newUnitName" sortable="custom"
align="center" header-align="center" min-width="180"
show-overflow-tooltip></el-table-column>
<el-table-column label="原代表团" prop="oldDbtName" sortable="custom"
align="center" header-align="center" min-width="140"
show-overflow-tooltip></el-table-column>
<el-table-column label="新代表团" prop="newDbtName" sortable="custom"
align="center" header-align="center" min-width="140"
show-overflow-tooltip></el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</template>
</guava>
</div>
<script nonce="${cspNonce!}">
new Vue({
el: "#app",
mixins: [initTableMixins],
data() {
return {
pageForm: {
searchKeyword: "",
sessionId: "",
unionId: "",
unitId: ""
},
sessionOptions: [],
unionOptions: [],
unitOptions: [],
pageRequestSequence: 0
}
},
methods: {
/** 查询分页数据;快速连续查询时只接收最后一次请求结果。 */
pageData() {
const requestSequence = ++this.pageRequestSequence
this.tableData = []
this.tableLoading = true
this.$axios.post(loc() + "/pageData", {
pageForm: JSON.stringify(this.pageForm)
}).then((res) => {
if (requestSequence !== this.pageRequestSequence) {
return
}
if (res.code === 0) {
this.tableData = res.data.list || []
this.pageForm.totalCount = res.data.totalCount || 0
} else {
this.$message.error(res.msg)
}
}).finally(() => {
if (requestSequence === this.pageRequestSequence) {
this.tableLoading = false
}
})
},
/** 切换工会时清空原单位条件,并重新加载该工会下的单位。 */
handleUnionChange() {
this.pageForm.unitId = ""
this.listUnit()
},
/** 加载教代会届次选项。 */
listSession() {
this.$axios.post("/platform/teacherCongress/common/listSession").then((res) => {
if (res.code === 0) {
this.sessionOptions = res.data || []
}
})
},
/** 加载当前账号可见的工会选项。 */
listUnion() {
this.$businessTool.listUnion().then((data) => {
this.unionOptions = data || []
})
},
/** 按当前工会条件加载单位选项。 */
listUnit() {
this.$businessTool.listUnit(this.pageForm.unionId).then((data) => {
this.unitOptions = data || []
})
}
},
created() {
this.listSession()
this.listUnion()
this.listUnit()
this.pageData()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,131 @@
const AddForm = {
template: /*language=HTML*/ `
<el-dialog title="新增代表" :visible.sync="dialogFormVisible" width="70%" :close-on-click-modal="false">
<el-form :model="formData" ref="formRef" label-width="120px" :rules="formRules">
<el-form-item prop="sessionId" label="届次">
<el-select v-model="formData.sessionId"
style="width: 100%"
placeholder="代表所属教代会"
@change="sessionChange">
<el-option v-for="item in sessionOptions"
:key="item.id"
:label="item.fullName"
:value="item.id"></el-option>
</el-select>
</el-form-item>
<el-form-item prop="delegationId" label="代表团">
<el-select v-model="formData.delegationId" filterable @change="delegationChange" clearable
style="width: 100%">
<el-option v-for="i in delegationOptions"
:label="i.name"
:key="i.id"
:value="i.id"></el-option>
</el-select>
</el-form-item>
<el-form-item prop="roleId" label="代表类型">
<el-select v-model="formData.roleId" filterable style="width: 100%">
<el-option v-for="i in roleOptions"
:label="i.name"
:key="i.id"
:value="i.id"></el-option>
</el-select>
</el-form-item>
<el-form-item prop="userIds" label="用户">
<user-select v-model="formData.userIds"
v-if="dialogFormVisible"
api="/platform/teacherCongress/delegate/manage/publicUser"
:api_params="{sessionId:formData.sessionId,delegationId:formData.delegationId}"
api_input_key_name="keyWord"
:option_label_func="(item)=>{return item.userName + item.loginName + '(' + item.unitName + ')'}"
:multiple="true"
style="width: 100%"></user-select>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">取 消</el-button>
<el-button type="primary" @click="doSubmit">确 定</el-button>
</div>
</el-dialog>
`,
data() {
return {
dialogFormVisible: false,
formData: {
userIds: [], sessionId: null, delegationId: null, roleId: null
},
formRules: {
sessionId: [{required: true, message: "必填", trigger: ["change", "blur"]}],
delegationId: [{required: true, message: "必填", trigger: ["change", "blur"]}],
roleId: [{required: true, message: "必填", trigger: ["change", "blur"]}],
userIds: [{required: true, message: "必填", trigger: ["change", "blur"]}]
},
sessionOptions: [],
delegationOptions: [],
roleOptions: []
}
},
methods: {
onOpen(sessionId, delegationId = null) {
if (!sessionId) {
return
}
this.formData = {
userIds: [], sessionId: sessionId, delegationId: delegationId, roleId: null
}
this.listSession()
this.listDelegation(sessionId)
this.listRole()
this.dialogFormVisible = true
},
listSession() {
this.$axios.post("/platform/teacherCongress/common/listSession").then((res) => {
if (res.code === 0) {
this.sessionOptions = res.data
}
})
},
listDelegation(sessionId) {
this.$axios.post("/platform/teacherCongress/common/listDelegation", {sessionId}).then((res) => {
if (res.code === 0) {
this.delegationOptions = res.data
}
})
},
listRole() {
this.$axios.post("/platform/teacherCongress/common/listDelegateRole").then((res) => {
if (res.code === 0) {
this.roleOptions = res.data
}
})
},
sessionChange(sessionId) {
this.listDelegation(sessionId)
this.formData.userIds = []
},
delegationChange() {
this.formData.userIds = []
},
doSubmit() {
this.$refs.formRef.validate((valid) => {
if (valid) {
this.$axios.post("/platform/teacherCongress/delegate/manage/insert", {data: JSON.stringify(this.formData)}).then((res) => {
if (res.code === 0) {
this.dialogFormVisible = false
this.$message.success(res.msg)
this.$emit("refresh")
}
})
}
})
}
}, created() {
}
}
@@ -0,0 +1,186 @@
var AdjustForm = {
template:
/*language=HTML*/
`
<el-dialog title="代表调整" :visible.sync="dialogFormVisible" width="65%" :close-on-click-modal="false">
<el-form :model="formData" ref="formRef" label-width="120px" :rules="formRules">
<el-row type="flex" justify="space-between">
<el-form-item prop="sessionId" label="届次">
<el-select v-model="formData.sessionId"
style="width: 100%"
placeholder="代表所属教代会"
@change="sessionChange">
<el-option v-for="item in sessionOptions"
:key="item.id"
:label="item.fullName"
:value="item.id"></el-option>
</el-select>
</el-form-item>
<el-form-item prop="userId" label="代表">
<user-select v-model="formData.userId"
ref="userSelectRef"
v-if="dialogFormVisible"
api="/platform/teacherCongress/delegate/manage/adjustUserList"
:api_params="{sessionId:formData.sessionId}"
api_input_key_name="keyWord"
placeholder="请选择代表"
:option_label_func="(item)=>{return item.userName + item.loginName + '(' + item.unitName + ')'}"
></user-select>
<el-button icon="el-icon-plus" type="primary" @click="move">添加到待调整列表</el-button>
</el-form-item>
</el-row>
<el-form-item prop="users" label="待调整代表">
<el-table :data="formData.users" size="small">
<el-table-column label="工号" prop="loginName"></el-table-column>
<el-table-column label="姓名" prop="userName"></el-table-column>
<el-table-column label="性别" prop="sex" width="50"></el-table-column>
<el-table-column label="所属工会" prop="unionName" show-overflow-tooltip></el-table-column>
<el-table-column label="所属单位" prop="unitName" show-overflow-tooltip></el-table-column>
<el-table-column label="代表团">
<template slot-scope="scope">
<el-form-item :prop="'users.'+scope.$index+'.delegationId'"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<el-select v-model="scope.row.delegationId" filterable>
<el-option v-for="d in delegationOptions" :label="d.name" :value="d.id"
:key="d.id"></el-option>
</el-select>
</el-form-item>
</template>
</el-table-column>
<el-table-column label="代表身份">
<template slot-scope="scope">
<el-form-item :prop="'users.'+scope.$index+'.roleId'"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<el-select v-model="scope.row.roleId" filterable style="width: 100%">
<el-option v-for="i in roleOptions"
:label="i.name"
:key="i.id"
:value="i.id"></el-option>
</el-select>
</el-form-item>
</template>
</el-table-column>
<el-table-column label="操作">
<template slot-scope="scope">
<el-link type="primary" @click="formData.users.splice(scope.$index,1)">取消调整
</el-link>
</template>
</el-table-column>
</el-table>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">取 消</el-button>
<el-button type="primary" @click="doSubmit">确 定</el-button>
</div>
</el-dialog>
`,
data() {
return {
dialogFormVisible: false,
formData: {},
formRules: {
sessionId: [{ required: true, message: "必填", trigger: ["change", "blur"] }]
},
sessionOptions: [],
delegationOptions: [],
roleOptions: []
}
},
methods: {
onOpen(sessionId) {
if (!sessionId) {
return
}
this.formData = {
sessionId: sessionId,
users: []
}
this.listRole()
this.listSession()
this.listDelegation(sessionId)
this.dialogFormVisible = true
},
listSession() {
this.$axios.post("/platform/teacherCongress/common/listSession").then((res) => {
if (res.code === 0) {
this.sessionOptions = res.data
}
})
},
listDelegation(sessionId) {
this.$axios.post("/platform/teacherCongress/common/listDelegation", { sessionId }).then((res) => {
if (res.code === 0) {
this.delegationOptions = res.data
}
})
},
listRole() {
this.$axios.post("/platform/teacherCongress/common/listDelegateRole").then((res) => {
if (res.code === 0) {
this.roleOptions = res.data
}
})
},
sessionChange(sessionId) {
this.listDelegation(sessionId)
},
move() {
if (!this.formData.userId) {
this.$message.warning("请先搜索需要调整的代表")
return
}
const user = this.$refs.userSelectRef.options.find((user) => user.id === this.formData.userId)
const repeat = this.formData.users.some((u) => u.id === user.id)
if (repeat) {
this.$message.warning("调整列表中已存在,请勿重复添加")
return
}
this.formData.users.unshift(user)
this.formData.userId = null
this.$refs.userSelectRef.clearOptions()
},
doSubmit() {
if (this.formData.users.length === 0) {
this.$message.warning("请先搜索并添加需要调整的代表")
return
}
this.$refs.formRef.validate((valid) => {
if (valid) {
const data = this.formData.users.map((param) => {
return {
id: param.id,
userId: param.userId,
delegationId: param.delegationId,
sessionId: this.formData.sessionId,
roleId: param.roleId
}
})
this.$axios
.post("/platform/teacherCongress/delegate/manage/doAdjustUser", {
data: JSON.stringify(data),
sessionId: this.formData.sessionId
})
.then((res) => {
if (res.code === 0) {
this.dialogFormVisible = false
this.$message.success(res.msg)
this.$emit("refresh")
}
})
}
})
}
},
created() {}
}
@@ -0,0 +1,116 @@
const editForm = {
template: /*language=HTML*/ `
<el-dialog title="编辑代表" :visible.sync="dialogFormVisible" width="40%" :close-on-click-modal="false">
<el-form :model="formData" ref="formRef" label-width="120px" :rules="formRules">
<el-form-item prop="sessionId" label="届次">
<el-select v-model="formData.sessionId"
disabled
style="width: 100%"
placeholder="代表所属教代会">
<el-option v-for="item in sessionOptions"
:key="item.id"
:label="item.fullName"
:value="item.id"></el-option>
</el-select>
</el-form-item>
<el-form-item prop="userName" label="姓名">
<el-input v-model="formData.userName" disabled></el-input>
</el-form-item>
<el-form-item prop="delegationId" label="代表团">
<el-select v-model="formData.delegationId" filterable clearable
style="width: 100%">
<el-option v-for="i in delegationOptions"
:label="i.name"
:key="i.id"
:value="i.id"></el-option>
</el-select>
</el-form-item>
<el-form-item prop="roleId" label="代表身份">
<el-select v-model="formData.roleId" filterable clearable
style="width: 100%">
<el-option v-for="i in roleOptions"
:label="i.name"
:key="i.id"
:value="i.id"></el-option>
</el-select>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">取 消</el-button>
<el-button type="primary" @click="doSubmit">确 定</el-button>
</div>
</el-dialog>
`,
data() {
return {
dialogFormVisible: false,
formData: {
userId: null, sessionId: null, delegationId: null, roleId: null
},
formRules: {
sessionId: [{required: true, message: "必填", trigger: ["change", "blur"]}],
delegationId: [{required: true, message: "必填", trigger: ["change", "blur"]}],
roleId: [{required: true, message: "必填", trigger: ["change", "blur"]}],
userId: [{required: true, message: "必填", trigger: ["change", "blur"]}]
},
sessionOptions: [],
delegationOptions: [],
roleOptions: []
}
},
methods: {
onOpen(row) {
this.formData = {
id: row.id,
roleId: row.roleId,
userName: row.userName,
sessionId: row.sessionId,
delegationId: row.delegationId,
userId: row.userId
}
this.listSession()
this.listDelegation(row.sessionId)
this.listRole()
this.dialogFormVisible = true
},
listSession() {
this.$axios.post("/platform/teacherCongress/common/listSession").then((res) => {
if (res.code === 0) {
this.sessionOptions = res.data
}
})
},
listDelegation(sessionId) {
this.$axios.post("/platform/teacherCongress/common/listDelegation", {sessionId}).then((res) => {
if (res.code === 0) {
this.delegationOptions = res.data
}
})
},
listRole() {
this.$axios.post("/platform/teacherCongress/common/listDelegateRole").then((res) => {
if (res.code === 0) {
this.roleOptions = res.data
}
})
},
doSubmit() {
this.$refs.formRef.validate((valid) => {
if (valid) {
this.$axios.post("/platform/teacherCongress/delegate/manage/update", this.formData).then((res) => {
if (res.code === 0) {
this.dialogFormVisible = false
this.$message.success(res.msg)
this.$emit("refresh")
}
})
}
})
}
}
}
@@ -0,0 +1,263 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app" v-cloak>
<el-card shadow="never">
<search @search="doSearch">
<search-item label="姓名/工号">
<el-input placeholder="请输入姓名或工号" clearable v-model="pageForm.searchKeyword"></el-input>
</search-item>
<search-item label="教代会">
<el-select v-model="pageForm.sessionId" @change="sessionChange">
<el-option v-for="item in sessionOptions" :label="item.fullName" :value="item.id" :key="item.id"></el-option>
</el-select>
</search-item>
<search-item label="代表团">
<el-select v-model="pageForm.delegationId" filterable @change="delegationChange" clearable style="width: 100%">
<el-option v-for="i in delegationOptions" :label="i.name" :key="i.id" :value="i.id"></el-option>
</el-select>
</search-item>
<search-item label="所属工会">
<el-select placeholder="请选择所属工会" v-model="pageForm.unionId" filterable @change="listUnit" clearable style="width: 100%">
<el-option v-for="i in unionOptions" :label="i.name" :key="i.id" :value="i.id"></el-option>
</el-select>
</search-item>
<search-item label="所属单位">
<el-select placeholder="请选择所属单位" v-model="pageForm.unitId" filterable clearable style="width: 100%">
<el-option v-for="i in unitOptions" :label="i.name" :key="i.id" :value="i.id"></el-option>
</el-select>
</search-item>
<search-item label="代表类型">
<el-select v-model="pageForm.roleId" filterable clearable style="width: 100%">
<el-option v-for="i in roleOptions" :label="i.name" :key="i.id" :value="i.id"></el-option>
</el-select>
</search-item>
</search>
</el-card>
<el-card shadow="never">
<table-tool>
<el-button size="small" type="primary" icon="el-icon-plus" @click="doAllocateDelegation">
{{ allocateButtonText }}
</el-button>
<el-button size="small" type="primary" icon="el-icon-plus" @click="excelImportDialog = true">导入代表</el-button>
<el-button size="small" type="primary" icon="el-icon-plus" @click="$refs.addFormRef.onOpen(pageForm.sessionId,pageForm.delegationId)">新增代表</el-button>
<el-button
size="small"
type="danger"
icon="el-icon-delete"
@click="batchDelete()"
:disabled="$refs.tableRef && $refs.tableRef.selection.length===0"
>
批量删除
</el-button>
<el-button size="small" type="primary" icon="el-icon-plus" @click="$refs.adjustFormRef.onOpen(pageForm.sessionId)">代表调整</el-button>
</table-tool>
<el-table :data="tableData" @sort-change="pageOrder" header-align="center" row-key="id" ref="tableRef" style="width: 100%">
<el-table-column type="selection" width="55" reserve-selection fixed="left"></el-table-column>
<el-table-column type="index" width="55" label="序号" :index="indexMethod" fixed="left"></el-table-column>
<el-table-column label="工号" prop="loginName" fixed="left"></el-table-column>
<el-table-column label="姓名" prop="userName" fixed="left" sortable></el-table-column>
<el-table-column label="性别" prop="sex" sortable></el-table-column>
<el-table-column label="年龄" prop="age" sortable></el-table-column>
<el-table-column label="联系方式" prop="mobile"></el-table-column>
<el-table-column label="代表团" prop="delegationId" width="150" show-overflow-tooltip sortable>
<template scope="{row}">
<dict-tag :options="delegationOptions" :value="row.delegationId" option_value="id" option_label="name"></dict-tag>
</template>
</el-table-column>
<el-table-column label="所属工会" prop="unionName" show-overflow-tooltip sortable></el-table-column>
<el-table-column label="所属单位" prop="unitName" show-overflow-tooltip sortable></el-table-column>
<el-table-column label="届次" prop="sessionId">
<template scope="{row}">
<dict-tag :options="sessionOptions" :value="row.sessionId" option_value="id" option_label="fullName"></dict-tag>
</template>
</el-table-column>
<el-table-column label="代表身份" prop="roleId" sortable>
<template scope="{row}">
<dict-tag :options="roleOptions" :value="row.roleId" option_value="id" option_label="name"></dict-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="200">
<template slot-scope="scope">
<!-- <el-button size="mini">查看</el-button>-->
<el-button size="mini" type="primary" @click="$refs.editFormRef.onOpen(scope.row)">编辑</el-button>
<el-button size="mini" type="danger" @click="doDelete([scope.row.id])">删除</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<add-form ref="addFormRef" @refresh="doSearch"></add-form>
<edit-form ref="editFormRef" @refresh="doSearch"></edit-form>
<adjust-form ref="adjustFormRef" @refresh="doSearch"></adjust-form>
<!--导入名单-->
<excel-import
ref="excelImportRef"
url="/platform/teacherCongress/delegate/manage/importByExcel"
template_url="/platform/teacherCongress/delegate/manage/downloadTemplate"
:visible.sync="excelImportDialog"
title="导入"
width="700px"
:extra_params="{sessionId:pageForm.sessionId}"
@import-success="doSearch"
></excel-import>
</div>
<script nonce="${cspNonce!}">
<!--#include("addForm.js"){}#-->
<!--#include("editForm.js"){}#-->
<!--#include("adjust.js"){}#-->
new Vue({
el: "#app",
mixins: [initTableMixins],
components: {
"add-form": AddForm,
"edit-form": editForm,
"adjust-form": AdjustForm
},
data() {
return {
pageForm: {
sessionId: null,
delegationId: null,
unionId: null,
unitId: null
},
sessionOptions: [],
delegationOptions: [],
unionOptions: [],
unitOptions: [],
roleOptions: [],
formRules: {},
excelImportDialog: false,
compositionMode: "${config.dbtzc!'unit'}"
}
},
computed: {
compositionLabel() {
return this.compositionMode === "union" ? "分工会" : "单位"
},
allocateButtonText() {
return "根据" + this.compositionLabel + "分配代表团"
}
},
methods: {
doAllocateDelegation() {
this.$confirm("确定要给尚未归团的代表,根据" + this.compositionLabel + "组成关系设置代表团吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "info"
}).then(() => {
this.$axios.post(loc() + "/doAllocateDelegation", {sessionId: this.pageForm.sessionId}).then((res) => {
if (res.code === 0) {
let message = "已分配" + res.data.assignedCount + "人"
if (res.data.unassignedCount > 0) {
message += ",另有" + res.data.unassignedCount + "人未找到对应代表团"
this.$message.warning(message)
} else {
this.$message.success(message)
}
this.doSearch()
}
})
})
},
sessionChange() {
this.pageForm.delegationId = null
this.delegationOptions = []
this.listDelegation()
this.doSearch()
},
delegationChange() {
this.pageForm.unionId = null
this.pageForm.unitId = null
},
listDelegation() {
this.delegationOptions = []
this.pageForm.delegationId = null
this.$axios.post("/platform/teacherCongress/common/listDelegation", { sessionId: this.pageForm.sessionId }).then((res) => {
if (res.code === 0) {
this.delegationOptions = res.data
}
})
},
listRole() {
this.$axios.post("/platform/teacherCongress/common/listDelegateRole").then((res) => {
if (res.code === 0) {
this.roleOptions = res.data
}
})
},
listUnion() {
this.$businessTool.listUnion().then((res) => {
this.unionOptions = res
})
},
listUnit() {
this.$businessTool.listUnit(this.pageForm.unionId).then((res) => {
this.unitOptions = res
})
},
doDelete(ids) {
this.$confirm("您确定要删除吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "info"
}).then(() => {
this.$axios.post(loc() + "/delete", { data: JSON.stringify({ ids: ids }) }).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.doSearch()
}
})
})
},
batchDelete() {
if (this.$refs.tableRef && this.$refs.tableRef.rowKey) {
const ids = this.$refs.tableRef.selection.map((row) => row[this.$refs.tableRef.rowKey])
if (ids.length === 0) {
this.$message.warning("请勾选数据后再删除")
return
}
this.doDelete(ids)
this.$refs.tableRef.clearSelection()
}
},
listSession() {
this.$axios.post("/platform/teacherCongress/common/listSession").then((res) => {
if (res.code === 0) {
this.sessionOptions = res.data
if (this.sessionOptions && this.sessionOptions.length > 0) {
this.pageForm.sessionId = this.sessionOptions[0].id
this.listDelegation()
this.pageData()
}
}
})
}
},
created() {
this.listRole()
this.listUnion()
this.listUnit()
this.listSession()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,113 @@
const auditInfo = {
template: /*language=HTML*/ `
<div>
<div class="proposal-info">
<div class="process-title">
基础信息
<el-link type="primary" @click="openChart">点击查看流程图</el-link>
</div>
<el-descriptions :column="3" border>
<el-descriptions-item label="姓名">{{ viewData.userName }}</el-descriptions-item>
<el-descriptions-item label="工号">{{viewData.loginName }}</el-descriptions-item>
<el-descriptions-item label="性别">{{viewData.sex }}</el-descriptions-item>
<el-descriptions-item label="出生年月">{{$moment(viewData.birthday).format("YYYY-MM-DD") }}
</el-descriptions-item>
<el-descriptions-item label="手机号">{{viewData.mobile }}</el-descriptions-item>
<el-descriptions-item label="民族">{{viewData.nation }}</el-descriptions-item>
<el-descriptions-item label="政治面貌">{{viewData.political }}</el-descriptions-item>
<el-descriptions-item label="所属工会">{{viewData.unionName }}</el-descriptions-item>
<el-descriptions-item label="所属单位">{{viewData.unitName }}</el-descriptions-item>
<el-descriptions-item label="文化程度">{{viewData.education }}</el-descriptions-item>
<el-descriptions-item label="职务">{{viewData.position }}</el-descriptions-item>
<el-descriptions-item label="职称">{{viewData.professionalTitle }}</el-descriptions-item>
<el-descriptions-item label="是否聘用制">{{viewData.employ?'是':'否' }}
</el-descriptions-item>
<el-descriptions-item label="是否高级职称">{{viewData.seniorTeacher?'是':'否' }}
</el-descriptions-item>
<el-descriptions-item label="是否中级职称及以下">{{viewData.intermediateBelow?'是':'否' }}
</el-descriptions-item>
<el-descriptions-item label="是否干部">{{viewData.cadre?'是':'否' }}</el-descriptions-item>
<el-descriptions-item label="是否工人">{{viewData.worker?'是':'否' }}</el-descriptions-item>
<el-descriptions-item label="校级领导">{{viewData.schoolLeader?'是':'否' }}</el-descriptions-item>
<el-descriptions-item label="中层领导">{{viewData.middleLevelLeader?'是':'否' }}
</el-descriptions-item>
</el-descriptions>
</div>
<template v-for="task in doneTasks">
<div class="mt10"
v-if="['0cacd1e7-7bb2-47dd-818b-6a73062e0c62'].includes(task.taskName)">
<div class="process-title">{{ task.displayName }}</div>
<el-descriptions border class="flow-task-form" :column="3" :key="task.id"
>
<el-descriptions-item label="办理用户">{{ task.taskFormData.userName
}}({{task.taskFormData.loginName}})
</el-descriptions-item>
<el-descriptions-item label="办理时间">{{ task.finishTime }}</el-descriptions-item>
<el-descriptions-item label="办理结果">
{{processSubmitTypeEnums.find(v=>v.name===task.ext.tf_type)?.message}}
<!-- {{dict.type.PROCESS_TASK_SUBMIT_TYPE.find(v=>v.code==task.ext.tf_type)}}-->
<!-- <dict-tag :options="dict.type.PROCESS_TASK_SUBMIT_TYPE"
:value=""></dict-tag>-->
</el-descriptions-item>
<el-descriptions-item label="办理意见" v-if="!task.ext.isFirstTaskNode">{{
task.taskFormData.opinion }}
</el-descriptions-item>
</el-descriptions>
</div>
</template>
<slot></slot>
<snaker-chart ref="snakerChartRef"></snaker-chart>
</div>
`,
dicts: ["PROCESS_TASK_SUBMIT_TYPE"],
data() {
return {
visible: false,
userData: [],
viewData: {},
row: null,
doneTasks: [],
loading: true,
search: "",
tableKey: "",
activeName: "1",
processSubmitTypeEnums:[]
}
},
methods: {
findOne() {
this.$axios.post("/platform/teacherCongress/delegate/push/write/finOne", {id: this.row.id}).then(resp => {
if (resp.code === 0) {
this.viewData = resp.data
}
})
},
// 打开
onOpen(row) {
this.row = row;
this.visible = true;
this.findOne();
this.getDoneTasks();
this.getEnumOptions()
},
// 获取已办任务审批记录
getDoneTasks() {
this.$axios.post("/flow/common/doneTasks", {bizId: this.row.id}).then((res) => {
if (res.code === 0) {
this.doneTasks = res.data
}
})
},
async getEnumOptions() {
const resp = await this.$axios.post("/open/common/dictEnumOptions", { name: "ProcessSubmitTypeEnum" })
this.processSubmitTypeEnums=resp.data
},
// 查看流程图
openChart() {
this.$refs.snakerChartRef.onOpenFull(this.row.instanceProcessDefineId, this.row.instanceId)
}
}
}
@@ -0,0 +1,309 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app" v-cloak>
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="姓名/工号">
<el-input placeholder="请输入姓名或工号" clearable v-model="pageForm.searchKeyword"></el-input>
</search-item>
<search-item label="教代会">
<el-select v-model="pageForm.sessionId">
<el-option v-for="item in sessionOptions" :label="item.fullName" :value="item.id"
:key="item.id"></el-option>
</el-select>
</search-item>
<search-item label="所属工会"
v-if="$auth.hasRole('SYSADMIN')||$auth.hasRole('SCHOOL_UNION_ADMIN')">
<el-select
@change="doSearch"
clearable
filterable
placeholder="报名所属分工会"
style="width: 100%"
v-model="pageForm.unionId"
>
<el-option :key="item.id" :label="item.name" :value="item.id"
v-for="item in unionOptions"></el-option>
</el-select>
</search-item>
</search>
</el-card>
<el-card shadow="never">
<push-progress ref="pushProgressRef"></push-progress>
</el-card>
<el-card shadow="never">
<table-tool>
<el-button icon="el-icon-check" size="small" type="primary" @click="onBatchSubmit">正式代表提交上报
</el-button>
<el-radio-group @change="doSearch" v-model="pageForm.isFormalOrAttendance" size="small">
<el-radio-button label="全部"></el-radio-button>
<el-radio-button label="正式代表"></el-radio-button>
<el-radio-button label="列席代表"></el-radio-button>
</el-radio-group>
<el-radio-group v-model="pageForm.approval" size="small"
@change="doSearch">
<el-radio-button :label="true">已审核</el-radio-button>
<el-radio-button :label="false">未审核</el-radio-button>
</el-radio-group>
</table-tool>
<el-table
ref="tableRef"
:data="tableData"
row-key="id"
@sort-change="pageOrder"
>
<el-table-column type="index" width="55" label="序号" :index="indexMethod"></el-table-column>
<el-table-column label="姓名" prop="userName" width="100"></el-table-column>
<el-table-column label="工号" prop="loginName"></el-table-column>
<el-table-column label="性别" prop="sex" width="50"></el-table-column>
<el-table-column label="分工会" prop="unionName" show-overflow-tooltip></el-table-column>
<el-table-column label="职务" prop="position"></el-table-column>
<el-table-column label="职称" prop="professionalTitle"></el-table-column>
<el-table-column label="是否聘用制" prop="employ">
<template v-slot="{row}">
<span v-if="row.employ" style="color:#0037ff;"></span>
<span v-else></span>
</template>
</el-table-column>
<el-table-column label="是否高级职称" prop="seniorTeacher">
<template v-slot="{row}">
<span v-if="row.seniorTeacher" style="color:#0037ff;"></span>
<span v-else></span>
</template>
</el-table-column>
<el-table-column label="是否中级职称及以下" prop="intermediateBelow">
<template v-slot="{row}">
<span v-if="row.intermediateBelow" style="color:#0037ff;"></span>
<span v-else></span>
</template>
</el-table-column>
<el-table-column label="是否干部" prop="cadre">
<template v-slot="{row}">
<span v-if="row.cadre" style="color:#0037ff;"></span>
<span v-else></span>
</template>
</el-table-column>
<el-table-column label="是否工人" prop="worker">
<template v-slot="{row}">
<span v-if="row.worker" style="color:#0037ff;"></span>
<span v-else></span>
</template>
</el-table-column>
<el-table-column label="教代会/工代会代表" prop="isJdh">
<template v-slot="{row}">
<span v-if="row.isJdh" style="color:#0037ff;"></span>
<span v-else></span>
</template>
</el-table-column>
<!-- <el-table-column label="工代会代表" prop="isGdh">-->
<!-- <template v-slot="{row}">-->
<!-- <span v-if="row.isGdh" style="color:#0037ff;">是</span>-->
<!-- <span v-else>否</span>-->
<!-- </template>-->
<!-- </el-table-column>-->
<el-table-column label="代表类型" prop="representativeType"></el-table-column>
<el-table-column prop="curTaskName" label="当前节点"></el-table-column>
<el-table-column label="审核时间" prop="finishTime" width="160">
<template slot-scope="{row}">
<span v-if="row.finishTime">{{$moment(row.finishTime).format('YYYY-MM-DD HH:mm:ss')}}</span>
</template>
</el-table-column>
<el-table-column prop="instanceState" label="流程状态">
<template slot-scope="{row}">
<enum-tag :value="row.instanceState" name="ProcessInstanceStateEnum" label_key="message"
size="small"></enum-tag>
</template>
</el-table-column>
<el-table-column label="操作" fixed="right" width="300px">
<template slot-scope="{row}">
<el-button @click="onView(row)" size="mini" type="primary">查看</el-button>
<el-button v-if="row.taskState === 10" @click="openAudit(row)" size="mini" type="primary">
审核
</el-button>
<el-button v-if="row.canRevoke" @click="onRevoke(row)" size="mini" type="danger">撤回
</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<template #edit>
<audit-info ref="auditInfoRef">
<div v-if="showApprovalForm">
<div class="process-title">
{{formData.taskName}}
</div>
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="0" label-suffix=""
class="flow-task-form">
<el-form-item label="审批意见" prop="tf_opinion"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<user-opinion-textarea v-model="formData.tf_opinion"></user-opinion-textarea>
</el-form-item>
</el-form>
<el-row type="flex" justify="end">
<el-button @click="handleTaskAction('AGREE')" size="small" type="primary">同意</el-button>
<el-button @click="handleTaskAction('ROLLBACK')" size="small" type="info">退回修改</el-button>
<el-button @click="$refs.guava.index()" size="small">取消</el-button>
</el-row>
</div>
</audit-info>
</template>
</guava>
</div>
<script nonce="${cspNonce!}">
<!--#include('push-progress.js'){}#-->
<!--#include('auditInfo.js'){}#-->
new Vue({
el: '#app',
mixins: [initTableMixins],
components: {
'push-progress': pushProgress,
'audit-info': auditInfo
},
data() {
return {
sessionOptions: [],
unionOptions: [],
pageForm: {
isFormalOrAttendance: "全部",
unionId: "",
sessionId: "",
approval: false,
},
showApprovalForm: false,
}
},
methods: {
async doSearch() {
await this.pageData()
const fullName = this.sessionOptions.find(v => v.id === this.pageForm.sessionId)?.fullName;
await this.$refs.pushProgressRef.refreshData(this.pageForm.sessionId, fullName, this.pageForm.unionId, "JG")
},
async pageData() {
try {
const resp = await this.$axios.post("/platform/teacherCongress/delegate/push/dwSjAudit/pageData", this.pageForm)
if (resp.code === 0) {
this.tableData = resp.data.list
this.pageForm.totalCount = resp.data.totalCount
}
} catch (e) {
console.log(e)
}
},
onBatchSubmit() {
this.$confirm('您确定要上报吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(async () => {
const loading = createLoading('正在提交中')
this.$axios.post('/platform/teacherCongress/delegate/push/dwSjAudit/batchSubmit', {
sessionId: this.pageForm.sessionId
}).then(resp => {
if (resp.code === 0) {
this.$message.success(resp.msg)
this.doSearch()
}
}).finally(() => {
loading.close()
})
})
},
openAudit(row) {
this.$refs.guava.edit(() => {
this.showApprovalForm = true
this.formData = {
bizId: row.id,
userId: row.userId,
processTaskId: row.taskId,
taskKey: row.taskKey,
taskName: row.taskName,
instanceId: row.instanceId,
submitType: 1,
}
this.$refs.auditInfoRef.onOpen(row)
})
},
onView(row) {
this.$refs.guava.edit(() => {
this.showApprovalForm = false
this.$refs.auditInfoRef.onOpen(row)
})
},
handleTaskAction(tf_type) {
this.$refs.formRef.validate((valid) => {
if (valid) {
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.formData.tf_type = tf_type
this.$axios.post("/flow/common/executeTask", {
data: JSON.stringify({
...this.formData,
})
}).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.doSearch()
this.$refs.guava.index()
}
})
})
}
})
},
onRevoke(row) {
this.$confirm("您确定要撤回吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "info"
}).then(() => {
this.$axios.post("/flow/common/revokeTask", {taskId: row.taskId}).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.doSearch()
}
})
})
},
listSession() {
this.$axios.post("/platform/teacherCongress/common/listSession").then((res) => {
if (res.code === 0) {
this.sessionOptions = res.data
if (this.sessionOptions && this.sessionOptions.length > 0) {
this.pageForm.sessionId = this.sessionOptions[0].id
this.doSearch()
}
}
})
}
},
async created() {
this.$businessTool.listUnion().then((res) => (this.unionOptions = res))
this.listSession()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,313 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style>
.write-dialog .el-dialog__body {
padding: 0;
}
</style>
<div id="app" v-cloak>
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="姓名/工号">
<el-input placeholder="请输入姓名或工号" clearable v-model="pageForm.searchKeyword"></el-input>
</search-item>
<search-item label="教代会">
<el-select v-model="pageForm.sessionId">
<el-option v-for="item in sessionOptions" :label="item.fullName" :value="item.id"
:key="item.id"></el-option>
</el-select>
</search-item>
<search-item label="分工会" v-if="$auth.hasRole('SYSADMIN') || $auth.hasRole('SCHOOL_UNION_ADMIN')">
<el-select v-model="pageForm.unionId" filterable clearable style="width: 100%">
<el-option v-for="i in unionOptions" :label="i.name" :key="i.id" :value="i.id"></el-option>
</el-select>
</search-item>
</search>
</el-card>
<el-card shadow="never">
<push-progress ref="pushProgressRef" @max-count="setMaxCount"></push-progress>
</el-card>
<el-card shadow="never">
<table-tool>
<el-button
icon="el-icon-plus"
size="small"
type="primary"
@click="doPushFormal"
>正式代表预选
</el-button>
<el-button
icon="el-icon-plus"
size="small"
type="primary"
@click="$refs.pushAttendanceRef.onOpen(pageForm.sessionId,pageForm.unionId)"
>列席代表预选
</el-button>
<!-- <el-button icon="el-icon-download" size="small" type="primary" @click="doExport">导出</el-button>-->
<el-radio-group v-model="pageForm.isFormalOrAttendance" size="small" class="ml10"
@change="doSearch">
<el-radio-button label="全部"></el-radio-button>
<el-radio-button label="正式代表"></el-radio-button>
<el-radio-button label="列席代表"></el-radio-button>
</el-radio-group>
</table-tool>
<el-table
ref="tableRef"
:data="tableData"
row-key="id"
@sort-change="pageOrder"
>
<!-- <el-table-column type="selection" width="55" reserve-selection fixed="left" :selectable="(row)=>{return row.taskKey==='0cacd1e7-7bb2-47dd-818b-6a73062e0c62'}"></el-table-column>-->
<el-table-column type="index" width="55" label="序号" :index="indexMethod"
fixed="left"></el-table-column>
<el-table-column label="姓名" prop="userName" width="100" fixed="left"></el-table-column>
<el-table-column label="年龄" prop="age" width="80"></el-table-column>
<el-table-column label="性别" prop="sex" width="80" fixed="left"></el-table-column>
<!-- <el-table-column label="民族" prop="nation" min-width="100"></el-table-column>-->
<el-table-column label="职称" prop="professionalTitle" min-width="150"></el-table-column>
<el-table-column label="职级" prop="professionalLevel" min-width="100"></el-table-column>
<el-table-column label="是否聘用制" prop="employ">
<template v-slot="{row}">
<span v-if="row.employ" style="color:#0037ff;"></span>
<span v-else></span>
</template>
</el-table-column>
<el-table-column label="是否高级职称" prop="seniorTeacher">
<template v-slot="{row}">
<span v-if="row.seniorTeacher" style="color:#0037ff;"></span>
<span v-else></span>
</template>
</el-table-column>
<el-table-column label="是否中级职称及以下" prop="intermediateBelow">
<template v-slot="{row}">
<span v-if="row.intermediateBelow" style="color:#0037ff;"></span>
<span v-else></span>
</template>
</el-table-column>
<el-table-column label="是否干部" prop="cadre">
<template v-slot="{row}">
<span v-if="row.cadre" style="color:#0037ff;"></span>
<span v-else></span>
</template>
</el-table-column>
<el-table-column label="是否工人" prop="worker">
<template v-slot="{row}">
<span v-if="row.worker" style="color:#0037ff;"></span>
<span v-else></span>
</template>
</el-table-column>
<el-table-column label="教代会/工代会代表" prop="isJdh">
<template v-slot="{row}">
<span v-if="row.isJdh" style="color:#0037ff;"></span>
<span v-else></span>
</template>
</el-table-column>
<el-table-column label="代表类型" prop="representativeType" show-overflow-tooltip
width="100"></el-table-column>
<el-table-column prop="taskName" label="当前节点" width="120" fixed="right"></el-table-column>
<el-table-column prop="instanceState" label="流程状态" fixed="right">
<template slot-scope="{row}">
<enum-tag :value="row.instanceState" name="ProcessInstanceStateEnum" label_key="message"
size="small"></enum-tag>
</template>
</el-table-column>
<el-table-column label="操作" fixed="right" width="300">
<template slot-scope="{row}">
<el-button @click="onView(row)" size="mini" type="primary">查看</el-button>
<el-button
v-if="row.taskKey === 'startTask'
|| row.taskKey==='53ff0c2a-ba93-45e9-a9fd-db51cdab3080'
|| row.taskKey==='97b0846b-22c6-4d34-9002-a6b67d592944'
|| !row.instanceId"
@click="onEdit(row)" size="mini"
type="primary">编辑
</el-button>
<template>
<el-button v-if="$auth.hasRoleOr('SYSADMIN, SCHOOL_UNION_ADMIN')" @click="onDelete(row.id)"
size="mini" type="danger">
删除
</el-button>
<el-button
v-else-if="row.taskKey === 'startTask'
|| row.taskKey==='53ff0c2a-ba93-45e9-a9fd-db51cdab3080'
|| row.taskKey=== null
|| row.taskKey==='0cacd1e7-7bb2-47dd-818b-6a73062e0c62' || !row.instanceId"
@click="onDelete(row.id)"
size="mini" type="danger">删除
</el-button>
</template>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<template #view>
<audit-info ref="auditInfoRef">
</audit-info>
</template>
</guava>
<push-formal-dialog ref="pushFormalRef" @refresh="doSearch" :max-push="formalPush"></push-formal-dialog>
<push-attendance-dialog ref="pushAttendanceRef" @refresh="doSearch"></push-attendance-dialog>
<el-dialog :close-on-click-modal="false"
class="write-dialog"
:visible.sync="writeDialog"
:title="isRead ? '查看' : '编辑'"
top="50px"
width="60%">
<div style="max-height: 75vh;overflow-y: auto">
<formal-write ref="formalWriteRef" :is_read="isRead" :user_id="userId"
:session_id="pageForm.sessionId"
:dialog="true"
@refresh="writeDialog=false;doSearch()"></formal-write>
</div>
<div slot="footer" class="dialog-footer">
<el-button @click="$refs.formalWriteRef.onSave()">保存草稿</el-button>
<el-button type="primary" @click="$refs.formalWriteRef.onSubmit()">提交信息</el-button>
</div>
</el-dialog>
</div>
<script nonce="${cspNonce!}">
<!--#include('push-progress.js'){}#-->
<!--#include('push-formal-dialog.js'){}#-->
<!--#include('push-attendance-dialog.js'){}#-->
<!--#include('write.js'){}#-->
<!--#include('auditInfo.js'){}#-->
new Vue({
el: '#app',
mixins: [initTableMixins],
components: {
'push-progress': pushProgress,
'push-formal-dialog': pushFormalDialog,
'push-attendance-dialog': pushAttendanceDialog,
'formal-write': write,
'audit-info': auditInfo
},
data() {
return {
pageForm: {
isFormalOrAttendance: "全部"
},
sessionOptions: [],
unionOptions: [],
writeDialog: false,
isRead: false,
userId: null,
// 当前分工会的最大推选人员
maxPush: 0,
// 剩余正式代表推选名额
formalPush: 0
}
},
methods: {
doPushFormal() {
if (this.tableData.length >= this.maxPush) {
this.$message.warning("当前正式代表已超过最大推选人员数,如需调整请在表格数据列中选中【删除】按钮")
return
}
this.$refs.pushFormalRef.onOpen(this.pageForm.sessionId, this.pageForm.unionId)
},
setMaxCount(data) {
this.maxPush = data
},
async doSearch() {
await this.pageData()
const fullName = this.sessionOptions.find(v => v.id === this.pageForm.sessionId)?.fullName;
await this.$refs.pushProgressRef.refreshData(this.pageForm.sessionId, fullName, this.pageForm.unionId)
this.formalPush = this.maxPush - this.tableData.length
},
onView(row) {
this.$refs.guava.view(() => {
this.$refs.auditInfoRef.onOpen(row)
})
},
onEdit(row) {
this.writeDialog = true
this.userId = row.userId
this.isRead = false
},
onDelete(id) {
this.$confirm("您确定要删除吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post("/platform/teacherCongress/delegate/push/delete", {id}).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.pageData()
}
})
})
},
doExport() {
},
listUnion() {
this.$businessTool.listUnion().then((res) => {
this.unionOptions = res
})
},
listSession() {
this.$axios.post("/platform/teacherCongress/common/listSession").then((res) => {
if (res.code === 0) {
this.sessionOptions = res.data
if (this.sessionOptions && this.sessionOptions.length > 0) {
this.pageForm.sessionId = this.sessionOptions[0].id
this.doSearch()
}
}
})
},
async pageData() {
try {
const resp = await this.$axios.post("/platform/teacherCongress/delegate/push/pageData", this.pageForm)
if (resp.code === 0) {
this.tableData = resp.data.list
this.pageForm.totalCount = resp.data.totalCount
}
} catch (e) {
console.log(e)
}
}
},
created() {
this.listUnion()
this.listSession()
}
})
</script>
<style>
.write-dialog .el-dialog__title {
font-size: 22px; /* 调整为您需要的大小 */
font-weight: 500;
}
.write-dialog .el-dialog__body {
padding-top: 0px;
}
</style>
<!--#
}
#-->
@@ -0,0 +1,142 @@
const pushAttendanceDialog = {
template: /*language=HTML*/ `
<el-dialog :close-on-click-modal="false"
:visible.sync="dialogVisible"
title="列席代表预选"
class="push-attendance-dialog"
width="70%">
<el-transfer
ref="transfer"
v-model="userValue"
:data="userData"
:filter-method="filterMethod"
:props="{key: 'id',label: 'name'}"
:titles="['可报人员名单', '当前选择']"
filterable
>
<div slot-scope="{ option }">
<div class="transfer-item">
<div class="transfer-item-name">{{ option.userName }} - {{ option.loginName }}</div>
<div class="transfer-item-details">
<span class="detail-item">{{ option.sex}}</span>
<span class="detail-item" v-if="option.age">{{ option.age }}岁</span>
<span class="detail-item"
v-if="option.professionalTitle">{{ option.professionalTitle }}</span>
<span class="detail-item"
v-if="option.professionalLevel">{{ option.professionalLevel }}</span>
<span class="detail-item" v-if="option.nation">{{ option.nation }}</span>
</div>
</div>
</div>
</el-transfer>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false">取 消</el-button>
<el-button type="primary" @click="onConfirm">确 定</el-button>
</span>
</el-dialog>
`,
data() {
return {
dialogVisible: false,
userValue: [],
userData: [],
rightChecked: [],
attendanceRightChecked: [],
sessionId: null
}
},
methods: {
async onOpen(sessionId, unionId) {
this.dialogVisible = true
this.sessionId = sessionId
this.userValue = []
this.userData = []
const {code, data} = await $.get('/platform/teacherCongress/delegate/push/getUnionUser', {
sessionId: sessionId,
unionId: unionId
})
if (code === 0) {
data.userData.forEach(v => {
this.userData.push({id: v.userId, ...v})
})
}
},
filterMethod(query, item) {
// 代表预选支持按姓名或工号筛选,兼容人员信息字段为空的情况。
const userName = item.userName || ""
const loginName = item.loginName || ""
return userName.indexOf(query) > -1 || loginName.indexOf(query) > -1
},
async onConfirm() {
const loading = createLoading('正在提交中')
const {code, msg} = await $.post('/platform/teacherCongress/delegate/push/addPreselectionDb', {
userValue: JSON.stringify(this.userValue),
sessionId: this.sessionId,
representativeType: '列席代表'
})
loading.close()
if (code === 0) {
this.dialogVisible = false
this.$message.success(msg)
this.$emit('refresh')
}
}
},
style: /*language=CSS*/ `
.push-attendance-dialog ::v-deep .el-transfer {
text-align: center !important;
}
.push-attendance-dialog ::v-deep .el-transfer-panel__item.el-checkbox {
height: auto;
display: block;
margin-right: 0;
padding: 0 15px;
}
.push-attendance-dialog ::v-deep .el-checkbox__input {
vertical-align: top;
margin-top: 5px;
}
.push-attendance-dialog ::v-deep .transfer-item {
padding: 5px;
font-size: 12px;
border-bottom: 1px solid #f0f0f0;
}
.push-attendance-dialog ::v-deep .transfer-item-name {
font-weight: bold;
margin-bottom: 3px;
color: #303133;
}
.push-attendance-dialog ::v-deep .transfer-item-details {
display: flex;
flex-wrap: wrap;
gap: 6px;
color: #606266;
}
.push-attendance-dialog ::v-deep .detail-item {
display: inline-flex;
align-items: center;
}
.push-attendance-dialog ::v-deep .el-transfer-panel {
height: 60vh;
text-align: left !important;
width: 35% !important;
}
.push-attendance-dialog ::v-deep .el-transfer-panel__body {
height: calc(100% - 40px) !important;
display: flex;
flex-direction: column;
}
.push-attendance-dialog ::v-deep .el-transfer-panel__list.is-filterable {
flex: 1;
}
`
}
@@ -0,0 +1,159 @@
const pushFormalDialog = {
template: /*language=HTML*/ `
<el-dialog :close-on-click-modal="false"
:visible.sync="dialogVisible"
title="正式代表预选"
class="push-formal-dialog"
width="70%">
<el-transfer
ref="transfer"
v-model="userValue"
:data="userData"
:filter-method="filterMethod"
:props="{key: 'id',label: 'name'}"
:titles="['教职工名单', '当前选择']"
filterable
@change="onTransferChange"
>
<div slot-scope="{ option }">
<div class="transfer-item">
<div class="transfer-item-name">{{ option.userName }} - {{ option.loginName }}</div>
<div class="transfer-item-details">
<span class="detail-item">{{ option.sex}}</span>
<span class="detail-item" v-if="option.age">{{ option.age }}岁</span>
<span class="detail-item"
v-if="option.professionalTitle">{{ option.professionalTitle }}</span>
<span class="detail-item"
v-if="option.professionalLevel">{{ option.professionalLevel }}</span>
<span class="detail-item" v-if="option.nation">{{ option.nation }}</span>
</div>
</div>
</div>
</el-transfer>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false">取 消</el-button>
<el-button type="primary" @click="onConfirm">确 定</el-button>
</span>
</el-dialog>
`,
props: {
maxPush: { type: Number, default: 1}
},
data() {
return {
dialogVisible: false,
userValue: [],
userData: [],
rightChecked: [],
attendanceRightChecked: [],
sessionId: null,
}
},
methods: {
onTransferChange(targetKeys, direction, movedKeys) {
// targetKeys 是新的 userValue
if (targetKeys.length > this.maxPush) {
this.$message.warning("剩余正式代表名额为【" + this.maxPush + "】人,请合理调配!");
// 只保留前 maxSelectCount 个(或根据业务逻辑决定保留哪些)
const validKeys = targetKeys.slice(0, this.maxPush);
// 更新 model 值(注意:避免无限触发 change)
this.userValue = validKeys;
}
},
async onOpen(sessionId, unionId) {
this.dialogVisible = true
this.sessionId = sessionId
this.userValue = []
this.userData = []
const {code, data} = await this.$axios.post('/platform/teacherCongress/delegate/push/getUnionUser', {
sessionId: sessionId,
unionId: unionId
})
if (code === 0) {
data.userData.forEach(v => {
this.userData.push({id: v.userId, ...v})
})
}
},
filterMethod(query, item) {
// 代表预选支持按姓名或工号筛选,兼容人员信息字段为空的情况。
const userName = item.userName || ""
const loginName = item.loginName || ""
return userName.indexOf(query) > -1 || loginName.indexOf(query) > -1
},
async onConfirm() {
const loading = createLoading('正在提交中')
const {code, msg} = await this.$axios.post('/platform/teacherCongress/delegate/push/addPreselectionDb', {
userValue: JSON.stringify(this.userValue),
sessionId: this.sessionId,
representativeType: '正式代表'
})
loading.close()
if (code === 0) {
this.dialogVisible = false
this.$message.success(msg)
this.$emit('refresh')
}
}
},
style: /*language=CSS*/ `
.push-formal-dialog ::v-deep .el-transfer {
text-align: center !important;
}
.push-formal-dialog ::v-deep .el-transfer-panel__item.el-checkbox {
height: auto;
display: block;
margin-right: 0;
padding: 0 15px;
}
.push-formal-dialog ::v-deep .el-checkbox__input {
vertical-align: top;
margin-top: 5px;
}
.push-formal-dialog ::v-deep .transfer-item {
padding: 5px;
font-size: 12px;
border-bottom: 1px solid #f0f0f0;
}
.push-formal-dialog ::v-deep .transfer-item-name {
font-weight: bold;
margin-bottom: 3px;
color: #303133;
}
.push-formal-dialog ::v-deep .transfer-item-details {
display: flex;
flex-wrap: wrap;
gap: 6px;
color: #606266;
}
.push-formal-dialog ::v-deep .detail-item {
display: inline-flex;
align-items: center;
}
.push-formal-dialog ::v-deep .el-transfer-panel {
height: 60vh;
text-align: left !important;
width: 35% !important;
}
.push-formal-dialog ::v-deep .el-transfer-panel__body {
height: calc(100% - 40px) !important;
display: flex;
flex-direction: column;
}
.push-formal-dialog ::v-deep .el-transfer-panel__list.is-filterable {
flex: 1;
}
`
}
@@ -0,0 +1,736 @@
const pushProgress = {
template: /*language=HTML*/ `
<div class="representative-allocation">
<div class="container-x">
<!-- 主卡片 -->
<div class="card">
<div class="header-x">
<div class="title">
<h1>正式代表名额分配概况</h1>
<p>{{teacherMeetName}}教职工代表大会代表名额分配情况</p>
</div>
<div class="buttons">
<!-- <el-button type="primary" icon="el-icon-download">导出数据</el-button>-->
</div>
</div>
<div class="grid-cols-3" style="grid-template-columns: repeat(8,1fr)">
<!-- 总代表数 -->
<div class="metric-card">
<div class="metric-header">
<div>
<div class="metric-title">总代表数</div>
<div class="metric-value">
{{ metrics.total.current }}
<span class="metric-target">
/ {{ metrics.total.target }}
</span>
</div>
</div>
<div class="metric-icon bg-primary-light">
<i class="fas fa-users text-primary"></i>
</div>
</div>
<div class="progress-bar">
<div class="progress-bar-inner bg-success"
:style="{width: metrics.total.progress * 100 + '%'}"></div>
</div>
<div class="progress-info">
<span v-if="metrics.total.progress>1" class="text-danger">
已超出
</span>
<span v-else-if="metrics.total.progress<1" class="text-primary">
未达标
</span>
<span v-else class="text-success">
已达标
</span>
<!-- <span class="text-gray-500" v-if="metrics.total.progress<1">剩余 {{ metrics.total.remaining }} 人</span>-->
</div>
</div>
<!-- 高级职称专任教师代表数 -->
<div class="metric-card">
<div class="metric-header">
<div>
<div class="metric-title">高级职称代表</div>
<div class="metric-value">{{ metrics.seniorTeacher.current }}<span
class="metric-target"
>/ {{ metrics.seniorTeacher.target }}</span></div>
</div>
<div class="metric-icon bg-primary-light">
<i class="fas fa-user-tie text-primary"/>
</div>
</div>
<div class="progress-bar">
<div class="progress-bar-inner bg-primary"
:style="{width: metrics.seniorTeacher.progress * 100 + '%'}"></div>
</div>
<div class="progress-info">
<span v-if="metrics.seniorTeacher.progress>=1 || metrics.seniorTeacher.target===0"
class="text-success">
已达标
</span>
<span v-else-if="metrics.seniorTeacher.progress<1" class="text-primary">
未达标
</span>
<span
v-if="metrics.seniorTeacher.remaining>0"
class="text-gray-500"
>剩余 {{ metrics.seniorTeacher.remaining }} 人</span>
</div>
</div>
<!-- 中级职称及以下-->
<div class="metric-card">
<div class="metric-header">
<div>
<div class="metric-title">中级职称及以下代表</div>
<div class="metric-value">{{ metrics.intermediateBelow.current }}<span
class="metric-target"
>/ {{ metrics.intermediateBelow.target }}</span></div>
</div>
<div class="metric-icon bg-primary-light">
<i class="fas fa-chalkboard-teacher text-primary"></i>
</div>
</div>
<div class="progress-bar">
<div
class="progress-bar-inner bg-primary"
:style="{width: metrics.intermediateBelow.progress * 100 + '%'}"
></div>
</div>
<div class="progress-info">
<span v-if="metrics.intermediateBelow.progress>=1 || metrics.intermediateBelow.target===0"
class="text-success">
已达标
</span>
<span v-else-if="metrics.intermediateBelow.progress<1" class="text-primary">
未达标
</span>
<span
v-if="metrics.intermediateBelow.remaining>0"
class="text-gray-500"
>剩余 {{ metrics.intermediateBelow.remaining }} 人</span>
</div>
</div>
<!-- 干部-->
<div class="metric-card">
<div class="metric-header">
<div>
<div class="metric-title">干部代表</div>
<div class="metric-value">{{ metrics.cadre.current }}<span
class="metric-target"
>/ {{ metrics.cadre.target }}</span></div>
</div>
<div class="metric-icon bg-primary-light">
<i class="fas fa-chalkboard-teacher text-primary"></i>
</div>
</div>
<div class="progress-bar">
<div class="progress-bar-inner bg-primary"
:style="{width: metrics.cadre.progress * 100 + '%'}"
></div>
</div>
<div class="progress-info">
<span v-if="metrics.cadre.progress>=1 || metrics.cadre.target===0"
class="text-success">
已达标
</span>
<span v-else-if="metrics.cadre.progress<1" class="text-primary">
未达标
</span>
<span
v-if="metrics.cadre.remaining>0"
class="text-gray-500"
>剩余 {{ metrics.cadre.remaining }} 人</span>
</div>
</div>
<!-- 工人-->
<div class="metric-card">
<div class="metric-header">
<div>
<div class="metric-title">工人代表</div>
<div class="metric-value">{{ metrics.worker.current }}<span
class="metric-target"
>/ {{ metrics.worker.target }}</span></div>
</div>
<div class="metric-icon bg-primary-light">
<i class="fas fa-chalkboard-teacher text-primary"></i>
</div>
</div>
<div class="progress-bar">
<div class="progress-bar-inner bg-primary"
:style="{width: metrics.worker.progress * 100 + '%'}"
></div>
</div>
<div class="progress-info">
<span v-if="metrics.worker.progress>=1 || metrics.worker.target===0"
class="text-success">
已达标
</span>
<span v-else-if="metrics.worker.progress<1" class="text-primary">
未达标
</span>
<span
v-if="metrics.worker.remaining>0"
class="text-gray-500"
>剩余 {{ metrics.worker.remaining }} 人</span>
</div>
</div>
<!-- 专任教师代表数 -->
<!-- <div class="metric-card">
<div class="metric-header">
<div>
<div class="metric-title">专任教师代表</div>
<div class="metric-value">{{ metrics.ordinaryTeacher.current }}<span
class="metric-target"
>/ {{ metrics.ordinaryTeacher.target }}</span></div>
</div>
<div class="metric-icon bg-primary-light">
<i class="fas fa-chalkboard-teacher text-primary"></i>
</div>
</div>
<div class="progress-bar">
<div
class="progress-bar-inner bg-primary"
:style="{width: metrics.ordinaryTeacher.progress * 100 + '%'}"
></div>
</div>
<div class="progress-info">
<span v-if="metrics.ordinaryTeacher.progress>=1 || metrics.ordinaryTeacher.target===0"
class="text-success">
已达标
</span>
<span v-else-if="metrics.ordinaryTeacher.progress<1" class="text-primary">
未达标
</span>
<span
v-if="metrics.ordinaryTeacher.remaining>0"
class="text-gray-500"
>剩余 {{ metrics.ordinaryTeacher.remaining }} 人</span>
</div>
</div>-->
<!-- 女代表数 -->
<div class="metric-card">
<div class="metric-header">
<div>
<div class="metric-title">女代表数</div>
<div class="metric-value">{{ metrics.female.current }}<span
class="metric-target"
>/ {{ metrics.female.target }}</span></div>
</div>
<div class="metric-icon bg-warning-light">
<i class="fas fa-female text-warning"></i>
</div>
</div>
<div class="progress-bar">
<div
class="progress-bar-inner bg-primary"
:style="{width: metrics.female.progress * 100 + '%'}"
></div>
</div>
<div class="progress-info">
<span v-if="metrics.female.progress>=1 || metrics.female.target===0"
class="text-success">
已达标
</span>
<span v-else-if="metrics.female.progress<1" class="text-primary">
未达标
</span>
<span v-if="metrics.female.remaining>0" class="text-gray-500">剩余 {{
metrics.female.remaining
}} 人</span>
</div>
</div>
<!-- 45岁以下代表数 -->
<!--<div class="metric-card">
<div class="metric-header">
<div>
<div class="metric-title">45岁以下代表</div>
<div class="metric-value">{{ metrics.under45.current }}<span
class="metric-target"
>/ {{ metrics.under45.target }}</span></div>
</div>
<div class="metric-icon bg-primary-light">
<i class="fas fa-user-graduate text-primary"></i>
</div>
</div>
<div class="progress-bar">
<div class="progress-bar-inner bg-primary"
:style="{width: metrics.under45.progress * 100 + '%'}"></div>
</div>
<div class="progress-info">
<span v-if="metrics.under45.progress>=1 || metrics.under45.target===0"
class="text-success">
已达标
</span>
<span v-else-if="metrics.under45.progress<1" class="text-primary">
未达标
</span>
<span v-if="metrics.under45.remaining>0" class="text-gray-500">剩余 {{
metrics.under45.remaining
}} 人</span>
</div>
</div>-->
<!-- 聘用制代表数 -->
<div class="metric-card">
<div class="metric-header">
<div>
<div class="metric-title">聘用制代表</div>
<div class="metric-value">{{ metrics.employ.current }}<span
class="metric-target"
>/ {{ metrics.employ.target }}</span></div>
</div>
<div class="metric-icon bg-primary-light">
<i class="fas fa-user-graduate text-primary"></i>
</div>
</div>
<div class="progress-bar">
<div class="progress-bar-inner bg-primary"
:style="{width: metrics.employ.progress * 100 + '%'}"></div>
</div>
<div class="progress-info">
<span v-if="metrics.employ.progress>=1 || metrics.employ.target===0"
class="text-success">
已达标
</span>
<span v-else-if="metrics.employ.progress<1" class="text-primary">
未达标
</span>
<span v-if="metrics.employ.remaining>0" class="text-gray-500">剩余 {{
metrics.employ.remaining
}} 人</span>
</div>
</div>
<!-- &lt;!&ndash; 少数民族数 &ndash;&gt;
<div class="metric-card">
<div class="metric-header">
<div>
<div class="metric-title">少数民族代表</div>
<div class="metric-value">{{ metrics.ethnicMinority.current }}<span
class="metric-target"
>/ {{ metrics.ethnicMinority.target }}</span></div>
</div>
<div class="metric-icon bg-primary-light">
<i class="fas fa-user-graduate text-primary"></i>
</div>
</div>
<div class="progress-bar">
<div class="progress-bar-inner bg-primary"
:style="{width: metrics.ethnicMinority.progress * 100 + '%'}"></div>
</div>
<div class="progress-info">
<span v-if="metrics.ethnicMinority.progress>=1 || metrics.ethnicMinority.target===0"
class="text-success">
已达标
</span>
<span v-else-if="metrics.ethnicMinority.progress<1" class="text-primary">
未达标
</span>
<span v-if="metrics.ethnicMinority.remaining>0" class="text-gray-500">剩余 {{
metrics.ethnicMinority.remaining
}} 人</span>
</div>
</div>
&lt;!&ndash; 校级领导 &ndash;&gt;
<div class="metric-card">
<div class="metric-header">
<div>
<div class="metric-title">校级领导代表</div>
<div class="metric-value">{{ metrics.schoolLeader.current }}<span
class="metric-target"
>/ {{ metrics.schoolLeader.target }}</span></div>
</div>
<div class="metric-icon bg-primary-light">
<i class="fas fa-user-graduate text-primary"></i>
</div>
</div>
<div class="progress-bar">
<div class="progress-bar-inner bg-primary"
:style="{width: metrics.schoolLeader.progress * 100 + '%'}"></div>
</div>
<div class="progress-info">
<span v-if="metrics.schoolLeader.progress>=1 || metrics.schoolLeader.target===0"
class="text-success">
已达标
</span>
<span v-else-if="metrics.schoolLeader.progress<1" class="text-primary">
未达标
</span>
<span v-if="metrics.schoolLeader.remaining>0" class="text-gray-500">剩余 {{
metrics.schoolLeader.remaining
}} 人</span>
</div>
</div>
&lt;!&ndash; 中层领导 &ndash;&gt;
<div class="metric-card">
<div class="metric-header">
<div>
<div class="metric-title">中层领导</div>
<div class="metric-value">{{ metrics.middleLevelLeader.current }}<span
class="metric-target"
>/ {{ metrics.middleLevelLeader.target }}</span></div>
</div>
<div class="metric-icon bg-primary-light">
<i class="fas fa-user-graduate text-primary"></i>
</div>
</div>
<div class="progress-bar">
<div class="progress-bar-inner bg-primary"
:style="{width: metrics.middleLevelLeader.progress * 100 + '%'}"></div>
</div>
<div class="progress-info">
<span v-if="metrics.middleLevelLeader.progress>=1 || metrics.middleLevelLeader.target===0"
class="text-success">
已达标
</span>
<span v-else-if="metrics.middleLevelLeader.progress<1" class="text-primary">
未达标
</span>
<span v-if="metrics.middleLevelLeader.remaining>0" class="text-gray-500">剩余 {{
metrics.middleLevelLeader.remaining
}} 人</span>
</div>
</div>-->
</div>
</div>
<div class="card">
<h2 class="legend-title">指标说明</h2>
<div class="legend-container">
<div class="legend-item">
<div class="legend-color bg-success"></div>
<span class="legend-text">已达标:当前数量已达到或超过目标值</span>
</div>
<div class="legend-item">
<div class="legend-color bg-primary"></div>
<span class="legend-text">未达标:当前数量未达到目标值,但已有代表选派</span>
</div>
</div>
<div class="update-time"></div>
</div>
<!-- <div class="card">
<h2 class="legend-title">上报说明</h2>
<div class="legend-container">
<div class="legend-item">
<div class="legend-color bg-warning "></div>
<span class="legend-text">正式代表完成信息填写后才能进行上报,列席代表可直接上报且不计入名额</span>
</div>
<div class="legend-item">
<div class="legend-color bg-warning "></div>
<span class="legend-text" style="color: red">当前代表为预推选,不计入代表总额,需等待党委书记审核后方才记录</span>
</div>
</div>
</div>-->
</div>
</div>
`,
props: {
sessionId: {
type: String,
required: false,
default: null
},
unionId: {
type: String,
required: false,
default: null
}
},
data() {
return {
metrics: {
total: {
current: 0,
target: 0,
progress: 0,
remaining: 0
},
female: {
current: 0,
target: 0,
progress: 0,
remaining: 0
},
seniorTeacher: {
current: 0,
target: 0,
progress: 0,
remaining: 0
},
intermediateBelow: {
current: 0,
target: 0,
progress: 0,
remaining: 0
},
cadre: {
current: 0,
target: 0,
progress: 0,
remaining: 0
},
worker: {
current: 0,
target: 0,
progress: 0,
remaining: 0
},
ordinaryTeacher: {
current: 0,
target: 0,
progress: 0,
remaining: 0
},
under45: {
current: 0,
target: 0,
progress: 0,
remaining: 0
},
ethnicMinority: {
current: 0,
target: 0,
progress: 0,
remaining: 0
},
schoolLeader: {
current: 0,
target: 0,
progress: 0,
remaining: 0
},
middleLevelLeader: {
current: 0,
target: 0,
progress: 0,
remaining: 0
},
employ: {
current: 0,
target: 0,
progress: 0,
remaining: 0
}
},
teacherMeetName: null
}
},
watch: {
sessionId(val) {
this.refreshData()
}
},
methods: {
async refreshData(sessionId, teacherMeetName, unionId) {
this.teacherMeetName = teacherMeetName
const {code, data} = await $.get('/platform/teacherCongress/delegate/push/selfUnionPushMetric', {
sessionId: sessionId,
unionId: unionId
})
if (code === 0) {
if (data) {
this.metrics = data
this.$emit('max-count', this.metrics.total.target)
} else {
this.$message.error('暂未分配名额')
}
}
}
},
style: /*language=CSS*/ `
.representative-allocation {
margin: 0;
padding: 0;
}
.representative-allocation .card {
background-color: white;
border-radius: 8px;
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.03);
margin-bottom: 24px;
}
.representative-allocation .header-x {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 24px;
}
.representative-allocation .header-x .title h1 {
font-size: 24px;
font-weight: 700;
margin: 0;
color: #111827;
}
.representative-allocation .header-x .title p {
font-size: 14px;
color: #6b7280;
margin-top: 8px;
margin-bottom: 0;
}
.representative-allocation .buttons {
display: flex;
gap: 16px;
}
.representative-allocation .grid-cols-3 {
display: grid;
grid-template-columns: repeat(8, 1fr);
gap: 24px;
}
.representative-allocation .metric-card {
background-color: #f3f3f3;
border-radius: 8px;
padding: 24px;
}
.representative-allocation .metric-card .metric-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 16px;
}
.representative-allocation .metric-card .metric-header .metric-title {
font-size: 14px;
color: #6b7280;
margin-bottom: 4px;
font-weight: 600;
}
.representative-allocation .metric-card .metric-header .metric-value {
font-size: 30px;
font-weight: 700;
color: #111827;
}
.representative-allocation .metric-card .metric-header .metric-value .metric-target {
font-size: 14px;
color: #6b7280;
margin-left: 4px;
}
.representative-allocation .metric-card .metric-icon {
width: 40px;
height: 40px;
border-radius: 50%;
align-items: center;
justify-content: center;
display: none;
}
.representative-allocation .progress-bar {
height: 4px;
border-radius: 2px;
background-color: #f0f0f0;
overflow: hidden;
}
.representative-allocation .progress-bar .progress-bar-inner {
height: 100%;
transition: width 0.3s ease;
}
.representative-allocation .progress-info {
display: flex;
justify-content: space-between;
margin-top: 8px;
font-size: 12px;
}
.representative-allocation .bg-primary {
background-color: #1677ff;
}
.representative-allocation .bg-primary-light {
background-color: rgba(22, 119, 255, 0.1);
}
.representative-allocation .text-primary {
color: #1677ff;
}
.representative-allocation .bg-secondary {
background-color: #4096ff;
}
.representative-allocation .bg-success {
background-color: #52c41a;
}
.representative-allocation .text-success {
color: #52c41a;
}
.representative-allocation .bg-warning {
background-color: #faad14;
}
.representative-allocation .text-warning {
color: #faad14;
}
.representative-allocation .bg-warning-light {
background-color: rgba(250, 173, 20, 0.1);
}
.representative-allocation .text-gray-500 {
color: #6b7280;
}
.representative-allocation .legend-title {
font-size: 18px;
font-weight: 700;
color: #111827;
margin-bottom: 16px;
}
.representative-allocation .legend-container {
display: grid;
grid-template-columns: 1fr;
gap: 16px;
}
.representative-allocation .legend-item {
display: flex;
align-items: center;
}
.representative-allocation .legend-item .legend-color {
width: 12px;
height: 12px;
border-radius: 50%;
margin-right: 8px;
}
.representative-allocation .legend-item .legend-text {
color: #6b7280;
}
.representative-allocation .update-time {
font-size: 14px;
color: #6b7280;
margin-top: 16px;
}
`
}
@@ -0,0 +1,33 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app" v-cloak>
<guava>
<formal-write ref="formalWriteRef"></formal-write>
</guava>
</div>
<script nonce="${cspNonce!}">
<!--#include('write.js'){}#-->
new Vue({
el: '#app',
components: {
'formal-write': write
},
store,
data(){
return{
isRead:false,
userId:null
}
},
created(){
this.userId = this.$store.state.user.id
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,655 @@
const write = {
template: /*language=HTML*/ `
<div class="container-x1" style="padding: 0">
<div class="form-container">
<header class="header-x">
<div class="header-left">
<h1 class="title">代表信息填写</h1>
</div>
<div class="header-right">
当前届次:
<el-select
v-model="formData.sessionId"
:disabled="session_id!=null && user_id!=null"
@change="teacherMeetIdChange"
>
<el-option v-for="item in sessionOptions" :label="item.fullName" :value="item.id"
:key="item.id"></el-option>
</el-select>
</div>
</header>
<div class="notice-panel" :class="{ hidden: isSelected }">
<div>
<i class="el-icon-warning notice-icon"></i>
<h2 class="notice-title">暂未被推选为教代会代表</h2>
<p class="notice-text">如有疑问,请联系所在单位</p>
</div>
</div>
<div class="info-box" :class="{ hidden: !isSelected }">
<div class="info-content">
<!-- <i class="fa fa-info-circle info-icon"></i>-->
<div class="info-text">
<h2 class="info-title" style="font-size: 18px;">推选信息</h2>
<p class="info-desc">您已被预选为{{ sessionName }}代表</p>
<div class="info-details">
<p>推选单位:{{ formData.unionName }}</p>
<p>推选时间:{{ formData.pushTime }}</p>
<p>代表类型:
<span>{{
[formData.isJdh && ('教代会'+formData.representativeType), formData.isGdh && ('工代会'+formData.representativeType)].filter(Boolean).join('、')
}}</span>
</p>
</div>
</div>
</div>
</div>
<el-tabs v-model="activeName">
<el-tab-pane label="填写信息" name="one">
<el-form
ref="formRef"
:model="formData"
:rules="rules"
label-width="150px"
:class="{ hidden: !isSelected }"
:disabled="(formData && !['53ff0c2a-ba93-45e9-a9fd-db51cdab3080','97b0846b-22c6-4d34-9002-a6b67d592944'].includes(formData.taskKey)) || is_read"
>
<div class="form-section">
<h2 class="section-title">基本信息</h3>
<div class="form-grid custom-grid">
<div class="grid-item">
<el-form-item label="姓名" prop="userName">
<el-input v-model="formData.userName" readonly></el-input>
</el-form-item>
</div>
<div class="grid-item">
<el-form-item label="工号" prop="loginName">
<el-input v-model="formData.loginName" readonly></el-input>
</el-form-item>
</div>
<div class="grid-item">
<el-form-item label="性别" prop="sex">
<el-radio-group v-model="formData.sex" size="small">
<el-radio border label="男">男</el-radio>
<el-radio border label="女">女</el-radio>
</el-radio-group>
</el-form-item>
</div>
<div class="grid-item">
<el-form-item label="出生年月" prop="birthday">
<el-date-picker
v-model="formData.birthday"
type="date"
placeholder="选择日期"
value-format="yyyy-MM-dd"
style="width: 100%"
></el-date-picker>
</el-form-item>
</div>
<div class="grid-item">
<el-form-item label="民族" prop="nation">
<dict-select v-model="formData.nation" style="width: 100%"
placeholder="请选择民族"
code="USER_NATION"></dict-select>
</el-form-item>
</div>
<div class="grid-item">
<el-form-item label="政治面貌" prop="political">
<el-input maxlength="100" placeholder="政治面貌"
v-model="formData.political"></el-input>
</el-form-item>
</div>
<div class="grid-item">
<el-form-item label="所属工会">
<el-input
v-model="formData.unionName"
readonly
placeholder="请输入所属工会"
clearable
></el-input>
</el-form-item>
</div>
<div class="grid-item">
<el-form-item label="所属单位">
<el-input
v-model="formData.unitName"
readonly
placeholder="请输入所属单位"
clearable
></el-input>
</el-form-item>
</div>
<div class="grid-item">
<el-form-item label="职称" prop="professionalTitle">
<dict-select v-model="formData.professionalTitle" style="width: 100%"
placeholder="请选择职称"
code="technical_title_level"></dict-select>
</el-form-item>
</div>
<div class="grid-item">
<el-form-item label="是否聘用制" prop="employ">
<el-radio-group v-model="formData.employ" size="small">
<el-radio border :label="true">是</el-radio>
<el-radio border :label="false">否</el-radio>
</el-radio-group>
</el-form-item>
</div>
<div class="grid-item">
<el-form-item label="是否高级职称" prop="seniorTeacher">
<el-radio-group v-model="formData.seniorTeacher" size="small">
<el-radio border :label="true">是</el-radio>
<el-radio border :label="false">否</el-radio>
</el-radio-group>
</el-form-item>
</div>
<div class="grid-item">
<el-form-item label="是否中级职称及以下" prop="intermediateBelow">
<el-radio-group v-model="formData.intermediateBelow" size="small">
<el-radio border :label="true">是</el-radio>
<el-radio border :label="false">否</el-radio>
</el-radio-group>
</el-form-item>
</div>
<div class="grid-item">
<el-form-item label="是否干部" prop="cadre">
<el-radio-group v-model="formData.cadre" size="small">
<el-radio border :label="true">是</el-radio>
<el-radio border :label="false">否</el-radio>
</el-radio-group>
</el-form-item>
</div>
<div class="grid-item">
<el-form-item label="是否工人" prop="worker">
<el-radio-group v-model="formData.worker" size="small">
<el-radio border :label="true">是</el-radio>
<el-radio border :label="false">否</el-radio>
</el-radio-group>
</el-form-item>
</div>
<div class="grid-item">
<el-form-item label="校级领导" prop="schoolLeader">
<el-radio-group v-model="formData.schoolLeader" size="small">
<el-radio border :label="true">是</el-radio>
<el-radio border :label="false">否</el-radio>
</el-radio-group>
</el-form-item>
</div>
<div class="grid-item">
<el-form-item label="中层领导" prop="middleLevelLeader">
<el-radio-group v-model="formData.middleLevelLeader" size="small">
<el-radio border :label="true">是</el-radio>
<el-radio border :label="false">否</el-radio>
</el-radio-group>
</el-form-item>
</div>
</div>
<div class="form-grid">
<el-form-item label="手机号" prop="mobile">
<el-input v-model="formData.mobile" maxlength="11"></el-input>
</el-form-item>
<!--<el-form-item label="电子邮箱" prop="email">
<el-input v-model="formData.email" maxlength="255"></el-input>
</el-form-item>-->
</div>
</div>
<div v-if="!dialog && formData && ['53ff0c2a-ba93-45e9-a9fd-db51cdab3080','97b0846b-22c6-4d34-9002-a6b67d592944'].includes(formData.taskKey)"
class="form-actions">
<el-button @click="onSave">保存草稿</el-button>
<el-button type="primary" @click="onSubmit">提交信息</el-button>
</div>
</el-form>
</el-tab-pane>
<el-tab-pane label="审核信息" name="two" v-if="doneTasks&&doneTasks.length>0">
<template v-for="task in doneTasks">
<div class="mt10"
v-if="['0cacd1e7-7bb2-47dd-818b-6a73062e0c62'].includes(task.taskName)">
<div class="process-title">{{ task.displayName }}</div>
<el-descriptions border class="flow-task-form" :column="3" :key="task.id"
>
<el-descriptions-item label="办理用户">{{ task.taskFormData.userName
}}({{task.taskFormData.loginName}})
</el-descriptions-item>
<el-descriptions-item label="办理时间">{{ task.finishTime }}
</el-descriptions-item>
<el-descriptions-item label="办理结果">
{{processSubmitTypeEnums.find(v=>v.name===task.ext.tf_type)?.message}}
<!-- <dict-tag :options="dict.type.PROCESS_TASK_SUBMIT_TYPE"
:value="task.ext.submitType"></dict-tag>-->
</el-descriptions-item>
<el-descriptions-item label="办理意见" v-if="!task.ext.isFirstTaskNode">{{
task.taskFormData.opinion }}
</el-descriptions-item>
</el-descriptions>
</div>
</template>
</el-tab-pane>
</el-tabs>
<div v-if="isSelected && formData && !['53ff0c2a-ba93-45e9-a9fd-db51cdab3080','97b0846b-22c6-4d34-9002-a6b67d592944'].includes(formData.taskKey)"
class="completion-panel">
<div>
<i class="el-icon-success completion-icon"></i>
<h2 class="completion-title">信息提交成功</h2>
<p class="completion-text">您已成功提交代表信息,感谢您的配合!</p>
<div class="completion-actions">
</div>
</div>
</div>
</div>
</div>
`,
mixins: [initTableMixins],
components: {},
props: {
user_id: {
type: String,
required: false,
default: null
},
session_id: {
type: String,
required: false,
default: null
},
is_read: {
type: Boolean,
required: false,
default: false
},
dialog: {
type: Boolean,
required: false,
default: null
},
},
data() {
return {
doneTasks: [],
activeName: "one",
processSubmitTypeEnums:[],
isSelected: true,
formData: {
teacherMeetId: null
},
rules: {
age: [{required: true, message: '必填', trigger: ['blur', 'change']}],
nation: [{required: true, message: '必填', trigger: ['blur', 'change']}],
mobile: [{required: true, message: '必填', trigger: ['blur', 'change']}],
position: [{required: false, message: '必填', trigger: ['blur', 'change']}],
political: [{required: true, message: '必填', trigger: ['blur', 'change']}],
education: [{required: true, message: '必填', trigger: ['blur', 'change']}],
academicDegree: [{required: true, message: '必填', trigger: ['blur', 'change']}],
jobTitle: [{required: false, message: '必填', trigger: ['blur', 'change']}],
email: [{required: false, message: '必填', trigger: ['blur', 'change']}],
vita: [{required: true, message: '必填', trigger: ['blur', 'change']}]
},
sessionOptions: [],
representativeTypeList: ['正式代表', '列席代表'],
}
},
computed: {
sessionName() {
if (this.session_id) {
return this.sessionOptions.find(v => v.id === this.session_id)?.fullName
} else if (this.formData.sessionId) {
return this.sessionOptions.find(v => v.id === this.formData.sessionId)?.fullName
}
return null
}
},
watch: {
user_id: {
handler(val) {
if (val && this.session_id) {
this.initOtherInfo()
}
},
immediate: true
},
session_id(val) {
if (val && this.user_id) {
this.formData.sessionId = val
this.initOtherInfo()
}
},
},
async created() {
await this.listSession()
if (!this.user_id && !this.session_id) {
await this.initInfo()
}
},
methods: {
// 获取已办任务审批记录
getDoneTasks() {
this.$axios.post("/flow/common/doneTasks", {bizId: this.formData.id}).then((res) => {
if (res.code === 0) {
this.doneTasks = res.data
}
})
},
async listSession() {
const res = await this.$axios.post("/platform/teacherCongress/common/listSession")
if (res.code === 0) {
this.sessionOptions = res.data
if (this.sessionOptions && this.sessionOptions.length > 0) {
this.$set(this.formData, 'sessionId', this.sessionOptions[0].id)
}
}
},
async initOtherInfo() {
const {code, data} = await $.get('/platform/teacherCongress/delegate/push/write/info', {
sessionId: this.session_id,
userId: this.user_id
})
if (code === 0) {
this.isSelected = data.isSelected
if (this.isSelected) {
this.formData = data.delegate
}
}
},
async getEnumOptions() {
const resp = await this.$axios.post("/open/common/dictEnumOptions", { name: "ProcessSubmitTypeEnum" })
this.processSubmitTypeEnums=resp.data
},
async initInfo() {
const {code, data} = await $.get('/platform/teacherCongress/delegate/push/write/info', {
sessionId: this.formData.sessionId
})
if (code === 0) {
this.isSelected = data.isSelected
if (this.isSelected) {
this.formData = data.delegate
this.getDoneTasks()
this.getEnumOptions()
}
}
},
teacherMeetIdChange() {
this.initInfo()
},
onSave() {
this.$refs.formRef.validate(async valid => {
if (valid) {
this.$confirm('保存后可继续编辑,您确定要保存吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(async () => {
const loading = createLoading('正在提交中')
this.$axios.post('/platform/teacherCongress/delegate/push/write/save', this.formData).then(async resp => {
loading.close()
if (resp.code === 0) {
this.$message.success('保存成功')
this.$emit('refresh')
if (this.session_id && this.user_id) {
await this.initOtherInfo()
} else {
await this.initInfo()
}
} else {
this.$message.warning('保存失败')
}
})
}).catch(() => {
})
}
})
},
onSubmit() {
this.$refs.formRef.validate(async valid => {
if (valid) {
this.$confirm('您确定要提交吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(async () => {
this.$axios.post('/platform/teacherCongress/delegate/push/write/submit', this.formData).then(async resp => {
if (resp.code === 0) {
this.$message.success('提交成功')
this.$emit('refresh')
if (this.session_id && this.user_id) {
await this.initOtherInfo()
} else {
await this.initInfo()
}
} else {
this.$message.warning('提交失败')
}
})
}).catch(() => {
})
}
})
}
},
style: /*language=CSS*/ `
.container-x1 {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
.header-x {
display: flex;
justify-content: space-between;
align-items: center;
background-color: white;
margin-bottom: 1px;
}
::v-deep .el-tabs__item {
font-size: 18px;/* 填写信息 */
font-weight: 500;
}
.header-x .header-left {
display: flex;
align-items: center;
gap: 16px;
}
.header-x .header-left .back-button {
color: #64748b;
font-size: 20px;
cursor: pointer;
background: none;
border: none;
padding: 0;
}
.header-x .header-left .back-button:hover {
color: #2563eb;
}
.header-x .header-left .title {
font-size: 24px;
font-weight: bold;
margin: 0;
}
.header-x .header-right {
display: flex;
align-items: center;
gap: 8px;
color: #64748b;
margin-top: 8px;
}
.notice-panel {
background-color: white;
border-radius: 8px;
padding: 32px;
margin-bottom: 20px;
text-align: center;
}
.notice-panel .notice-icon {
color: #ccc;
font-size: 48px;
margin-bottom: 16px;
}
.notice-panel .notice-title {
font-size: 20px;
font-weight: 500;
margin-bottom: 8px;
}
.notice-panel .notice-text {
color: #666;
}
.completion-panel {
background-color: white;
border-radius: 8px;
padding: 40px;
margin-bottom: 20px;
text-align: center;
}
.completion-panel .completion-icon {
color: #67c23a;
font-size: 48px;
margin-bottom: 16px;
}
.completion-panel .completion-title {
font-size: 20px;
font-weight: 500;
margin-bottom: 8px;
}
.completion-panel .completion-text {
color: #666;
margin-bottom: 24px;
}
.completion-panel ::v-deep .completion-actions {
display: flex;
justify-content: center;
gap: 16px;
}
::v-deep .form-container {
background-color: white;
border-radius: 8px;
padding: 32px;
padding-top: 20px;
margin-bottom: 20px;
}
::v-deep .info-box {
border-left: 4px solid #2563eb;
background-color: #ebf5ff;
padding: 16px;
margin-bottom: 32px;
margin-top: 10px;
}
.info-box ::v-deep .info-content {
display: flex;
align-items: flex-start;
}
.info-box .info-content ::v-deep .info-icon {
color: #2563eb;
margin-right: 12px;
margin-top: 2px;
}
.info-box .info-content ::v-deep .info-text {
flex: 1;
}
.info-box .info-content .info-text ::v-deep .info-title {
font-weight: 600;
margin-bottom: 8px;
font-size: 18px; /* 推选信息没用 */
}
.info-box .info-content .info-text ::v-deep .info-desc {
color: #666;
margin-bottom: 8px;
}
.info-box .info-content .info-text ::v-deep .info-details {
font-size: 14px;
color: #666;
margin-top: 8px;
}
.info-box .info-content .info-text .info-details p {
margin: 4px 0;
}
::v-deep .form-section {
margin-bottom: 32px;
}
.form-section ::v-deep .section-title {
font-size: 18px;/* 基本信息没用 */
font-weight: 500;
margin-bottom: 16px;
}
.form-section ::v-deep .form-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
column-gap: 12px;
}
.form-section ::v-deep .form-grid.full-width {
grid-template-columns: 1fr;
}
/* Form actions styles */
::v-deep .form-actions {
display: flex;
justify-content: flex-end;
gap: 16px;
margin-top: 32px;
padding-top: 24px;
border-top: 1px solid #dcdfe6;
}
.form-actions ::v-deep .el-button {
border-radius: 4px !important;
padding: 10px 24px;
font-weight: 500;
}
::v-deep .hidden {
display: none !important;
}
::v-deep .custom-grid {
display: flex;
flex-wrap: wrap;
gap: 16px;
margin: 0 -8px 16px;
}
::v-deep .grid-item {
flex: 1 1 calc(50% - 16px);
min-width: 200px; /* 防止在窄屏过度压缩 */
padding: 0 8px;
}
`
}
@@ -0,0 +1,311 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app" v-cloak>
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="姓名/工号">
<el-input placeholder="请输入姓名或工号" clearable v-model="pageForm.searchKeyword"></el-input>
</search-item>
<search-item label="教代会">
<el-select v-model="pageForm.sessionId">
<el-option v-for="item in sessionOptions" :label="item.fullName" :value="item.id"
:key="item.id"></el-option>
</el-select>
</search-item>
<search-item label="所属工会">
<el-select placeholder="请选择所属工会" v-model="pageForm.unionId" filterable clearable style="width: 100%">
<el-option v-for="i in unionOptions" :label="i.name" :key="i.id" :value="i.id"></el-option>
</el-select>
</search-item>
</search>
</el-card>
<el-card shadow="never">
<table-tool>
<el-radio-group v-model="pageForm.approval" size="small" class="ml10"
@change="doSearch">
<el-radio-button :label="true">已审核</el-radio-button>
<el-radio-button :label="false">未审核</el-radio-button>
</el-radio-group>
<template v-if="!pageForm.approval">
<el-button type="primary" size="small" @click="doBatchApproval(1)"
:disabled="!selectDataList || selectDataList.length <= 0"
class="ml10">批量通过</el-button>
<el-button type="danger" size="small" @click="doBatchApproval(2)"
:disabled="!selectDataList || selectDataList.length <= 0"
class="ml10">批量拒绝</el-button>
</template>
<el-radio-group @change="doSearch" v-model="pageForm.isFormalOrAttendance" size="small" style="margin-left: 10px">
<el-radio-button label="全部"></el-radio-button>
<el-radio-button label="正式代表"></el-radio-button>
<el-radio-button label="列席代表"></el-radio-button>
</el-radio-group>
<el-button type="primary" size="small" @click="exportExcel" class="ml10">导出</el-button>
</table-tool>
<el-table
ref="tableRef"
:data="tableData"
row-key="id"
@selection-change="tableHandleSelectionChange"
@sort-change="pageOrder"
>
<el-table-column type="selection" width="55" reserve-selection></el-table-column>
<el-table-column type="index" width="55" label="序号" :index="indexMethod"></el-table-column>
<el-table-column label="姓名" prop="userName" width="100"></el-table-column>
<el-table-column label="工号" prop="loginName"></el-table-column>
<el-table-column label="性别" prop="sex" width="50"></el-table-column>
<el-table-column label="分工会" prop="unionName" show-overflow-tooltip></el-table-column>
<!-- <el-table-column label="民族" prop="nation"></el-table-column>&lt;!&ndash;
<el-table-column label="政治面貌" prop="political"
show-overflow-tooltip></el-table-column>
<el-table-column label="学历" prop="education"></el-table-column>-->
<el-table-column label="职称" prop="professionalTitle"></el-table-column>
<el-table-column label="职级" prop="professionalLevel"></el-table-column>
<el-table-column label="是否高级职称" prop="seniorTeacher">
<template v-slot="{row}">
<span v-if="row.seniorTeacher" style="color:#0037ff;"></span>
<span v-else></span>
</template>
</el-table-column>
<el-table-column label="是否中级职称及以下" prop="intermediateBelow">
<template v-slot="{row}">
<span v-if="row.intermediateBelow" style="color:#0037ff;"></span>
<span v-else></span>
</template>
</el-table-column>
<el-table-column label="是否干部" prop="cadre">
<template v-slot="{row}">
<span v-if="row.cadre" style="color:#0037ff;"></span>
<span v-else></span>
</template>
</el-table-column>
<el-table-column label="是否工人" prop="worker">
<template v-slot="{row}">
<span v-if="row.worker" style="color:#0037ff;"></span>
<span v-else></span>
</template>
</el-table-column>
<el-table-column label="教代会代表" prop="isJdh">
<template v-slot="{row}">
<span v-if="row.isJdh" style="color:#0037ff;"></span>
<span v-else></span>
</template>
</el-table-column>
<el-table-column label="工代会代表" prop="isGdh">
<template v-slot="{row}">
<span v-if="row.isGdh" style="color:#0037ff;"></span>
<span v-else></span>
</template>
</el-table-column>
<el-table-column label="代表类型" prop="representativeType"></el-table-column>
<el-table-column prop="curTaskName" label="当前节点"></el-table-column>
<el-table-column label="审核时间" prop="finishTime" width="160">
<template slot-scope="{row}">
<span v-if="row.finishTime">{{$moment(row.finishTime).format('YYYY-MM-DD HH:mm:ss')}}</span>
</template>
</el-table-column>
<el-table-column prop="instanceState" label="流程状态">
<template slot-scope="{row}">
<enum-tag :value="row.instanceState" name="ProcessInstanceStateEnum" label_key="message"
size="small"></enum-tag>
</template>
</el-table-column>
<el-table-column label="操作" fixed="right" width="300px">
<template slot-scope="{row}">
<el-button @click="onView(row)" size="mini" type="primary">查看</el-button>
<el-button v-if="row.taskState === 10" @click="handleTaskAction(row,1)" size="mini" type="primary">
通过
</el-button>
<el-button v-if="row.taskState === 10" @click="handleTaskAction(row,2)" size="mini" type="danger">
拒绝
</el-button>
<el-button v-if="row.canRevoke" @click="onRevoke(row)" size="mini" type="danger">撤回
</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<template #edit>
<audit-info ref="auditInfoRef">
</audit-info>
</template>
</guava>
<el-dialog :close-on-click-modal="false"
class="write-dialog"
:visible.sync="writeDialog"
:title="isRead ? '查看' : '编辑'"
top="50px"
width="60%">
<div style="max-height: 75vh;overflow-y: auto">
<formal-write ref="formalWriteRef" :is_read="isRead" :user_id="userId"
:session_id="pageForm.sessionId"
:dialog="true"
@refresh="writeDialog=false;doSearch()"></formal-write>
</div>
<div slot="footer" class="dialog-footer">
<el-button @click="$refs.formalWriteRef.onSave()">保存草稿</el-button>
<el-button type="primary" @click="$refs.formalWriteRef.onSubmit()">提交信息</el-button>
</div>
</el-dialog>
</div>
<script nonce="${cspNonce!}">
<!--#include('write.js'){}#-->
<!--#include('auditInfo.js'){}#-->
new Vue({
el: '#app',
mixins: [initTableMixins],
components: {
'formal-write': write,
'audit-info': auditInfo
},
data() {
return {
sessionOptions: [],
unionOptions: [],
pageForm: {
isFormalOrAttendance: "全部",
unionId: "",
sessionId: "",
approval: false,
},
writeDialog: false,
isRead: false,
userId: null,
selectDataList: [],
}
},
methods: {
/**
* 批量审核
*/
tableHandleSelectionChange(val) {
this.selectDataList = val
},
/**
* 批量审核
*/
doBatchApproval(submitType) {
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
const loading = createLoading()
const data = this.selectDataList.map(v => {
return {
processTaskId: v.taskId,
taskName: v.curTaskName,
submitType: submitType,
id: v.id
}
})
this.$axios.post("/platform/teacherCongress/delegate/push/zcAudit/submitBatch", {
data: JSON.stringify(data)
}).then(res => {
loading.close()
if (res.code === 0) {
this.$message.success(res.msg)
this.$refs.tableRef.clearSelection()
this.doSearch()
} else {
this.$message.error(res.msg)
}
})
})
},
exportExcel() {
this.$downLoad("/platform/teacherCongress/delegate/push/zcAudit/exportExcel", this.pageForm)
},
onView(row) {
this.$refs.guava.edit(() => {
this.showApprovalForm = false
this.$refs.auditInfoRef.onOpen(row)
})
},
handleTaskAction(row, submitType) {
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.formData = {
processTaskId: row.taskId,
taskName: row.curTaskName
}
this.$axios.post("/platform/teacherCongress/delegate/push/zcAudit/submit", {
data: JSON.stringify({
...this.formData,
submitType: submitType
}),
id: row.id
}).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.doSearch()
}
})
})
},
onRevoke(row) {
this.$confirm("您确定要撤回吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "info"
}).then(() => {
this.$axios.post("/flow/common/revokeTask", {taskId: row.taskId}).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.doSearch()
}
})
})
},
listUnion() {
this.$businessTool.listUnion().then((res) => {
this.unionOptions = res
})
},
listSession() {
this.$axios.post("/platform/teacherCongress/common/listSession").then((res) => {
if (res.code === 0) {
this.sessionOptions = res.data
if (this.sessionOptions && this.sessionOptions.length > 0) {
this.pageForm.sessionId = this.sessionOptions[0].id
this.pageData()
}
}
})
}
},
async created() {
this.listUnion()
this.listSession()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,184 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app" v-cloak>
<el-card shadow="never">
<search @search="doSearch">
<search-item label="姓名/工号">
<el-input placeholder="请输入姓名或工号" clearable v-model="pageForm.searchKeyword"></el-input>
</search-item>
<search-item label="教代会">
<el-select v-model="pageForm.sessionId" @change="sessionChange">
<el-option v-for="item in sessionOptions" :label="item.fullName" :value="item.id" :key="item.id"></el-option>
</el-select>
</search-item>
<search-item label="代表团">
<el-select v-model="pageForm.delegationId" filterable @change="delegationChange" clearable style="width: 100%">
<el-option v-for="i in delegationOptions" :label="i.name" :key="i.id" :value="i.id"></el-option>
</el-select>
</search-item>
<search-item label="所属工会">
<el-select placeholder="请选择所属工会" v-model="pageForm.unionId" filterable @change="listUnit" clearable style="width: 100%">
<el-option v-for="i in unionOptions" :label="i.name" :key="i.id" :value="i.id"></el-option>
</el-select>
</search-item>
<search-item label="所属单位">
<el-select placeholder="请选择所属单位" v-model="pageForm.unitId" clearable filterable style="width: 100%">
<el-option v-for="i in unitOptions" :label="i.name" :key="i.id" :value="i.id"></el-option>
</el-select>
</search-item>
<search-item label="代表类型">
<el-select v-model="pageForm.roleId" filterable clearable style="width: 100%">
<el-option v-for="i in roleOptions" :label="i.name" :key="i.id" :value="i.id"></el-option>
</el-select>
</search-item>
</search>
</el-card>
<el-card shadow="never">
<table-tool>
<el-button size="small" type="primary" icon="el-icon-download" @click="exportXlsx">导出Excel</el-button>
<el-button size="small" type="primary" icon="el-icon-download" @click="exportDocx">导出Word</el-button>
</table-tool>
<el-table :data="tableData" @sort-change="pageOrder" header-align="center" row-key="id" ref="tableRef" style="width: 100%">
<el-table-column type="selection" width="55" reserve-selection fixed="left"></el-table-column>
<el-table-column type="index" width="55" label="序号" :index="indexMethod" fixed="left"></el-table-column>
<el-table-column label="工号" prop="loginName" fixed="left"></el-table-column>
<el-table-column label="姓名" prop="userName" fixed="left" sortable></el-table-column>
<el-table-column label="性别" prop="sex" sortable></el-table-column>
<el-table-column label="年龄" prop="age" sortable></el-table-column>
<el-table-column label="联系方式" prop="mobile"></el-table-column>
<el-table-column label="代表团" prop="delegationId" width="150" show-overflow-tooltip sortable>
<template scope="{row}">
<dict-tag :options="delegationOptions" :value="row.delegationId" option_value="id" option_label="name"></dict-tag>
</template>
</el-table-column>
<el-table-column label="所属工会" prop="unionName" show-overflow-tooltip sortable></el-table-column>
<el-table-column label="所属单位" prop="unitName" show-overflow-tooltip sortable></el-table-column>
<el-table-column label="届次" prop="sessionId">
<template scope="{row}">
<dict-tag :options="sessionOptions" :value="row.sessionId" option_value="id" option_label="fullName"></dict-tag>
</template>
</el-table-column>
<el-table-column label="代表身份" prop="roleId" sortable>
<template scope="{row}">
<dict-tag :options="roleOptions" :value="row.roleId" option_value="id" option_label="name"></dict-tag>
</template>
</el-table-column>
<!-- <el-table-column label="操作" width="100">-->
<!-- <template slot-scope="scope">-->
<!-- <el-button size="mini">查看</el-button>-->
<!-- </template>-->
<!-- </el-table-column>-->
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</div>
<script nonce="${cspNonce!}">
new Vue({
el: "#app",
mixins: [initTableMixins],
data() {
return {
pageForm: {
sessionId: null,
delegationId: null,
unionId: null,
unitId: null
},
sessionOptions: [],
delegationOptions: [],
unionOptions: [],
unitOptions: [],
roleOptions: []
}
},
methods: {
sessionChange() {
this.pageForm.delegationId = null
this.delegationOptions = []
this.listDelegation()
this.doSearch()
},
delegationChange() {
this.pageForm.unionId = null
this.pageForm.unitId = null
},
listDelegation() {
this.delegationOptions = []
this.pageForm.delegationId = null
this.$axios.post("/platform/teacherCongress/common/listDelegation", { sessionId: this.pageForm.sessionId }).then((res) => {
if (res.code === 0) {
this.delegationOptions = res.data
}
})
},
listRole() {
this.$axios.post("/platform/teacherCongress/common/listDelegateRole").then((res) => {
if (res.code === 0) {
this.roleOptions = res.data
}
})
},
listUnion() {
this.$businessTool.listUnion().then((res) => {
this.unionOptions = res
})
},
listUnit() {
this.$businessTool.listUnit(this.pageForm.unionId).then((res) => {
this.unitOptions = res
})
},
exportXlsx() {
this.$downLoad(loc() + "/exportXlsx", this.pageForm)
},
exportDocx() {
this.$downLoad(loc() + "/exportDocx", this.pageForm)
},
listSession() {
this.$axios.post("/platform/teacherCongress/common/listSession").then((res) => {
if (res.code === 0) {
this.sessionOptions = res.data
if (this.sessionOptions && this.sessionOptions.length > 0) {
this.pageForm.sessionId = this.sessionOptions[0].id
this.listDelegation()
this.pageData()
}
}
})
},
pageData() {
this.tableLoading = true
this.$axios
.post(loc() + "/pageData", {
pageForm: JSON.stringify(this.pageForm)
})
.then((res) => {
this.tableLoading = false
if (res.code === 0) {
this.tableData = res.data.list
this.pageForm.totalCount = res.data.totalCount
}
})
}
},
created() {
this.listRole()
this.listUnion()
this.listUnit()
this.listSession()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,85 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app" v-cloak>
<el-card shadow="never">
<search @search="doSearch">
<search-item label="教代会">
<el-select v-model="pageForm.sessionId" @change="doSearch">
<el-option v-for="item in sessionOptions" :label="item.fullName" :value="item.id"
:key="item.id"></el-option>
</el-select>
</search-item>
</search>
</el-card>
<el-card shadow="never">
<el-table :data="tableData" @sort-change="pageOrder" header-align="center" row-key="id" ref="tableRef"
style="width: 100%">
<el-table-column type="index" width="55" label="序号" :index="indexMethod" fixed="left"></el-table-column>
<el-table-column label="代表团名称" prop="name" fixed="left"></el-table-column>
<el-table-column label="上届次代表数" prop="lastCount"></el-table-column>
<el-table-column label="增补代表数" prop="addCount"></el-table-column>
<el-table-column label="转入代表数" prop="transferCount"></el-table-column>
<el-table-column label="转出代表数" prop="transferOutCount"></el-table-column>
<el-table-column label="减少代表数" prop="reduceCount"></el-table-column>
<el-table-column label="本届代表数" prop="currentCount"></el-table-column>
<el-table-column label="操作">
<template slot-scope="scope">
<el-button type="primary" size="mini" @click="onView(scope.row)">查看</el-button>
</template>
</el-table-column>
</el-table>
</el-card>
<transition-docx ref="transitionDocxRef"></transition-docx>
</div>
<script nonce="${cspNonce!}">
<!--#include('transitionDocx.js'){}#-->
const app = new Vue({
el: "#app",
mixins: [initTableMixins],
components: {
'transition-docx': transitionDocx
},
data() {
return {
sessionOptions: [],
}
},
methods: {
listSession() {
this.$axios.post("/platform/teacherCongress/common/listSession").then((res) => {
if (res.code === 0) {
this.sessionOptions = res.data
if (this.sessionOptions && this.sessionOptions.length > 0) {
this.pageForm.sessionId = this.sessionOptions[0].id
this.pageData()
}
}
})
},
pageData() {
this.$axios.post("/platform/zhgh/democratic/teacherCongress/delegate/transition/pageData", this.pageForm).then((res) => {
if (res.code === 0) {
this.tableData = res.data
}
})
},
onView(row) {
this.$refs.transitionDocxRef.onOpen(this.pageForm.sessionId, row.id)
}
},
created() {
this.listSession()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,426 @@
const transitionDocx = {
template: /*language=HTML*/ `
<el-dialog title="调动情况" :visible.sync="visible" width="210mm">
<div class="document-container">
<!-- 文档标题 -->
<div class="document-header">
<h2 class="document-title">{{ transition.sessionName }}</h2>
<h3 class="document-subtitle">增补、更换代表与代表调动情况统计表</h3>
<div class="document-info">
<span class="info-item">代表团名称:{{ transition.delegationName }}</span>
<span class="info-item">填表人:{{ fillPerson }}</span>
<span class="info-item">填表日期:{{ currentDate }}</span>
</div>
</div>
<!-- 主表格 -->
<div class="main-table-container">
<table class="document-table">
<thead>
<tr>
<th class="sequence-col">序号</th>
<th class="name-col">代表姓名</th>
<th class="original-col">原代表团名称</th>
<th class="current-col">现代表团名称</th>
<th class="reason-col">变动类型</th>
</tr>
</thead>
<tbody>
<!-- 增补代表块 -->
<template v-if="transition.addUser && transition.addUser.length > 0">
<tr class="section-header">
<td colspan="5" class="section-title">增补代表 ({{ transition.addUser.length }}人)</td>
</tr>
<tr v-for="(user, index) in transition.addUser" :key="'add-' + index" class="data-row add-row">
<td class="sequence-col">{{ index + 1 }}</td>
<td class="name-col">{{ user.userName }}</td>
<td class="original-col">{{ user.lastDelegationName || '-' }}</td>
<td class="current-col">{{ user.delegationName }}</td>
<td class="reason-col">新增代表</td>
</tr>
</template>
<!-- 调出代表块 -->
<template v-if="transition.transferOutUser && transition.transferOutUser.length > 0">
<tr class="section-header">
<td colspan="5" class="section-title">调出代表 ({{ transition.transferOutUser.length }}人)</td>
</tr>
<tr v-for="(user, index) in transition.transferOutUser" :key="'out-' + index" class="data-row out-row">
<td class="sequence-col">{{ index + 1 }}</td>
<td class="name-col">{{ user.userName }}</td>
<td class="original-col">{{ user.lastDelegationName }}</td>
<td class="current-col">{{ user.delegationName || '-' }}</td>
<td class="reason-col">调出代表</td>
</tr>
</template>
<!-- 调入代表块 -->
<template v-if="transition.transferUser && transition.transferUser.length > 0">
<tr class="section-header">
<td colspan="5" class="section-title">调入代表 ({{ transition.transferUser.length }}人)</td>
</tr>
<tr v-for="(user, index) in transition.transferUser" :key="'transfer-' + index" class="data-row transfer-row">
<td class="sequence-col">{{ index + 1 }}</td>
<td class="name-col">{{ user.userName }}</td>
<td class="original-col">{{ user.lastDelegationName || '-' }}</td>
<td class="current-col">{{ user.delegationName }}</td>
<td class="reason-col">调入代表</td>
</tr>
</template>
<!-- 减少代表块 -->
<template v-if="transition.reduceUser && transition.reduceUser.length > 0">
<tr class="section-header">
<td colspan="5" class="section-title">减少代表 ({{ transition.reduceUser.length }}人)</td>
</tr>
<tr v-for="(user, index) in transition.reduceUser" :key="'reduce-' + index" class="data-row reduce-row">
<td class="sequence-col">{{ index + 1 }}</td>
<td class="name-col">{{ user.userName }}</td>
<td class="original-col">{{ user.lastDelegationName }}</td>
<td class="current-col">-</td>
<td class="reason-col">减少代表</td>
</tr>
</template>
<!-- 空数据提示 -->
<template v-if="!hasAnyData">
<tr class="empty-data-row">
<td colspan="5" class="empty-message">暂无代表变动数据</td>
</tr>
</template>
</tbody>
</table>
</div>
<!-- 统计信息 -->
<div class="statistics-text">
本代表团按照民主程序,增补调整以上 <span class="number-blank">{{ totalChangeCount }}</span>
名代表,实际本代表团代表
<span class="number-blank">{{ transition.currentCount || 0 }}</span> 人。
</div>
<!-- 签名区域 -->
<div class="signature-area">
<div class="signature-left">
<span>院党委组织负责人签字:</span>
<span class="signature-line"></span>
</div>
<div class="signature-right">
<span>(院党委组织盖章)</span>
</div>
</div>
<!-- 日期 -->
<div class="date-area">
<span class="date-text">{{ currentYear }} 年 {{ currentMonth }} 月 {{ currentDay }} 日</span>
</div>
</div>
<div slot="footer" class="dialog-footer">
<el-button @click="visible = false">关闭</el-button>
<el-button type="primary" @click="printDocument">打印</el-button>
</div>
</el-dialog>
`,
data() {
return {
visible: false,
sessionId: '',
delegationId: '',
transition: {},
fillPerson: ''
}
},
computed: {
totalRows() {
let count = 0;
if (this.transition.addUser) count += this.transition.addUser.length;
if (this.transition.transferOutUser) count += this.transition.transferOutUser.length;
if (this.transition.transferUser) count += this.transition.transferUser.length;
if (this.transition.reduceUser) count += this.transition.reduceUser.length;
return count;
},
totalChangeCount() {
let count = 0;
if (this.transition.addUser) count += this.transition.addUser.length;
if (this.transition.transferOutUser) count += this.transition.transferOutUser.length;
if (this.transition.reduceUser) count += this.transition.reduceUser.length;
return count;
},
hasAnyData() {
return (this.transition.addUser && this.transition.addUser.length > 0) ||
(this.transition.transferOutUser && this.transition.transferOutUser.length > 0) ||
(this.transition.transferUser && this.transition.transferUser.length > 0) ||
(this.transition.reduceUser && this.transition.reduceUser.length > 0);
},
currentDate() {
const now = new Date();
return this.$moment().format('YYYY年MM月DD日');
},
currentYear() {
return new Date().getFullYear();
},
currentMonth() {
return new Date().getMonth() + 1;
},
currentDay() {
return new Date().getDate();
}
},
methods: {
onOpen(sessionId, delegationId) {
this.sessionId = sessionId;
this.delegationId = delegationId;
this.visible = true;
this.getDetail();
},
getDetail() {
this.$axios.post('/platform/zhgh/democratic/teacherCongress/delegate/transition/detail', {
sessionId: this.sessionId,
delegationId: this.delegationId
}).then(res => {
if (res.code === 0) {
this.transition = res.data
}
})
},
getAddReason(user) {
if (user.lastDelegationName) {
return `` + user.lastDelegationName + '调入';
}
return '新增代表';
},
printDocument() {
this.$downLoad('/platform/zhgh/democratic/teacherCongress/delegate/transition/exportDocx',{
sessionId: this.sessionId,
delegationId: this.delegationId
})
}
},
style: /*language=CSS*/ `
/* 对话框样式 */
/deep/ .el-dialog__body {
max-height: 70vh;
overflow-y: auto;
padding: 0;
}
/* 文档容器 */
/deep/ .document-container {
width: 210mm;
min-height: 297mm;
max-width: 100%;
margin: 0 auto;
padding: 20mm;
background: white;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
font-family: 'SimSun', '宋体', serif;
font-size: 12px;
line-height: 1.5;
color: #000;
box-sizing: border-box;
}
/* 文档标题样式 */
/deep/ .document-header {
text-align: center;
margin-bottom: 30px;
}
/deep/ .document-title {
font-size: 18px;
font-weight: bold;
margin: 0 0 10px 0;
color: #333;
}
/deep/ .document-subtitle {
font-size: 16px;
font-weight: bold;
margin: 0 0 20px 0;
color: #333;
}
/deep/ .document-info {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
font-size: 14px;
}
/deep/ .info-item {
flex: 1;
text-align: center;
}
/* 主表格样式 */
/deep/ .main-table-container {
margin: 20px 0;
}
/deep/ .document-table {
width: 100%;
border-collapse: collapse;
border: 2px solid #000;
font-size: 14px;
}
/deep/ .document-table th,
/deep/ .document-table td {
border: 1px solid #000;
padding: 8px 4px;
text-align: center;
vertical-align: middle;
word-wrap: break-word;
}
/deep/ .document-table th {
font-weight: bold;
height: 40px;
}
/deep/ .document-table td {
height: 35px;
min-height: 35px;
}
/* 列宽设置 */
/deep/ .sequence-col {
width: 8%;
min-width: 50px;
}
/deep/ .name-col {
width: 20%;
min-width: 100px;
}
/deep/ .original-col {
width: 25%;
min-width: 120px;
}
/deep/ .reason-col {
width: 25%;
min-width: 120px;
}
/deep/ .transfer-name-col {
width: 20%;
min-width: 100px;
}
/deep/ .original-delegation-col {
width: 25%;
min-width: 120px;
}
/deep/ .current-delegation-col {
width: 25%;
min-width: 120px;
}
/* 分组标题样式 */
/deep/ .section-header {
font-weight: bold;
}
/deep/ .section-title {
text-align: center;
font-size: 14px;
font-weight: bold;
color: #333;
padding: 8px 0;
border: 1px solid #000;
}
/* 数据行样式 */
/deep/ .data-row:nth-child(even) {
}
/deep/ .data-row:nth-child(odd) {
}
/* 空数据样式 */
/deep/ .empty-data-row {
height: 60px;
}
/deep/ .empty-message {
text-align: center;
color: #999;
font-style: italic;
padding: 20px 0;
}
/* 子表头样式 */
/deep/ .sub-header th {
background-color: #e8f4f8;
font-weight: bold;
}
/* 统计信息样式 */
/deep/ .statistics-text {
margin: 30px 0 20px 0;
text-align: center;
font-size: 14px;
line-height: 1.8;
}
/deep/ .number-blank {
display: inline-block;
min-width: 30px;
border-bottom: 1px solid #000;
text-align: center;
font-weight: bold;
margin: 0 5px;
padding: 0 5px;
}
/* 签名区域样式 */
/deep/ .signature-area {
display: flex;
justify-content: space-between;
align-items: center;
margin: 40px 0 20px 0;
font-size: 14px;
}
/deep/ .signature-left {
display: flex;
align-items: center;
}
/deep/ .signature-line {
display: inline-block;
width: 150px;
border-bottom: 1px solid #000;
margin-left: 10px;
height: 20px;
}
/deep/ .signature-right {
font-size: 14px;
}
/* 日期区域样式 */
/deep/ .date-area {
text-align: right;
margin: 20px 0;
font-size: 14px;
}
/deep/ .date-text {
margin-right: 50px;
}
/* 对话框样式调整 */
/deep/ .dialog-footer {
text-align: center;
padding: 20px 0;
}
`
}
@@ -0,0 +1,82 @@
const AU_FORM_TEMPLATE = {
template: `
<el-dialog :title="formData.id ? '编辑':'新增'" :visible.sync="dialogFormVisible" width="700px" :close-on-click-modal="false">
<el-form :model="formData" ref="formRef" size="small" label-width="120px" :rules="formRules">
<el-form-item prop="sessionId" label="教代会">
<el-select v-model="formData.sessionId">
<el-option v-for="item in sessionOptions" :label="item.fullName" :value="item.id" :key="item.id"></el-option>
</el-select>
</el-form-item>
<el-form-item prop="name" label="代表团名称">
<el-input placeholder="请输入代表团名称" v-model="formData.name" maxlength="100"></el-input>
</el-form-item>
<el-form-item prop="code" label="代表团编码">
<el-input placeholder="请输入代表团编码" v-model="formData.code" maxlength="50"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">取 消</el-button>
<el-button type="primary" @click="doSubmit">确 定</el-button>
</div>
</el-dialog>
`,
data() {
return {
dialogFormVisible: false,
formData: {},
formRules: {
sessionId: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
name: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
code: [{ required: true, message: "必填", trigger: ["change", "blur"] }]
},
sessionOptions: []
}
},
methods: {
onOpen(id) {
this.dialogFormVisible = true
this.listSession()
if (id) {
this.$axios.post("/platform/teacherCongress/delegation/findOne", { id }).then((res) => {
if (res.code === 0) {
this.formData = res.data
}
})
} else {
this.formData = {}
this.$nextTick(() => {
if (this.$refs.formRef) {
this.$refs.formRef.clearValidate()
}
})
}
},
doSubmit() {
this.$refs.formRef.validate((valid) => {
if (valid) {
this.$axios
.post("/platform/teacherCongress/delegation" + (this.formData.id ? "/update" : "/insert"), this.formData)
.then((res) => {
if (res.code === 0) {
this.dialogFormVisible = false
this.$message.success(res.msg)
this.$emit("refresh", null)
}
})
}
})
},
listSession() {
this.$axios.post("/platform/teacherCongress/common/listSession").then((res) => {
if (res.code === 0) {
this.sessionOptions = res.data
}
})
}
},
created() {
this.listSession()
}
}
@@ -0,0 +1,164 @@
const HEAD_FORM_TEMPLATE = {
template: `
<el-dialog title="设置团长" :visible.sync="headDialogFormVisible" width="700px" :close-on-click-modal="false">
<el-form :model="formData" ref="headFormRef" size="small" label-width="80px" :rules="formRules">
<el-form-item prop="sessionId" label="教代会">
<el-select v-model="formData.sessionId" disabled>
<el-option v-for="item in sessionOptions" :label="item.fullName" :value="item.id" :key="item.id"></el-option>
</el-select>
</el-form-item>
<el-form-item prop="userId" label="团长">
<template #label>
<el-tooltip content="候选人从此代表团的正式代表名单中选择" placement="bottom">
<i class="el-icon-question"></i>
</el-tooltip>
团长
</template>
<user-select v-model="formData.userId"
v-if="headDialogFormVisible"
api="/platform/teacherCongress/delegation/notHeadUser"
:api_params="{sessionId:formData.sessionId,delegationId:formData.delegationId}"
api_input_key_name="keyWord"
:option_list="headOptions"
option_value="userId"
:option_label_func="(item)=>{return item.userName + item.loginName + '(' + item.unitName + ')'}"
placeholder="请输入工号或者姓名"
style="width: 100%"></user-select>
</el-form-item>
<el-form-item prop="viceUserIds" label="副团长">
<user-select v-model="formData.viceUserIds"
v-if="headDialogFormVisible"
api="/platform/teacherCongress/delegation/notHeadUser"
:api_params="{sessionId:formData.sessionId,delegationId:formData.delegationId}"
api_input_key_name="keyWord"
:option_list="viceHeadOptions"
:multiple="true"
option_value="userId"
:option_label_func="(item)=>{return item.userName + item.loginName + '(' + item.unitName + ')'}"
placeholder="请输入工号或者姓名"
style="width: 100%"></user-select>
</el-form-item>
<el-form-item prop="contactUserId" label="联络人">
<user-select v-model="formData.contactUserId"
v-if="headDialogFormVisible"
api="/platform/teacherCongress/delegation/notContactUser"
:api_params="{sessionId:formData.sessionId,delegationId:formData.delegationId}"
api_input_key_name="keyWord"
:option_list="contactOptions"
option_value="userId"
:option_label_func="(item)=>{return item.userName + item.loginName + '(' + item.unitName + ')'}"
placeholder="请输入工号或者姓名"
style="width: 100%"></user-select>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="headDialogFormVisible = false">取 消</el-button>
<el-button type="primary" @click="doSubmitHead">确 定</el-button>
</div>
</el-dialog>
`,
data() {
return {
formData: {},
headDialogFormVisible: false,
headOptions: [],
viceHeadOptions: [],
contactOptions: [],
sessionOptions: [],
formRules: {
sessionId: [{required: true, message: "必填", trigger: ["change", "blur"]}],
name: [{required: true, message: "必填", trigger: ["change", "blur"]}],
code: [{required: true, message: "必填", trigger: ["change", "blur"]}],
userId: [{required: true, message: "必填", trigger: ["change", "blur"]}],
//viceUserIds: [{required: true, message: "必填", trigger: ["change", "blur"]}],
//contactUserId: [{required: true, message: "必填", trigger: ["change", "blur"]}]
}
}
},
methods: {
onOpen(delegationId, sessionId) {
if (!delegationId || !sessionId) {
return
}
this.headDialogFormVisible = true
this.listSession()
this.formData = {
sessionId,
delegationId,
viceUserIds: []
}
this.findHeadUser()
},
// 查询团长、副团长、联络人
findHeadUser() {
this.$axios.post("/platform/teacherCongress/delegation/headUser", {
...this.formData,
type: 'TEACHER_CONGRESS_DELEGATION_HEAD'
}).then((res) => {
if (res.code === 0) {
if (res.data) {
this.headOptions = res.data
this.$set(this.formData, "userId", res.data.length > 0 ? res.data[0].userId : null)
}
}
})
this.$axios.post("/platform/teacherCongress/delegation/headUser", {
...this.formData,
type: 'TEACHER_CONGRESS_VICE_DELEGATION_HEAD'
}).then((res) => {
if (res.code === 0) {
if (res.data) {
this.viceHeadOptions = res.data
this.$set(this.formData, "viceUserIds", res.data.map((item) => item.userId))
}
}
})
this.$axios.post("/platform/teacherCongress/delegation/headUser", {
...this.formData,
type: 'TEACHER_CONGRESS_DELEGATION_CONTACT'
}).then((res) => {
if (res.code === 0) {
if (res.data) {
this.contactOptions = res.data
this.$set(this.formData, "contactUserId", res.data.length > 0 ? res.data[0].userId : null)
}
}
})
},
doSubmitHead() {
this.$refs.headFormRef.validate((valid) => {
if (valid) {
// 多选数组必须使用同名参数重复提交,确保后端 String[] 能正确接收全部副团长ID。
const submitData = new URLSearchParams()
submitData.append("delegationId", this.formData.delegationId)
submitData.append("sessionId", this.formData.sessionId)
submitData.append("userId", this.formData.userId)
if (this.formData.contactUserId) {
submitData.append("contactUserId", this.formData.contactUserId)
}
const viceUserIds = this.formData.viceUserIds || []
viceUserIds.forEach((viceUserId) => {
submitData.append("viceUserIds", viceUserId)
})
this.$axios.post("/platform/teacherCongress/delegation/insertHead", submitData).then((res) => {
if (res.code === 0) {
this.headDialogFormVisible = false
this.$message.success(res.msg)
this.$emit("refresh", null)
}
})
}
})
},
listSession() {
this.$axios.post("/platform/teacherCongress/common/listSession").then((res) => {
if (res.code === 0) {
this.sessionOptions = res.data
}
})
}
}
}
@@ -0,0 +1,104 @@
const HEAD_TABLE_TEMPLATE = {
template: `
<div>
<table-tool>
<el-button size="small" type="primary" icon="el-icon-edit" @click="open">添加团长</el-button>
</table-tool>
<el-table :data="tableData" border>
<el-table-column type="index" label="序号" width="100px"></el-table-column>
<el-table-column prop="roleName" label="类型"></el-table-column>
<el-table-column prop="loginName" label="工号"></el-table-column>
<el-table-column prop="userName" label="姓名"></el-table-column>
<el-table-column prop="mobile" label="电话"></el-table-column>
<el-table-column label="操作" width="100px">
<template scope="scope">
<el-link type="danger" @click="doDelete(scope.row.userId, scope.row.roleType)">删除</el-link>
</template>
</el-table-column>
</el-table>
</div>
`,
props: {
session_id: {
type: String,
required: true
},
delegation_id: {
type: String,
required: true
}
},
data() {
return {
tableData: [],
pageForm: {}
}
},
watch: {
session_id: {
handler: function (val) {
if (val) {
this.pageData()
}
},
immediate: true
},
delegation_id: {
handler: function (val) {
if (val) {
this.pageData()
}
},
immediate: true
}
},
methods: {
// 查询团长和副团长,副团长可能存在多人,需要完整展示。
pageData() {
const headRequest = this.listHeadUser("TEACHER_CONGRESS_DELEGATION_HEAD", "团长")
const viceHeadRequest = this.listHeadUser("TEACHER_CONGRESS_VICE_DELEGATION_HEAD", "副团长")
Promise.all([headRequest, viceHeadRequest]).then((values) => {
this.tableData = values[0].concat(values[1])
})
},
// 按角色查询负责人,并补充表格展示所需的角色名称和角色编码。
listHeadUser(roleType, roleName) {
return this.$axios
.post("/platform/teacherCongress/delegation/headUser", {
sessionId: this.session_id,
delegationId: this.delegation_id,
type: roleType
})
.then((res) => {
if (res.code === 0 && res.data) {
return res.data.map((item) => Object.assign({roleName, roleType}, item))
}
return []
})
},
open() {
this.$emit("open", this.delegation_id, this.session_id)
},
doDelete(userId, roleType) {
this.$confirm("您确定要删除吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "info"
}).then(() => {
this.$axios
.post("/platform/teacherCongress/delegation/deleteHead", {
userId,
sessionId: this.session_id,
delegationId: this.delegation_id,
type: roleType
})
.then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.pageData()
}
})
})
}
}
}
@@ -0,0 +1,178 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app" v-cloak>
<el-row :gutter="10" style="height: calc(100vh - 84px)" type="flex">
<el-col :span="5">
<tree @node-click="treeNodeClick" @session-change="sessionChange" ref="treeRef"></tree>
</el-col>
<el-col :span="19">
<el-card shadow="never" style="height: 100%;" :body-style="{ height: '100%' , display: 'flex' , 'flex-direction': 'column' }">
<template v-if="!currentTreeNode || (currentTreeNode && currentTreeNode.level===1)">
<el-card shadow="never" style="border: 1px solid var(--border-color-lighter);flex-shrink: 0;">
<el-row type="flex">
<el-input clearable placeholder="请输入代表团名称" style="width: 220px" v-model="pageForm.searchKeyword"></el-input>
<el-button @click="doSearch" class="ml5" icon="el-icon-search" size="small" type="primary"></el-button>
</el-row>
</el-card>
<el-card shadow="never" style="border: 1px solid var(--border-color-lighter);flex: 1" :body-style="{ height: '100%', display: 'flex' , 'flex-direction': 'column' }">
<table-tool label="代表团">
<el-button @click="$refs.auFormRef.onOpen()" icon="el-icon-plus" size="small" type="primary">新增</el-button>
</table-tool>
<el-table :data="tableData" @sort-change="pageOrder" border header-align="center" height="100%" style="width: 100%">
<el-table-column :index="indexMethod" label="序号" type="index" width="100px"></el-table-column>
<el-table-column label="名称" prop="name"></el-table-column>
<el-table-column label="编码" prop="code" width="150px"></el-table-column>
<el-table-column label="教代会" prop="sessionName"></el-table-column>
<el-table-column label="团长" prop="delegationHead"></el-table-column>
<el-table-column label="副团长" prop="viceDelegationHead"></el-table-column>
<el-table-column label="联络人" prop="delegationContact"></el-table-column>
<el-table-column label="操作" width="300">
<template slot-scope="scope">
<el-link @click="$refs.auFormRef.onOpen(scope.row.id)" size="mini" type="primary">编辑</el-link>
<el-link @click="$refs.headFormRef.onOpen(scope.row.id,scope.row.sessionId)" size="mini" type="primary">
设置团长
</el-link>
<el-link @click="$refs.partUnitRef.onOpen(scope.row.id,scope.row.sessionId)" size="mini" type="primary">
{{ compositionButtonText }}
</el-link>
<el-link @click="doDelete(scope.row.id)" size="mini" type="danger">删除</el-link>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</template>
<template v-else>
<el-tabs v-model="secondLevelTabActive">
<el-tab-pane :label="compositionTabLabel" name="partUnitTable">
<el-card class="mt10" shadow="never" style="border: 1px solid var(--border-color-lighter)">
<part-unit-table
:delegation_id="currentTreeData.id"
:session_id="pageForm.sessionId"
:composition_mode="compositionMode"
@open="(delegation_id,session_id)=>{$refs.partUnitRef.onOpen(delegation_id,session_id)}"
ref="partUnitTableRef"
></part-unit-table>
</el-card>
</el-tab-pane>
<el-tab-pane label="设置团长" name="head">
<el-card class="mt10" shadow="never" style="border: 1px solid var(--border-color-lighter)">
<head-table
:delegation_id="currentTreeData.id"
:session_id="pageForm.sessionId"
@open="(delegation_id,session_id)=>{$refs.headFormRef.onOpen(delegation_id,session_id)}"
ref="headTableRef"
></head-table>
</el-card>
</el-tab-pane>
</el-tabs>
</template>
</el-card>
</el-col>
</el-row>
<au-form @refresh="refresh" ref="auFormRef"></au-form>
<part-unit :composition_mode="compositionMode" @refresh="refresh" ref="partUnitRef"></part-unit>
<head-form @refresh="refresh" ref="headFormRef"></head-form>
</div>
<script nonce="${cspNonce!}">
<!--#include("tree.js"){}#-->
<!--#include("auForm.js"){}#-->
<!--#include("partUnit.js"){}#-->
<!--#include("partUnitTable.js"){}#-->
<!--#include("headForm.js"){}#-->
<!--#include("headTable.js"){}#-->
new Vue({
el: "#app",
mixins: [initTableMixins],
data() {
return {
sessionOptions: [],
currentTreeNode: null,
currentTreeData: null,
currentTreeSessionId: null,
secondLevelTabActive: "partUnitTable",
compositionMode: "${config.dbtzc!'unit'}"
}
},
computed: {
compositionLabel() {
return this.compositionMode === "union" ? "分工会" : "单位"
},
compositionButtonText() {
return "设置组成" + this.compositionLabel
},
compositionTabLabel() {
return "组成" + this.compositionLabel
}
},
components: {
tree: TREE_TEMPLATE,
"au-form": AU_FORM_TEMPLATE,
"part-unit": PART_UNIT_TEMPLATE,
"part-unit-table": PART_UNIT_TABLE_TEMPLATE,
"head-form": HEAD_FORM_TEMPLATE,
"head-table": HEAD_TABLE_TEMPLATE
},
methods: {
refresh() {
this.$refs.treeRef.listTree()
if (this.$refs.partUnitTableRef) {
this.$refs.partUnitTableRef.doSearch()
}
if (this.$refs.headTableRef) {
this.$refs.headTableRef.pageData()
}
this.pageData()
},
sessionChange(id) {
this.pageForm.sessionId = id
this.pageData()
},
treeNodeClick(data, node) {
this.currentTreeData = data
this.currentTreeNode = node
},
doDelete(id) {
this.$confirm("您确定要删除吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "info"
}).then(() => {
this.$axios.post("/platform/teacherCongress/delegation/delete", { id }).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.refresh()
}
})
})
},
pageData() {
this.$axios
.post(loc() + "/pageData", {
...this.pageForm,
sessionId: this.pageForm.sessionId
})
.then((res) => {
if (res.code === 0) {
this.tableData = res.data.list
this.pageForm.totalCount = res.data.totalCount
}
})
}
},
created() {}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,84 @@
const PART_UNIT_TEMPLATE = {
template: [
'<el-dialog :title="dialogTitle" :visible.sync="partUnitDialogFormVisible" width="1000px" :close-on-click-modal="false">',
'<el-transfer ref="transferRef" :titles="transferTitles" filterable ',
':props="{key: \'id\', label: \'name\'}" ',
':filter-method="filterItem" v-model="selectedIds" :data="allItems"></el-transfer>',
'<div slot="footer" class="dialog-footer">',
'<el-button @click="partUnitDialogFormVisible = false">取 消</el-button>',
'<el-button type="primary" @click="doSubmitPartUnit">确 定</el-button>',
'</div><slot></slot></el-dialog>'
].join(''),
props: {
composition_mode: {
type: String,
default: "unit"
}
},
data() {
return {
partUnitDialogFormVisible: false,
selectedIds: [],
allItems: [],
delegationId: null,
sessionId: null
}
},
computed: {
compositionLabel() {
return this.composition_mode === "union" ? "分工会" : "单位"
},
dialogTitle() {
return "设置组成" + this.compositionLabel
},
transferTitles() {
return ["可选" + this.compositionLabel, "当前组成" + this.compositionLabel]
}
},
methods: {
filterItem(query, item) {
return item.name.indexOf(query) > -1
},
onOpen(delegationId, sessionId) {
if (!delegationId || !sessionId) {
return
}
this.partUnitDialogFormVisible = true
this.delegationId = delegationId
this.sessionId = sessionId
if (this.$refs.transferRef) {
this.$refs.transferRef.clearQuery("left")
this.$refs.transferRef.clearQuery("right")
}
this.$axios
.post("/platform/teacherCongress/delegation/compositionTransferData", {
delegationId,
sessionId
})
.then((res) => {
if (res.code === 0) {
this.selectedIds = res.data.selectedIds
this.allItems = res.data.allItems
}
})
},
doSubmitPartUnit() {
this.$axios
.post(loc() + "/compositionSet", {
itemIds: JSON.stringify(this.selectedIds),
delegationId: this.delegationId,
sessionId: this.sessionId
})
.then((res) => {
if (res.code === 0) {
this.partUnitDialogFormVisible = false
this.$message.success(res.msg)
this.$emit("refresh", null)
}
})
}
},
created() {}
}
@@ -0,0 +1,81 @@
const PART_UNIT_TABLE_TEMPLATE = {
template: [
'<div><table-tool>',
'<el-button size="small" type="primary" icon="el-icon-edit" @click="open">{{ buttonText }}</el-button>',
'</table-tool><el-table :data="tableData" border>',
'<el-table-column type="index" label="序号" width="100px"></el-table-column>',
'<el-table-column prop="code" label="编码"></el-table-column>',
'<el-table-column prop="name" label="名称"></el-table-column>',
'</el-table><el-row class="el-pagination-container" style="margin-top: 20px">',
'<el-pagination @size-change="pageSizeChange" @current-change="pageNumberChange" ',
':current-page="pageForm.pageNumber" :page-sizes="[5,10,20,30,50]" ',
':page-size="pageForm.pageSize" layout="total, sizes, prev, pager, next" ',
':total="pageForm.totalCount"></el-pagination>',
'</el-row><slot></slot></div>'
].join(''),
mixins: [initTableMixins],
props: {
session_id: {
type: String,
required: true
},
delegation_id: {
type: String,
required: true
},
composition_mode: {
type: String,
default: "unit"
}
},
computed: {
buttonText() {
return "设置组成" + (this.composition_mode === "union" ? "分工会" : "单位")
}
},
data() {
return {
tableData: [],
pageForm: {}
}
},
watch: {
session_id: {
handler: function(val) {
if (val) {
this.doSearch()
}
},
immediate: true
},
delegation_id: {
handler: function(val) {
if (val) {
this.doSearch()
}
},
immediate: true
}
},
methods: {
pageData() {
this.$axios
.post("/platform/teacherCongress/delegation/compositionPageData", {
...this.pageForm,
sessionId: this.session_id,
delegationId: this.delegation_id
})
.then((res) => {
if (res.code === 0) {
this.tableData = res.data.list
this.pageForm.totalCount = res.data.totalCount
}
})
},
open() {
this.$emit("open", this.delegation_id, this.session_id)
}
},
created() {
}
}
@@ -0,0 +1,75 @@
const TREE_TEMPLATE = {
template: /*language=HTML*/ `
<el-card shadow="never" style="height: 100%" :body-style="{ height: '100%' }">
<el-select placeholder="输入关键字进行查找" v-model="sessionId" clearable class="mb10">
<el-option v-for="item in sessionOptions" :label="item.fullName" :value="item.id"
:key="item.id"></el-option>
</el-select>
<div style="height: calc(100% - 50px);overflow-y: auto">
<el-tree
:data="treeData"
ref="treeRef"
:expand-on-click-node="false"
:props="{
children: 'children',
label: 'name'
}"
default-expand-all
@node-click="treeNodeClick"
:filter-node-method="filterNode"
>
<template slot-scope="{ node, data }">
<span class="el-tree-node__label">
<i class="el-icon-folder-opened" v-if="node.level===1"></i>
<i class="el-icon-folder" v-else></i>
{{node.label}}
</span>
</template>
</el-tree>
</div>
</el-card>
`,
data() {
return {
currentTreeNode: null,
currentTreeData: null,
sessionOptions: [],
sessionId: null,
treeData: []
}
},
watch: {
sessionId(val) {
this.$emit("session-change", val)
this.listTree()
}
},
methods: {
treeNodeClick(data, node) {
this.$emit("node-click", data, node)
},
filterNode() {
},
listTree() {
this.$axios.post("/platform/teacherCongress/delegation/tree", {sessionId: this.sessionId}).then((res) => {
if (res.code === 0) {
this.treeData = res.data
}
})
},
listSession() {
this.$axios.post("/platform/teacherCongress/common/listSession").then((res) => {
if (res.code === 0) {
this.sessionOptions = res.data
if (this.sessionOptions && this.sessionOptions.length > 0) {
this.sessionId = this.sessionOptions[0].id
this.listTree()
}
}
})
}
},
created() {
this.listSession()
}
}
@@ -0,0 +1,295 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style>
.card-container {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
gap: 20px;
}
.guild-hall-card {
background: #fff;
overflow: hidden;
transition: all 0.3s ease;
border: 1px solid #e8e8e8;
}
.card-image {
width: 100%;
height: 200px;
position: relative;
overflow: hidden;
background: #f5f5f5;
}
.card-image img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.3s ease;
}
.guild-hall-card:hover .card-image img {
transform: scale(1.05);
}
.card-content {
padding: 16px 16px 10px 16px;
}
.card-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 12px;
}
.card-title {
font-size: 18px;
font-weight: 600;
color: #333;
margin: 0;
line-height: 1.4;
flex: 1;
}
.card-info {
margin-bottom: 16px;
}
.info-item {
display: flex;
align-items: center;
color: #666;
font-size: 14px;
line-height: 1.5;
}
.info-item i {
margin-right: 6px;
color: #999;
}
.card-actions {
display: flex;
align-items: center;
justify-content: space-around;
padding-top: 8px;
border-top: 1px solid #f0f0f0;
}
.action-item {
display: flex;
align-items: center;
gap: 4px;
padding: 6px 12px;
cursor: pointer;
color: #666;
font-size: 14px;
transition: color 0.3s ease;
user-select: none;
}
.action-item:hover {
color: var(--color-primary);
}
.action-item.danger:hover {
color: var(--color-danger);
}
.action-item i {
font-size: 14px;
}
.action-divider {
width: 1px;
height: 16px;
background: #e8e8e8;
margin: 0 8px;
}
</style>
<div id="app" v-cloak>
<el-card shadow="never">
<search @search="doSearch">
<search-item label="名称">
<el-input placeholder="请输入名称" clearable v-model="pageForm.searchKeyword"></el-input>
</search-item>
</search>
</el-card>
<el-card shadow="never">
<table-tool>
<el-button size="small" type="primary" icon="el-icon-plus" @click="onAdd()">新增</el-button>
</table-tool>
<div class="card-container">
<div class="guild-hall-card" v-for="(item, index) in tableData" :key="item.id">
<div class="card-image">
<img :src="item.cover" :alt="item.name" v-if="item.cover"/>
</div>
<div class="card-content">
<div class="card-header">
<h3 class="card-title">{{ item.name }}</h3>
</div>
<div class="card-info">
<div class="info-item">
<i class="el-icon-location-outline"></i>
<span>{{ item.address }}</span>
</div>
</div>
<div class="card-actions">
<div class="action-item" @click="onEdit(item)">
<i class="el-icon-edit"></i>
<span>编辑</span>
</div>
<div class="action-divider"></div>
<div class="action-item" @click="onSeat(item)">
<i class="el-icon-s-custom"></i>
<span>座位</span>
</div>
<div class="action-divider"></div>
<div class="action-item danger" @click="onDelete(item.id)">
<i class="el-icon-delete"></i>
<span>删除</span>
</div>
</div>
</div>
</div>
</div>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<el-dialog :title="formData.id ? '编辑' : '新增'" :visible.sync="dialogVisible" width="70%">
<el-form ref="formRef" :model="formData" :rules="formRules" label-width="80px">
<el-form-item label="名称" prop="name">
<el-input v-model="formData.name" placeholder="请输入名称"></el-input>
</el-form-item>
<el-form-item label="地址" prop="address">
<el-input v-model="formData.address" placeholder="请输入地址"></el-input>
</el-form-item>
<el-form-item label="封面图" prop="cover">
<file-upload
style="--upload-width: 250px; --upload-height: 120px;"
:value.sync="formData.cover"
:upload_number="1"
upload_mode="image"
upload_result_category="interval"
upload_result_type="url"
></file-upload>
</el-form-item>
<el-form-item label="描述" prop="introduce">
<text-editor v-model="formData.introduce"></text-editor>
</el-form-item>
<el-form-item label="排序" prop="sortCode">
<el-input-number v-model="formData.sortCode" :min="0"></el-input-number>
</el-form-item>
<el-form-item label="状态" prop="enabled">
<el-switch v-model="formData.enabled"></el-switch>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="onSave">提交</el-button>
</div>
</el-dialog>
<seat ref="seatRef"></seat>
</div>
<script nonce="${cspNonce!}">
<!--#include('seat.js'){}#-->
new Vue({
el: '#app',
mixins: [initTableMixins],
components: {
seat
},
data() {
return {
dialogVisible: false,
formRules: {
name: [{required: true, message: '请输入名称', trigger: 'blur'}],
address: [{required: true, message: '请输入地址', trigger: 'blur'}],
cover: [{required: true, message: '请上传封面图', trigger: 'blur'}],
introduce: [{required: true, message: '请输入描述', trigger: 'blur'}],
sortCode: [{required: true, message: '请输入排序', trigger: 'blur'}],
enabled: [{required: true, message: '请选择状态', trigger: 'blur'}]
},
pageForm: {
pageSize: 4,
totalCount: 0
}
}
},
methods: {
onDelete(id) {
this.$confirm('您确定要删除吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.$axios.post('/platform/guildHall/delete', {id}).then(res => {
if (res.code === 0) {
this.$message.success('删除成功')
this.doSearch()
}
})
}).catch(() => {
});
},
onAdd() {
this.dialogVisible = true
this.formData = {
id: null,
name: null,
address: null,
cover: null,
description: null,
sortCode: null,
enabled: true
}
},
onEdit(row) {
this.dialogVisible = true
this.formData = {...row}
},
onSave() {
this.$refs.formRef.validate(valid => {
if (!valid) return
this.$confirm('您确定要提交吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.$axios.post('/platform/guildHall/' + (this.formData.id ? 'update' : 'save'), this.formData).then(res => {
if (res.code === 0) {
this.$message.success(res.msg)
this.dialogVisible = false
this.doSearch()
}
})
}).catch(() => {
});
})
},
onSeat(row) {
this.$refs.seatRef.onOpen(row)
}
},
created() {
this.pageData()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,313 @@
const seat = {
template: /*language=HTML*/ `
<el-dialog :visible.sync="dialogVisible" title="座位设置" width="90%">
<div class="seat-layout">
<!-- 控制面板 -->
<div class="control-panel">
<div class="panel-section">
<h4>座位设置</h4>
<div class="control-group">
<label>行数:</label>
<el-input-number v-model="seatConfig.rows" :min="1" :max="20"
size="small"></el-input-number>
</div>
<div class="control-group">
<label>列数:</label>
<el-input-number v-model="seatConfig.cols" :min="1" :max="30"
size="small"></el-input-number>
</div>
<div class="control-group">
<el-button type="primary" size="small" @click="generateSeats">生成座位</el-button>
<el-button type="success" size="small" @click="saveSeats">保存</el-button>
</div>
</div>
<div class="panel-section">
<h4>操作说明</h4>
<div class="legend">
<div class="legend-item">
<div class="seat-icon enabled" v-html="getSeatSvg(true)"></div>
<span>启用座位</span>
</div>
<div class="legend-item">
<div class="seat-icon disabled" v-html="getSeatSvg(false)"></div>
<span>禁用座位</span>
</div>
</div>
<p class="tip">点击座位可切换启用/禁用状态</p>
</div>
</div>
<!-- 座位区域 -->
<div class="seat-area">
<div class="seat-grid" :style="gridStyle">
<div
v-for="seat in seats"
:key="seat.id"
class="seat-item"
:class="{ 'enabled': seat.enable, 'disabled': !seat.enable }"
@click="toggleSeat(seat)"
:title="'第' + seat.rowNumber + '排第' + seat.colNumber + '列'"
>
<div class="seat-svg" v-html="getSeatSvg(seat.enable)"></div>
<div class="seat-label">{{ seat.rowNumber }}-{{ seat.colNumber }}</div>
</div>
</div>
</div>
</div>
</el-dialog>
`,
data() {
return {
dialogVisible: false,
row: {},
seatConfig: {
rows: 8,
cols: 12
},
seats: []
}
},
computed: {
gridStyle() {
return {
'grid-template-columns': 'repeat(' + this.seatConfig.cols + ', 1fr)'
}
}
},
methods: {
onOpen(row) {
this.dialogVisible = true
this.row = row
this.seats = []
this.loadSeats()
},
getSeatSvg(enabled) {
const color = enabled ? '#409eff' : '#dcdfe6'
const strokeColor = enabled ? '#337ecc' : '#c0c4cc'
return '<svg width="32" height="32" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">' +
'<!-- 座椅靠背 -->' +
'<rect x="4" y="6" width="24" height="16" rx="2" ry="2" ' +
'fill="' + color + '" stroke="' + strokeColor + '" stroke-width="1"/>' +
'<!-- 座椅坐垫 -->' +
'<rect x="6" y="20" width="20" height="8" rx="2" ry="2" ' +
'fill="' + color + '" stroke="' + strokeColor + '" stroke-width="1"/>' +
'<!-- 扶手 -->' +
'<rect x="2" y="12" width="3" height="12" rx="1" ry="1" ' +
'fill="' + color + '" stroke="' + strokeColor + '" stroke-width="1"/>' +
'<rect x="27" y="12" width="3" height="12" rx="1" ry="1" ' +
'fill="' + color + '" stroke="' + strokeColor + '" stroke-width="1"/>' +
'</svg>'
},
generateSeats() {
this.seats = []
for (let row = 1; row <= this.seatConfig.rows; row++) {
for (let col = 1; col <= this.seatConfig.cols; col++) {
this.seats.push({
id: this.row.id + '_' + row + '_' + col,
hallId: this.row.id,
rowNumber: row.toString(),
colNumber: col.toString(),
enable: true
})
}
}
},
toggleSeat(seat) {
seat.enable = !seat.enable
},
loadSeats() {
// 加载现有座位数据
this.$axios.post('/platform/guildHall/selectSeatList', {hallId: this.row.id}).then(res => {
if (res.code === 0 && res.data && res.data.length > 0) {
this.seats = res.data
// 根据现有数据计算行列数
const maxRow = Math.max(...this.seats.map(s => parseInt(s.rowNumber)))
const maxCol = Math.max(...this.seats.map(s => parseInt(s.colNumber)))
this.seatConfig.rows = maxRow
this.seatConfig.cols = maxCol
} else {
// 没有数据时生成默认座位
// this.generateSeats()
}
}).catch(() => {
// this.generateSeats()
})
},
saveSeats() {
this.$confirm('确定要保存座位设置吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.$axios.post('/platform/guildHall/saveSeat', {
hallId: this.row.id,
seats: JSON.stringify(this.seats)
}).then(res => {
if (res.code === 0) {
this.$message.success('保存成功')
this.dialogVisible = false
}
})
})
}
},
style: /*language=CSS*/ `
/deep/ .seat-layout {
display: flex;
gap: 20px;
height: 70vh;
}
/deep/ .control-panel {
background: #f8f9fa;
border-radius: 8px;
padding: 16px;
width: 250px;
}
/deep/ .panel-section {
margin-bottom: 24px;
}
/deep/ .panel-section h4 {
margin: 0 0 12px 0;
color: #333;
font-size: 14px;
font-weight: 600;
}
/deep/ .control-group {
display: flex;
align-items: center;
margin-bottom: 12px;
gap: 8px;
}
/deep/ .control-group label {
width: 50px;
font-size: 13px;
color: #666;
}
/deep/ .legend {
margin-bottom: 12px;
}
/deep/ .legend-item {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 8px;
font-size: 13px;
color: #666;
}
/deep/ .seat-icon {
width: 32px;
height: 32px;
}
/deep/ .tip {
font-size: 12px;
color: #999;
margin: 0;
line-height: 1.4;
}
/deep/ .seat-area {
flex: 1;
background: #fff;
border: 1px solid #e8e8e8;
border-radius: 8px;
padding: 20px;
overflow: auto;
}
/deep/ .seat-grid {
display: grid;
gap: 8px;
justify-items: center;
max-width: 100%;
}
/deep/ .seat-item {
display: flex;
flex-direction: column;
align-items: center;
cursor: pointer;
transition: all 0.3s ease;
padding: 4px;
border-radius: 4px;
}
/deep/ .seat-item:hover {
background: rgba(64, 158, 255, 0.1);
transform: scale(1.05);
}
/deep/ .seat-item.disabled:hover {
background: rgba(220, 223, 230, 0.3);
}
/deep/ .seat-svg {
margin-bottom: 2px;
}
/deep/ .seat-label {
font-size: 10px;
color: #666;
text-align: center;
line-height: 1;
}
/deep/ .seat-item.enabled .seat-label {
color: #409eff;
font-weight: 500;
}
/deep/ .seat-item.disabled .seat-label {
color: #c0c4cc;
}
/* 响应式设计 */
@media (max-width: 1200px) {
.seat-layout {
flex-direction: column;
height: auto;
}
.control-panel {
width: 100%;
display: flex;
gap: 20px;
}
.panel-section {
flex: 1;
margin-bottom: 0;
}
}
@media (max-width: 768px) {
.control-panel {
flex-direction: column;
gap: 16px;
}
.seat-grid {
gap: 6px;
}
.seat-item {
padding: 2px;
}
}
`
}
@@ -0,0 +1,192 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style>
/* 固定会议编辑弹框,避免表单内容撑高整个弹框。 */
.guild-hall-meeting-dialog {
height: calc(100vh - 120px);
max-width: calc(100vw - 32px);
max-height: 700px;
display: flex;
flex-direction: column;
}
.guild-hall-meeting-dialog .el-dialog__header,
.guild-hall-meeting-dialog .el-dialog__footer {
flex-shrink: 0;
}
/* 表单内容超出可用高度时,仅在弹框内容区内滚动。 */
.guild-hall-meeting-dialog .el-dialog__body {
flex: 1;
min-height: 0;
overflow-y: auto;
}
</style>
<div id="app" v-cloak>
<el-card shadow="never">
<search @search="doSearch">
<search-item label="名称">
<el-input placeholder="请输入名称" clearable v-model="pageForm.searchKeyword"></el-input>
</search-item>
<search-item label="年度">
<el-date-picker v-model="pageForm.year" type="year" placeholder="请选择年度" style="width: 100%;"></el-date-picker>
</search-item>
</search>
</el-card>
<el-card shadow="never">
<table-tool>
<el-button type="primary" icon="el-icon-plus" size="small" @click="onAdd">新增</el-button>
</table-tool>
<el-table :data="tableData" ref="tableRef" @sort-change="pageOrder">
<el-table-column type="index" :index="indexMethod" width="50" label="序号"></el-table-column>
<el-table-column prop="name" label="名称"></el-table-column>
<el-table-column prop="year" 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 label="操作" width="200px">
<template slot-scope="scope">
<el-button type="primary" size="mini" @click="onEdit(scope.row)">编辑</el-button>
<el-button type="danger" size="mini" @click="onDelete(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<el-dialog :title="formData.id ? '编辑' : '新增'" :visible.sync="dialogVisible" width="1000px"
custom-class="guild-hall-meeting-dialog">
<el-form ref="formRef" :model="formData" :rules="formRules" label-width="80px">
<el-form-item label="名称" prop="name">
<el-input v-model="formData.name" placeholder="请输入名称"></el-input>
</el-form-item>
<el-form-item label="年度" prop="year">
<el-date-picker v-model="formData.year" type="year" value-format="yyyy"
placeholder="选择年度" style="width: 100%;"></el-date-picker>
</el-form-item>
<el-form-item label="开始时间" prop="startTime">
<el-date-picker
v-model="formData.startTime"
type="datetime"
placeholder="选择开始时间"
value-format="yyyy-MM-dd HH:mm:ss"
style="width: 100%;">
</el-date-picker>
</el-form-item>
<el-form-item label="结束时间" prop="endTime">
<el-date-picker
v-model="formData.endTime"
type="datetime"
placeholder="选择结束时间"
value-format="yyyy-MM-dd HH:mm:ss"
style="width: 100%;">
</el-date-picker>
</el-form-item>
<el-form-item label="会厅选择" prop="hallId">
<el-select v-model="formData.hallId" placeholder="请选择会厅" style="width: 100%">
<el-option v-for="item in hallList" :key="item.id" :label="item.name" :value="item.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="内容" prop="content">
<text-editor v-model="formData.content"></text-editor>
</el-form-item>
<el-form-item label="参与组别" prop="groupId">
<permission-group :value.sync="formData.groupId"></permission-group>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="onSave">提交</el-button>
</div>
</el-dialog>
</div>
<script nonce="${cspNonce!}">
const vue = new Vue({
el: '#app',
mixins: [initTableMixins],
data() {
return {
dialogVisible: false,
formRules: {
name: [{required: true, message: '必填', trigger: 'blur'}],
year: [{required: true, message: '必填', trigger: 'change'}],
startTime: [{required: true, message: '必填', trigger: 'change'}],
endTime: [{required: true, message: '必填', trigger: 'change'}],
hallId: [{required: true, message: '必填', trigger: 'blur'}],
content: [{required: true, message: '必填', trigger: 'blur'}],
},
hallList: [],
}
},
methods: {
onAdd() {
this.dialogVisible = true;
this.formData = {
id: null,
name: null,
year: null,
startTime: null,
endTime: null,
content: null,
groupId: null
}
},
onEdit(row) {
this.dialogVisible = true;
row.year = row.year.toString()
this.formData = {...row}
},
onSave() {
this.$refs.formRef.validate(valid => {
if (!valid) return
this.$confirm('您确定要提交吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.$axios.post('/platform/guildHall/meeting/' + (this.formData.id ? 'update' : 'save'), this.formData).then(res => {
if (res.code === 0) {
this.$message.success(res.msg)
this.dialogVisible = false
this.doSearch()
}
})
}).catch(() => {
});
})
},
onDelete(row) {
this.$confirm('您确定要删除吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.$axios.post('/platform/guildHall/meeting/delete', {id: row.id}).then(res => {
this.doSearch();
this.$message.success(res.msg)
})
})
},
selectList() {
this.$axios.post('/platform/guildHall/selectList').then(res => {
this.hallList = res.data
})
},
},
created() {
this.selectList();
this.doSearch();
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,81 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style>
</style>
<div id="app" v-cloak>
<guava>
<el-card shadow="never">
<search @search="doSearch">
<search-item label="会议">
<el-select clearable v-model="pageForm.meetingId" filterable placeholder="请选择会议">
<el-option
v-for="item in meetings"
:key="item.id"
:label="item.name"
:value="item.id">
</el-option>
</el-select>
</search-item>
</search>
</el-card>
<el-card shadow="never" class="mt20">
<table-tool label="选座人员">
<el-button size="small" type="primary" @click="exportExcel">导出选座人员</el-button>
</table-tool>
<el-table :data="tableData" @sort-change='pageOrder'>
<el-table-column type="index" width="50px" label="序号" :index="indexMethod"></el-table-column>
<el-table-column align="center" header-align="center" label="姓名" prop="userName"></el-table-column>
<el-table-column align="center" header-align="center" label="工号" prop="loginName"></el-table-column>
<el-table-column align="center" header-align="center" label="性别" prop="sex"></el-table-column>
<el-table-column align="center" header-align="center" label="所属单位" prop="unitName"></el-table-column>
<el-table-column align="center" header-align="center" label="所属工会" prop="unionName"></el-table-column>
<el-table-column align="center" header-align="center" label="联系方式" prop="mobile"></el-table-column>
<el-table-column align="center" header-align="center" label="座位" prop="seat">
<template scope="{row}">
{{row.rowNumber + '排' + row.colNumber + '列'}}
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</guava>
</div>
<script nonce="${cspNonce!}">
let vue = new Vue({
el: '#app',
mixins: [initTableMixins],
data() {
return {
meetings: []
}
},
methods: {
// 加载会议列表
loadMeetings() {
$.post('/platform/guildHall/seatSummary/listMeeting').then(res => {
if (res.code === 0) {
this.meetings = res.data
if (this.meetings.length > 0) {
this.pageForm.meetingId = this.meetings[0].id
}
this.pageData()
}
})
},
exportExcel() {
this.$downLoad(loc() + "/exportExcel", {
meetingId: this.pageForm.meetingId
})
}
},
async created() {
this.loadMeetings()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,837 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style>
.container-seat {
margin: 0 auto;
background: white;
min-height: 100vh;
}
.header-seat {
background-color: #ffffff;
color: #000000;
padding: 10px 20px;
border-bottom: 1px solid #ddd;
}
.header-seat h1 {
font-size: 24px;
margin-bottom: 5px;
font-weight: 500;
}
.header-seat p {
opacity: 0.9;
font-size: 14px;
}
.main-content-seat {
display: flex;
min-height: calc(100vh - 80px);
}
.seat-area {
flex: 1;
padding: 30px;
text-align: center;
}
.stage {
text-align: center;
padding: 15px;
background-color: #1867b0;
color: white;
margin-bottom: 30px;
border-radius: 4px;
font-size: 16px;
font-weight: 500;
}
.legend {
display: flex;
justify-content: center;
gap: 20px;
margin-bottom: 30px;
font-size: 14px;
}
.legend-item {
display: flex;
align-items: center;
gap: 8px;
}
.legend-seat-svg {
width: 24px;
height: 24px;
margin-right: 4px;
}
.seat-grid {
display: grid;
grid-template-columns: repeat(10, 1fr);
gap: 8px;
margin: 0 auto;
padding: 20px;
background-color: #fafafa;
border-radius: 8px;
border: 1px solid #e0e0e0;
width: fit-content;
justify-self: center;
}
.seat {
width: 60px;
height: 60px;
border-radius: 4px;
border: 1px solid transparent;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: 10px;
font-weight: 500;
cursor: pointer;
transition: all 0.2s ease;
position: relative;
}
.seat-icon {
width: 40px;
height: 40px;
margin-bottom: 2px;
}
.seat-number {
font-size: 10px;
font-weight: 600;
text-align: center;
}
.seat-back, .seat-cushion, .seat-armrest {
transition: all 0.2s ease;
}
.seat.available .seat-back {
fill: #f8f9fa;
stroke: #dee2e6;
stroke-width: 1;
}
.seat.available .seat-cushion {
fill: #ffffff;
stroke: #dee2e6;
stroke-width: 1;
}
.seat.available .seat-armrest {
fill: #e9ecef;
stroke: #dee2e6;
stroke-width: 1;
}
.seat.available .seat-number {
color: #666;
}
.seat.available:hover .seat-back {
fill: #e3f2fd;
stroke: #1867b0;
}
.seat.available:hover .seat-cushion {
fill: #f0f8ff;
stroke: #1867b0;
}
.seat.available:hover .seat-armrest {
fill: #e3f2fd;
stroke: #1867b0;
}
.seat.available:hover .seat-number {
color: #1867b0;
}
.seat.occupied .seat-back {
fill: #adb5bd;
stroke: #6c757d;
stroke-width: 1;
}
.seat.occupied .seat-cushion {
fill: #d0d0d0;
stroke: #6c757d;
stroke-width: 1;
}
.seat.occupied .seat-armrest {
fill: #adb5bd;
stroke: #6c757d;
stroke-width: 1;
}
.seat.occupied .seat-number {
color: #666;
}
.seat.occupied {
cursor: not-allowed;
}
.seat.selected .seat-back {
fill: #0d47a1;
stroke: #1867b0;
stroke-width: 2;
}
.seat.selected .seat-cushion {
fill: #1867b0;
stroke: #0d47a1;
stroke-width: 2;
}
.seat.selected .seat-armrest {
fill: #0d47a1;
stroke: #1867b0;
stroke-width: 2;
}
.seat.selected .seat-number {
/*color: white;*/
font-weight: 700;
}
.seat.my-seat .seat-back {
fill: #c62828;
stroke: #ff3742;
stroke-width: 2;
}
.seat.my-seat .seat-cushion {
fill: #ff4757;
stroke: #c62828;
stroke-width: 2;
}
.seat.my-seat .seat-armrest {
fill: #c62828;
stroke: #ff3742;
stroke-width: 2;
}
.seat.my-seat .seat-number {
/*color: white;*/
font-weight: 700;
}
.seat.disabled .seat-back {
fill: #f5f5f5;
stroke: #cccccc;
stroke-width: 1;
}
.seat.disabled .seat-cushion {
fill: #f0f0f0;
stroke: #cccccc;
stroke-width: 1;
}
.seat.disabled .seat-armrest {
fill: #f5f5f5;
stroke: #cccccc;
stroke-width: 1;
}
.seat.disabled .seat-number {
color: #999;
}
.seat.disabled {
cursor: not-allowed;
opacity: 0.6;
}
.sidebar-seat {
width: 300px;
background-color: #fafafa;
border-left: 1px solid #e0e0e0;
}
.section {
background: white;
padding: 20px;
margin-bottom: 20px;
}
.section h3 {
color: #333;
margin-bottom: 15px;
font-size: 16px;
font-weight: 600;
}
.form-group {
margin-bottom: 15px;
}
.form-group label {
display: block;
margin-bottom: 5px;
color: #555;
font-size: 14px;
}
.form-group input {
width: 100%;
padding: 8px 12px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 14px;
}
.form-group input:focus {
outline: none;
border-color: #1867b0;
}
.btn {
width: 100%;
padding: 10px;
border: none;
border-radius: 4px;
font-size: 14px;
cursor: pointer;
transition: background-color 0.2s ease;
margin-bottom: 10px;
}
.btn-primary {
background-color: #1867b0;
color: white;
}
.btn-primary:hover:not(:disabled) {
background-color: #155a8a;
}
.btn-secondary {
background-color: #6c757d;
color: white;
}
.btn-secondary:hover:not(:disabled) {
background-color: #5a6268;
}
.btn:disabled {
opacity: 0.6;
cursor: not-allowed;
}
.my-booking {
padding: 15px;
background-color: #f8f9fa;
border-radius: 4px;
border-left: 3px solid #1867b0;
}
.my-booking p {
margin-bottom: 8px;
font-size: 14px;
color: #666;
}
.my-booking strong {
color: #333;
}
.alert {
padding: 12px;
border-radius: 4px;
margin-bottom: 15px;
font-size: 14px;
}
.alert-success {
background-color: #d4edda;
color: #155724;
border: 1px solid #c3e6cb;
}
.alert-error {
background-color: #f8d7da;
color: #721c24;
border: 1px solid #f5c6cb;
}
.loading {
text-align: center;
padding: 50px;
color: #666;
}
@media (max-width: 768px) {
.main-content-seat {
flex-direction: column;
}
.sidebar-seat {
width: 100%;
border-left: none;
border-top: 1px solid #e0e0e0;
}
.seat-grid {
gap: 6px;
padding: 15px;
}
.seat {
width: 40px;
height: 40px;
font-size: 11px;
}
.header-seat {
padding: 15px 20px;
}
.seat-area, .sidebar-seat {
padding: 20px;
}
}
/* 会议选择弹窗样式 */
.meeting-modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: center;
z-index: 1000;
}
.meeting-modal-content {
background: white;
border-radius: 8px;
padding: 30px;
max-width: 600px;
width: 90%;
max-height: 80vh;
overflow-y: auto;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
}
.meeting-modal h2 {
color: #333;
margin-bottom: 20px;
font-size: 20px;
text-align: center;
}
.meeting-list {
display: flex;
flex-direction: column;
gap: 15px;
}
.meeting-item {
border: 2px solid #e0e0e0;
border-radius: 8px;
padding: 20px;
cursor: pointer;
transition: all 0.3s ease;
background: #fafafa;
}
.meeting-item:hover {
border-color: #1867b0;
background: #f0f8ff;
}
.meeting-item.selected {
border-color: #1867b0;
background: #e8f4fd;
}
.meeting-name {
font-size: 16px;
font-weight: 600;
color: #333;
margin-bottom: 8px;
}
.meeting-info {
font-size: 14px;
color: #666;
margin-bottom: 5px;
}
.meeting-time {
font-size: 13px;
color: #999;
}
.modal-buttons {
display: flex;
gap: 15px;
margin-top: 25px;
justify-content: center;
}
.modal-btn {
padding: 10px 25px;
border: none;
border-radius: 4px;
font-size: 14px;
cursor: pointer;
transition: background-color 0.2s ease;
}
.modal-btn-primary {
background-color: #1867b0;
color: white;
}
.modal-btn-primary:hover:not(:disabled) {
background-color: #155a8a;
}
.modal-btn-secondary {
background-color: #6c757d;
color: white;
}
.modal-btn-secondary:hover:not(:disabled) {
background-color: #5a6268;
}
.modal-btn:disabled {
opacity: 0.6;
cursor: not-allowed;
}
</style>
<div id="app" v-cloak>
<guava>
<!-- 会议选择弹窗 -->
<div v-if="showMeetingModal" class="meeting-modal">
<div class="meeting-modal-content">
<h2>请选择会议</h2>
<div class="meeting-list">
<div
v-for="meeting in meetings"
:key="meeting.id"
:class="['meeting-item', { selected: selectedMeetingId === meeting.id }]"
@click="selectMeeting(meeting)"
>
<div class="meeting-name">{{ meeting.name }}</div>
<div class="meeting-info">地点:{{ meeting.address }}</div>
<div class="meeting-time">时间:{{ meeting.startTime }} 至 {{ meeting.endTime }}</div>
</div>
</div>
<div class="modal-buttons">
<button
class="modal-btn"
@click="showMeetingModal = false"
>
取消选择
</button>
<button
class="modal-btn modal-btn-primary"
@click="confirmMeetingSelection"
:disabled="!selectedMeetingId"
>
确认选择
</button>
</div>
</div>
</div>
<div class="container-seat">
<div class="header-seat" v-if="meeting">
<h1>{{ meeting.name }}</h1>
<p>{{ meeting.startTime + ' 至 ' + meeting.endTime}}</p>
</div>
<div class="main-content-seat">
<div class="seat-area">
<!-- <div class="stage">主席台</div>-->
<div class="legend">
<div class="legend-item">
<svg class="legend-seat-svg" viewBox="0 0 50 50" xmlns="http://www.w3.org/2000/svg">
<rect x="8" y="5" width="34" height="20" rx="3" ry="3" fill="#f8f9fa" stroke="#dee2e6" stroke-width="1"/>
<rect x="5" y="22" width="40" height="18" rx="4" ry="4" fill="#ffffff" stroke="#dee2e6" stroke-width="1"/>
<rect x="2" y="20" width="6" height="15" rx="2" ry="2" fill="#e9ecef" stroke="#dee2e6" stroke-width="1"/>
<rect x="42" y="20" width="6" height="15" rx="2" ry="2" fill="#e9ecef" stroke="#dee2e6" stroke-width="1"/>
</svg>
<span>可选座位</span>
</div>
<div class="legend-item">
<svg class="legend-seat-svg" viewBox="0 0 50 50" xmlns="http://www.w3.org/2000/svg">
<rect x="8" y="5" width="34" height="20" rx="3" ry="3" fill="#adb5bd" stroke="#6c757d" stroke-width="1"/>
<rect x="5" y="22" width="40" height="18" rx="4" ry="4" fill="#d0d0d0" stroke="#6c757d" stroke-width="1"/>
<rect x="2" y="20" width="6" height="15" rx="2" ry="2" fill="#adb5bd" stroke="#6c757d" stroke-width="1"/>
<rect x="42" y="20" width="6" height="15" rx="2" ry="2" fill="#adb5bd" stroke="#6c757d" stroke-width="1"/>
</svg>
<span>已被占用</span>
</div>
<div class="legend-item">
<svg class="legend-seat-svg" viewBox="0 0 50 50" xmlns="http://www.w3.org/2000/svg">
<rect x="8" y="5" width="34" height="20" rx="3" ry="3" fill="#0d47a1" stroke="#1867b0" stroke-width="2"/>
<rect x="5" y="22" width="40" height="18" rx="4" ry="4" fill="#1867b0" stroke="#0d47a1" stroke-width="2"/>
<rect x="2" y="20" width="6" height="15" rx="2" ry="2" fill="#0d47a1" stroke="#1867b0" stroke-width="2"/>
<rect x="42" y="20" width="6" height="15" rx="2" ry="2" fill="#0d47a1" stroke="#1867b0" stroke-width="2"/>
</svg>
<span>当前选择</span>
</div>
<div class="legend-item">
<svg class="legend-seat-svg" viewBox="0 0 50 50" xmlns="http://www.w3.org/2000/svg">
<rect x="8" y="5" width="34" height="20" rx="3" ry="3" fill="#c62828" stroke="#ff3742" stroke-width="2"/>
<rect x="5" y="22" width="40" height="18" rx="4" ry="4" fill="#ff4757" stroke="#c62828" stroke-width="2"/>
<rect x="2" y="20" width="6" height="15" rx="2" ry="2" fill="#c62828" stroke="#ff3742" stroke-width="2"/>
<rect x="42" y="20" width="6" height="15" rx="2" ry="2" fill="#c62828" stroke="#ff3742" stroke-width="2"/>
</svg>
<span>我的座位</span>
</div>
<div class="legend-item">
<svg class="legend-seat-svg" viewBox="0 0 50 50" xmlns="http://www.w3.org/2000/svg">
<rect x="8" y="5" width="34" height="20" rx="3" ry="3" fill="#f5f5f5" stroke="#cccccc" stroke-width="1"/>
<rect x="5" y="22" width="40" height="18" rx="4" ry="4" fill="#f0f0f0" stroke="#cccccc" stroke-width="1"/>
<rect x="2" y="20" width="6" height="15" rx="2" ry="2" fill="#f5f5f5" stroke="#cccccc" stroke-width="1"/>
<rect x="42" y="20" width="6" height="15" rx="2" ry="2" fill="#f5f5f5" stroke="#cccccc" stroke-width="1"/>
</svg>
<span>禁用座位</span>
</div>
</div>
<div v-if="loading" class="loading">
<p>正在加载座位信息...</p>
</div>
<div v-else class="seat-grid" :style="gridStyle">
<div
v-for="seat in seats"
:key="seat.id"
:class="getSeatClass(seat)"
class="seat"
@click="selectSeat(seat)"
:title="getSeatTitle(seat)"
>
<svg class="seat-icon" viewBox="0 0 50 50" xmlns="http://www.w3.org/2000/svg">
<!-- 座位靠背 -->
<rect x="8" y="5" width="34" height="20" rx="3" ry="3" class="seat-back"/>
<!-- 座位坐垫 -->
<rect x="5" y="22" width="40" height="18" rx="4" ry="4" class="seat-cushion"/>
<!-- 扶手 -->
<rect x="2" y="20" width="6" height="15" rx="2" ry="2" class="seat-armrest"/>
<rect x="42" y="20" width="6" height="15" rx="2" ry="2" class="seat-armrest"/>
</svg>
<span class="seat-number">{{ seat.rowNumber }}-{{ seat.colNumber }}</span>
</div>
</div>
</div>
<div class="sidebar-seat">
<div class="section">
<h3>操作列</h3>
<button
class="btn btn-primary mt10"
@click="showMeetingModal = true"
>
切换会议
</button>
</div>
<div class="section">
<h3>座位选择</h3>
<div v-if="selectedSeat" class="my-booking" style="border-left-color: #28a745;">
<p><strong>选中座位:</strong> {{ selectedSeat.seatNumber }}</p>
<p><strong>位置:</strong> 第{{ selectedSeat.rowNumber }}排第{{ selectedSeat.colNumber }}列</p>
</div>
<div v-else class="my-booking">
<p style="color: #999;">请点击座位进行选择</p>
</div>
<div v-if="alertMessage" :class="'alert alert-' + alertType">
{{ alertMessage }}
</div>
<button
class="btn btn-primary mt10"
@click="confirmSelection"
:disabled="!selectedSeat || submitting"
>
{{ submitting ? '提交中...' : '提交选座' }}
</button>
</div>
<div class="section">
<h3>我的座位</h3>
<div v-if="myCurrentSeat" class="my-booking">
<p><strong>座位号:</strong> {{ myCurrentSeat.rowNumber }}-{{ myCurrentSeat.colNumber }} </p>
<p><strong>位置:</strong> 第{{ myCurrentSeat.rowNumber }}排第{{ myCurrentSeat.colNumber }}列</p>
<p><strong>选择时间:</strong> {{ formatTime(myCurrentSeat.selectTime) }}</p>
</div>
<div v-else class="my-booking">
<p style="color: #999;">暂未选择座位</p>
</div>
</div>
</div>
</div>
</div>
</guava>
</div>
<script nonce="${cspNonce!}">
new Vue({
el: '#app',
data() {
return {
meetings: [], // 会议列表
selectedMeetingId: null, // 选中的会议ID
showMeetingModal: true, // 显示会议选择弹窗
meeting: null,
seats: [],
selectedSeat: null,
myCurrentSeat: null,
loading: false,
submitting: false,
alertMessage: '',
alertType: 'success',
seatConfig: {
rows: 8,
cols: 12
},
}
},
mounted() {
this.loadMeetings();
},
computed: {
gridStyle() {
return {
'grid-template-columns': 'repeat(' + this.seatConfig.cols + ', 1fr)'
}
}
},
methods: {
// 加载会议列表
loadMeetings() {
$.post('/platform/guildHall/meeting/selectList').then(res => {
if (res.code === 0) {
this.meetings = res.data
}
})
},
// 选择会议
selectMeeting(meeting) {
this.selectedMeetingId = meeting.id;
},
// 确认会议选择
confirmMeetingSelection() {
if (!this.selectedMeetingId) {
this.$message.error('请选择一个会议');
return;
}
const selectedMeeting = this.meetings.find(m => m.id === this.selectedMeetingId);
if (selectedMeeting) {
this.meeting = selectedMeeting
this.loadSeats();
}
},
// 查询选座情况
async loadSeats() {
if (!this.meeting.id) {
return;
}
this.loading = true;
const {code,data,msg} = await $.post('/platform/guildHall/selectSeat/loadSeats', {meetingId: this.meeting.id})
if (code === 0) {
if(data.length === 0) {
this.$message.warning('该会议暂未设置座位')
return
}
this.seats = data;
this.myCurrentSeat = this.seats.find(seat => seat.isMine);
// 根据现有数据计算行列数
const maxRow = Math.max(...this.seats.map(s => parseInt(s.rowNumber)))
const maxCol = Math.max(...this.seats.map(s => parseInt(s.colNumber)))
this.seatConfig.rows = maxRow
this.seatConfig.cols = maxCol
}
this.loading = false
this.showMeetingModal = false;
},
selectSeat(seat) {
if (!seat.enable) {
this.$message.error('该座位已被禁用');
return;
}
if (seat.isOccupied && !seat.isMine) {
this.$message.error('该座位已被占用');
return;
}
if (seat.isMine) {
this.$message.success('这是您当前的座位');
return;
}
this.selectedSeat = seat;
this.$set(this.selectedSeat, 'seatNumber', seat.rowNumber + '-' + seat.colNumber)
},
async confirmSelection() {
if (!this.selectedSeat) {
this.$message.error('请先选择座位');
return;
}
this.submitting = true;
const {code,data,msg} = await $.post('/platform/guildHall/selectSeat/doSelect', {
meetingId: this.meeting.id,
seatNumber: this.selectedSeat.seatNumber,
rowNumber: this.selectedSeat.rowNumber,
colNumber: this.selectedSeat.colNumber
})
this.submitting = false
if (code === 0) {
this.$message.success("选座成功")
this.loadSeats();
}
},
getSeatClass(seat) {
if (!seat.enable) return 'disabled';
if (seat.isMine) return 'my-seat';
if (seat === this.selectedSeat) return 'selected';
if (seat.isOccupied) return 'occupied';
return 'available';
},
getSeatTitle(seat) {
if (seat.isMine) return '我的座位';
if (seat === this.selectedSeat) return '当前选择';
if (seat.status === 1) return '已被占用';
return '点击选择此座位';
},
formatTime(time) {
if (!time) return '';
return new Date(time).toLocaleString('zh-CN');
},
showAlert(message, type) {
this.alertMessage = message;
this.alertType = type;
setTimeout(() => {
this.alertMessage = '';
}, 3000);
}
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,149 @@
const BASIC_TABLE_COMPONENT = {
template: `
<div>
<el-row type="flex">
<el-col></el-col>
</el-row>
<table-tool>
<el-button type="primary" size="small" icon="el-icon-plus" @click="openAdd()">新建机构</el-button>
</table-tool>
<el-table key="1" :data="tableData" ref="tableRef">
<el-table-column label="序号" width="100px" type="index" :index="indexMethod"></el-table-column>
<el-table-column prop="name" label="机构名称"></el-table-column>
<el-table-column prop="introduce" label="描述"></el-table-column>
<el-table-column label="操作" width="100px">
<template slot-scope="{row}">
<el-link size="mini" type="danger" @click="del(row.id)">删除</el-link>
</template>
</el-table-column>
</el-table>
<el-dialog :visible.sync="dialogFormVisible" :title="formData.id?'编辑':'新增'" width="40%">
<el-form :model="formData" ref="formRef" :rules="rules" label-width="100px">
<el-form-item label="机构名称" prop="ids">
<el-cascader
v-model="ids"
:options="treeList"
:props="props"
@change="parentChange"
placeholder="请选择机构"
style="width: 100%"
></el-cascader>
</el-form-item>
<el-form-item label="机构代码" prop="code">
<el-input placeholder="请输入机构代码" v-model="formData.code" disabled></el-input>
</el-form-item>
<el-form-item label="描述" prop="introduce">
<el-input v-model="formData.introduce" placeholder="请输入描述"></el-input>
</el-form-item>
<el-form-item label="备注" prop="notes">
<el-input v-model="formData.notes" placeholder="请输入备注"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">取 消</el-button>
<el-button type="primary" @click="doSubmit">确 定</el-button>
</div>
</el-dialog>
</div>
`,
mixins: [initTableMixins],
props: {
sessionId: {
type: String,
required: true
},
parentId: {
type: String,
required: true
}
},
data() {
return {
rules: {
name: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
code: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
parentId: [{ required: true, message: "必填", trigger: ["change", "blur"] }]
},
parentData: {},
parentIds: [],
ids: [],
treeList: [],
treeFlat: [],
props: {
checkStrictly: true,
multiple: false,
label: "name",
value: "id"
},
dialogFormVisible: false
}
},
methods: {
pageData() {
this.$axios
.post(loc() + "/pageData", {
...this.pageForm,
sessionId: this.sessionId,
parentId: this.parentId
})
.then((res) => {
if (res.code === 0) {
this.tableData = res.data.list
this.pageForm.totalCount = res.data.total
}
})
},
openAdd() {
this.dialogFormVisible = true
this.formData = {}
this.ids = []
$.post("/platform/teacherCongress/institution/formTree", { sessionId: this.sessionId }).then((res) => {
if (res.code === 0) {
this.treeList = res.data.treeList
this.treeFlat = res.data.treeFlat
}
})
},
// 上级机构选择变化
parentChange(val) {
const id = val[val.length - 1]
const tree = this.treeFlat.find((tree) => tree.id === id)
this.$set(this.formData, "code", tree?.code)
this.$set(this.formData, "name", tree?.name)
},
doSubmit() {
this.$refs.formRef.validate((valid) => {
this.formData.id = this.ids[this.ids.length - 1]
this.formData.parentId = this.ids[this.ids.length - 2] || this.parentId
this.formData.sessionId = this.sessionId
if (valid) {
this.$axios.post(loc() + "/insert", this.formData).then((res) => {
if (res.code === 0) {
this.dialogFormVisible = false
this.$message.success(res.msg)
this.doSearch()
this.$emit("refresh", null)
}
})
}
})
},
del(id) {
this.$confirm("您确定要删除吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post(loc() + "/delete", { id }).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.doSearch()
this.$emit("refresh", null)
}
})
})
}
}
}
@@ -0,0 +1,78 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app" v-cloak>
<el-row type="flex" :gutter="10" style="height: calc(100vh - 84px)">
<el-col :span="5">
<tree @node-click="treeNodeClick" ref="treeRef"></tree>
</el-col>
<el-col :span="19">
<el-card shadow="never" style="height: 100%">
<template>
<basic-table
:session-id="sessionId"
:parent-id="currentTreeData.id"
v-if="showInstitutionTable || (currentTreeData && currentTreeData.id==='0')"
ref="basicTableRef"
@refresh="$refs.treeRef.listTree()"
></basic-table>
</template>
<user-table
:session-id="sessionId"
:institution-id="currentTreeData.id"
ref="userTableRef"
v-if="!showInstitutionTable && sessionId"
></user-table>
</el-card>
</el-col>
</el-row>
</div>
<script nonce="${cspNonce!}">
<!--#include("tree.js"){}#-->
<!--#include("userTable.js"){}#-->
<!--#include("basicTable.js"){}#-->
new Vue({
el: "#app",
mixins: [initTableMixins],
components: {
tree: TREE_COMPONENT,
"user-table": USER_TABLE_COMPONENT,
"basic-table": BASIC_TABLE_COMPONENT
},
computed: {
showInstitutionTable() {
const hasChildren = this.currentTreeData?.children?.length > 0
return hasChildren
}
},
data() {
return {
currentTreeNode: null,
currentTreeData: null,
sessionId: null
}
},
methods: {
treeNodeClick(data, node, sessionId) {
this.currentTreeData = data
this.currentTreeNode = node
this.sessionId = sessionId
this.$nextTick(() => {
if (this.showInstitutionTable) {
this.$refs.basicTableRef && this.$refs.basicTableRef.doSearch()
} else {
this.$refs.userTableRef && this.$refs.userTableRef.doSearch()
}
})
},
openEdit(row) {}
},
created() {}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,72 @@
const TREE_COMPONENT = {
template: /*language=HTML*/ `
<el-card shadow="never" style="height: 100%" :body-style="{ height: '100%' }">
<el-select v-model="sessionId" :clearable="false" style="width: 100%" @change="listTree">
<el-option v-for="i in sessionOptions" :label="i.fullName" :value="i.id" :key="i.id"></el-option>
</el-select>
<div style="height: calc(100% - 50px);overflow-y: auto">
<el-tree
:data="treeData"
ref="treeRef"
:expand-on-click-node="false"
:props="{
children: 'children',
label: 'name'
}"
default-expand-all
@node-click="treeNodeClick"
:filter-node-method="filterNode"
>
<template slot-scope="{ node, data }">
<span class="el-tree-node__label">
<i class="el-icon-folder-opened" v-if="node.level===1"></i>
<i class="el-icon-folder" v-else></i>
{{node.label}}
</span>
</template>
</el-tree>
</div>
</el-card>
`,
data() {
return {
currentTreeNode: null,
currentTreeData: null,
sessionOptions: [],
sessionId: null,
name: null,
treeData: []
}
},
methods: {
treeNodeClick(data, node) {
this.currentTreeData = data
this.currentTreeNode = node
this.$emit("node-click", data, node, this.sessionId)
},
filterNode() {},
listTree() {
this.$axios.post("/platform/teacherCongress/institution/leftTree", { sessionId: this.sessionId }).then((res) => {
if (res.code === 0) {
this.treeData = res.data
this.$emit("node-click", this.treeData[0], null, this.sessionId)
}
})
},
listSession() {
this.$axios.post("/platform/teacherCongress/common/listSession").then((res) => {
if (res.code === 0) {
this.sessionOptions = res.data
if (this.sessionOptions && this.sessionOptions.length > 0) {
this.sessionId = this.sessionOptions[0].id
this.listTree()
}
}
})
}
},
created() {
this.listSession()
}
}
@@ -0,0 +1,148 @@
const USER_TABLE_COMPONENT = {
template: `
<div>
<el-card shadow="never" style="height: 100%">
<el-row type="flex" :gutter="20">
<el-col :span="4">
<el-input v-model="pageForm.searchKeyword" clearable placeholder="请输入姓名或者工号">" @keyup.enter.native="doSearch">
</el-input>
</el-col>
<el-col :span="4">
<div class="search-query">
<el-button type="primary" icon="el-icon-search" @click="doSearch">搜索</el-button>
</div>
</el-col>
</el-row>
<el-divider class="mb10 mt10"></el-divider>
<table-tool>
<el-button type="primary" size="small" icon="el-icon-plus" @click="openAdd()">设置人员</el-button>
</table-tool>
<el-table key="1" :data="tableData" ref="tableRef">
<el-table-column label="序号" width="100px" type="index" :index="indexMethod"></el-table-column>
<el-table-column prop="username" label="姓名"></el-table-column>
<el-table-column prop="loginname" label="工号"></el-table-column>
<el-table-column prop="sex" label="性别"></el-table-column>
<el-table-column prop="mobile" label="手机号码"></el-table-column>
<el-table-column prop="unitName" label="单位" show-overflow-tooltip></el-table-column>
<el-table-column prop="identity" label="身份" show-overflow-tooltip></el-table-column>
<el-table-column label="操作" width="100px">
<template slot-scope="{row}">
<el-link size="mini" type="danger" @click="del(row.id)">删除</el-link>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<el-dialog title="设置人员" width="50%" :visible.sync="dialogVisible">
<el-form :model="formData" ref="formRef" label-width="120px" :rules="formRules">
<el-form-item label="届次" prop="sessionId">
<el-select v-model="formData.sessionId" disabled>
<el-option v-for="i in sessionOptions" :label="i.fullName" :value="i.id" :key="i.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="工号或姓名" prop="userId">
<user-select
v-model="formData.userId"
style="width: 100%"
api_input_key_name="query"
:option_label_func="(item)=>{return item.username + item.loginname}"
></user-select>
</el-form-item>
<el-form-item label="身份" prop="identity">
<dict-select v-model="formData.identity" code="TEACHER_CONGRESS_INSTITUTION_USER_ROLE"></dict-select>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false">取 消</el-button>
<el-button type="primary" @click="doSubmit">确 定</el-button>
</div>
</el-dialog>
</div>
`,
mixins: [initTableMixins],
props: {
sessionId: {
required: true,
type: String
},
institutionId: {
required: true,
type: String
}
},
data() {
return {
formRules: {
sessionId: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
userId: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
identity: [{ required: true, message: "必填", trigger: ["change", "blur"] }]
},
dialogVisible: false,
sessionOptions: []
}
},
methods: {
pageData() {
this.$axios
.post(loc() + "/userPageData", {
...this.pageForm,
sessionId: this.sessionId,
institutionId: this.institutionId
})
.then((res) => {
if (res.code === 0) {
this.tableData = res.data.list
this.pageForm.totalCount = res.data.totalCount
}
})
},
doSubmit() {
this.$refs.formRef.validate((valid) => {
if (valid) {
this.$axios.post("/platform/teacherCongress/institution/userInsert", this.formData).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.dialogVisible = false
this.pageData()
}
})
}
})
},
del(id) {
this.$confirm("确定删除吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
})
.then(() => {
this.$axios.post("/platform/teacherCongress/institution/userDelete", { id }).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.doSearch()
}
})
})
.catch(() => {})
},
listSession() {
this.$axios.post("/platform/teacherCongress/common/listSession").then((res) => {
if (res.code === 0) {
this.sessionOptions = res.data
}
})
},
openAdd() {
this.dialogVisible = true
this.formData = {
sessionId: this.sessionId,
institutionId: this.institutionId
}
this.listSession()
}
}
}
@@ -0,0 +1,197 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app" v-cloak>
<el-card shadow="never">
<search @search="doSearch">
<search-item label="教代会">
<el-select v-model="pageForm.sessionId" clearable>
<el-option v-for="item in sessionOptions" :label="item.fullName" :value="item.id" :key="item.id"></el-option>
</el-select>
</search-item>
<search-item label="名称">
<el-input placeholder="请输入名称查询" clearable v-model="pageForm.searchKeyword"></el-input>
</search-item>
<search-item label="所属类型">
<el-select v-model="pageForm.meetingType" clearable filterable placeholder="请选择会议活动所属类型">
<el-option label="代表团会议活动" value="delegation"></el-option>
<el-option label="分工会会议活动" value="union"></el-option>
</el-select>
</search-item>
</search>
</el-card>
<el-card shadow="never">
<table-tool>
<el-button size="small" type="primary" icon="el-icon-plus" @click="openAdd">新增</el-button>
</table-tool>
<el-table :data="tableData" @sort-change="pageOrder" header-align="center" style="width: 100%">
<el-table-column type="index" :index="indexMethod" width="50" label="序号"></el-table-column>
<el-table-column prop="name" label="名称"></el-table-column>
<el-table-column prop="sessionId" label="教代会">
<template slot-scope="{row}">
<dict-tag :options="sessionOptions" :value="row.sessionId" option_value="id" option_label="fullName"></dict-tag>
</template>
</el-table-column>
<el-table-column prop="type" label="类型"></el-table-column>
<el-table-column prop="createdAt" label="上传时间">
<template slot-scope="{row}">{{$moment(row.createdAt).format("YYYY-MM-DD HH:mm:ss")}}</template>
</el-table-column>
<el-table-column prop="pass" label="是否通过">
<template slot-scope="{row}">
<i class="fa fa-circle" :class="row.pass ? 'text-success' : 'text-danger'" style="margin-left: 5px"></i>
</template>
</el-table-column>
<el-table-column label="操作" width="300">
<template slot-scope="scope">
<el-button size="mini" type="" @click="openView(scope.row.id)">查看</el-button>
<el-button size="mini" type="primary" @click="openEdit(scope.row.id)">编辑</el-button>
<el-button size="mini" type="danger" @click="doDelete(scope.row.id)">删除</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<el-dialog :title="formData.id ? '编辑':'新增'" :visible.sync="dialogFormVisible" width="60%" :close-on-click-modal="false">
<el-form :model="formData" ref="formRef" size="small" label-width="135px" :rules="formRules">
<el-form-item prop="sessionId" label="教代会">
<el-select v-model="formData.sessionId">
<el-option v-for="item in sessionOptions" :label="item.fullName" :value="item.id" :key="item.id"></el-option>
</el-select>
</el-form-item>
<el-form-item prop="name" label="文件名称">
<el-input placeholder="请输入文件名称" v-model="formData.name" maxlength="1000"></el-input>
</el-form-item>
<el-form-item prop="type" label="文件类型">
<dict-select v-model="formData.type" code="TEACHER_CONGRESS_PREPARE_FILE_TYPE"></dict-select>
</el-form-item>
<el-form-item prop="meetingType" label="会议资料所属类型">
<el-select v-model="formData.meetingType" style="width: 100%;" placeholder="请选择会议资料所属类型">
<el-option label="代表团会议资料" value="delegation"
v-if="$auth.hasRole('SYSADMIN')
|| $auth.hasRole('SCHOOL_UNION_ADMIN')
|| $auth.hasRole('TEACHER_CONGRESS_DELEGATION_HEAD')"></el-option>
<el-option label="分工会会议资料" value="union"
v-if="$auth.hasRole('SYSADMIN')
|| $auth.hasRole('SCHOOL_UNION_ADMIN')
|| $auth.hasRole('BRANCH_UNION_CHAIRMAN')"></el-option>
</el-select>
</el-form-item>
<el-form-item prop="pass" label="是否通过">
<el-radio-group v-model="formData.pass" size="small">
<el-radio :label="true" border></el-radio>
<el-radio :label="false" border></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item prop="files" label="文件">
<file-upload :value.sync="formData.files" :upload_number="5" upload_result_category="array" complete_result></file-upload>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">取 消</el-button>
<el-button type="primary" @click="doSubmit">确 定</el-button>
</div>
</el-dialog>
<el-dialog title="查看" :visible.sync="viewDialogVisible" width="60%">
<file-preview :files="viewData.files" complete_result></file-preview>
</el-dialog>
</div>
<script src="/assets/platform/module/democratic/teachercongress/teacherCongressCommonApi.js"></script>
<script nonce="${cspNonce!}">
new Vue({
el: "#app",
mixins: [initTableMixins],
data() {
return {
dialogFormVisible: false,
formRules: {
sessionId: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
name: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
type: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
enable: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
pass: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
files: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
meetingType: [{ required: true, message: "必填", trigger: ["change", "blur"] }]
},
sessionOptions: []
}
},
methods: {
openAdd() {
this.dialogFormVisible = true
this.$nextTick(() => {
this.formData = {}
})
},
openEdit(id) {
this.dialogFormVisible = true
this.$axios.post(loc() + "/findOne", { id }).then((res) => {
if (res.code === 0) {
this.formData = res.data
}
})
},
doDelete(id) {
this.$confirm("您确定要删除吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post(loc() + "/delete", { id }).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.doSearch()
}
})
})
},
doSubmit() {
this.$refs.formRef.validate((valid) => {
if (valid) {
this.$axios.post(loc() + (this.formData.id ? "/update" : "/insert"), { file: JSON.stringify(this.formData) }).then((res) => {
if (res.code === 0) {
this.dialogFormVisible = false
this.$message.success(res.msg)
this.doSearch()
}
})
}
})
},
openView(id) {
this.viewDialogVisible = true
this.$axios.post(loc() + "/findOne", { id }).then((res) => {
if (res.code === 0) {
this.viewData = res.data
}
})
},
listSession() {
this.$axios.post("/platform/teacherCongress/common/listSession").then((res) => {
if (res.code === 0) {
this.sessionOptions = res.data
}
})
}
},
created() {
this.pageData()
this.listSession()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,298 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app" v-cloak>
<el-card shadow="never">
<search @search="doSearch">
<search-item label="教代会">
<el-select v-model="pageForm.sessionId" style="width: 100%">
<el-option v-for="item in sessionOptions" :label="item.fullName" :value="item.id"
:key="item.id"></el-option>
</el-select>
</search-item>
<search-item label="会议类型">
<el-select v-model="pageForm.type" clearable filterable placeholder="请选择类型">
<el-option
v-for="item in dict.type.TEACHER_CONGRESS_MEETING_TYPE"
:label="item.name"
:value="item.code"
:key="item.id"
></el-option>
</el-select>
</search-item>
<search-item label="名称">
<el-input v-model="pageForm.searchKeyword" placeholder="请输入名称" clearable></el-input>
</search-item>
<search-item label="所属类型">
<el-select v-model="pageForm.meetingType" clearable filterable placeholder="请选择会议活动所属类型">
<el-option label="代表团会议活动" value="delegation"></el-option>
<el-option label="分工会会议活动" value="union"></el-option>
</el-select>
</search-item>
</search>
</el-card>
<el-card shadow="never">
<table-tool>
<el-button size="small" type="primary" icon="el-icon-plus" @click="openAdd">新增</el-button>
</table-tool>
<el-table :data="tableData" @sort-change="pageOrder" header-align="center" style="width: 100%">
<el-table-column type="index" :index="indexMethod" width="50" label="序号"></el-table-column>
<el-table-column prop="name" label="名称"></el-table-column>
<el-table-column prop="sessionName" label="教代会">
<template scope="scope">
<dict-tag :options="sessionOptions" :value="scope.row.sessionId" option_value="id"
option_label="fullName"></dict-tag>
</template>
</el-table-column>
<el-table-column prop="name" label="名称"></el-table-column>
<el-table-column prop="startDateTime" label="开始时间"></el-table-column>
<el-table-column prop="endDateTime" label="结束时间"></el-table-column>
<el-table-column prop="site" label="场地"></el-table-column>
<el-table-column prop="type" label="类型">
<template scope="scope">
<dict-tag :options="dict.type.TEACHER_CONGRESS_MEETING_TYPE" :value="scope.row.type"></dict-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="250">
<template slot-scope="scope">
<el-button size="mini" type="primary" @click="openView(scope.row.id)">查看</el-button>
<el-button size="mini" type="primary" @click="openEdit(scope.row.id)">编辑</el-button>
<el-button size="mini" type="danger" @click="doDelete(scope.row.id)">删除</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<el-dialog :title="formData.id ? '编辑':'新增'" :visible.sync="dialogFormVisible" width="60%"
:close-on-click-modal="false">
<el-form :model="formData" ref="formRef" size="small" label-width="140px" :rules="formRules">
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="发布人">
<el-input :value="$store.state.user.username" disabled></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="工号">
<el-input :value="$store.state.user.loginname" disabled></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item prop="sessionId" label="教代会">
<el-select v-model="formData.sessionId" style="width: 100%;" placeholder="请选择教代会">
<el-option v-for="item in sessionOptions" :label="item.fullName" :value="item.id"
:key="item.id"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item prop="meetingType" label="会议活动所属类型">
<el-select v-model="formData.meetingType" style="width: 100%;" placeholder="请选择会议活动所属类型">
<el-option label="代表团会议活动" value="delegation"
v-if="$auth.hasRole('SYSADMIN')
|| $auth.hasRole('SCHOOL_UNION_ADMIN')
|| $auth.hasRole('TEACHER_CONGRESS_DELEGATION_HEAD')"></el-option>
<el-option label="分工会会议活动" value="union"
v-if="$auth.hasRole('SYSADMIN')
|| $auth.hasRole('SCHOOL_UNION_ADMIN')
|| $auth.hasRole('BRANCH_UNION_CHAIRMAN')"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="会议活动名称" prop="name">
<el-input v-model="formData.name" maxlength="100" placeholder="请输入名称"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="会议活动类型" prop="type">
<dict-select v-model="formData.type" code="TEACHER_CONGRESS_MEETING_TYPE"
placeholder="请选择类型"></dict-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="会议活动时间" prop="times">
<el-date-picker
style="width: 100%"
v-model="formData.times"
type="datetimerange"
value-format="yyyy-MM-dd HH:mm:ss"
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="['12:00:00', '08:00:00']"
></el-date-picker>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="经费预算" prop="budget">
<el-input placeholder="请输入经费预算" v-model="formData.budget" maxlength="2000"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-form-item label="场地" prop="site">
<el-input placeholder="请输入场地地点" v-model="formData.site" maxlength="50"></el-input>
</el-form-item>
<el-form-item label="内容" prop="content">
<el-input v-model="formData.content" type="textarea" rows="5" maxlength="2000"
show-word-limit></el-input>
</el-form-item>
<el-form-item label="纪要" prop="summary">
<el-input v-model="formData.summary" type="textarea" rows="5" maxlength="1000"
show-word-limit></el-input>
</el-form-item>
<el-form-item label="附件" prop="files">
<file-upload :value.sync="formData.files" :upload_number="5" upload_result_category="array"
complete_result></file-upload>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">取 消</el-button>
<el-button type="primary" @click="doSubmit">确 定</el-button>
</div>
</el-dialog>
<el-dialog title="查看" :visible.sync="viewDialogVisible" width="60%" :close-on-click-modal="false">
<el-descriptions :column="3" border>
<el-descriptions-item label="会议活动名称" :span="3">{{viewData.name}}</el-descriptions-item>
<el-descriptions-item label="发布人">{{viewData.publisher}}</el-descriptions-item>
<el-descriptions-item label="教代会" :span="2">{{viewData.meetingName}}</el-descriptions-item>
<el-descriptions-item label="会议活动所属类型">{{viewData.meetingType}}</el-descriptions-item>
<el-descriptions-item label="会议活动类型" :span="2">{{viewData.type}}</el-descriptions-item>
<el-descriptions-item label="开始时间" :span="3">{{viewData.startDateTime}}</el-descriptions-item>
<el-descriptions-item label="结束时间" :span="3">{{viewData.endDateTime}}</el-descriptions-item>
<el-descriptions-item label="经费预算">{{viewData.budget}}</el-descriptions-item>
<el-descriptions-item label="场地" :span="2">{{viewData.site}}</el-descriptions-item>
<el-descriptions-item label="内容" :span="3">{{viewData.content}}</el-descriptions-item>
<el-descriptions-item label="纪要" :span="3">{{viewData.summary}}</el-descriptions-item>
<el-descriptions-item label="附件" :span="3">
<file-preview :files="viewData.files" complete_result></file-preview>
</el-descriptions-item>
</el-descriptions>
</el-dialog>
</div>
<script src="/assets/platform/module/democratic/teachercongress/teacherCongressCommonApi.js"></script>
<script nonce="${cspNonce!}">
new Vue({
el: "#app",
store,
mixins: [initTableMixins],
dicts: ["TEACHER_CONGRESS_MEETING_TYPE"],
data() {
return {
deleteUrl: loc() + "/delete",
dialogFormVisible: false,
formRules: {
sessionId: [{required: true, message: "必填", trigger: ["change", "blur"]}],
name: [{required: true, message: "必填", trigger: ["change", "blur"]}],
meetingType: [{required: true, message: "必填", trigger: ["change", "blur"]}],
code: [{required: true, message: "必填", trigger: ["change", "blur"]}],
type: [{required: true, message: "必填", trigger: ["change", "blur"]}],
},
sessionOptions: [],
typeOptions: [],
pageForm: {
sessionId: null,
type: null,
searchKeyword: null
}
}
},
methods: {
doDelete(id) {
this.$confirm("您确定要删除吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
$.post(loc() + "/delete", { id }).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.doSearch()
}
})
})
},
openAdd() {
this.formData = {
userId: this.$store.state.user.id,
times: []
}
this.dialogFormVisible = true
this.$nextTick(() => {
if (this.$refs.formRef) {
this.$refs.formRef.clearValidate()
}
})
},
openEdit(id) {
this.dialogFormVisible = true
this.$axios.post(loc() + "/findOne", {id}).then((res) => {
if (res.code === 0) {
res.data.times = [res.data.startDateTime, res.data.endDateTime]
if (res.data.files) {
try {
res.data.files = JSON.parse(res.data.files)
} catch (e) {
res.data.files = []
}
}
this.formData = res.data
}
})
},
doSubmit() {
this.$refs.formRef.validate((valid) => {
if (valid) {
const formData = this.formData
formData.startDateTime = this.formData.times[0]
formData.endDateTime = this.formData.times[1]
this.$axios.post(loc() + (this.formData.id ? "/update" : "/insert"), {data: JSON.stringify(formData)}).then((res) => {
if (res.code === 0) {
this.dialogFormVisible = false
this.$message.success(res.msg)
this.doSearch()
}
})
}
})
},
openView(id) {
this.viewDialogVisible = true
this.$axios.post(loc() + "/findOne", {id}).then((res) => {
if (res.code === 0) {
if (res.data.meetingType === 'delegation') {
res.data.meetingType = '代表团会议活动';
} else if (res.data.meetingType === 'union') {
res.data.meetingType = '分工会会议活动';
}
this.viewData = res.data
}
})
},
listSession() {
this.$axios.post("/platform/teacherCongress/common/listSession").then((res) => {
if (res.code === 0) {
this.sessionOptions = res.data
if (this.sessionOptions && this.sessionOptions.length > 0) {
this.pageForm.sessionId = this.sessionOptions[0].id
this.pageData()
}
}
})
}
},
created() {
this.listSession()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,193 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app" v-cloak>
<el-card shadow="never">
<search @search="doSearch">
<search-item label="名称">
<el-input clearable placeholder="请输入名称" v-model="pageForm.searchKeyword"></el-input>
</search-item>
<search-item label="教代会">
<el-select v-model="pageForm.sessionId" clearable>
<el-option :key="item.id" :label="item.fullName" :value="item.id" v-for="item in sessionOptions"></el-option>
</el-select>
</search-item>
</search>
</el-card>
<el-card shadow="never">
<table-tool>
<el-button @click="openAdd" icon="el-icon-plus" size="small" type="primary">新增</el-button>
</table-tool>
<el-table :data="tableData" @sort-change="pageOrder" header-align="center" style="width: 100%">
<el-table-column :index="indexMethod" label="序号" width="50" type="index"></el-table-column>
<el-table-column label="名称" prop="name"></el-table-column>
<el-table-column label="教代会" prop="j">
<template scope="scope">
<dict-tag :options="sessionOptions" :value="scope.row.sessionId" option_value="id" option_label="fullName"></dict-tag>
</template>
</el-table-column>
<el-table-column label="类型" prop="type"></el-table-column>
<el-table-column label="上传人" prop="userName"></el-table-column>
<el-table-column label="上传时间" prop="createdAt">
<template scope="{row}">{{$moment(row.createdAt).format('YYYY-MM-DD HH:mm:ss')}}</template>
</el-table-column>
<el-table-column label="是否通过" prop="pass">
<template slot-scope="{row}">
<i class="fa fa-circle" :class="row.pass ? 'text-success' : 'text-danger'" style="margin-left: 5px"></i>
</template>
</el-table-column>
<el-table-column label="操作" width="300">
<template slot-scope="scope">
<el-button @click="openView(scope.row.id)" size="mini" type="">查看</el-button>
<el-button @click="openEdit(scope.row.id)" size="mini" type="primary">编辑</el-button>
<el-button @click="doDelete(scope.row.id)" size="mini" type="danger">删除</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<el-dialog :close-on-click-modal="false" :title="formData.id ? '编辑':'新增'" :visible.sync="dialogFormVisible" width="60%">
<el-form :model="formData" :rules="formRules" label-width="120px" ref="formRef" size="small">
<el-form-item label="教代会" prop="sessionId">
<el-select v-model="formData.sessionId">
<el-option :key="item.id" :label="item.fullName" :value="item.id" v-for="item in sessionOptions"></el-option>
</el-select>
</el-form-item>
<el-form-item label="文件名称" prop="name">
<el-input maxlength="1000" placeholder="请输入文件名称" v-model="formData.name"></el-input>
</el-form-item>
<el-form-item label="文件类型" prop="type">
<dict-select code="TEACHER_CONGRESS_PREPARE_FILE_TYPE" v-model="formData.type"></dict-select>
</el-form-item>
<el-form-item label="是否通过" prop="pass">
<el-radio-group size="small" v-model="formData.pass">
<el-radio :label="true" border></el-radio>
<el-radio :label="false" border></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="文件" prop="files">
<file-upload :upload_number="5" :upload_size="1024 * 1024 * 5" :value.sync="formData.files" complete_result upload_result_category="array"></file-upload>
</el-form-item>
</el-form>
<div class="dialog-footer" slot="footer">
<el-button @click="dialogFormVisible = false">取 消</el-button>
<el-button @click="doSubmit" type="primary">确 定</el-button>
</div>
</el-dialog>
<el-dialog :visible.sync="viewDialogVisible" title="查看" width="60%">
<el-descriptions :column="3" border>
<el-descriptions-item label="名称" :span="3">{{viewData.name}}</el-descriptions-item>
<el-descriptions-item label="教代会">
<dict-tag :options="sessionOptions" :value="viewData.sessionId" option_value="id" option_label="fullName"></dict-tag>
</el-descriptions-item>
<el-descriptions-item label="类型">{{viewData.type}}</el-descriptions-item>
<el-descriptions-item label="上传人">{{viewData.userName}}</el-descriptions-item>
<el-descriptions-item label="上传时间">{{$moment(viewData.createdAt).format('YYYY-MM-DD HH:mm:ss')}}</el-descriptions-item>
<el-descriptions-item label="是否通过" :span="2">
<el-tag :type="viewData.pass?'success':'danger'" size="small">{{viewData.pass ? '是' :'否'}}</el-tag>
</el-descriptions-item>
<el-descriptions-item label="文件" :span="3">
<file-preview :files="viewData.files" complete_result></file-preview>
</el-descriptions-item>
</el-descriptions>
</el-dialog>
</div>
<script nonce="${cspNonce!}">
new Vue({
el: "#app",
mixins: [initTableMixins],
data() {
return {
dialogFormVisible: false,
formRules: {
sessionId: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
name: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
type: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
enable: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
pass: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
files: [{ required: true, message: "必填", trigger: ["change", "blur"] }]
},
sessionOptions: []
}
},
methods: {
openAdd() {
this.dialogFormVisible = true
this.$nextTick(() => {
this.formData = {}
})
},
openEdit(id) {
this.dialogFormVisible = true
this.$axios.post(loc() + "/findOne", { id }).then((res) => {
if (res.code === 0) {
this.formData = res.data
}
})
},
doSubmit() {
this.$refs.formRef.validate((valid) => {
if (valid) {
this.$axios.post(loc() + (this.formData.id ? "/update" : "/insert"), { file: JSON.stringify(this.formData) }).then((res) => {
if (res.code === 0) {
this.dialogFormVisible = false
this.$message.success(res.msg)
this.doSearch()
}
})
}
})
},
openView(id) {
this.viewDialogVisible = true
this.$axios.post(loc() + "/findOne", { id }).then((res) => {
if (res.code === 0) {
this.viewData = res.data
}
})
},
doDelete(id) {
this.$confirm("您确定要删除吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "info"
}).then(() => {
this.$axios.post(loc() + "/delete", { id }).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.doSearch()
}
})
})
},
listSession() {
this.$axios.post("/platform/teacherCongress/common/listSession").then((res) => {
if (res.code === 0) {
this.sessionOptions = res.data
}
})
}
},
created() {
this.pageData()
this.listSession()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,118 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app" v-cloak>
<el-card shadow="never">
<search @search="doSearch">
<search-item label="教代会">
<el-select
v-model="pageForm.sessionId"
filterable
placeholder="请选择教代会"
style="width:100%;"
@change="doSearch"
>
<el-option
v-for="item in sessionOptions"
:key="item.id"
:label="item.fullName"
:value="item.id"
></el-option>
</el-select>
</search-item>
<search-item label="所属工会">
<el-select clearable filterable placeholder="请选择所属工会" style="width: 100%" v-model="pageForm.unionId">
<el-option :key="item.id" :label="item.name" :value="item.id"
v-for="item in unionOptions"></el-option>
</el-select>
</search-item>
</search>
</el-card>
<el-card shadow="never">
<table-tool label="名额分配列表">
<el-button
size="small"
type="primary"
@click="openManual"
>分配名额
</el-button>
</table-tool>
<el-table :data="tableData" @sort-change="pageOrder" style="width: 100%">
<el-table-column type="index" width="50" :index="indexMethod" label="序号"></el-table-column>
<el-table-column prop="unionName" label="工会名称"></el-table-column>
<template v-if="$auth.hasRoleOr('SYSADMIN, SCHOOL_UNION_ADMIN')">
<el-table-column prop="memberCount" label="会员人数"></el-table-column>
</template>
<!-- <el-table-column prop="dbCount" label="代表人数"></el-table-column>-->
<el-table-column prop="allocationNum" label="名额分配人数"></el-table-column>
<el-table-column prop="seniorTeaNum" label="高级职称代表数"></el-table-column>
<el-table-column prop="intermediateBelowNum" label="中级职称及以下代表数"></el-table-column>
<el-table-column prop="cadreNum" label="干部代表数"></el-table-column>
<el-table-column prop="workerNum" label="工人代表数"></el-table-column>
<!-- <el-table-column prop="ordinaryTeaNum" label="专任教师代表数"></el-table-column>-->
<el-table-column prop="femaleNum" label="女代表数"></el-table-column>
<!-- <el-table-column prop="less45Num" label="45岁以下代表数"></el-table-column>-->
<el-table-column prop="employNum" label="聘用制代表数"></el-table-column>
</el-table>
</el-card>
<manual-allocation-dialog ref="manualAllocationDialog" @refresh="doSearch"></manual-allocation-dialog>
</div>
<script nonce="${cspNonce!}">
<!--#include("manualAllocationDialog.js"){}#-->
const vue = new Vue({
el: "#app",
mixins: [initTableMixins],
data() {
return {
sessionOptions: [],
unionOptions: [],
}
},
components: {
"manual-allocation-dialog": MANUAL_ALLOCATION_DIALOG
},
methods: {
openManual() {
this.$refs.manualAllocationDialog.onOpen(this.pageForm.sessionId)
},
pageData() {
this.tableLoading = true
this.$axios.post("/platform/teacherCongress/prepare/quotaAllocation/pageData", this.pageForm).then(resp => {
this.tableLoading = false
if (resp.code === 0) {
this.tableData = resp.data
} else {
this.$message.error(resp.msg)
}
})
},
getAllJdh() {
this.$axios.post("/platform/teacherCongress/common/listSession", {}).then(resp => {
if (resp.code === 0) {
this.sessionOptions = resp.data
if (this.sessionOptions && this.sessionOptions.length > 0) {
this.$set(this.pageForm, 'sessionId', this.sessionOptions[0].id)
this.pageData()
}
}
})
},
},
async created() {
this.unionOptions = await this.$businessTool.listUnion()
await this.getAllJdh()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,408 @@
const MANUAL_ALLOCATION_DIALOG = {
template: /*language=HTML*/ `
<el-dialog :visible.sync="manualAllocationDialog" title="手动分配名额" width="80%" :close-on-click-modal="false"
top="50px">
<table-tool label="分段设置">
<el-button @click="unionLimitQuickSetting" size="small"
type="primary">
应用分段设置
</el-button>
</table-tool>
<el-row :gutter="20" :key="index"
class="mb5" v-for="(item,index) in unionUserNumCalc">
<el-col :span="7">
<el-input-number :min="1" :precision="0"
:step="1" placeholder="请输入最小人数"
style="width: 100%"
v-model="item.startNum"></el-input-number>
</el-col>
<el-col :span="7">
<el-input-number :min="1" :precision="0"
:step="1" placeholder="请输入最大人数"
style="width: 100%"
v-model="item.endNum"></el-input-number>
</el-col>
<el-col :span="6">
<el-input-number :min="1" :precision="0"
:step="1" placeholder="请输入限制百分比"
style="width: 100%"
v-model="item.resultNum"></el-input-number>
</el-col>
<el-col :span="4" class="text-right">
<el-button @click="unionUserNumCalc.push({})"
icon="el-icon-plus"></el-button>
<el-button :disabled="unionUserNumCalc.length===1"
@click="unionUserNumCalc.splice(index,1)"
icon="el-icon-minus"></el-button>
</el-col>
</el-row>
<el-row class="mt10">
<div class="text-danger"
v-for="(item,index) in unionUserNumCalcTips">
<span class="mr10">({{index+1}}).</span> {{item}}
</div>
</el-row>
<table-tool label="比例设置">
<el-select v-model="settingsType"
placeholder="需要设置的列表"
style="width: 30%;">
<el-option :label="item.label"
:value="item.value"
:key="item.value"
v-for="item in settingsTypeOptions"></el-option>
</el-select>
一键比例:
<el-input-number
style="width: 150px"
v-model="unionUserNumOneKeyRatio"
:precision="0"
:step="1"
:min="0"
placeholder="请输入一键比例"
size="small"
:max="100"
></el-input-number>
<el-button
size="small"
type="primary"
style="margin-left: 6px"
@click="applyScaleSettings"
>应用比例设置
</el-button>
</table-tool>
<el-table :data="unionLimit" max-height="500" :summary-method="getSummaries"
width="100%" show-summary>
<el-table-column prop="unionName" label="分工会"></el-table-column>
<template v-if="$auth.hasRoleOr('SYSADMIN, SCHOOL_UNION_ADMIN')">
<el-table-column prop="memberCount" label="会员人数"></el-table-column>
</template>
<el-table-column align="center" prop="ratio" label="比例(%)">
<template v-slot="{$index, row}">
<el-input-number
style="width: 100%"
v-model="row.ratio"
:precision="0"
:step="1"
:min="0"
:max="100"
@change="(val) => ratioChange(val, $index)"
></el-input-number>
</template>
</el-table-column>
<el-table-column prop="allocationNum" label="分配人数">
<template v-slot="{row}">
<el-input-number
style="width: 100%"
v-model="row.allocationNum"
:precision="0"
:step="1"
:min="0"
></el-input-number>
</template>
</el-table-column>
<el-table-column prop="seniorTeaNum" label="高级职称代表数">
<template v-slot="{row}">
<el-input-number
style="width: 100%"
v-model="row.seniorTeaNum"
:precision="0"
:step="1"
:min="0"
:max="row.allocationNum"
></el-input-number>
</template>
</el-table-column>
<el-table-column prop="intermediateBelowNum" label="中级职称及以下代表数">
<template v-slot="{row}">
<el-input-number
style="width: 100%"
v-model="row.intermediateBelowNum"
:precision="0"
:step="1"
:min="0"
:max="row.allocationNum"
></el-input-number>
</template>
</el-table-column>
<el-table-column prop="cadreNum" label="干部代表数">
<template v-slot="{row}">
<el-input-number
style="width: 100%"
v-model="row.cadreNum"
:precision="0"
:step="1"
:min="0"
:max="row.allocationNum"
></el-input-number>
</template>
</el-table-column>
<el-table-column prop="workerNum" label="工人代表数">
<template v-slot="{row}">
<el-input-number
style="width: 100%"
v-model="row.workerNum"
:precision="0"
:step="1"
:min="0"
:max="row.allocationNum"
></el-input-number>
</template>
</el-table-column>
<!-- <el-table-column prop="ordinaryTeaNum" label="专任教师代表数">
<template v-slot="{row}">
<el-input-number
style="width: 100%"
v-model="row.ordinaryTeaNum"
:precision="0"
:step="1"
:min="0"
:max="row.allocationNum"
></el-input-number>
</template>
</el-table-column>-->
<el-table-column prop="femaleNum" label="女代表数">
<template v-slot="{row}">
<el-input-number
style="width: 100%"
v-model="row.femaleNum"
:precision="0"
:step="1"
:min="0"
:max="row.allocationNum"
></el-input-number>
</template>
</el-table-column>
<!-- <el-table-column prop="less45Num" label="45岁以下代表数">-->
<!-- <template v-slot="{row}">-->
<!-- <el-input-number-->
<!-- style="width: 100%"-->
<!-- v-model="row.less45Num"-->
<!-- :precision="0"-->
<!-- :step="1"-->
<!-- :min="0"-->
<!-- :max="row.allocationNum"-->
<!-- ></el-input-number>-->
<!-- </template>-->
<!-- </el-table-column>-->
<el-table-column prop="employNum" label="聘用制代表数">
<template v-slot="{row}">
<el-input-number
style="width: 100%"
v-model="row.employNum"
:precision="0"
:step="1"
:min="0"
:max="row.allocationNum"
></el-input-number>
</template>
</el-table-column>
</el-table>
<el-row class="mt20" justify="end" type="flex">
<el-button type="danger" @click="clearUnionLimit">清空当前已分配</el-button>
</el-row>
<span slot="footer" class="dialog-footer">
<el-button @click="manualAllocationDialog = false">取 消</el-button>
<el-button type="primary" @click="doManualAllocationSub">确 定</el-button>
</span>
</el-dialog>
`,
data() {
return {
unionUserNumOneKeyRatio: null,
settingsType: "allocationNum",
sessionId: "",
unionLimit: [],
manualAllocationDialog: false,
unionUserNumCalc: [{}],
unionUserNumCalcTips: [],
settingsTypeOptions: [
{label: "分配人数", value: "allocationNum"},
{label: "高级职称代表数", value: "seniorTeaNum"},
{label: "中级职称及以下代表数", value: "intermediateBelowNum"},
{label: "干部代表数", value: "cadreNum"},
{label: "工人代表数", value: "workerNum"},
{label: "女代表数", value: "femaleNum"},
// {label: "45岁以下代表数", value: "less45Num"},
{label: "聘用制代表数", value: "employNum"},
]
}
},
// watch: {
// unionLimit: {
// handler(list) {
// list.forEach(row => {
// const keys = [
// 'seniorTeaNum',
// 'intermediateBelowNum',
// 'cadreNum',
// 'workerNum',
// 'femaleNum',
// 'employNum'
// ]
// const sum = keys.reduce((s, k) => s + (row[k] || 0), 0)
// if (sum > row.allocationNum) {
// const excess = sum - row.allocationNum
// row.seniorTeaNum = Math.max(0, row.seniorTeaNum - excess)
// }
// })
// },
// deep: true
// }
// },
methods: {
getSummaries(param) {
const {columns, data} = param;
const sums = [];
columns.forEach((column, index) => {
if (index === 0) {
sums[index] = '占代表总数的';
return;
}
const values = data.map(item => Number(item[column.property]));
if (!values.every(value => isNaN(value))) {
if (index === 2) {
sums[index] = null;
} else if ([1, 3].includes(index)) {
sums[index] = values.reduce((prev, curr) => {
const value = Number(curr);
if (!isNaN(value)) {
return Math.floor((prev + curr) * 100) / 100;
} else {
return prev;
}
}, 0);
sums[index] += ' 人';
} else {
const part = values.reduce((prev, curr) => {
const value = Number(curr);
if (!isNaN(value)) {
return Math.floor((prev + curr) * 100) / 100;
} else {
return prev;
}
}, 0);
const totalValues = data.map(item => Number(item.allocationNum));
const total = totalValues.reduce((prev, curr) => {
const value = Number(curr);
if (!isNaN(value)) {
return Math.floor((prev + curr) * 100) / 100;
} else {
return prev;
}
}, 0);
sums[index] = ((part / total) * 100).toFixed(2) + ' %'
console.log(((part / total) * 100).toFixed(2))
}
} else {
sums[index] = null;
}
});
return sums;
},
unionLimitQuickSetting() {
this.unionUserNumCalc.forEach((v, i) => {
const that = this
const startNum = v.startNum
const endNum = v.endNum
const resultNum = v.resultNum
if (startNum > endNum) {
this.notifyWarning("第" + (i + 1) + "行设置错误")
} else {
this.unionLimit.forEach((x) => {
if (x.memberCount >= startNum && x.memberCount <= endNum) {
x.ratio = resultNum
const num = parseFloat((x.memberCount * resultNum / 100).toFixed(0))
debugger
that.$set(x, "allocationNum", (num ? num : 0))
// v.allocationNum = num ? num : 0
}
})
this.$forceUpdate()
}
})
},
async doManualAllocationSub() {
const hasNull = this.unionLimit.some(v => v.allocationNum === undefined)
if (hasNull) {
this.$message.warning('还有未设置的数据!')
return
}
const confirm = await this.$confirm('您确定要分配吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).catch(err => err)
if (confirm === 'confirm') {
const {
code,
msg
} = await this.$axios.post('/platform/teacherCongress/prepare/quotaAllocation/doQuotaAllocation', {
list: JSON.stringify(this.unionLimit),
sessionId: this.sessionId
})
if (code === 0) {
this.manualAllocationDialog = false
this.$message.success(msg)
this.$emit('refresh')
}
}
},
async clearUnionLimit() {
const confirm = await this.$confirm('确定要清空分工会人数限制吗, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).catch(err => err)
if (confirm === 'confirm') {
// this.unionLimit = []
this.unionUserNumOneKeyRatio = null
// await this.getUnionUsers()
// 除了工会和会员数据,其他设置为0
this.unionLimit.forEach(v => {
v.ratio = 0
this.settingsTypeOptions.forEach( item => {
v[item.value] = 0
})
})
}
},
applyScaleSettings() {
const settingsType = this.settingsTypeOptions.find(v => v.value === this.settingsType)
this.unionLimit.forEach(v => {
if (settingsType.value === "allocationNum") {
v.ratio = this.unionUserNumOneKeyRatio
}
const num = parseFloat((v.memberCount * this.unionUserNumOneKeyRatio / 100).toFixed(0))
v[settingsType.value] = (num === 0 ? 1 : num)
})
},
ratioChange(val, index) {
const v = this.unionLimit[index]
const num = parseFloat((v.memberCount * v.ratio / 100).toFixed(0))
v.allocationNum = (num === 0 ? 1 : num)
this.$forceUpdate()
},
getUnionUsers() {
this.$axios.post('/platform/teacherCongress/prepare/quotaAllocation/getUnionLimit', {sessionId: this.sessionId}).then(resp => {
if (resp.code === 0) {
this.unionLimit = resp.data
}
})
},
async onOpen(sessionId) {
this.sessionId = sessionId
this.unionUserNumCalc = [{}]
this.manualAllocationDialog = true
this.unionUserNumOneKeyRatio = 0
this.settingsType = "allocationNum"
this.getUnionUsers()
}
}
}
@@ -0,0 +1,276 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app" v-cloak>
<el-card shadow="never">
<search @search="doSearch">
<search-item label="年份">
<el-date-picker
:clearable="false"
v-model="pageForm.year"
value-format="yyyy"
formData="yyyy"
type="year"
placeholder="选择年份"
clearable
></el-date-picker>
</search-item>
<search-item label="届数">
<dict-select v-model="pageForm.j" code="TEACHER_CONGRESS_J"></dict-select>
</search-item>
<search-item label="次数">
<dict-select v-model="pageForm.c" code="TEACHER_CONGRESS_C"></dict-select>
</search-item>
</search>
</el-card>
<el-card shadow="never">
<table-tool>
<el-button size="small" type="primary" icon="el-icon-plus" @click="openAdd">新增</el-button>
</table-tool>
<el-table :data="tableData" @sort-change="pageOrder" style="width: 100%">
<el-table-column type="index" width="50" :index="indexMethod" label="序号"></el-table-column>
<el-table-column prop="year" label="年份" sortable></el-table-column>
<el-table-column prop="j" label="届数" sortable></el-table-column>
<el-table-column prop="c" label="次数" sortable></el-table-column>
<el-table-column prop="proposalType" label="提案类型" min-width="180">
<template slot-scope="{row}">
<el-tag v-for="item in parseProposalTypes(row.proposalType)" :key="item" size="small"
style="margin-right: 5px">{{item}}</el-tag>
</template>
</el-table-column>
<el-table-column prop="description" label="描述"></el-table-column>
<el-table-column prop="startDate" label="开启时间"></el-table-column>
<el-table-column prop="enable" label="开启状态">
<template slot-scope="{row}">
<i class="fa fa-circle" :class="row.enable ? 'text-success' : 'text-danger'"
style="margin-left: 5px"></i>
</template>
</el-table-column>
<el-table-column prop="collectStartTime" label="提案征集开始时间"></el-table-column>
<el-table-column prop="collectEndTime" label="提案征集结束时间"></el-table-column>
<el-table-column label="操作" width="200">
<template slot-scope="scope">
<el-button size="mini" type="primary" @click="openEdit(scope.row.id)">编辑</el-button>
<el-button size="mini" type="danger" @click="doDelete(scope.row.id)">删除</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<el-dialog :title="formData.id ? '编辑':'新增'" :visible.sync="dialogFormVisible" width="60%"
:close-on-click-modal="false">
<el-form :model="formData" ref="formRef" size="small" label-width="140px" :rules="formRules">
<el-form-item prop="year" label="年份">
<el-date-picker
style="width: 100%"
:clearable="false"
v-model="formData.year"
value-format="yyyy"
formData="yyyy"
type="year"
placeholder="选择年"
></el-date-picker>
</el-form-item>
<el-form-item prop="j" label="届数">
<dict-select v-model="formData.j" code="TEACHER_CONGRESS_J"></dict-select>
</el-form-item>
<el-form-item prop="c" label="教代会次数">
<dict-select v-model="formData.c" code="TEACHER_CONGRESS_C"></dict-select>
</el-form-item>
<!-- 支持多选历史类型,也允许直接输入并创建新的届次提案类型。 -->
<el-form-item prop="proposalType" label="提案类型">
<el-select v-model="formData.proposalType" multiple clearable filterable allow-create default-first-option
placeholder="请选择或输入提案类型" style="width: 100%">
<el-option v-for="item in proposalTypeOptions" :key="item.proposalType"
:label="item.proposalType" :value="item.proposalType"></el-option>
</el-select>
</el-form-item>
<el-form-item prop="description" label="描述">
<el-input type="textarea" :rows="2" style="width: 100%" placeholder="请输入教代会描述"
v-model="formData.description"></el-input>
</el-form-item>
<el-form-item prop="enable" label="状态">
<el-radio-group v-model="formData.enable" size="small">
<el-radio :label="true" border>开启</el-radio>
<el-radio :label="false" border>关闭</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item prop="isExtend" label="是否延用" v-if="!formData.id">
<el-radio-group v-model="formData.isExtend" size="small">
<el-radio :label="true" border></el-radio>
<el-radio :label="false" border></el-radio>
</el-radio-group>
<div>
延用上一次教代会的组织机构及代表信息,包含【筹备领导小组;资格审查小组;主席团;执行委员会;专门委员会;代表团;教代会代表】。
</div>
</el-form-item>
<el-form-item prop="collectStartTime" label="提案征集开始时间">
<el-date-picker
style="width: 100%"
v-model="formData.collectStartTime"
type="datetime"
value-format="yyyy-MM-dd HH:mm:ss"
placeholder="选择时间"
></el-date-picker>
</el-form-item>
<el-form-item prop="collectEndTime" label="提案征集结束时间">
<el-date-picker
style="width: 100%"
v-model="formData.collectEndTime"
type="datetime"
value-format="yyyy-MM-dd HH:mm:ss"
placeholder="选择时间"
></el-date-picker>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">取 消</el-button>
<el-button type="primary" @click="doSubmit">确 定</el-button>
</div>
</el-dialog>
</div>
<script nonce="${cspNonce!}">
new Vue({
el: "#app",
mixins: [initTableMixins],
data() {
// 多选项至少保留一项,单个自定义类型最多 50 个字符,序列化后总长度不超过数据库字段限制。
const validateProposalTypes = (rule, value, callback) => {
const proposalTypes = value || []
if (!proposalTypes.length) {
callback(new Error("请至少选择或输入一个提案类型"))
return
}
if (proposalTypes.some((item) => item && item.trim().length > 50)) {
callback(new Error("单个提案类型最多50个字符"))
return
}
if (JSON.stringify(proposalTypes).length > 1000) {
callback(new Error("提案类型数据不能超过1000个字符"))
return
}
callback()
}
return {
dialogFormVisible: false,
formRules: {
year: [{required: true, message: "必填", trigger: ["change", "blur"]}],
j: [{required: true, message: "必填", trigger: ["change", "blur"]}],
c: [{required: true, message: "必填", trigger: ["change", "blur"]}],
proposalType: [
{validator: validateProposalTypes, trigger: ["change", "blur"]}
],
enable: [{required: true, message: "必填", trigger: ["change", "blur"]}],
description: [{required: true, message: "必填", trigger: ["change", "blur"]}],
isExtend: [{required: true, message: "必填", trigger: ["change", "blur"]}],
collectStartTime: [{required: true, message: "必填", trigger: ["change", "blur"]}],
collectEndTime: [{required: true, message: "必填", trigger: ["change", "blur"]}]
},
proposalTypeOptions: []
}
},
methods: {
openAdd() {
this.dialogFormVisible = true
this.$nextTick(() => {
this.formData = {}
this.$set(this.formData, "proposalType", [])
})
},
openEdit(id) {
this.dialogFormVisible = true
this.$axios.post(loc() + "/findOne", {id}).then((res) => {
if (res.code === 0) {
res.data.year = res.data.year.toString()
this.$set(res.data, "proposalType", this.parseProposalTypes(res.data.proposalType))
this.formData = res.data
}
})
},
doSubmit() {
this.$refs.formRef.validate((valid) => {
if (valid) {
const loading = createLoading()
const submitData = {
...this.formData,
proposalType: JSON.stringify(this.formData.proposalType || [])
}
this.$axios.post(loc() + (this.formData.id ? "/update" : "/insert"), submitData).then((res) => {
if (res.code === 0) {
this.dialogFormVisible = false
this.$message.success(res.msg)
this.doSearch()
this.listProposalTypes()
}
}).finally(() => {
loading.close()
})
}
})
},
// 数据库存储 JSON 数组;同时兼容字段调整前可能存在的单值内容。
parseProposalTypes(proposalType) {
if (Array.isArray(proposalType)) {
return proposalType
}
if (!proposalType) {
return []
}
try {
const values = JSON.parse(proposalType)
return Array.isArray(values) ? values : [proposalType]
} catch (e) {
return [proposalType]
}
},
doDelete(id) {
this.$confirm("您确定要删除吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post(loc() + "/delete", {id}).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.doSearch()
}
})
})
},
// 查询历史届次已保存的提案类型,作为可输入下拉框的候选项。
listProposalTypes() {
this.$axios.post(loc() + "/listProposalTypes").then((res) => {
if (res.code === 0) {
this.proposalTypeOptions = res.data || []
}
})
}
},
created() {
this.pageData()
this.listProposalTypes()
}
})
</script>
<!--#
}
#-->