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,316 @@
const PROPOSAL_INFO = {
name: "ProposalInfo",
/*language=HTML*/
template: `
<div class="proposal-info">
<div class="process-title">
提案基础信息
<el-link type="primary" @click="openChart">点击查看流程图</el-link>
</div>
<h3 style="text-align: center;font-weight: 600" class="pt10 pb10">
{{ viewData.name }}
</h3>
<el-descriptions :column="3" border>
<el-descriptions-item label="提案编号">{{ viewData.code }}</el-descriptions-item>
<el-descriptions-item label="立案编号">{{ viewData.caseFilingCode || '暂无' }}</el-descriptions-item>
<el-descriptions-item label="提案人">{{viewData.createUserName }}</el-descriptions-item>
<el-descriptions-item label="提案时间">{{ viewData.createTime }}</el-descriptions-item>
<el-descriptions-item label="教代会届次"> {{ viewData.sessionName || '暂无' }}</el-descriptions-item>
<el-descriptions-item label="提案人单位">{{ viewData.unitName }}</el-descriptions-item>
<el-descriptions-item :label="viewData.mannerCode!=='W03'?'代表团名称':'委员会名称'">
{{ viewData.mannerCode !== 'W03' ? viewData.delegationName : viewData.committeeName }}
</el-descriptions-item>
<el-descriptions-item label="提案类别">
{{viewData.typeName}}
</el-descriptions-item><!--
<el-descriptions-item label="建议承办单位">
{{viewData.suggestUnits}}
</el-descriptions-item>-->
<el-descriptions-item label="立案结果" :span="2">
<dict-tag :options="dict.type.PROPOSAL_CASE_FILING_RESULT"
:value="viewData.caseFilingResult"></dict-tag>
</el-descriptions-item>
<!--<el-descriptions-item label="调研情况" :span="3">
<div class="text-left">{{viewData.researchFindings}}</div>
</el-descriptions-item>-->
<el-descriptions-item label="提案案由" :span="3">
<div class="text-left" v-html="viewData.brief"></div>
</el-descriptions-item>
<el-descriptions-item label="建议措施" :span="3">
<div class="text-left" v-html="viewData.measures"></div>
</el-descriptions-item>
<el-descriptions-item label="附件" :span="3">
<file-preview :files="viewData.files" complete_result></file-preview>
</el-descriptions-item>
<!-- <el-descriptions-item label="签字" :span="3">-->
<!-- <el-image :src="viewData.signature" class="signature-image">-->
<!-- <div slot="error" class="image-slot">-->
<!-- <i class="el-icon-picture-outline"></i>-->
<!-- </div>-->
<!-- </el-image>-->
<!-- </el-descriptions-item>-->
</el-descriptions>
<!--并案信息-->
<template v-if="viewData.merges">
<div class="process-title">
并案信息
</div>
<el-table v-loading="tableLoading" :data="viewData.merges" size="medium">
<el-table-column label="序号" type="index" width="100px"></el-table-column>
<el-table-column label="提案编号" prop="code" sortable></el-table-column>
<el-table-column label="提案名称" prop="name" show-overflow-tooltip></el-table-column>
<el-table-column label="提案人" prop="createUserName"></el-table-column>
<el-table-column label="提案类别" prop="typeName"></el-table-column>
<el-table-column label="代表团" prop="delegationName"></el-table-column>
<el-table-column label="操作" width="100px">
<template slot-scope="{row}">
<el-link type="primary" size="mini" @click="openView(row)">查看</el-link>
</template>
</el-table-column>
</el-table>
</template>
<!--委员会成员意见-->
<template v-if="viewData.commissionerOpinions && viewData.commissionerOpinions.length">
<div class="process-title">
委员会成员意见
</div>
<el-table v-loading="tableLoading" :data="viewData.commissionerOpinions" size="medium">
<el-table-column label="序号" type="index" width="100px"></el-table-column>
<el-table-column label="委员" prop="commissionerName">
<template slot-scope="{row}">
{{row.commissionerName}}({{row.commissionerLoginName}})
</template>
</el-table-column>
<el-table-column label="立案结果" prop="caseFilingType">
<template slot-scope="{row}">
<div style="display: flex;justify-content: center">
<dict-tag :options="dict.type.PROPOSAL_CASE_FILING_RESULT"
:value="row.caseFilingResult"></dict-tag>
<!-- 普通提案/重点提案暂不展示,历史数据仍保留。 -->
<template v-if="false">
(
<dict-tag :options="dict.type.PROPOSAL_CASE_FILING_TYPE"
:value="row.caseFilingType"></dict-tag>
)
</template>
</div>
</template>
</el-table-column>
<el-table-column label="意见" prop="opinionText"></el-table-column>
<el-table-column label="时间" prop="opinionTime"></el-table-column>
</el-table>
</template>
<el-dialog title="提案详情" :visible.sync="viewDialogVisible" width="1200px" append-to-body top="5vh">
<div style="max-height: 80vh;overflow-y: auto">
<proposal-info ref="infoDialogRef"></proposal-info>
</div>
</el-dialog>
<!--审核信息支持按需同时展开多条记录,初次加载和切换提案时仍保持全部折叠。-->
<template v-if="doneTasks.length">
<div class="process-title">审核信息</div>
<el-collapse v-model="activeTaskIds">
<el-collapse-item v-for="task in doneTasks" :key="task.id" :name="task.id">
<template slot="title">
<!--折叠标题使用独立的单行布局,避免复用 process-title 后产生外边距和高度冲突。-->
<div style="display: flex;align-items: center;justify-content: space-between;width: 100%;min-width: 0;padding-left: 10px">
<span style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;font-size: 15px;font-weight: 600">
{{ task.displayName }}
</span>
<span style="flex-shrink: 0;margin-right: 8px;color: var(--color-primary);font-weight: 400">
{{ activeTaskIds.includes(task.id) ? '收起' : '展开' }}
</span>
</div>
</template>
<el-descriptions border class="flow-task-form" :column="3" :key="task.id"
v-if="task.ext.isFirstTaskNode">
<el-descriptions-item label="申请用户">{{ task.ext.initiatorName
}}({{task.ext.initiatorAccount}})
</el-descriptions-item>
<el-descriptions-item label="申请时间">{{ task.finishTime }}</el-descriptions-item>
<el-descriptions-item label="办理结果">
<dict-tag :options="dict.type.PROCESS_TASK_SUBMIT_TYPE"
:value="task.ext.submitType"></dict-tag>
</el-descriptions-item>
</el-descriptions>
<!--邀请附议人-->
<el-descriptions border class="flow-task-form" :column="3" :key="task.id"
v-else-if="task.taskName === 'invite'">
<el-descriptions-item label="办理用户">{{ task.taskFormData.userName
}}({{task.taskFormData.loginName}})
</el-descriptions-item>
<el-descriptions-item label="办理时间" :span="2">{{ task.finishTime }}</el-descriptions-item>
<el-descriptions-item label="附议人" :span="3" v-if="task.taskName === 'invite'">
<el-table v-loading="tableLoading" :data="task?.taskFormData?.seconder">
<el-table-column label="姓名" prop="userName"></el-table-column>
<el-table-column label="工号" prop="loginName"></el-table-column>
<el-table-column label="性别" prop="sex"></el-table-column>
<el-table-column label="联系方式" prop="mobile"></el-table-column>
<el-table-column label="单位" prop="unitName"></el-table-column>
<el-table-column label="分工会" prop="unionName"></el-table-column>
<el-table-column label="代表团" prop="delegationName"></el-table-column>
</el-table>
</el-descriptions-item>
</el-descriptions>
<!--提案委员会立案-->
<el-descriptions border class="flow-task-form" :column="3" :key="task.id"
v-else-if="task.taskName === 'committee'||task.taskName === 'committeeFilingUnit'">
<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="立案结果">
<div style="display: flex;justify-content: center">
<dict-tag :options="dict.type.PROPOSAL_CASE_FILING_RESULT"
:value="task.ext.tf_caseFilingResult"></dict-tag>
<!-- 普通提案/重点提案暂不展示,历史流程变量仍保留。 -->
<template v-if="false">
(
<dict-tag :options="dict.type.PROPOSAL_CASE_FILING_TYPE"
:value="task.ext.tf_caseFilingType"></dict-tag>
)
</template>
</div>
</el-descriptions-item>
<template v-if="['CONFIRM_FILING','SUGGESTION'].includes(task.ext.tf_caseFilingResult)">
<el-descriptions-item v-if="task.ext.tf_caseFilingResult === 'SUGGESTION'" label="承办单位" :span="3">{{task?.ext?.tf_masterUnitNameStr || task?.ext?.tf_slaveUnitNameStr}}
</el-descriptions-item>
<template v-else>
<el-descriptions-item label="主办单位" :span="3">{{task?.ext?.tf_masterUnitNameStr}}
</el-descriptions-item>
<el-descriptions-item label="协办单位" :span="3">{{task?.ext?.tf_slaveUnitNameStr}}
</el-descriptions-item>
</template>
</template>
<el-descriptions-item label="办理意见" :span="3">
<div v-html="task.taskFormData.tf_opinion"></div>
</el-descriptions-item>
</el-descriptions>
<el-descriptions border class="flow-task-form" :column="3" :key="task.id" v-else>
<el-descriptions-item label="承办单位"
v-if="['opinion_unit_reply','unit_reply','two_unit_reply','master_reply','slave_reply'].includes(task.taskName)" :span="3">
{{task.ext.underTakeName}}
</el-descriptions-item>
<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="办理评价" v-if="['feedback'].includes(task.taskName)" :span="3">
<dict-tag :options="dict.type.PROPOSAL_FEEDBACK"
:value="task.ext.tf_feedback"></dict-tag>
</el-descriptions-item>
<el-descriptions-item label="办理结果" v-else>
<dict-tag :options="dict.type.PROCESS_TASK_SUBMIT_TYPE"
:value="task.ext.submitType"></dict-tag>
</el-descriptions-item>
<el-descriptions-item label="办理意见" :span="3" v-if="!task.ext.isFirstTaskNode">
<div v-html="task.taskFormData.tf_opinion"></div>
</el-descriptions-item>
</el-descriptions>
</el-collapse-item>
</el-collapse>
</template>
<slot></slot>
<snaker-chart ref="snakerChartRef"></snaker-chart>
</div>
`,
dicts: ["PROPOSAL_TYPE", "PROPOSAL_CASE_FILING_RESULT", "PROPOSAL_CASE_FILING_TYPE", "PROCESS_TASK_SUBMIT_TYPE", "PROPOSAL_FEEDBACK"],
props: {
hide_slave: false
},
data() {
return {
tableLoading: false,
viewData: {},
doneTasks: [],
activeTaskIds: [],
row: null,
viewDialogVisible: false
}
},
methods: {
/**
* 加载提案详情和已办审核记录,两个请求都结束后执行完成回调。
*
* @param row 当前提案列表行,必须包含提案 id 及流程实例信息
* @param loadComplete 可选完成回调;未传入时由组件自动创建并关闭全屏加载遮罩
* @return 无返回值;详情通过 viewData、doneTasks 回显,并通过 done-tasks 事件通知审核页面
*/
onOpen(row, loadComplete) {
// 公共详情组件统一管理加载提示,保证所有查看和审核入口使用相同交互。
const loading = loadComplete ? null : createLoading("数据加载中")
const handleLoadComplete = loadComplete || (() => {
loading.close()
})
this.row = row
this.visible = true
// 详情中的表格与详情、审核记录请求共用加载状态,两个请求全部完成后再关闭。
this.$set(this, "tableLoading", true)
// 切换提案时先清空上一条提案的审核记录和展开状态,避免异步加载期间展示旧数据。
this.doneTasks = []
this.activeTaskIds = []
let pendingRequestCount = 2
const handleRequestComplete = () => {
pendingRequestCount--
if (pendingRequestCount === 0) {
this.$set(this, "tableLoading", false)
handleLoadComplete()
}
}
this.getInfo().finally(handleRequestComplete)
this.getDoneTasks().finally(handleRequestComplete)
},
// 获取申请信息
getInfo() {
return this.$axios.post("/platform/proposal/common/proposalInfo", {id: this.row.id}).then((res) => {
if (res.code === 0) {
this.viewData = res.data
}
})
},
// 查看提案
openView(row) {
this.viewDialogVisible = true
this.$nextTick(() => {
this.$refs.infoDialogRef.onOpen(row)
})
},
// 获取已办任务审批记录
getDoneTasks() {
return this.$axios.post("/flow/common/doneTasks", {bizId: this.row.id}).then((res) => {
if (res.code === 0) {
const tasks = res.data || []
this.doneTasks = tasks
// 审核记录加载完成后默认全部折叠,由用户按需展开查看。
this.activeTaskIds = []
// 通知外层页面已办节点数据已加载完成,便于当前环节做表单回显。
this.$emit("done-tasks", tasks)
}
})
},
openChart(){
this.$refs.snakerChartRef.onOpenFull(this.row.instanceProcessDefineId, this.row.instanceId)
}
},
style:
/*language=CSS*/
`
.proposal-info .el-descriptions__body .el-descriptions__table .el-descriptions-item__cell {
}
`
}
@@ -0,0 +1,123 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app" v-cloak>
<el-card shadow="never">
<template #header>
<h3 style="color: var(--color-primary)">提案全局配置</h3>
</template>
<el-form :model="formData" :rules="formRules" label-width="200px" ref="formRef" label-position="top" size="small">
<el-form-item label="附议人数量" prop="seconderNum">
<el-input-number :min="0" :max="10" v-model="formData.seconderNum"></el-input-number>
</el-form-item>
<el-form-item label="案由最少字数" prop="briefMinLength">
<el-input-number :min="0" v-model="formData.briefMinLength"></el-input-number>
</el-form-item>
<el-form-item label="校领导单位" prop="schoolLeaderUnitIds">
<el-select clearable filterable placeholder="校领导单位" multiple v-model="formData.schoolLeaderUnitIds" style="width: 100%">
<el-option :key="item.id" :label="item.name" :value="item.id" v-for="item in unitOptions"></el-option>
</el-select>
</el-form-item>
<el-form-item label="协办单位是否需要答复" prop="slaveUnitNeedReply">
<el-radio-group v-model="formData.slaveUnitNeedReply" size="small">
<el-radio border :label="true"></el-radio>
<el-radio border :label="false"></el-radio>
</el-radio-group>
</el-form-item>
<!-- <el-form-item label="协办单位是否首先答复" prop="slaveUnitFirstReply" v-if="formData.slaveUnitNeedReply">-->
<!-- <span slot="label">-->
<!-- 协办单位是否首先答复-->
<!-- <el-tooltip content="开启后协办单位答复完成之后主办单位才可答复" placement="right">-->
<!-- <i class="el-icon-question"></i>-->
<!-- </el-tooltip>-->
<!-- </span>-->
<!-- <el-radio-group v-model="formData.slaveUnitFirstReply" size="small">-->
<!-- <el-radio border :label="true">是</el-radio>-->
<!-- <el-radio border :label="false">否</el-radio>-->
<!-- </el-radio-group>-->
<!-- </el-form-item>-->
<!-- <el-form-item label="协办单位领导单位是否需要审批" prop="slaveUnitLeaderNeedApprove">-->
<!-- <el-radio-group v-model="formData.slaveUnitLeaderNeedApprove" size="small">-->
<!-- <el-radio border :label="true">是</el-radio>-->
<!-- <el-radio border :label="false">否</el-radio>-->
<!-- </el-radio-group>-->
<!-- </el-form-item>-->
<el-form-item label="撰写须知" prop="writeRemind">
<text-editor v-model="formData.writeRemind"></text-editor>
</el-form-item>
</el-form>
<el-row type="flex" justify="end">
<el-button type="primary" @click="save" style="width: 200px">保存</el-button>
</el-row>
</el-card>
</div>
<script nonce="${cspNonce!}">
new Vue({
el: "#app",
data() {
return {
unitOptions: [],
formData: {},
formRules: {
seconderNum: [{ required: true, message: "请输入附议人数量", trigger: ["blur", "change"] }],
briefMinLength: [{ required: true, message: "请输入案由最少字数", trigger: ["blur", "change"] }],
slaveUnitNeedReply: [{ required: true, message: "请选择协办单位是否需要答复", trigger: ["blur", "change"] }],
slaveUnitFirstReply: [{ required: true, message: "请选择协办单位是否首先答复", trigger: ["blur", "change"] }],
slaveUnitLeaderNeedApprove: [{ required: true, message: "请选择协办单位领导单位是否需要审批", trigger: ["blur", "change"] }],
writeRemind: [
{
required: true,
validator: (rule, value, callback) => {
value === "<p><br></p>" ? callback(new Error("请输入撰写须知")) : callback()
},
message: "请输入撰写须知",
trigger: ["blur", "change"]
}
],
schoolLeaderUnitIds: [{ required: true, message: "请选择校领导单位", trigger: ["blur", "change"] }]
}
}
},
watch: {
"formData.writeRemind"(val) {
this.$refs.formRef.validateField(["writeRemind"], (errMsg) => {})
}
},
methods: {
init() {
this.$axios.post(loc() + "/findOne").then((res) => {
if (res.code === 0) {
this.formData = res.data
}
})
},
save() {
this.$refs.formRef.validate((valid) => {
if (valid) {
this.$axios
.post(loc() + "/update", {
config: JSON.stringify(this.formData)
})
.then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.init()
}
})
}
})
},
listUnit() {
this.$businessTool.listUnit().then((res) => (this.unitOptions = res))
}
},
created() {
this.init()
this.listUnit()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,106 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app" v-cloak>
<el-card shadow="never">
<search @search="doSearch">
<search-item label="名称">
<el-input v-model="pageForm.name" placeholder="请输入名称"></el-input>
</search-item>
</search>
</el-card>
<el-card shadow="never">
<table-tool>
<el-button type="primary" size="mini" icon="el-icon-plus" @click="openAdd">新增</el-button>
</table-tool>
<el-table v-loading="tableLoading" :data="tableData" border stripe @sort-change="pageOrder">
<el-table-column label="序号" type="index" :index="indexMethod" width="50px"></el-table-column>
<el-table-column prop="name" label="名称" sortable="custom"></el-table-column>
<el-table-column prop="code" label="编码" sortable="custom"></el-table-column>
<el-table-column label="操作" width="150px">
<template slot-scope="{row}">
<el-button size="mini" type="primary" @click="openEdit(row)">编辑</el-button>
<el-button size="mini" type="danger" @click="doDelete(row.id)">删除</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<el-dialog :visible.sync="dialogVisible" :title="formData.id?'编辑':'新增'" width="500px">
<el-form :model="formData" :rules="formRules" label-width="80px" ref="formRef" size="small">
<el-form-item label="名称" prop="name">
<el-input v-model="formData.name" placeholder="请输入名称" max="10"></el-input>
</el-form-item>
<el-form-item label="编码" prop="code">
<el-input v-model="formData.code" placeholder="请输入编码" max="10"></el-input>
</el-form-item>
</el-form>
<div slot="footer">
<el-button @click="dialogVisible=false">取消</el-button>
<el-button type="primary" @click="submit">提交</el-button>
</div>
</el-dialog>
</div>
<script nonce="${cspNonce!}">
new Vue({
el: "#app",
mixins: [initTableMixins],
data() {
return {
formRules: {
name: [{ required: true, message: "请输入名称", trigger: ["blur", "change"] }],
code: [{ required: true, message: "请输入编码", trigger: ["blur", "change"] }]
},
dialogVisible: false
}
},
methods: {
openAdd() {
this.formData = {}
this.dialogVisible = true
},
openEdit(row) {
this.formData = { ...row }
this.dialogVisible = true
},
submit() {
this.$refs.formRef.validate((valid) => {
if (valid) {
this.$axios.post(loc() + (this.formData.id ? "/update" : "/insert"), this.formData).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.dialogVisible = false
this.pageData()
}
})
}
})
},
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.pageData()
}
})
})
}
},
created() {
this.pageData()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,92 @@
const BASIC_XC_FORM_COMPONENT = {
template: `
<div>
<table-tool>
<el-button type="primary" size="small" icon="el-icon-plus" @click="openAdd()">新建机构</el-button>
</table-tool>
<el-table v-loading="tableLoading" key="1" :data="tableData" ref="tableRef">
<el-table-column label="序号" type="index" :index="indexMethod"></el-table-column>
<el-table-column prop="name" label="机构名称"></el-table-column>
<el-table-column prop="name" label="机构编码"></el-table-column>
<el-table-column prop="name" label="备注"></el-table-column>
<el-table-column label="操作" width="100px">
<template slot-scope="{row}">
<el-link size="mini" type="primary" @click="openEdit(row)">编辑</el-link>
<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="上级机构">
<el-input :value="formData.parentName" disabled></el-input>
</el-form-item>
<el-form-item label="机构名称" prop="name">
<el-select v-if="parentData.name==='专门委员会'"
v-model="formData.committee"
value-key="id"
style="width: 100%"
@change="committeeChange"
:disabled="formData.id!=null">
<el-option v-for="i in committeeOptions" :label="i.name" :value="i" :key="i.id"></el-option>
</el-select>
<el-input v-else placeholder="请输入机构名称" :disabled="formData.id!=null"
v-model="formData.name"></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],
data() {
return {
rules: {},
parentNode: {},
parentData: {},
committeeOptions: []
}
},
methods: {
openEdit(row) {},
doSubmit() {
this.$refs.formRef.validate((valid) => {
if (valid) {
this.$axios.post(loc() + (this.formData.id ? "/update" : "/insert"), this.formData).then((res) => {
if (res.code === 0) {
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)
}
})
})
},
committeeChange(val) {}
}
}
@@ -0,0 +1,113 @@
<!--#
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%" :body-style="{ height: '100%' , display: 'flex' , 'flex-direction': 'column' }">
<el-card shadow="never" style="border: 1px solid var(--border-color-lighter);flex-shrink: 0">
<el-row type="flex" :gutter="20">
<el-col :span="6">
<el-input v-model="pageForm.searchKeyword" clearable placeholder="请输入关键字"></el-input>
</el-col>
<el-col :span="4">
<el-button type="primary" icon="el-icon-search" @click="doSearch">搜索</el-button>
</el-col>
</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>
<el-button type="primary" size="small" icon="el-icon-refresh" @click="syncSysUnit">同步系统单位</el-button>
</table-tool>
<el-table v-loading="tableLoading" :data="tableData" border ref="tableRef" height="100%" @sort-change="pageOrder">
<el-table-column label="序号" type="index" :index="indexMethod" width="60"></el-table-column>
<el-table-column prop="name" label="单位名称" sortable="custom" show-overflow-tooltip></el-table-column>
<el-table-column prop="code" label="单位编码" sortable="custom" width="150px"></el-table-column>
<!-- <el-table-column prop="branchSchoolLeader" label="分管校领导及联系方式" width="180px"></el-table-column>-->
<el-table-column prop="unitLeader" label="单位领导" sortable="custom" width="180px" show-overflow-tooltip></el-table-column>
<el-table-column label="操作" width="350px">
<template slot-scope="{row}">
<!-- <el-button size="mini" type="primary" @click="$refs.userRef.onOpen(row.id,true)">设置分管校领导</el-button>-->
<el-button size="mini" type="primary" @click="$refs.userRef.onOpen(row.id,false)">设置单位领导</el-button>
<el-button size="mini" type="danger" @click="onDelete(row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</el-card>
</el-col>
</el-row>
<user ref="userRef" @refresh="doSearch"></user>
</div>
<script nonce="${cspNonce!}">
<!--#include("tree.js"){}#-->
<!--#include("user.js"){}#-->
new Vue({
el: "#app",
mixins: [initTableMixins],
components: {
tree: TREE_COMPONENT,
user: USER_COMPONENT
},
computed: {
hasChildren() {
if (this.currentTreeData) {
return this.currentTreeData.children && this.currentTreeData.children.length > 0
} else {
return false
}
}
},
data() {
return {
currentTreeNode: null,
currentTreeData: null
}
},
methods: {
treeNodeClick(data, node) {
this.currentTreeData = data
this.currentTreeNode = node
},
syncSysUnit() {
this.$axios.post(loc() + "/syncSysUnit").then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.$refs.treeRef.listTree()
}
})
},
onDelete (row) {
this.$confirm("您确定要删除吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "info"
}).then(() => {
$.post(loc() + "/delete", { id: row.id }).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.doSearch()
this.$refs.treeRef.listTree()
}
})
})
},
},
created() {
this.pageData()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,66 @@
const TREE_COMPONENT = {
template: `
<el-card shadow="never" style="height: 100%" :body-style="{ height: '100%' }">
<el-input placeholder="输入关键字进行查找" v-model="name" clearable class="mb10">
</el-input>
<div style="max-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: [],
name: null,
treeData: []
}
},
watch: {
name(val) {
this.$refs.treeRef.filter(val)
}
},
methods: {
treeNodeClick(data, node) {
this.currentTreeData = data
this.currentTreeNode = node
this.$emit("node-click", data, node)
},
filterNode(value, data, node) {
if (!value) return true
return data.name.indexOf(value) !== -1
},
listTree() {
this.$axios.post("/platform/proposal/config/unit/tree").then((res) => {
if (res.code === 0) {
this.treeData = res.data
this.$emit("node-click", this.treeData[0], null)
}
})
}
},
created() {
this.listTree()
}
}
@@ -0,0 +1,66 @@
const USER_COMPONENT = {
template: `
<el-dialog title="设置领导" :visible.sync="visible" width="1000px" :close-on-click-modal="false">
<el-transfer
ref="transferRef"
:titles="['可选人员', '已选人员']"
filterable
:props="{
key: 'id',
label: 'label'
}"
:left-default-checked="[]"
:filter-method="filterUnit"
v-model="selectUserIds"
:data="allUsers"
></el-transfer>
<div slot="footer" class="dialog-footer">
<el-button @click="visible = false">取 消</el-button>
<el-button type="primary" @click="doSubmit">确 定</el-button>
</div>
</el-dialog>
`,
data() {
return {
visible: false,
selectUserIds: [],
allUsers: [],
unitId: null,
isSchoolLeader: ""
}
},
methods: {
onOpen(id, isSchoolLeader) {
this.isSchoolLeader = isSchoolLeader
this.unitId = id
this.visible = true
this.$axios
.post("/platform/proposal/config/unit/" + (isSchoolLeader ? "branchSchoolLeaderTransferData" : "unitUsersTransferData"), { id })
.then((res) => {
this.selectUserIds = res.data.selectUserIds
this.allUsers = res.data.allUsers
})
this.$refs.transferRef.clearQuery("left")
this.$refs.transferRef.clearQuery("right")
},
doSubmit() {
this.$axios
.post("/platform/proposal/config/unit/" + (this.isSchoolLeader ? "updateBranchSchoolLeader" : "updateUnitLeader"), {
userIds: JSON.stringify(this.selectUserIds),
id: this.unitId
})
.then((res) => {
if (res.code === 0) {
this.visible = false
this.$message.success(res.msg)
this.$emit("refresh", null)
}
})
},
filterUnit(query, item) {
return item.username.indexOf(query) > -1
}
}
}
@@ -0,0 +1,349 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style>
.nodes-title {
font-size: 16px;
font-weight: 600;
color: #303133;
}
.nodes-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 20px;
}
.node-card {
background: #fff;
padding: 20px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
border-top: 4px solid var(--theme-color);
transition: all 0.3s ease;
display: flex;
align-items: center;
min-height: 80px;
position: relative;
}
.node-card:hover {
transform: translateY(-2px);
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
cursor: pointer;
}
.node-card.selected {
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15);
border-top-width: 4px;
}
.node-card.selected .node-icon {
transform: scale(1.1);
}
.node-icon {
width: 50px;
height: 50px;
border-radius: 50%;
background: var(--theme-color);
display: flex;
align-items: center;
justify-content: center;
margin-right: 16px;
font-size: 24px;
color: #fff;
}
.node-content {
flex: 1;
}
.node-name {
font-size: 16px;
font-weight: 600;
color: #303133;
margin-bottom: 8px;
line-height: 1.4;
}
.node-count {
font-size: 28px;
font-weight: 700;
color: var(--theme-color);
line-height: 1;
}
.task-toggle {
position: absolute;
top: 8px;
right: 8px;
display: flex;
background: rgba(255, 255, 255, 0.9);
padding: 2px;
}
.task-toggle-btn {
padding: 4px 8px;
font-size: 12px;
border: none;
background: transparent;
color: #666;
cursor: pointer;
transition: all 0.2s ease;
min-width: 36px;
}
.task-toggle-btn.active {
background: var(--theme-color);
color: #fff;
}
.task-toggle-btn:hover:not(.active) {
background: rgba(0, 0, 0, 0.05);
}
@media (max-width: 768px) {
.nodes-title {
font-size: 14px;
}
.nodes-grid {
grid-template-columns: 1fr;
gap: 15px;
}
.node-card {
padding: 16px;
min-height: 70px;
}
.node-icon {
width: 40px;
height: 40px;
font-size: 20px;
margin-right: 12px;
}
.node-name {
font-size: 14px;
}
.node-count {
font-size: 24px;
}
}
</style>
<div id="app" v-cloak>
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="教代会">
<el-select @change="sessionChange" clearable filterable placeholder="所属教代会"
v-model="pageForm.sessionId">
<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" class="mt10">
<div slot="header" class="nodes-title">统计看板</div>
<div class="nodes-grid">
<div
v-for="(node, index) in nodes"
:key="node.id"
class="node-card"
:class="{ selected: pageForm.selectNodeId === node.id }"
:style="'--theme-color:' + getThemeColor(index)"
@click="selectNode(node,index)"
>
<!-- task类型节点的切换按钮 -->
<div v-if="node.type === 'task'" class="task-toggle" @click.stop>
<button
class="task-toggle-btn"
:class="{ active: getNodeDisplayMode(node.id) === 'todo' }"
@click="setNodeDisplayMode(node, 'todo')"
>
待办
</button>
<button
class="task-toggle-btn"
:class="{ active: getNodeDisplayMode(node.id) === 'done' }"
@click="setNodeDisplayMode(node, 'done')"
>
已办
</button>
</div>
<div class="node-icon">
<i class="fa fa-tasks"></i>
</div>
<div class="node-content">
<div class="node-name">{{ node.name || '未命名节点' }}</div>
<div class="node-count">{{ getNodeCount(node) }}</div>
</div>
</div>
</div>
</el-card>
<el-card shadow="never" class="mt10">
<div slot="header" class="clearfix">
<span class="nodes-title">{{ tableCardTitle }}</span>
</div>
<el-table v-loading="tableLoading" :data="tableData" @sort-change="pageOrder" header-align="center" style="width: 100%" row-key="id">
<el-table-column label="序号" width="50" type="index" :index="indexMethod"></el-table-column>
<el-table-column label="提案编号" prop="code" sortable="custom" width="100px" show-overflow-tooltip></el-table-column>
<el-table-column label="提案名称" prop="name" sortable="custom" show-overflow-tooltip></el-table-column>
<el-table-column label="提案人" prop="createUserName" sortable="custom"></el-table-column>
<el-table-column label="提案类别" prop="typeName" sortable="custom"></el-table-column>
<el-table-column label="代表团" prop="delegationName" sortable="custom"></el-table-column>
<el-table-column label="立案结果" prop="caseFilingResult" sortable="custom">
<template scope="{row}">
<dict-tag :options="dict.type.PROPOSAL_CASE_FILING_RESULT" :value="row.caseFilingResult"></dict-tag>
</template>
</el-table-column>
<el-table-column label="是否并案" prop="isConsolidation" sortable="custom" width="100">
<template scope="{row}">
<el-tag size="mini" v-if="row.isConsolidation" type="success"></el-tag>
<el-tag size="mini" v-else type="danger"></el-tag>
</template>
</el-table-column>
<el-table-column label="主办单位" prop="masterUnitName" sortable="custom" show-overflow-tooltip></el-table-column>
<el-table-column label="协办单位" prop="slaveUnitNames" sortable="custom" show-overflow-tooltip></el-table-column>
<el-table-column prop="curTaskName" label="当前节点" sortable="custom"></el-table-column>
<el-table-column prop="instanceState" label="流程状态" sortable="custom">
<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="200px">
<template scope="{row}">
<el-button size="mini" type="primary" @click="openView(row)">查看</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<template #view>
<proposal-info ref="infoRef"></proposal-info>
</template>
</guava>
</div>
<script nonce="${cspNonce!}">
<!--#include("../common/info.js"){}#-->
new Vue({
el: '#app',
dicts: ["PROPOSAL_TYPE", "PROPOSAL_CASE_FILING_RESULT"],
components: {
"proposal-info": PROPOSAL_INFO
},
mixins: [initTableMixins],
data() {
return {
sessionOptions: [],
nodes: [],
nodeDisplayModes: {}, // 存储每个节点的显示模式
pageForm: {
selectNodeId: null,
selectNodeType: null,
pageSize: 5
}
}
},
methods: {
// 查看
openView(row) {
this.$refs.guava.view(() => {
this.$refs.infoRef.onOpen(row)
})
},
// 届次改变
sessionChange() {
this.getNodes()
this.doSearch()
},
// 获取届次
listSession() {
this.$axios.post("/platform/proposal/common/listSession").then((res) => {
if (res.code === 0) {
this.sessionOptions = res.data
if (this.sessionOptions) {
this.$set(this.pageForm, "sessionId", this.sessionOptions[0].id)
this.getNodes()
this.doSearch()
}
}
})
},
// 获取节点
getNodes() {
this.$axios.post('/platform/proposal/dashboard/listNode', {sessionId: this.pageForm.sessionId}).then(res => {
if (res.code === 0) {
this.nodes = res.data
}
})
},
// 获取主题色
getThemeColor(index) {
const colors = ['#409EFF', '#67C23A', '#E6A23C', '#F56C6C', '#909399', '#722ED1']
return colors[index % colors.length]
},
// 节点选择
selectNode(node, index) {
this.pageForm.selectNodeId = node.id
this.pageForm.selectNodeType = node.type
this.pageForm.selectNodeMode = this.getNodeDisplayMode(node.id)
this.doSearch()
},
// 获取节点显示数量
getNodeCount(node) {
if (node.type === 'task') {
const displayMode = this.getNodeDisplayMode(node.id)
return displayMode === 'todo' ? (node.todoCount || 0) : (node.doneCount || 0)
}
return node.count || 0
},
// 获取节点显示模式
getNodeDisplayMode(nodeId) {
return this.nodeDisplayModes[nodeId] || 'todo' // 默认显示待办
},
// 设置节点显示模式
setNodeDisplayMode(node, mode) {
this.$set(this.nodeDisplayModes, node.id, mode)
this.selectNode(node, null)
}
},
computed: {
tableCardTitle() {
if (this.pageForm.selectNodeId) {
const selectedNode = this.nodes.find(node => node.id === this.pageForm.selectNodeId)
return selectedNode ? selectedNode.name : '提案总数'
}
return '提案总数'
}
},
created() {
this.listSession()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,398 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style>
.el-tag {
cursor: pointer;
}
</style>
<div id="app" v-cloak>
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="教代会">
<el-select @change="meetingChange" clearable filterable placeholder="所属教代会"
v-model="pageForm.sessionId">
<el-option :key="item.id" :label="item.fullName" :value="item.id"
v-for="item in sessionOptions"></el-option>
</el-select>
</search-item>
<search-item label="名称/编号">
<el-input @keyup.enter.native="doSearch" clearable placeholder="请输入内容"
v-model="pageForm.proposalKeyword">
<el-select slot="prepend" style="width: 110px" v-model="pageForm.proposalSearchField">
<el-option label="提案名称" value="name"></el-option>
<el-option label="提案编号" value="code"></el-option>
<el-option label="立案编号" value="caseFilingCode"></el-option>
</el-select>
</el-input>
</search-item>
<search-item label="姓名/工号">
<el-input @keyup.enter.native="doSearch" clearable placeholder="请输入姓名或工号"
v-model="pageForm.createUserKeyword"></el-input>
</search-item>
<search-item label="代表团">
<el-select clearable filterable placeholder="所属代表团" v-model="pageForm.delegationId">
<el-option :key="item.id" :label="item.name" :value="item.id"
v-for="item in delegationOptions"></el-option>
</el-select>
</search-item>
<search-item label="提案分工会">
<el-select clearable filterable placeholder="分工会" v-model="pageForm.unionId"
@change="pageForm.unitId=null;listUnit();">
<el-option :key="item.id" :label="item.name" :value="item.id"
v-for="item in unionOptions"></el-option>
</el-select>
</search-item>
<search-item label="提案单位">
<el-select clearable filterable placeholder="提案单位" v-model="pageForm.unitId">
<el-option :key="item.id" :label="item.name" :value="item.id"
v-for="item in unitOptions"></el-option>
</el-select>
</search-item>
<search-item label="承办单位">
<el-select clearable filterable placeholder="承办单位" v-model="pageForm.underTakeUnitId">
<el-option :key="item.code" :label="item.name" :value="item.id"
v-for="item in underTakeOptions"></el-option>
</el-select>
</search-item>
</search>
</el-card>
<el-card shadow="never">
<div style="display: flex; align-items: center; min-height: 70px; border-bottom: 1px dashed rgb(230, 230, 230)">
<div style="width: 90px;margin-right: 10px">提案类别</div>
<div style="flex: 1;display: flex;gap: 5px;">
<el-tag
v-for="item in typeOptions"
:key="item.id"
:effect="pageForm.typeIds && pageForm.typeIds.includes(item.id) ? 'dark':'plain'"
@click="tagToggle('typeIds',item.id)"
>
{{ item.name }}
</el-tag>
</div>
</div>
<div style="display: flex; align-items: center; min-height: 70px; border-bottom: 1px dashed rgb(230, 230, 230)">
<div style="width: 90px;margin-right: 10px">立案结果</div>
<div style="flex: 1;display: flex;gap: 5px;">
<el-tag
v-for="item in dict.type.PROPOSAL_CASE_FILING_RESULT"
:key="item.code"
:effect="pageForm.caseFilingResults && pageForm.caseFilingResults.includes(item.code) ? 'dark':'plain'"
@click="tagToggle('caseFilingResults',item.code)"
>
{{ item.label }}
</el-tag>
</div>
</div>
</el-card>
<el-card shadow="never">
<table-tool :columns.sync="tableColumns">
<el-dropdown @command="handleBatchExportCommand" trigger="click" class="mr10">
<el-button type="primary" size="small">
批量导出提案表<i class="el-icon-arrow-down el-icon--right"></i>
</el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="zip">导出压缩包(每个提案一个文档)</el-dropdown-item>
<el-dropdown-item command="docx">导出汇集文档(所有提案合并)</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<el-button type="primary" size="small" @click="exportCollectZip">导出提案征集表压缩包</el-button>
<el-button type="primary" size="small" @click="exportAllProposalFeedBackAsZip">导出反馈表压缩包
</el-button>
<el-button type="primary" size="small" @click="exportSummaryAsExcel">导出汇总表</el-button>
<el-button type="primary" size="small" @click="exportUndertakeUnitTablesAsZip">导出承办单位表压缩包</el-button>
<!-- <el-button type="primary" size="small" @click="exportProposalRegisterSummaryAsExcel">导出立案汇总表-->
<el-button type="primary" size="small" @click="exportCustomAsExcel">自定义导出</el-button>
</table-tool>
<el-table v-loading="tableLoading" :data="tableData" @sort-change="pageOrder" header-align="center" style="width: 100%" row-key="id">
<el-table-column label="序号" width="50" type="index" :index="indexMethod"
fixed="left"></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:key="column.key"
:min-width="column.width"
:fixed="column.fixed"
sortable="custom"
show-overflow-tooltip
v-for="column in tableColumns"
v-if="column.visible !== false"
>
<template v-if="column.prop === 'caseFilingResult'" scope="{row}">
<dict-tag :options="dict.type.PROPOSAL_CASE_FILING_RESULT"
:value="row.caseFilingResult"></dict-tag>
</template>
<template v-else-if="column.prop === 'caseFilingType'" scope="{row}">
<dict-tag :options="dict.type.PROPOSAL_CASE_FILING_TYPE"
:value="row.caseFilingType"></dict-tag>
</template>
<template v-else-if="column.prop === 'merge'" scope="{row}">
<el-tag v-if="row.merge" size="small"></el-tag>
</template>
<template v-else-if="column.prop === 'instanceState'" scope="{row}">
<enum-tag :value="row.instanceState" name="ProcessInstanceStateEnum" label_key="message"
size="small"></enum-tag>
</template>
<template v-else-if="column.prop === 'undertakeUnits'" scope="{row}">
{{ getUndertakeDisplay(row) }}
</template>
</el-table-column>
<el-table-column label="操作" fixed="right" min-width="200px">
<template scope="{row}">
<el-button size="mini" type="primary" @click="openView(row)">查看</el-button>
<el-button size="mini" type="primary" @click="exportDocx(row.id)">导出</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<template #view>
<proposal-info ref="infoRef"></proposal-info>
</template>
</guava>
</div>
<script nonce="${cspNonce!}">
<!--#include("../../common/info.js"){}#-->
new Vue({
el: "#app",
dicts: ["PROPOSAL_TYPE", "PROPOSAL_CASE_FILING_RESULT", "PROPOSAL_CASE_FILING_TYPE"],
store,
mixins: [initTableMixins],
components: {
"proposal-info": PROPOSAL_INFO
},
data() {
return {
sessionOptions: [],
typeOptions: [],
delegationOptions: [],
underTakeOptions: [],
unionOptions: [],
unitOptions: [],
businessNo: "",
tabActive: "0",
pageForm: {
proposalSearchField: "name",
proposalKeyword: "",
typeIds: [],
caseFilingResults: [],
unionId: null,
unitId: null
},
tableColumns: [
{label: "提案编号", prop: "code"},
{label: "立案编号", prop: "caseFilingCode"},
{label: "提案名称", prop: "name"},
{label: "提案人", prop: "createUserName"},
{label: "提案类别", prop: "typeName"},
{label: "届次", prop: "sessionName"},
{label: "代表团", prop: "delegationName"},
{label: "立案结果", prop: "caseFilingResult"},
{label: "立案类型", prop: "caseFilingType", visible: false},
{label: "是否并案", prop: "merge"},
{label: "案由", prop: "brief", visible: false},
{label: "建议措施", prop: "measures", visible: false},
{label: "承办单位", prop: "undertakeUnits", width: "260px"},
{label: "当前节点", prop: "curTaskName"},
{label: "流程状态", prop: "instanceState"}
]
}
},
methods: {
/**
* 导出列表页沿用查询口径,确保“作为建议”展示为承办单位,
* “确定立案”则保留主办/协办信息。
*/
getUndertakeDisplay(row) {
var masterUnitNames = this.formatUnitNames(row.masterUnitName)
var slaveUnitNames = this.formatUnitNames(row.slaveUnitNames)
if (row.caseFilingResult === "SUGGESTION") {
return masterUnitNames || slaveUnitNames
}
if (row.caseFilingResult === "CONFIRM_FILING") {
return [masterUnitNames ? "主办:" + masterUnitNames : "", slaveUnitNames ? "协办:" + slaveUnitNames : ""].filter(function (item) {
return item
}).join("")
}
return ""
},
formatUnitNames(unitNames) {
if (!unitNames) {
return ""
}
if (Array.isArray(unitNames)) {
return unitNames.filter(function (item) {
return item
}).join("")
}
return unitNames
},
openView(row) {
this.$refs.guava.view(() => {
this.$refs.infoRef.onOpen(row)
})
},
handleBatchExportCommand(command) {
if (command === "docx") {
this.exportAllProposalAsDocx()
return
}
this.exportAllProposalAsZip()
},
exportAllProposalAsZip() {
this.$downLoad(loc() + "/exportAllProposalAsZip", {
pageForm: JSON.stringify(this.pageForm)
})
},
exportAllProposalAsDocx() {
this.$downLoad(loc() + "/exportAllProposalAsDocx", {
pageForm: JSON.stringify(this.pageForm)
})
},
exportCollectZip() {
this.$downLoad(loc() + "/exportCollectZip", {
pageForm: JSON.stringify(this.pageForm)
})
},
exportAllProposalFeedBackAsZip() {
this.$downLoad(loc() + "/exportAllProposalFeedBackAsZip", {
pageForm: JSON.stringify(this.pageForm)
})
},
exportDocx(id) {
this.$downLoad("/platform/proposal/common/exportProposalAsDocx", {id})
},
exportSummaryAsExcel() {
this.$downLoad("/platform/proposal/export/comprehensive/exportSummaryAsExcel", {
pageForm: JSON.stringify(this.pageForm)
})
},
exportUndertakeUnitTablesAsZip() {
if (!this.pageForm.sessionId) {
this.$message.warning("请选择教代会")
return
}
this.$downLoad(loc() + "/exportUndertakeUnitTablesAsZip", {
pageForm: JSON.stringify(this.pageForm)
})
},
exportProposalRegisterSummaryAsExcel() {
this.$downLoad("/platform/proposal/export/comprehensive/exportProposalRegisterSummaryAsExcel", {
pageForm: JSON.stringify(this.pageForm)
})
},
exportCustomAsExcel() {
this.$downLoad("/platform/proposal/export/comprehensive/exportCustomAsExcel", {
pageForm: JSON.stringify(this.pageForm),
tableColumns: JSON.stringify(this.tableColumns.filter(item => item.visible !== false))
})
},
tagToggle(key, val) {
if (this.pageForm[key].includes(val)) {
this.pageForm[key].splice(this.pageForm[key].indexOf(val), 1)
} else {
this.pageForm[key].push(val)
}
this.doSearch()
},
listProposalType() {
if (!this.pageForm.sessionId) {
this.$set(this, "typeOptions", [])
return Promise.resolve()
}
return this.$axios.post(loc() + "/listSessionProposalTypes", {
sessionId: this.pageForm.sessionId
}).then((res) => {
if (res.code === 0) {
this.$set(this, "typeOptions", res.data)
}
})
},
meetingChange(val) {
// searchSessionId 是后端列表查询实际使用的单届次筛选参数,需与页面选择保持同步
this.$set(this.pageForm, "searchSessionId", val)
// 切换届次后旧类别和代表团不再适用,需清空选择并加载当前届次数据
this.$set(this.pageForm, "typeIds", [])
this.$set(this, "typeOptions", [])
this.listProposalType()
this.$set(this.pageForm, "delegationId", null)
this.listDelegation()
this.doSearch()
},
listDelegation() {
this.$axios.post("/platform/proposal/common/listDelegation", {sessionId: this.pageForm.sessionId}).then((res) => {
if (res.code === 0) {
this.delegationOptions = res.data
}
})
},
listSession() {
this.$axios.post("/platform/proposal/common/listSession").then((res) => {
if (res.code === 0) {
this.$set(this, "sessionOptions", res.data)
if (this.sessionOptions && this.sessionOptions.length > 0) {
this.$set(this.pageForm, "sessionId", this.sessionOptions[0].id)
this.$set(this.pageForm, "searchSessionId", this.sessionOptions[0].id)
this.listProposalType()
this.listDelegation()
this.pageData()
}
}
})
},
listUnderTake() {
this.$axios.post("/platform/proposal/common/listUnderTake").then((res) => {
if (res.code === 0) {
this.underTakeOptions = res.data
}
})
},
listUnion() {
this.$businessTool.listUnion().then((res) => (this.unionOptions = res))
},
listUnit() {
this.$businessTool.listUnit(this.pageForm.unionId).then((res) => (this.unitOptions = res))
},
pageData() {
// 自定义查询覆盖了公共 mixin,请求期间手动维护表格加载状态。
this.$set(this, "tableLoading", true)
this.$axios
.post(loc() + "/pageData", {
pageForm: JSON.stringify(this.pageForm)
})
.then((res) => {
if (res.code === 0) {
res.data.list.map((item) => {
item.brief = removeHTMLTag(item.brief)
item.measures = removeHTMLTag(item.measures)
})
this.tableData = res.data.list
this.pageForm.totalCount = res.data.totalCount
}
})
.finally(() => {
this.$set(this, "tableLoading", false)
})
}
},
created() {
this.listSession()
this.listUnderTake()
this.listUnion()
this.listUnit()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,185 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app" v-cloak>
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="教代会">
<el-select @change="meetingChange" clearable filterable placeholder="所属教代会" v-model="pageForm.sessionId">
<el-option :key="item.id" :label="item.fullName" :value="item.id" v-for="item in sessionOptions"></el-option>
</el-select>
</search-item>
<search-item label="提案编号">
<el-input v-model="pageForm.code" clearable placeholder="提案编号"></el-input>
</search-item>
<search-item label="提案名称">
<el-input v-model="pageForm.name" clearable placeholder="提案名称"></el-input>
</search-item>
<search-item label="姓名/工号">
<el-input v-model="pageForm.createUserKeyword" clearable placeholder="请输入姓名或工号"></el-input>
</search-item>
</search>
</el-card>
<el-card shadow="never">
<table-tool :columns.sync="tableColumns"></table-tool>
<el-table v-loading="tableLoading" :data="tableData" @sort-change="pageOrder" style="width: 100%">
<el-table-column label="序号" width="50" type="index" :index="indexMethod" fixed="left"></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:key="column.key"
:min-width="column.width"
:fixed="column.fixed"
sortable="custom"
show-overflow-tooltip
v-for="column in tableColumns"
v-if="column.visible !== false"
>
<template v-if="column.prop === 'instanceState'" 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="260px">
<template slot-scope="{row}">
<el-button size="mini" type="primary" @click="openView(row)">查看</el-button>
<el-button size="mini" type="warning" @click="openExportDialog(row)">导出提案表</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<template #view>
<proposal-info ref="infoRef"></proposal-info>
</template>
<el-dialog title="导出提案表(选择环节)" width="620px" :visible.sync="exportDialogVisible" append-to-body>
<div style="margin-bottom: 8px; color: #666;">
当前提案:{{ exportRow.code }} - {{ exportRow.name }}
</div>
<div style="margin-bottom: 10px;">
<el-button size="mini" @click="selectAllStages">全选</el-button>
<el-button size="mini" @click="clearAllStages">清空</el-button>
</div>
<el-checkbox-group v-model="exportForm.stageTaskNames">
<el-checkbox v-for="item in stageOptions" :label="item.value" :key="item.value" style="margin-right: 16px; margin-bottom: 8px;">
{{ item.label }}
</el-checkbox>
</el-checkbox-group>
<div style="margin-top: 8px; color: #999;">说明:基础内容固定导出,勾选项用于控制附加环节内容。</div>
<span slot="footer">
<el-button size="small" @click="exportDialogVisible=false">取消</el-button>
<el-button size="small" type="primary" @click="exportSelectedDocx">确定导出</el-button>
</span>
</el-dialog>
</guava>
</div>
<script nonce="${cspNonce!}">
<!--#include('../../common/info.js'){}#-->
new Vue({
el: "#app",
store,
mixins: [initTableMixins],
components: {
"proposal-info": PROPOSAL_INFO
},
data() {
return {
tableColumns: [
{label: "提案编号", prop: "code"},
{label: "提案名称", prop: "name", width: "220px"},
{label: "提案人", prop: "createUserName", width: "100px"},
{label: "提案类型", prop: "typeName"},
{label: "教代会", prop: "sessionName", width: "200px"},
{label: "代表团", prop: "delegationName", width: "120px"},
{label: "当前节点", prop: "curTaskName"},
{label: "流程状态", prop: "instanceState"}
],
pageForm: {
sessionId: ""
},
sessionOptions: [],
exportDialogVisible: false,
exportRow: {},
stageOptions: [],
exportForm: {
stageTaskNames: []
}
}
},
created() {
this.listOpenSession()
this.pageData()
},
methods: {
openView(row) {
this.$refs.guava.view(() => {
this.$refs.infoRef.onOpen(row)
})
},
meetingChange() {
this.pageData()
},
listOpenSession() {
this.$axios.post("/platform/proposal/common/listOpenSession").then((res) => {
if (res.code === 0) {
this.sessionOptions = res.data || []
if (this.sessionOptions.length > 0) {
this.pageForm.sessionId = this.sessionOptions[0].id
this.pageData()
}
}
})
},
openExportDialog(row) {
this.exportRow = row
this.exportForm.stageTaskNames = []
this.stageOptions = []
this.exportDialogVisible = true
this.$axios.post(loc() + "/stageOptions", {id: row.id}).then((res) => {
if (res.code === 0) {
this.stageOptions = res.data || []
this.exportForm.stageTaskNames = this.stageOptions.map(v => v.value)
}
})
},
selectAllStages() {
this.exportForm.stageTaskNames = this.stageOptions.map(v => v.value)
},
clearAllStages() {
this.exportForm.stageTaskNames = []
},
exportSelectedDocx() {
if (!this.exportRow || !this.exportRow.id) {
return
}
this.$downLoad(loc() + "/exportSelectedDocx", {
id: this.exportRow.id,
stageTaskNamesJson: JSON.stringify(this.exportForm.stageTaskNames || [])
})
this.exportDialogVisible = false
},
pageData() {
// 自定义查询覆盖了公共 mixin,请求期间手动维护表格加载状态。
this.$set(this, "tableLoading", true)
this.$axios.post(loc() + "/pageData", this.pageForm).then((res) => {
if (res.code === 0) {
this.tableData = res.data.list
this.totalCount = res.data.totalCount
this.pageSize = res.data.pageSize
this.pageNumber = res.data.pageNumber
}
}).finally(() => {
this.$set(this, "tableLoading", false)
})
}
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,470 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style>
.page-title-wrap {
display: flex;
align-items: center;
gap: 10px;
}
.page-title-accent {
width: 6px;
height: 20px;
border-radius: 4px;
background: linear-gradient(180deg, #2f7df6 0%, #5aa2ff 100%);
}
.page-title-text {
font-size: 16px;
font-weight: 700;
color: #22324d;
letter-spacing: 0.3px;
}
.dimension-pills {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 6px;
}
.analysis-toolbar {
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
gap: 12px;
}
.analysis-toolbar-main {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 12px 18px;
flex: 1;
min-width: 0;
}
.analysis-field {
display: flex;
align-items: center;
gap: 8px;
min-width: 330px;
}
.analysis-field-label {
flex: 0 0 auto;
color: #4b617f;
font-size: 13px;
font-weight: 600;
}
.analysis-field-select {
width: 240px;
}
.analysis-dimension-box {
display: flex;
align-items: center;
gap: 10px;
min-width: 420px;
}
.analysis-view-switch {
flex: 0 0 auto;
}
.dimension-pill {
padding: 3px 10px;
border-radius: 999px;
font-size: 12px;
color: #2f5fa8;
background: #edf4ff;
border: 1px solid #cfe1ff;
line-height: 1.4;
cursor: pointer;
transition: all 0.2s;
}
.dimension-pill.is-active {
color: #ffffff;
background: #2f7df6;
border-color: #2f7df6;
}
.analysis-tip {
margin-bottom: 10px;
padding: 10px 12px;
border-left: 4px solid #2f7df6;
background: linear-gradient(90deg, #eef5ff 0%, #f8fbff 100%);
border-radius: 4px;
color: #3b4a66;
font-size: 13px;
}
.chart-card-title {
display: flex;
align-items: center;
gap: 8px;
color: #1f2d3d;
font-weight: 600;
}
.chart-card-dot {
width: 8px;
height: 8px;
border-radius: 50%;
background: #409eff;
box-shadow: 0 0 0 3px rgba(64, 158, 255, 0.18);
}
.analysis-card-title {
font-weight: 700;
margin-bottom: 8px;
color: #1f2d3d;
display: flex;
align-items: center;
gap: 8px;
}
.analysis-card-title::before {
content: "";
width: 4px;
height: 14px;
border-radius: 2px;
background: #2f7df6;
}
.analysis-card-meta {
margin-bottom: 8px;
padding: 8px 10px;
border-left: 3px solid #66a6ff;
background: #f4f9ff;
color: #4b617f;
line-height: 1.6;
border-radius: 4px;
}
.analysis-card-text {
padding: 8px 10px;
background: #f7faff;
border-radius: 4px;
color: #2f3d4f;
line-height: 1.7;
}
.keyword-tag {
display: inline-block;
padding: 2px 8px;
margin: 0 4px 4px 0;
border-radius: 4px;
font-size: 12px;
color: #2b5a9f;
background: #eaf3ff;
border: 1px solid #c9ddff;
}
</style>
<div id="app" v-cloak>
<el-card shadow="never">
<div class="analysis-toolbar">
<div class="analysis-toolbar-main">
<div class="analysis-field">
<span class="analysis-field-label">教代会届次</span>
<el-select class="analysis-field-select" @change="doSearch" clearable filterable placeholder="请选择教代会届次" v-model="pageForm.sessionId">
<el-option :key="item.id" :label="item.fullName" :value="item.id" v-for="item in sessionOptions"></el-option>
</el-select>
</div>
<div class="analysis-dimension-box">
<span class="analysis-field-label">统计维度</span>
<div class="dimension-pills">
<span
class="dimension-pill"
:class="{'is-active': pageForm.dimension === item.value}"
@click="toggleDimension(item.value)"
v-for="item in dimensionOptions"
:key="item.value"
>{{ item.label }}</span>
</div>
</div>
</div>
<el-button class="analysis-view-switch" size="mini" type="primary" @click="toggleChartView">
{{ showChart ? '切换表格展示' : '切换图形化展示' }}
</el-button>
</div>
</el-card>
<el-card shadow="never" class="mt10" v-if="!showChart">
<div slot="header" style="display:flex;justify-content:space-between;align-items:center;gap:10px;">
<div>
<div class="page-title-wrap">
<span class="page-title-accent"></span>
<span class="page-title-text">统计数据</span>
</div>
</div>
<el-button size="mini" type="primary" @click="exportStatistics">导出统计数据</el-button>
</div>
<el-table :data="statisticsRows" border stripe style="width: 100%" v-loading="tableLoading"
@sort-change="statisticsOrder">
<el-table-column prop="dimension" label="统计维度" sortable="custom" width="180"></el-table-column>
<el-table-column prop="itemName" label="分类项" sortable="custom" min-width="260" show-overflow-tooltip></el-table-column>
<el-table-column prop="count" label="数量" sortable="custom" width="120"></el-table-column>
<el-table-column prop="rate" label="占比" sortable="custom" width="120"></el-table-column>
</el-table>
</el-card>
<el-card shadow="never" class="mt10" v-if="!showChart">
<div slot="header" style="display:flex;justify-content:space-between;align-items:center;">
<div class="page-title-wrap">
<span class="page-title-accent"></span>
<span class="page-title-text">分析数据</span>
</div>
<el-button size="mini" type="primary" @click="exportAnalysis">导出分析数据</el-button>
</div>
<el-table :data="analysisRows" border stripe style="width: 100%" v-loading="tableLoading"
@sort-change="analysisOrder">
<el-table-column prop="dimension" label="统计维度" sortable="custom" width="160"></el-table-column>
<el-table-column prop="total" label="总量" sortable="custom" width="100"></el-table-column>
<el-table-column prop="categoryCount" label="分类数量" sortable="custom" width="120"></el-table-column>
<el-table-column prop="topItem" label="最高项" sortable="custom" min-width="180" show-overflow-tooltip></el-table-column>
<el-table-column prop="topCount" label="最高数量" sortable="custom" width="120"></el-table-column>
<el-table-column prop="topRate" label="最高占比" sortable="custom" width="120"></el-table-column>
<el-table-column prop="analysis" label="分析结论" sortable="custom" min-width="320" show-overflow-tooltip></el-table-column>
</el-table>
</el-card>
<el-card shadow="never" class="mt10" v-if="showChart">
<div slot="header" style="display:flex;justify-content:space-between;align-items:center;">
<div>
<div class="page-title-wrap">
<span class="page-title-accent"></span>
<span class="page-title-text">图形化统计展示(混合图)</span>
</div>
</div>
<div>
<el-button size="mini" type="primary" @click="exportStatistics">导出统计数据</el-button>
<el-button size="mini" type="primary" @click="exportAnalysis">导出分析数据</el-button>
</div>
</div>
<div class="analysis-tip">提示:蓝色标记区域为关键指标说明,可快速对比每个维度的最高项及占比。</div>
<el-row :gutter="12">
<el-col :span="12" v-for="item in chartGroups" :key="item.domId" class="mb10">
<el-card shadow="never">
<div slot="header" class="chart-card-title">
<span class="chart-card-dot"></span>
<span>{{ item.dimension }}</span>
</div>
<div :id="item.domId" style="height: 300px;"></div>
</el-card>
</el-col>
</el-row>
</el-card>
<el-card shadow="never" class="mt10" v-if="showChart">
<div slot="header" class="page-title-wrap">
<span class="page-title-accent"></span>
<span class="page-title-text">分析结论</span>
</div>
<div class="analysis-tip">提示:每张卡片中的蓝色竖线信息用于提炼重点,下面是自动生成的文字分析。</div>
<el-row :gutter="12">
<el-col :span="12" v-for="row in analysisRows" :key="row.dimension" class="mb10">
<el-card shadow="hover">
<div class="analysis-card-title">{{ row.dimension }}</div>
<div class="analysis-card-meta">总量:{{ row.total }},最高项:{{ row.topItem }}{{ row.topRate }}</div>
<div class="analysis-card-text">{{ row.analysis }}</div>
</el-card>
</el-col>
</el-row>
</el-card>
</div>
<script nonce="${cspNonce!}">
new Vue({
el: "#app",
data() {
return {
pageForm: {
sessionId: "",
dimension: "",
statisticsOrderName: "",
statisticsOrderBy: "",
analysisOrderName: "",
analysisOrderBy: ""
},
dimensionOptions: [
{label: "提案人单位", value: "提案人单位"},
{label: "提案类型", value: "提案类型"},
{label: "代表团", value: "代表团"},
{label: "立案结果", value: "立案结果"},
{label: "满意度", value: "满意度"}
],
sessionOptions: [],
statisticsRows: [],
analysisRows: [],
tableLoading: false,
showChart: false,
chartMap: {}
}
},
computed: {
chartGroups() {
const grouped = {}
this.statisticsRows.forEach(v => {
if (!grouped[v.dimension]) {
grouped[v.dimension] = []
}
grouped[v.dimension].push(v)
})
return Object.keys(grouped).map((k, idx) => ({
dimension: k,
domId: "chart_dimension_" + idx,
items: grouped[k]
}))
}
},
created() {
this.listSession()
},
methods: {
// 统计数据表使用独立排序参数,避免与分析数据表的排序状态相互覆盖。
statisticsOrder(column) {
this.pageForm.statisticsOrderName = column.prop
this.pageForm.statisticsOrderBy = column.order
this.doSearch()
},
// 分析数据表使用独立排序参数,两个接口刷新时分别应用各自白名单。
analysisOrder(column) {
this.pageForm.analysisOrderName = column.prop
this.pageForm.analysisOrderBy = column.order
this.doSearch()
},
toggleChartView() {
this.showChart = !this.showChart
if (this.showChart) {
this.$nextTick(() => this.renderCharts())
} else {
this.destroyCharts()
}
},
destroyCharts() {
Object.keys(this.chartMap).forEach(k => {
if (this.chartMap[k] && this.chartMap[k].destroy) {
this.chartMap[k].destroy()
}
})
this.chartMap = {}
},
isPieDimension(dimension) {
return ["立案结果", "满意度"].includes(dimension)
},
toggleDimension(dimension) {
this.pageForm.dimension = this.pageForm.dimension === dimension ? "" : dimension
this.doSearch()
},
renderCharts() {
this.destroyCharts()
this.chartGroups.forEach(group => {
const top8 = group.items.slice(0, 8)
let chart
if (this.isPieDimension(group.dimension)) {
chart = new G2Plot.Pie(group.domId, {
data: top8,
angleField: "count",
colorField: "itemName",
radius: 0.75,
innerRadius: 0.45,
legend: {position: "bottom"},
label: {
type: "spider",
content: "{name}: {percentage}"
},
statistic: {
title: {content: group.dimension},
content: {content: top8.reduce((s, x) => s + Number(x.count || 0), 0).toString()}
}
})
} else {
chart = new G2Plot.Bar(group.domId, {
data: top8,
xField: "count",
yField: "itemName",
seriesField: "itemName",
legend: false,
maxBarWidth: 18,
label: {
position: "right",
style: {fill: "#666"}
},
meta: {
itemName: {alias: "分类项"},
count: {alias: "数量"}
},
yAxis: {
label: {
autoHide: true
}
}
})
}
chart.render()
this.chartMap[group.domId] = chart
})
},
listSession() {
this.$axios.post("/platform/proposal/common/listSession").then((res) => {
if (res.code === 0) {
this.sessionOptions = res.data || []
if (this.sessionOptions.length > 0) {
this.pageForm.sessionId = this.sessionOptions[0].id
this.doSearch()
}
}
})
},
doSearch() {
if (!this.pageForm.sessionId) {
this.statisticsRows = []
this.analysisRows = []
this.destroyCharts()
return
}
this.tableLoading = true
Promise.all([
this.$axios.post(loc() + "/statisticsData", this.pageForm),
this.$axios.post(loc() + "/analysisData", this.pageForm)
]).then((resList) => {
const statisticsRes = resList[0]
const analysisRes = resList[1]
if (statisticsRes.code === 0) {
this.statisticsRows = statisticsRes.data || []
if (this.showChart) {
this.$nextTick(() => this.renderCharts())
}
}
if (analysisRes.code === 0) {
this.analysisRows = analysisRes.data || []
}
}).finally(() => {
this.tableLoading = false
})
},
exportStatistics() {
if (!this.pageForm.sessionId) {
this.$message.warning("请先选择教代会届次")
return
}
this.$downLoad(loc() + "/exportStatisticsData", this.pageForm)
},
exportAnalysis() {
if (!this.pageForm.sessionId) {
this.$message.warning("请先选择教代会届次")
return
}
this.$downLoad(loc() + "/exportAnalysisData", this.pageForm)
}
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,268 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app">
<el-card shadow="never">
<el-row type="flex" justify="center">
<el-select @change="doSearch" clearable filterable placeholder="所属教代会" v-model="pageForm.sessionId" style="width: 100%">
<el-option :key="item.id" :label="item.fullName" :value="item.id" v-for="item in sessionOptions"></el-option>
</el-select>
</el-row>
</el-card>
<el-row :gutter="10" class="mt10">
<el-col :span="12" v-loading="loading.satisfiedLoading">
<el-card class="box-card" shadow="never">
<div slot="header">
<span>提案满意度</span>
</div>
<div class="text item">
<div id="satisfiedChart"></div>
</div>
</el-card>
</el-col>
<el-col :span="12" v-loading="loading.typeLoading">
<el-card class="box-card" shadow="never">
<div slot="header" class="clearfix">
<span>提案类别</span>
</div>
<div class="text item">
<div id="typeChart"></div>
</div>
</el-card>
</el-col>
</el-row>
<el-row :gutter="10" class="mt10">
<el-col :span="12" v-loading="loading.resultLoading">
<el-card shadow="never">
<div slot="header" class="clearfix">
<span>立案结果</span>
</div>
<div class="text item">
<div id="resultChart"></div>
</div>
</el-card>
</el-col>
<el-col :span="12" v-loading="loading.stateLoading">
<el-card shadow="never">
<div slot="header" class="clearfix">
<span>提案状态</span>
</div>
<div class="text item">
<div id="stateChart"></div>
</div>
</el-card>
</el-col>
</el-row>
</div>
<script nonce="${cspNonce!}">
<!--#include("../../common/info.js"){}#-->
const chart = {
satisfiedChart: undefined,
resultChart: undefined,
typeChart: undefined,
stateChart: undefined
}
new Vue({
el: "#app",
mixins: [initTableMixins],
data() {
return {
pageForm: {
sessionId: null
},
sessionOptions: [],
loading: {
satisfiedLoading: false,
resultLoading: false,
typeLoading: false,
stateLoading: false
}
}
},
methods: {
listSession() {
this.$axios.post("/platform/proposal/common/listSession").then((res) => {
if (res.code === 0) {
this.sessionOptions = res.data
if (this.sessionOptions) {
this.$set(this.pageForm, "sessionId", this.sessionOptions[0].id)
this.doSearch()
}
}
})
},
doSearch() {
this.typeChart()
this.resultChart()
this.stateChart()
this.feedBackScoreChart()
},
typeChart() {
this.$axios.post(loc() + "/typeData", this.pageForm).then((res) => {
if (res.code === 0) {
this.loading.typeLoading = false
if (chart.typeChart) {
chart.typeChart.changeData(res.data)
return
}
chart.typeChart = new G2Plot.Column("typeChart", {
data: res.data,
xField: "typeName",
yField: "count",
meta: {
typeName: {
alias: "类别"
},
count: {
alias: "数量"
}
},
xAxis: {
label: {
autoRotate: true,
autoHide: false,
autoEllipsis: false
}
}
})
chart.typeChart.render()
}
})
},
resultChart() {
this.$axios.post(loc() + "/resultData", this.pageForm).then((res) => {
if (res.code === 0) {
if (chart.resultChart) {
chart.resultChart.changeData(res.data)
return
}
chart.resultChart = new G2Plot.Radar("resultChart", {
data: res.data,
xField: "name",
yField: "count",
seriesField: "type",
meta: {
count: {
alias: "数量",
min: 0
}
},
xAxis: {
line: null,
tickLine: null,
grid: {
line: {
style: {
lineDash: null
}
}
}
},
yAxis: {
line: null,
tickLine: null,
grid: {
line: {
type: "line",
style: {
lineDash: null
}
}
}
},
area: {},
point: {
size: 2
}
})
chart.resultChart.render()
}
})
},
stateChart() {
this.$axios.post(loc() + "/stateData", this.pageForm).then((res) => {
if (res.code === 0) {
if (chart.stateChart) {
chart.stateChart.changeData(res.data)
return
}
chart.stateChart = new G2Plot.Radar("stateChart", {
data: res.data,
xField: "name",
yField: "count",
meta: {
count: {
alias: '数量',
},
},
xAxis: {
line: null,
tickLine: null,
grid: {
line: {
style: {
lineDash: null
}
}
}
},
yAxis: {
line: null,
tickLine: null,
grid: {
line: {
type: "line",
style: {
lineDash: null
}
}
}
},
point: {
size: 2
}
})
chart.stateChart.render()
}
})
},
feedBackScoreChart() {
this.$axios.post(loc() + "/feedBackScoreData", this.pageForm).then((res) => {
if (res.code === 0) {
if (chart.feedBackScoreChart) {
chart.feedBackScoreChart.changeData(res.data)
return
}
chart.satisfiedChart = new G2Plot.Pie("satisfiedChart", {
data: res.data,
appendPadding: 10,
angleField: "count",
colorField: "name",
radius: 0.75,
color: ["#9661BC", "#5B8FF9", "#61DDAA"],
label: {
type: "spider",
labelHeight: 28,
content: "{name}\n{percentage}"
},
interactions: [{ type: "element-selected" }, { type: "element-active" }]
})
chart.satisfiedChart.render()
}
})
}
},
created() {
this.listSession()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,256 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style>
</style>
<div id="app" v-cloak>
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="教代会">
<el-select @change="meetingChange" clearable filterable placeholder="所属教代会"
v-model="pageForm.sessionId">
<el-option :key="item.id" :label="item.fullName" :value="item.id"
v-for="item in sessionOptions"></el-option>
</el-select>
</search-item>
<search-item label="名称/编号">
<el-input @keyup.enter.native="doSearch" clearable placeholder="请输入内容"
v-model="pageForm.proposalKeyword">
<el-select slot="prepend" style="width: 110px" v-model="pageForm.proposalSearchField">
<el-option label="提案名称" value="name"></el-option>
<el-option label="提案编号" value="code"></el-option>
<el-option label="立案编号" value="caseFilingCode"></el-option>
</el-select>
</el-input>
</search-item>
<search-item label="姓名/工号">
<el-input placeholder="请输入姓名或工号" clearable
v-model="pageForm.createUserKeyword"></el-input>
</search-item>
<search-item label="代表团">
<el-select clearable filterable placeholder="所属代表团" v-model="pageForm.delegationId">
<el-option :key="item.id" :label="item.name" :value="item.id"
v-for="item in delegationOptions"></el-option>
</el-select>
</search-item>
<search-item label="提案分工会">
<el-select clearable filterable placeholder="分工会" v-model="pageForm.unionId"
@change="pageForm.unitId=null;listUnit();">
<el-option :key="item.id" :label="item.name" :value="item.id"
v-for="item in unionOptions"></el-option>
</el-select>
</search-item>
<search-item label="提案单位">
<el-select clearable filterable placeholder="提案单位" v-model="pageForm.unitId">
<el-option :key="item.id" :label="item.name" :value="item.id"
v-for="item in unitOptions"></el-option>
</el-select>
</search-item>
<search-item label="提案类别">
<el-select clearable filterable multiple placeholder="提案类别" v-model="pageForm.typeIds">
<el-option :key="item.id" :label="item.name" :value="item.id"
v-for="item in typeOptions"></el-option>
</el-select>
</search-item>
<search-item label="立案结果">
<el-select clearable filterable multiple placeholder="立案结果"
v-model="pageForm.caseFilingResults">
<el-option :key="item.code" :label="item.label" :value="item.code"
v-for="item in dict.type.PROPOSAL_CASE_FILING_RESULT"></el-option>
</el-select>
</search-item>
<search-item label="征集阶段">
<el-select v-model="pageForm.collectIds" clearable multiple filterable>
<el-option :key="item.id" :label="item.name" :value="item.id"
v-for="item in collectOptions"></el-option>
</el-select>
</search-item>
</search>
</el-card>
<el-card shadow="never">
<table-tool :columns="tableColumns" @update:columns="handleTableColumnsChange">
<el-button type="primary" size="small" @click="exportCustomAsExcel">自定义导出</el-button>
</table-tool>
<el-table v-loading="tableLoading" :data="tableData" :key="tableKey" ref="tableRef" @sort-change="pageOrder"
header-align="center" style="width: 100%" row-key="id">
<el-table-column label="序号" width="50" type="index" :index="indexMethod"></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:key="column.prop"
:min-width="column.width"
:fixed="column.fixed"
sortable="custom"
show-overflow-tooltip
v-for="column in tableColumns"
v-if="column.visible !== false"
>
<template v-if="column.prop === 'instanceState'" 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="100px">
<template scope="{row}">
<el-button size="mini" type="primary" @click="openView(row)">查看</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<template #view>
<proposal-info ref="infoRef"></proposal-info>
</template>
</guava>
</div>
<script nonce="${cspNonce!}">
<!--#include("../../common/info.js"){}#-->
new Vue({
el: "#app",
dicts: ["PROPOSAL_TYPE", "PROPOSAL_CASE_FILING_RESULT", "PROPOSAL_CASE_FILING_TYPE"],
store,
mixins: [initTableMixins],
components: {
"proposal-info": PROPOSAL_INFO
},
data() {
return {
tableColumns: [
{label: "提案编号", prop: "code"},
{label: "立案编号", prop: "caseFilingCode"},
{label: "提案名称", prop: "name", width: "200px"},
{label: "提案人", prop: "createUserName"},
{label: "代表团", prop: "delegationName"},
{label: "邀请附议人数", prop: "inviteCount"},
{label: "已附议人数", prop: "finishCount"},
{label: "当前节点", prop: "curTaskName"},
{label: "流程状态", prop: "instanceState"}
],
sessionOptions: [],
collectOptions: [],
typeOptions: [],
delegationOptions: [],
underTakeOptions: [],
unionOptions: [],
unitOptions: [],
pageForm: {
proposalSearchField: "name",
proposalKeyword: "",
typeIds: [],
caseFilingResults: [],
unionId: null,
unitId: null,
collectIds: []
}
}
},
methods: {
/** 应用列设置后重新计算表格布局,保证右侧固定操作列保持可见。 */
handleTableColumnsChange(columns) {
this.$set(this, "tableColumns", columns)
this.$set(this, "tableKey", new Date().getTime())
this.$nextTick(() => {
if (this.$refs.tableRef) {
this.$refs.tableRef.doLayout()
}
})
},
/** 按当前筛选条件和可见字段顺序导出全部征集进度数据。 */
exportCustomAsExcel() {
var exportColumns = this.tableColumns.filter((item) => item.visible !== false)
if (!exportColumns.length) {
this.$message.warning("请至少选择一个导出字段")
return
}
this.$downLoad(loc() + "/exportCustomAsExcel", {
pageForm: JSON.stringify(this.pageForm),
tableColumns: JSON.stringify(exportColumns)
})
},
openView(row) {
this.$refs.guava.view(() => {
this.$refs.infoRef.onOpen(row)
})
},
listCollectState() {
this.$axios.post("/platform/proposal/query/collectProgress/collectState").then((res) => {
if (res.code === 0) {
this.collectOptions = res.data
}
})
},
listProposalType() {
this.$axios.post("/platform/proposal/common/listProposalType").then((res) => {
if (res.code === 0) {
this.typeOptions = res.data
}
})
},
async meetingChange(val) {
this.pageForm.delegationId = null
this.listDelegation()
},
listDelegation() {
this.$axios.post("/platform/proposal/common/listDelegation", {sessionId: this.pageForm.sessionId}).then((res) => {
if (res.code === 0) {
this.delegationOptions = res.data
}
})
},
listSession() {
this.$axios.post("/platform/proposal/common/listSession").then((res) => {
if (res.code === 0) {
this.sessionOptions = res.data
if (this.sessionOptions) {
this.$set(this.pageForm, "sessionId", this.sessionOptions[0].id)
this.listDelegation()
this.pageData()
}
}
})
},
listUnion() {
this.$businessTool.listUnion().then((res) => (this.unionOptions = res))
},
listUnit() {
this.$businessTool.listUnit(this.pageForm.unionId).then((res) => (this.unitOptions = res))
},
pageData() {
// 自定义查询覆盖了公共 mixin,请求期间手动维护表格加载状态。
this.$set(this, "tableLoading", true)
this.$axios
.post(loc() + "/pageData", {
pageForm: JSON.stringify(this.pageForm)
})
.then((res) => {
if (res.code === 0) {
this.tableData = res.data.list
this.pageForm.totalCount = res.data.totalCount
}
})
.finally(() => {
this.$set(this, "tableLoading", false)
})
}
},
created() {
this.listSession()
this.listUnion()
this.listUnit()
this.listProposalType()
this.listCollectState()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,470 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style>
.el-tag {
cursor: pointer;
}
.search-container {
display: flex;
align-items: center;
min-height: 50px;
border-bottom: 1px solid #ddd;
padding: 12px 0;
margin-bottom: 0;
}
.search-label {
width: 90px;
margin-right: 10px;
font-weight: normal;
color: #333;
font-size: 14px;
}
.search-content {
flex: 1;
display: flex;
gap: 5px;
}
.custom-search-box {
display: flex;
align-items: center;
width: 100%;
background: #ffffff;
border: 1px solid #ccc;
border-radius: 3px;
}
.custom-search-box:hover {
border-color: #999;
}
.custom-search-box:focus-within {
border-color: #4a90e2;
box-shadow: 0 0 3px rgba(74, 144, 226, 0.3);
}
.search-input {
flex: 1;
height: 35px;
padding: 0 10px;
border: none;
outline: none;
font-size: 14px;
color: #333;
background: transparent;
font-family: inherit;
width: 100%;
}
.search-input::placeholder {
color: #999;
}
.filter-row {
display: flex;
align-items: center;
min-height: 50px;
border-bottom: 1px dashed rgb(230, 230, 230);
}
.filter-label {
width: 90px;
margin-right: 10px;
}
.filter-tags {
flex: 1;
display: flex;
gap: 5px;
}
</style>
<div id="app" v-cloak>
<guava ref="guava">
<el-card shadow="never">
<!-- 万能搜索框 -->
<div class="search-container">
<div class="search-label">万能搜索</div>
<div class="search-content">
<div class="custom-search-box">
<input
type="text"
v-model="pageForm.commonKeyword"
placeholder="请输入关键词进行搜索"
class="search-input"
@keyup.enter="doSearch"
/>
</div>
</div>
</div>
<div class="filter-row">
<div class="filter-label">搜索来源</div>
<div class="filter-tags">
<el-tag
v-for="item in origins"
:key="item.value"
:effect="pageForm.origins && pageForm.origins.includes(item.value) ? 'dark':'plain'"
@click="tagToggle('origins',item.value)"
>
{{ item.label }}
</el-tag>
</div>
</div>
<div class="filter-row">
<div class="filter-label">届次</div>
<div class="filter-tags">
<el-tag
v-for="item in sessionOptions"
:key="item.id"
:effect="pageForm.sessionIds && pageForm.sessionIds.includes(item.id) ? 'dark':'plain'"
@click="tagToggle('sessionIds',item.id)"
>
{{ item.fullName }}
</el-tag>
</div>
</div>
<div class="filter-row">
<div class="filter-label">提案类别</div>
<div class="filter-tags">
<el-tag
v-for="item in typeOptions"
:key="item.code"
:effect="pageForm.typeIds && pageForm.typeIds.includes(item.id) ? 'dark':'plain'"
@click="tagToggle('typeIds',item.id)"
>
{{ item.name }}
</el-tag>
</div>
</div>
<div class="filter-row">
<div class="filter-label">立案结果</div>
<div class="filter-tags">
<el-tag
v-for="item in dict.type.PROPOSAL_CASE_FILING_RESULT"
:key="item.code"
:effect="pageForm.caseFilingResults && pageForm.caseFilingResults.includes(item.code) ? 'dark':'plain'"
@click="tagToggle('caseFilingResults',item.code)"
>
{{ item.label }}
</el-tag>
</div>
</div>
<!-- <div class="filter-row">
<div class="filter-label">立案类型</div>
<div class="filter-tags">
<el-tag
v-for="item in dict.type.PROPOSAL_CASE_FILING_TYPE"
:key="item.code"
:effect="pageForm.caseFilingTypes && pageForm.caseFilingTypes.includes(item.code) ? 'dark':'plain'"
@click="tagToggle('caseFilingTypes',item.code)"
>
{{ item.label }}
</el-tag>
</div>
</div>-->
<search @search="doSearch" class="mt10">
<search-item label="代表团">
<el-select clearable filterable placeholder="请选择所属代表团" v-model="pageForm.delegationId">
<el-option :key="item.id" :label="item.name" :value="item.id"
v-for="item in delegationOptions"></el-option>
</el-select>
</search-item>
<search-item label="所属工会">
<el-select clearable filterable placeholder="请选择所属工会" v-model="pageForm.unionId"
@change="pageForm.unitId=null;listUnit();">
<el-option :key="item.id" :label="item.name" :value="item.id"
v-for="item in unionOptions"></el-option>
</el-select>
</search-item>
<search-item label="所属单位">
<el-select clearable filterable placeholder="请选择所属单位" v-model="pageForm.unitId">
<el-option :key="item.id" :label="item.name" :value="item.id"
v-for="item in unitOptions"></el-option>
</el-select>
</search-item>
</search>
</el-card>
<el-card shadow="never">
<table-tool :columns="tableColumns" @update:columns="handleTableColumnsChange">
<el-button type="primary" size="small" @click="exportCustomAsExcel">自定义导出</el-button>
</table-tool>
<el-table :data="tableData" :key="tableKey" @sort-change="pageOrder" header-align="center" ref="tableRef"
v-loading="tableLoading"
style="width: 100%" row-key="id">
<el-table-column label="序号" width="50" type="index" :index="indexMethod"></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:key="column.prop"
:min-width="column.width"
:fixed="column.fixed"
sortable="custom"
show-overflow-tooltip
v-for="column in tableColumns"
v-if="column.visible !== false"
>
<template v-if="column.prop === 'caseFilingResult'" scope="{row}">
<dict-tag :options="dict.type.PROPOSAL_CASE_FILING_RESULT"
:value="row.caseFilingResult"></dict-tag>
</template>
<!-- 立案类型在数据库中保存字典编码,列表统一转换为中文名称展示。 -->
<template v-else-if="column.prop === 'caseFilingType'" scope="{row}">
<dict-tag :options="dict.type.PROPOSAL_CASE_FILING_TYPE"
:value="row.caseFilingType"></dict-tag>
</template>
<template v-else-if="column.prop === 'merge'" scope="{row}">
<el-tag v-if="row.merge" size="small"></el-tag>
<el-tag v-else type="warning" size="small"></el-tag>
</template>
<template v-else-if="column.prop === 'instanceState'" scope="{row}">
<enum-tag :value="row.instanceState" name="ProcessInstanceStateEnum" label_key="message"
size="small"></enum-tag>
</template>
<template v-else-if="column.prop === 'undertakeUnits'" scope="{row}">
{{ getUndertakeDisplay(row) }}
</template>
</el-table-column>
<el-table-column label="操作" fixed="right" width="200px">
<template scope="{row}">
<el-button size="mini" type="primary" @click="openView(row)">查看</el-button>
<el-button size="mini" type="primary" @click="exportDocx(row.id)">导出</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<template #view>
<proposal-info ref="infoRef"></proposal-info>
</template>
</guava>
</div>
<script nonce="${cspNonce!}">
<!--#include("../../common/info.js"){}#-->
const vue = new Vue({
el: "#app",
dicts: ["PROPOSAL_TYPE", "PROPOSAL_CASE_FILING_RESULT", "PROPOSAL_CASE_FILING_TYPE"],
store,
mixins: [initTableMixins],
components: {
"proposal-info": PROPOSAL_INFO
},
data() {
return {
tableColumns: [
{label: "提案编号", prop: "code"},
{label: "立案编号", prop: "caseFilingCode"},
{label: "提案名称", prop: "name", width: "200px"},
{label: "提案人", prop: "createUserName"},
{label: "提案类别", prop: "typeName"},
{label: "代表团", prop: "delegationName"},
{label: "立案结果", prop: "caseFilingResult"},
// {label: "立案类型", prop: "caseFilingType"},
{label: "是否并案", prop: "merge"},
{label: "承办单位", prop: "undertakeUnits", width: "260px"},
{label: "当前节点", prop: "curTaskName"},
{label: "流程状态", prop: "instanceState"}
],
sessionOptions: [],
typeOptions: [],
delegationOptions: [],
underTakeOptions: [],
unionOptions: [],
unitOptions: [],
pageForm: {
origins: [],
sessionIds: [],
typeIds: [],
caseFilingResults: [],
caseFilingTypes: [],
unionId: null,
unitId: null
},
origins: [
{
label: '提案名称',
value: 'name'
},
{
label: '案由',
value: 'brief'
},
{
label: '答复内容',
value: 'answer'
},
{
label: '提案人',
value: 'createUserName'
},
{
label: '立案编号',
value: 'caseFilingCode'
}
]
}
},
methods: {
/**
* 应用列设置后重建表格并重新计算固定列布局,
* 避免动态隐藏字段后右侧操作列继续使用旧宽度而被裁切。
*/
handleTableColumnsChange(columns) {
this.$set(this, "tableColumns", columns)
this.$set(this, "tableKey", new Date().getTime())
this.$nextTick(() => {
if (this.$refs.tableRef) {
this.$refs.tableRef.doLayout()
}
})
},
/**
* 查询列表按立案结果切换承办单位展示口径:
* 立案显示“主办/协办”,作为建议只显示“承办单位”。
*/
getUndertakeDisplay(row) {
var masterUnitNames = this.formatUnitNames(row.masterUnitName)
var slaveUnitNames = this.formatUnitNames(row.slaveUnitNames)
if (row.caseFilingResult === "SUGGESTION") {
return masterUnitNames || slaveUnitNames
}
if (row.caseFilingResult === "CONFIRM_FILING") {
return [masterUnitNames ? "主办:" + masterUnitNames : "", slaveUnitNames ? "协办:" + slaveUnitNames : ""].filter(function(item) {
return item
}).join("")
}
return ""
},
formatUnitNames(unitNames) {
if (!unitNames) {
return ""
}
if (Array.isArray(unitNames)) {
return unitNames.filter(function(item) {
return item
}).join("")
}
return unitNames
},
openView(row) {
this.$refs.guava.view(() => {
this.$refs.infoRef.onOpen(row)
})
},
exportDocx(id) {
this.$downLoad("/platform/proposal/common/exportProposalAsDocx", {id})
},
/**
* 按列设置中当前可见的字段顺序导出全部筛选结果;
* 未选择任何数据列时不发起下载,避免生成无表头文件。
*/
exportCustomAsExcel() {
var exportColumns = this.tableColumns.filter((item) => item.visible !== false)
if (!exportColumns.length) {
this.$message.warning("请至少选择一个导出字段")
return
}
this.$downLoad(loc() + "/exportCustomAsExcel", {
pageForm: JSON.stringify(this.pageForm),
tableColumns: JSON.stringify(exportColumns)
})
},
tagToggle(key, val) {
if (this.pageForm[key].includes(val)) {
this.pageForm[key].splice(this.pageForm[key].indexOf(val), 1)
} else {
this.pageForm[key].push(val)
}
this.doSearch()
},
listProposalType() {
this.$axios.post("/platform/proposal/common/listProposalType").then((res) => {
if (res.code === 0) {
this.typeOptions = res.data
}
})
},
async meetingChange(val) {
this.pageForm.delegationId = null
this.listDelegation()
},
listDelegation() {
this.$axios.post("/platform/proposal/common/listDelegation", {sessionId: this.pageForm.sessionId}).then((res) => {
if (res.code === 0) {
this.delegationOptions = res.data
}
})
},
listSession() {
this.$axios.post("/platform/proposal/common/listSession", {
orderBy: "desc"
}).then((res) => {
if (res.code === 0) {
this.sessionOptions = res.data
if (this.sessionOptions && this.sessionOptions.length > 0) {
// 届次按开始时间倒序返回,首项作为页面默认选中的最新一届。
this.$set(this.pageForm, "sessionId", this.sessionOptions[0].id)
this.$set(this.pageForm, "sessionIds", [this.sessionOptions[0].id])
this.listDelegation()
this.pageData()
}
}
})
},
listUnderTake() {
this.$axios.post("/platform/proposal/common/listUnderTake").then((res) => {
if (res.code === 0) {
this.underTakeOptions = res.data
}
})
},
listUnion() {
this.$businessTool.listUnion().then((res) => (this.unionOptions = res))
},
listUnit() {
this.$businessTool.listUnit(this.pageForm.unionId).then((res) => (this.unitOptions = res))
},
pageData() {
this.tableLoading = true
this.$axios
.post(loc() + "/pageData", {
pageForm: JSON.stringify(this.pageForm)
})
.then((res) => {
if (res.code === 0) {
this.tableData = res.data.list
this.pageForm.totalCount = res.data.totalCount
}
})
.finally(() => {
// 无论查询成功或异常都结束加载状态,避免列表持续显示加载动画
this.tableLoading = false
})
}
},
created() {
this.listSession()
this.listUnderTake()
this.listUnion()
this.listUnit()
this.listProposalType()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,208 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app">
<guava ref="guava">
<template>
<el-card shadow="never">
<el-row type="flex" justify="center">
<el-select @change="doSearch" clearable filterable placeholder="所属教代会" v-model="sessionId" style="width: 100%">
<el-option :key="item.id" :label="item.fullName" :value="item.id" v-for="item in sessionOptions"></el-option>
</el-select>
</el-row>
</el-card>
<el-card shadow="never" class="mt10">
<table-tool label="代表团列表" :columns="tableColumns" @update:columns="handleTableColumnsChange">
<el-button type="primary" size="small" @click="exportCustomAsExcel">自定义导出</el-button>
</table-tool>
<el-table v-loading="tableLoading" :data="tableData" :key="tableKey" ref="tableRef" header-align="center" style="width: 100%" row-key="id"
show-summary @sort-change="pageOrder">
<el-table-column
:index="indexMethod"
label="序号"
type="index"
width="80px"
fixed="left"
></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:key="column.prop"
:min-width="column.width"
:fixed="column.fixed"
sortable="custom"
show-overflow-tooltip
v-for="column in tableColumns"
v-if="column.visible !== false"
>
<template scope="{row}" v-if="column.prop=='dbtName'">
<el-link @click="openView(row)" type="primary">{{row.dbtName}}</el-link>
</template>
<template scope="{row}" v-else-if="column.prop=='caseRate'">
<span v-if="!isNaN(row.CONFIRM_FILING) && !isNaN(row.TOTAL) && row.TOTAL > 0">
{{ ((row.CONFIRM_FILING / row.TOTAL) * 100).toFixed(2) }}%
</span>
</template>
</el-table-column>
</el-table>
</el-card>
</template>
</guava>
<el-dialog :title="dialogTitle" :visible.sync="delegationVisible" width="70%" :close-on-click-modal="false">
<proposal-table
:delegation-id="delegationId"
:session-id="sessionId"
@view-single-proposal="viewSingleProposal"
ref="proposalTable"
></proposal-table>
</el-dialog>
<el-dialog title="提案详情" :visible.sync="proposalInfoVisible" width="1200px" append-to-body top="5vh">
<div style="max-height: 80vh; overflow-y: auto">
<proposal-info ref="infoRef"></proposal-info>
</div>
</el-dialog>
</div>
<!-- 提案明细组件模板独立放在页面中,避免在JavaScript中使用模板字符串。 -->
<script type="text/x-template" id="proposal-table-template" nonce="${cspNonce!}">
<div>
<el-table v-loading="tableLoading" :data="tableData" ref="tableRef" header-align="center" style="width: 100%" row-key="id"
@sort-change="pageOrder">
<el-table-column label="序号" width="50px" type="index" :index="indexMethod"></el-table-column>
<el-table-column label="提案编号" prop="code" sortable="custom" width="200px"></el-table-column>
<el-table-column label="提案名称" prop="name" sortable="custom"></el-table-column>
<el-table-column label="提案人" prop="createUserName" sortable="custom"></el-table-column>
<el-table-column label="提案类别" prop="typeName" sortable="custom"></el-table-column>
<el-table-column label="届次" prop="sessionName" sortable="custom"></el-table-column>
<el-table-column label="代表团" prop="delegationName" sortable="custom"></el-table-column>
<el-table-column label="当前节点" prop="curTaskName" sortable="custom"></el-table-column>
<el-table-column label="操作" fixed="right" width="100px">
<template scope="{row}">
<el-button size="mini" type="primary" @click="$emit('view-single-proposal',row)">查看</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</div>
</script>
<script nonce="${cspNonce!}">
<!--#include("proposalTable.js"){}#-->
<!--#include("../../common/info.js"){}#-->
new Vue({
el: "#app",
mixins: [initTableMixins],
data() {
return {
sessionId: "",
sessionOptions: [],
tableColumns: [
{ label: "代表团名称", prop: "dbtName" },
{ label: "提案总数", prop: "TOTAL" },
],
delegationId: "",
dialogTitle: "",
delegationVisible: false,
proposalInfoVisible: false
}
},
components: {
"proposal-table": PROPOSAL_TABLE,
"proposal-info": PROPOSAL_INFO
},
methods: {
/** 应用列设置后重建表格,保证动态统计列宽和固定区域及时更新。 */
handleTableColumnsChange(columns) {
this.$set(this, "tableColumns", columns)
this.$set(this, "tableKey", new Date().getTime())
this.$nextTick(() => {
if (this.$refs.tableRef) {
this.$refs.tableRef.doLayout()
}
})
},
/** 按当前届次、排序条件和可见字段导出全部代表团统计。 */
exportCustomAsExcel() {
var exportColumns = this.tableColumns.filter((item) => item.visible !== false)
if (!exportColumns.length) {
this.$message.warning("请至少选择一个导出字段")
return
}
this.$downLoad(loc() + "/exportCustomAsExcel", {
pageForm: JSON.stringify(this.pageForm),
sessionId: this.sessionId,
tableColumns: JSON.stringify(exportColumns)
})
},
openView(row) {
this.delegationId = row.id
this.dialogTitle = row.dbtName + "所属提案"
this.delegationVisible = true
this.$nextTick(() => {
this.$refs.proposalTable.pageData()
})
},
viewSingleProposal(row) {
this.proposalInfoVisible = true
this.$nextTick(() => {
this.$refs.infoRef.onOpen(row)
})
},
listSession() {
this.$axios.post("/platform/proposal/common/listSession").then((res) => {
if (res.code === 0) {
this.sessionOptions = res.data
if (this.sessionOptions) {
this.$set(this, "sessionId", this.sessionOptions[0].id)
this.pageData()
}
}
})
},
setTableColumnsByProposalResult() {
this.$businessTool.getDictOptions("PROPOSAL_CASE_FILING_RESULT").then((data) => {
var columns = this.tableColumns.filter((column) => ["dbtName", "TOTAL"].includes(column.prop))
data.forEach((item) => {
columns.push({
label: item.name,
prop: item.code
})
})
columns.push({
label: "立案率",
prop: "caseRate"
})
this.$set(this, "tableColumns", columns)
})
},
pageData() {
// 代表团统计为自定义查询,请求结束后统一关闭表格加载状态。
this.$set(this, "tableLoading", true)
this.$axios
.post(loc() + "/pageData", {
sessionId: this.sessionId,
pageOrderName: this.pageForm.pageOrderName,
pageOrderBy: this.pageForm.pageOrderBy
})
.then((res) => {
if (res.code === 0) {
this.tableData = res.data
}
})
.finally(() => {
this.$set(this, "tableLoading", false)
})
}
},
created() {
this.listSession()
this.setTableColumnsByProposalResult()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,36 @@
const PROPOSAL_TABLE = {
// 组件模板由页面中的text/x-template节点提供,避免使用JavaScript模板字符串。
template: "#proposal-table-template",
props: {
sessionId: {
type: String,
required: true
},
delegationId: {
type: String,
required: true
}
},
mixins: [initTableMixins],
data() {
return {
pageForm: {}
}
},
methods: {
pageData() {
this.pageForm.sessionId = this.sessionId
this.pageForm.delegationId = this.delegationId
// 弹窗明细表使用组件自身的加载状态,不影响外层代表团统计表。
this.$set(this, "tableLoading", true)
this.$axios.post("/platform/proposal/query/delegation/getProposalsByDelegation", this.pageForm).then((res) => {
if (res.code === 0) {
this.tableData = res.data.list
this.pageForm.totalCount = res.data.totalCount
}
}).finally(() => {
this.$set(this, "tableLoading", false)
})
}
}
}
@@ -0,0 +1,293 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style>
.el-tag {
cursor: pointer;
}
</style>
<div id="app" v-cloak>
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="教代会">
<el-select @change="meetingChange" clearable filterable placeholder="所属教代会" v-model="pageForm.sessionId">
<el-option :key="item.id" :label="item.fullName" :value="item.id" v-for="item in sessionOptions"></el-option>
</el-select>
</search-item>
<search-item label="提案名称">
<el-input
@keyup.enter.native="doSearch"
clearable
placeholder="请输入提案名称"
v-model="pageForm.name"
style="width: 100%"
></el-input>
</search-item>
<search-item label="提案编号">
<el-input
@keyup.enter.native="doSearch"
clearable
placeholder="请输入提案编号"
v-model="pageForm.code"
style="width: 100%"
></el-input>
</search-item>
<search-item label="提案人姓名">
<el-input
@keyup.enter.native="doSearch"
clearable
placeholder="请输入提案人姓名"
v-model="pageForm.createUserName"
style="width: 100%"
></el-input>
</search-item>
<search-item label="提案人工号">
<el-input
@keyup.enter.native="doSearch"
clearable
placeholder="请输入提案人工号"
v-model="pageForm.createUserLoginName"
style="width: 100%"
></el-input>
</search-item>
<search-item label="代表团">
<el-select clearable filterable placeholder="所属代表团" v-model="pageForm.delegationId">
<el-option :key="item.id" :label="item.name" :value="item.id" v-for="item in delegationOptions"></el-option>
</el-select>
</search-item>
<search-item label="提案分工会">
<el-select clearable filterable placeholder="分工会" v-model="pageForm.unionId" @change="pageForm.unitId=null;listUnit();">
<el-option :key="item.id" :label="item.name" :value="item.id" v-for="item in unionOptions"></el-option>
</el-select>
</search-item>
<search-item label="提案单位">
<el-select clearable filterable placeholder="提案单位" v-model="pageForm.unitId">
<el-option :key="item.id" :label="item.name" :value="item.id" v-for="item in unitOptions"></el-option>
</el-select>
</search-item>
<search-item label="提案类别">
<el-select clearable filterable multiple placeholder="提案类别" v-model="pageForm.typeIds">
<el-option :key="item.id" :label="item.name" :value="item.id" v-for="item in typeOptions"></el-option>
</el-select>
</search-item>
<search-item label="立案结果">
<el-select clearable filterable multiple placeholder="立案结果" v-model="pageForm.caseFilingResults">
<el-option :key="item.code" :label="item.label" :value="item.code" v-for="item in dict.type.PROPOSAL_CASE_FILING_RESULT"></el-option>
</el-select>
</search-item>
<search-item label="立案类型">
<el-select clearable filterable multiple placeholder="立案类型" v-model="pageForm.caseFilingTypes">
<el-option :key="item.code" :label="item.label" :value="item.code" v-for="item in dict.type.PROPOSAL_CASE_FILING_TYPE"></el-option>
</el-select>
</search-item>
<!-- <search-item label="承办单位">-->
<!-- <el-select clearable filterable placeholder="承办单位" v-model="pageForm.undertakeUnitId">-->
<!-- <el-option :key="item.code" :label="item.name" :value="item.code" v-for="item in underTakeOptions"></el-option>-->
<!-- </el-select>-->
<!-- </search-item>-->
</search>
</el-card>
<el-card shadow="never">
<table-tool></table-tool>
<el-table v-loading="tableLoading" :data="tableData" @sort-change="pageOrder" header-align="center" style="width: 100%" row-key="id">
<el-table-column label="序号" width="50" type="index" :index="indexMethod"></el-table-column>
<el-table-column label="提案编号" prop="code" width="120px" sortable="custom"></el-table-column>
<el-table-column label="提案名称" prop="name" sortable="custom" show-overflow-tooltip></el-table-column>
<el-table-column label="提案人" prop="createUserName" sortable="custom"></el-table-column>
<el-table-column label="届次" prop="sessionName" sortable="custom"></el-table-column>
<el-table-column label="代表团" prop="delegationName" sortable="custom"></el-table-column>
<el-table-column label="立案结果" prop="caseFilingResult" sortable="custom">
<template scope="{row}">
<dict-tag :options="dict.type.PROPOSAL_CASE_FILING_RESULT" :value="row.caseFilingResult"></dict-tag>
</template>
</el-table-column>
<el-table-column label="立案类型" prop="caseFilingType" sortable="custom">
<template scope="{row}">
<dict-tag :options="dict.type.PROPOSAL_CASE_FILING_TYPE"
:value="row.caseFilingType"></dict-tag>
</template>
</el-table-column>
<el-table-column label="是否并案" prop="merge" sortable="custom">
<template slot-scope="{row}">
<el-tag v-if="row.merge" size="small"></el-tag>
<el-tag v-else type="warning" size="small"></el-tag>
</template>
</el-table-column>
<el-table-column label="承办单位" prop="undertakeUnits" sortable="custom" show-overflow-tooltip>
<template slot-scope="{row}">
{{ getUndertakeDisplay(row) }}
</template>
</el-table-column>
<el-table-column prop="curTaskName" label="当前节点" sortable="custom"></el-table-column>
<el-table-column prop="instanceState" label="流程状态" sortable="custom">
<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="200px">
<template scope="{row}">
<el-button size="mini" type="primary" @click="openView(row)">查看</el-button>
<el-button size="mini" type="primary" @click="exportDocx(row.id)">导出</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<template #view>
<proposal-info ref="infoRef"></proposal-info>
</template>
</guava>
</div>
<script nonce="${cspNonce!}">
<!--#include("../../common/info.js"){}#-->
new Vue({
el: "#app",
dicts: ["PROPOSAL_TYPE", "PROPOSAL_CASE_FILING_RESULT", "PROPOSAL_CASE_FILING_TYPE"],
store,
mixins: [initTableMixins],
components: {
"proposal-info": PROPOSAL_INFO
},
data() {
return {
sessionOptions: [],
typeOptions: [],
delegationOptions: [],
underTakeOptions: [],
unionOptions: [],
unitOptions: [],
pageForm: {
typeIds: [],
caseFilingResults: [],
caseFilingTypes: [],
unionId: null,
unitId: null
}
}
},
methods: {
/**
* 历史查询里统一把承办单位合并成一列展示,
* 便于“确定立案”和“作为建议”两种口径同时查看。
*/
getUndertakeDisplay(row) {
var masterUnitNames = this.formatUnitNames(row.masterUnitName)
var slaveUnitNames = this.formatUnitNames(row.slaveUnitNames)
if (row.caseFilingResult === "SUGGESTION") {
return masterUnitNames || slaveUnitNames
}
if (row.caseFilingResult === "CONFIRM_FILING") {
return [masterUnitNames ? "主办:" + masterUnitNames : "", slaveUnitNames ? "协办:" + slaveUnitNames : ""].filter(function(item) {
return item
}).join("")
}
return ""
},
formatUnitNames(unitNames) {
if (!unitNames) {
return ""
}
if (Array.isArray(unitNames)) {
return unitNames.filter(function(item) {
return item
}).join("")
}
return unitNames
},
openView(row) {
this.$refs.guava.view(() => {
this.$refs.infoRef.onOpen(row)
})
},
exportDocx(id) {
this.$downLoad("/platform/proposal/common/exportProposalAsDocx", {id})
},
tagToggle(key, val) {
if (this.pageForm[key].includes(val)) {
this.pageForm[key].splice(this.pageForm[key].indexOf(val), 1)
} else {
this.pageForm[key].push(val)
}
this.doSearch()
},
listProposalType() {
this.$axios.post("/platform/proposal/common/listProposalType").then((res) => {
if (res.code === 0) {
this.typeOptions = res.data
}
})
},
async meetingChange(val) {
this.pageForm.delegationId = null
this.listDelegation()
},
listDelegation() {
this.$axios.post("/platform/proposal/common/listDelegation", { sessionId: this.pageForm.sessionId }).then((res) => {
if (res.code === 0) {
this.delegationOptions = res.data
}
})
},
listSession() {
this.$axios.post("/platform/proposal/common/listSession").then((res) => {
if (res.code === 0) {
this.sessionOptions = res.data
if (this.sessionOptions) {
this.$set(this.pageForm, "sessionId", this.sessionOptions[0].id)
this.listDelegation()
this.pageData()
}
}
})
},
listUnderTake() {
this.$axios.post("/platform/proposal/common/listUnderTake").then((res) => {
if (res.code === 0) {
this.underTakeOptions = res.data
}
})
},
listUnion() {
this.$businessTool.listUnion().then((res) => (this.unionOptions = res))
},
listUnit() {
this.$businessTool.listUnit(this.pageForm.unionId).then((res) => (this.unitOptions = res))
},
pageData() {
// 自定义查询覆盖了公共 mixin,请求期间手动维护表格加载状态。
this.$set(this, "tableLoading", true)
this.$axios
.post(loc() + "/pageData", {
pageForm: JSON.stringify(this.pageForm)
})
.then((res) => {
if (res.code === 0) {
this.tableData = res.data.list
this.pageForm.totalCount = res.data.totalCount
}
})
.finally(() => {
this.$set(this, "tableLoading", false)
})
}
},
created() {
this.listSession()
this.listUnderTake()
this.listUnion()
this.listUnit()
this.listProposalType()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,571 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style>
.plagiarism-check-container {
}
.search-section {
margin-bottom: 20px;
}
.settings-section {
margin-bottom: 20px;
}
.similarity-level {
display: flex;
align-items: center;
margin: 10px 0;
}
.similarity-level .level-label {
width: 100px;
font-weight: bold;
}
.similarity-high {
color: #f56c6c;
}
.similarity-medium {
color: #e6a23c;
}
.similarity-low {
color: var( --color-success);
}
.result-card {
margin-bottom: 15px;
border-left: 4px solid #ddd;
transition: all 0.3s;
}
.result-card.high-similarity {
border-left-color: #f56c6c;
background-color: #fef0f0;
}
.result-card.medium-similarity {
border-left-color: #e6a23c;
background-color: #fdf6ec;
}
.result-card.low-similarity {
border-left-color: #67c23a;
background-color: #f0f9ff;
}
.similarity-progress {
margin: 10px 0;
}
.similar-content {
background-color: #f5f7fa;
padding: 10px;
border-radius: 4px;
margin: 10px 0;
font-size: 14px;
line-height: 1.6;
}
.highlight {
background-color: #ffeb3b;
padding: 2px 4px;
border-radius: 2px;
}
.stats-card {
text-align: center;
padding: 20px;
}
.stats-number {
font-size: 24px;
font-weight: bold;
color: var(--color-primary);
}
.loading-container {
text-align: center;
padding: 50px;
}
.empty-result {
text-align: center;
padding: 50px;
color: #909399;
}
</style>
<div id="app" v-cloak>
<div class="plagiarism-check-container">
<!-- 搜索区域 -->
<el-card shadow="never" class="search-section">
<div slot="header">
<span style="font-weight: 600">📝 提案查重检测</span>
</div>
<el-row :gutter="20">
<el-col :span="16">
<el-input
v-model="searchForm.keywords"
placeholder="请输入要查重的关键字或提案内容..."
type="textarea"
:rows="3"
maxlength="500"
show-word-limit
@keyup.ctrl.enter.native="startPlagiarismCheck"
></el-input>
</el-col>
<el-col :span="8">
<div style="height: 100%; display: flex; flex-direction: column; justify-content: space-between;">
<el-button
type="primary"
size="medium"
:loading="checking"
@click="startPlagiarismCheck"
style="margin-bottom: 10px;"
>
<i class="el-icon-search"></i> 开始查重
</el-button>
<el-button
size="medium"
@click="clearSearch"
style="margin: 0"
>
<i class="el-icon-refresh-left"></i> 清空重置
</el-button>
</div>
</el-col>
</el-row>
</el-card>
<!-- 查重设置区域 -->
<el-card shadow="never" class="settings-section">
<div slot="header">
<span style="font-weight: 600">⚙️ 查重设置</span>
</div>
<el-row :gutter="20">
<el-col :span="6">
<div>
<label>教代会届次:</label>
<el-select
v-model="searchForm.sessionId"
placeholder="选择届次"
clearable
style="width: 100%; margin-top: 5px;"
>
<el-option label="全部届次" value=""></el-option>
<el-option
v-for="item in sessionOptions"
:key="item.id"
:label="item.fullName"
:value="item.id"
></el-option>
</el-select>
</div>
</el-col>
<el-col :span="6">
<div>
<label>相似度阈值:{{ searchForm.similarityThreshold }}%</label>
<el-slider
v-model="searchForm.similarityThreshold"
:min="10"
:max="90"
:step="5"
show-stops
style="margin-top: 15px;"
></el-slider>
</div>
</el-col>
<el-col :span="6">
<div>
<label>匹配范围:</label>
<el-select v-model="searchForm.matchScope" multiple clearable
style="width: 100%; margin-top: 5px;">
<el-option label="全部" value="all"></el-option>
<el-option label="案名" value="name"></el-option>
<el-option label="案由" value="brief"></el-option>
<el-option label="建议措施" value="measures"></el-option>
</el-select>
</div>
</el-col>
<el-col :span="6">
<div>
<label>提案类别:</label>
<el-select
v-model="searchForm.typeId"
placeholder="选择类别"
clearable
style="width: 100%; margin-top: 5px;"
>
<el-option label="全部类别" value=""></el-option>
<el-option
v-for="item in typeOptions"
:key="item.id"
:label="item.name"
:value="item.id"
></el-option>
</el-select>
</div>
</el-col>
</el-row>
</el-card>
<!-- 结果统计区域 -->
<el-card shadow="never" v-if="hasSearched && !checking">
<div slot="header">
<span>📊 查重结果统计</span>
</div>
<el-row :gutter="20">
<el-col :span="6">
<div class="stats-card">
<div class="stats-number">{{ totalResults }}</div>
<div>检测到相似提案</div>
</div>
</el-col>
<el-col :span="6">
<div class="stats-card">
<div class="stats-number similarity-high">{{ highSimilarityCount }}</div>
<div>高度相似 (≥80%)</div>
</div>
</el-col>
<el-col :span="6">
<div class="stats-card">
<div class="stats-number similarity-medium">{{ mediumSimilarityCount }}</div>
<div>中度相似 (60-79%)</div>
</div>
</el-col>
<el-col :span="6">
<div class="stats-card">
<div class="stats-number similarity-low">{{ lowSimilarityCount }}</div>
<div>低度相似 (10-59%)</div>
</div>
</el-col>
</el-row>
</el-card>
<!-- 加载状态 -->
<div v-if="checking" class="loading-container">
<el-icon class="is-loading"><i class="el-icon-loading"></i></el-icon>
<p>正在进行查重检测,请稍候...</p>
</div>
<!-- 查重结果展示区域 -->
<div v-if="hasSearched && !checking">
<el-card shadow="never" v-if="plagiarismResults.length === 0">
<div class="empty-result">
<i class="el-icon-document" style="font-size: 48px; color: #c0c4cc;"></i>
<p>未发现相似提案</p>
<p style="font-size: 14px; color: #909399;">您可以尝试调整查重设置或更换关键词</p>
</div>
</el-card>
<div v-else>
<!-- 结果操作工具栏 -->
<el-card shadow="never" style="margin-bottom: 20px;">
<el-row>
<el-col :span="12">
<span style="font-weight: bold;">共找到 {{ plagiarismResults.length }} 个相似提案</span>
</el-col>
<el-col :span="12" style="text-align: right;">
<el-button-group>
<el-button size="mini" @click="sortResults('similarity')">
<i class="el-icon-sort"></i> 按相似度排序
</el-button>
<el-button size="mini" @click="sortResults('time')">
<i class="el-icon-time"></i> 按时间排序
</el-button>
</el-button-group>
</el-col>
</el-row>
</el-card>
<!-- 结果筛选 -->
<el-card shadow="never" style="margin-bottom: 20px;">
<div style="display: flex; align-items: center; gap: 20px;">
<span>快速筛选:</span>
<el-button-group>
<el-button
size="mini"
:type="resultFilter === 'all' ? 'primary' : ''"
@click="filterResults('all')"
>
全部 ({{ totalResults }})
</el-button>
<el-button
size="mini"
:type="resultFilter === 'high' ? 'danger' : ''"
@click="filterResults('high')"
>
高度相似 ({{ highSimilarityCount }})
</el-button>
<el-button
size="mini"
:type="resultFilter === 'medium' ? 'warning' : ''"
@click="filterResults('medium')"
>
中度相似 ({{ mediumSimilarityCount }})
</el-button>
<el-button
size="mini"
:type="resultFilter === 'low' ? 'success' : ''"
@click="filterResults('low')"
>
低度相似 ({{ lowSimilarityCount }})
</el-button>
</el-button-group>
</div>
</el-card>
<!-- 结果列表 -->
<el-card
v-for="(result, index) in filteredResults"
:key="index"
shadow="hover"
:class="['result-card', getSimilarityClass(result.similarity)]"
>
<div>
<el-row>
<el-col :span="18">
<h4 style="margin: 0 0 10px 0; color: #303133;">
{{ result.title }}
</h4>
<div style="margin-bottom: 10px;">
<el-tag size="mini" type="info">{{ result.sessionName }}</el-tag>
<el-tag size="mini" type="primary" style="margin-left: 5px;">{{ result.typeName }}
</el-tag>
<span style="margin-left: 10px; color: #909399; font-size: 12px;">
提案人: {{ result.createUserName }} | {{ result.createTime }}
</span>
</div>
</el-col>
<el-col :span="6" style="text-align: right;">
<div style="margin-bottom: 10px;">
<span :class="getSimilarityClass(result.similarity)"
style="font-size: 18px; font-weight: bold;">
{{ result.similarity }}%
</span>
</div>
<el-progress
:percentage="result.similarity"
:color="getSimilarityColor(result.similarity)"
:show-text="false"
class="similarity-progress"
></el-progress>
</el-col>
</el-row>
<div class="similar-content" v-if="result.similarContent">
<strong>相似内容片段:</strong>
<div v-html="highlightSimilarText(result.similarContent)"></div>
</div>
<div style="margin-top: 15px;">
<el-button size="mini" type="primary" @click="viewProposalDetail(result)">
<i class="el-icon-view"></i> 查看详情
</el-button>
</div>
</div>
</el-card>
</div>
</div>
</div>
<el-dialog title="提案详情" :visible.sync="viewDialogVisible" width="70%">
<proposal-info ref="infoRef"></proposal-info>
</el-dialog>
</div>
<script nonce="${cspNonce!}">
<!--#include("../../common/info.js"){}#-->
new Vue({
el: "#app",
dicts: ["PROPOSAL_TYPE", "PROPOSAL_CASE_FILING_RESULT"],
mixins: [initTableMixins],
components: {
"proposal-info": PROPOSAL_INFO
},
data() {
return {
checking: false,
hasSearched: false,
sessionOptions: [],
typeOptions: [],
searchForm: {
keywords: '',
sessionId: '',
similarityThreshold: 10,
matchScope: [],
typeId: ''
},
plagiarismResults: [],
resultFilter: 'all',
sortBy: 'similarity',
sortOrder: 'desc',
// 模拟数据,实际应从后端获取
mockResults: [],
viewDialogVisible: false,
}
},
computed: {
filteredResults() {
let results = [...this.plagiarismResults];
// 筛选
if (this.resultFilter !== 'all') {
results = results.filter(result => {
if (this.resultFilter === 'high') return result.similarity >= 80;
if (this.resultFilter === 'medium') return result.similarity >= 60 && result.similarity < 80;
if (this.resultFilter === 'low') return result.similarity < 60;
});
}
// 排序
results.sort((a, b) => {
let aValue, bValue;
if (this.sortBy === 'similarity') {
aValue = a.similarity;
bValue = b.similarity;
} else if (this.sortBy === 'time') {
aValue = new Date(a.createTime);
bValue = new Date(b.createTime);
}
if (this.sortOrder === 'desc') {
return bValue - aValue;
} else {
return aValue - bValue;
}
});
return results;
},
totalResults() {
return this.plagiarismResults.length;
},
highSimilarityCount() {
return this.plagiarismResults.filter(item => item.similarity >= 80).length;
},
mediumSimilarityCount() {
return this.plagiarismResults.filter(item => item.similarity >= 60 && item.similarity < 80).length;
},
lowSimilarityCount() {
return this.plagiarismResults.filter(item => item.similarity >= 10 && item.similarity < 60).length;
}
},
methods: {
startPlagiarismCheck() {
if (!this.searchForm.keywords.trim()) {
this.$message.warning('请输入要查重的关键字或内容');
return;
}
this.checking = true;
this.hasSearched = true;
this.$axios.post('/platform/proposal/query/plagiarismCheck/query', {
...this.searchForm,
matchScope: JSON.stringify(this.searchForm.matchScope)
}).then(res => {
if (res.code === 0) {
this.plagiarismResults = res.data;
if (this.plagiarismResults.length > 0) {
this.$message.success('查重完成,发现 ' + this.plagiarismResults.length + ' 个相似提案');
} else {
this.$message.info('查重完成,未发现相似提案');
}
}
}).finally(() => {
this.checking = false;
})
},
clearSearch() {
this.searchForm.keywords = '';
this.searchForm.sessionId = '';
this.searchForm.typeId = '';
this.searchForm.similarityThreshold = 60;
this.searchForm.matchScope = [];
this.plagiarismResults = [];
this.hasSearched = false;
},
getSimilarityClass(similarity) {
if (similarity >= 80) return 'high-similarity';
if (similarity >= 60) return 'medium-similarity';
return 'low-similarity';
},
getSimilarityColor(similarity) {
if (similarity >= 80) return '#f56c6c';
if (similarity >= 60) return '#e6a23c';
return '#67c23a';
},
//关键词高亮处理
highlightSimilarText(text) {
const keywords = this.searchForm.keywords.split(/\s+/).filter(k => k.trim());
let highlightedText = text;
keywords.forEach(keyword => {
const regex = new RegExp('(' + keyword + ')', 'gi');
highlightedText = highlightedText.replace(regex, '<span class="highlight">$1</span>');
});
return highlightedText;
},
// 排序功能
sortResults(type) {
if (this.sortBy === type) {
this.sortOrder = this.sortOrder === 'desc' ? 'asc' : 'desc';
} else {
this.sortBy = type;
this.sortOrder = 'desc';
}
},
// 筛选功能
filterResults(filter) {
this.resultFilter = filter;
},
// 查看提案详情功能
viewProposalDetail(result) {
this.viewDialogVisible = true;
this.$nextTick(() => {
this.$refs.infoRef.onOpen(result)
})
},
listSession() {
this.$axios.post("/platform/proposal/common/listSession").then((res) => {
if (res.code === 0) {
this.sessionOptions = res.data
}
})
},
listProposalType() {
this.$axios.post("/platform/proposal/common/listProposalType").then((res) => {
if (res.code === 0) {
this.typeOptions = res.data
}
})
}
},
created() {
this.listSession();
this.listProposalType();
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,166 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app" v-cloak>
<el-card shadow="never">
<search @search="doSearch">
<search-item label="教代会">
<el-select @change="meetingChange" clearable filterable placeholder="所属教代会" v-model="pageForm.sessionId">
<el-option :key="item.id" :label="item.fullName" :value="item.id" v-for="item in sessionOptions"></el-option>
</el-select>
</search-item>
<search-item label="承办单位">
<el-select clearable filterable placeholder="承办单位" v-model="pageForm.undertakeUnitId">
<el-option :key="item.code" :label="item.name" :value="item.id" v-for="item in underTakeOptions"></el-option>
</el-select>
</search-item>
<search-item label="立案结果">
<el-select clearable filterable placeholder="立案结果" v-model="pageForm.caseFilingResult">
<el-option :key="item.code" :label="item.label" :value="item.code" v-for="item in dict.type.PROPOSAL_CASE_FILING_RESULT"></el-option>
</el-select>
</search-item>
</search>
</el-card>
<el-card shadow="never">
<table-tool :columns="tableColumns" @update:columns="handleTableColumnsChange">
<el-button type="primary" size="small" @click="exportCustomAsExcel">自定义导出</el-button>
</table-tool>
<el-table v-loading="tableLoading" :data="tableData" :key="tableKey" ref="tableRef" @sort-change="pageOrder">
<el-table-column label="序号" type="index" width="50"></el-table-column>
<el-table-column v-for="column in normalTableColumns" :key="column.prop" :label="column.label"
:prop="column.prop" :width="column.width" sortable="custom"
show-overflow-tooltip></el-table-column>
<el-table-column label="主办提案" v-if="masterTableColumns.length">
<el-table-column v-for="column in masterTableColumns" :key="column.prop" :label="column.tableLabel"
:prop="column.prop" sortable="custom"></el-table-column>
</el-table-column>
<el-table-column label="协办提案" v-if="slaveTableColumns.length">
<el-table-column v-for="column in slaveTableColumns" :key="column.prop" :label="column.tableLabel"
:prop="column.prop" sortable="custom"></el-table-column>
</el-table-column>
</el-table>
</el-card>
</div>
<script nonce="${cspNonce!}">
<!--#include("../../common/info.js"){}#-->
new Vue({
el: "#app",
dicts: ["PROPOSAL_CASE_FILING_RESULT"],
mixins: [initTableMixins],
components: {
"proposal-info": PROPOSAL_INFO
},
data() {
return {
tableColumns: [
{label: "单位名称", prop: "unitName", width: "400"},
{label: "提案总数", prop: "sum"},
{label: "主办提案数量", tableLabel: "提案数量", prop: "masterSum", group: "master"},
{label: "主办已答复", tableLabel: "已答复", prop: "masterReplySum", group: "master"},
{label: "主办未答复", tableLabel: "未答复", prop: "masterNoReplySum", group: "master"},
{label: "协办提案数量", tableLabel: "提案数量", prop: "slaveSum", group: "slave"},
{label: "协办已答复", tableLabel: "已答复", prop: "slaveReplySum", group: "slave", slaveReply: true},
{label: "协办未答复", tableLabel: "未答复", prop: "slaveNoReplySum", group: "slave", slaveReply: true}
],
sessionOptions: [],
underTakeOptions: [],
slaveNeedReply: false
}
},
computed: {
normalTableColumns() {
return this.tableColumns.filter((column) => !column.group && column.visible !== false)
},
masterTableColumns() {
return this.tableColumns.filter((column) => column.group === "master" && column.visible !== false)
},
slaveTableColumns() {
return this.tableColumns.filter((column) => column.group === "slave" && column.visible !== false)
}
},
methods: {
/** 应用列设置后重新计算多级表头布局,避免隐藏子列后表头宽度残留。 */
handleTableColumnsChange(columns) {
this.$set(this, "tableColumns", columns)
this.$set(this, "tableKey", new Date().getTime())
this.$nextTick(() => {
if (this.$refs.tableRef) {
this.$refs.tableRef.doLayout()
}
})
},
/** 根据协办答复配置增减可选字段,避免页面和导出出现不可用列。 */
syncSlaveReplyColumns(slaveNeedReply) {
var columns = this.tableColumns.slice()
if (!slaveNeedReply) {
columns = columns.filter((column) => !column.slaveReply)
} else if (!columns.some((column) => column.slaveReply)) {
columns.push({label: "协办已答复", tableLabel: "已答复", prop: "slaveReplySum", group: "slave", slaveReply: true})
columns.push({label: "协办未答复", tableLabel: "未答复", prop: "slaveNoReplySum", group: "slave", slaveReply: true})
}
this.$set(this, "tableColumns", columns)
},
/** 按当前筛选条件和列设置导出承办单位办理统计。 */
exportCustomAsExcel() {
var exportColumns = this.tableColumns.filter((column) => column.visible !== false)
if (!exportColumns.length) {
this.$message.warning("请至少选择一个导出字段")
return
}
this.$downLoad(loc() + "/exportCustomAsExcel", {
pageForm: JSON.stringify(this.pageForm),
sessionId: this.pageForm.sessionId,
undertakeUnitId: this.pageForm.undertakeUnitId,
caseFilingResult: this.pageForm.caseFilingResult,
tableColumns: JSON.stringify(exportColumns)
})
},
meetingChange() {
this.doSearch()
},
listSession() {
this.$axios.post("/platform/proposal/common/listSession").then((res) => {
if (res.code === 0) {
this.sessionOptions = res.data
if (this.sessionOptions) {
this.$set(this.pageForm, "sessionId", this.sessionOptions[0].id)
this.pageData()
}
}
})
},
listUnderTake() {
this.$axios.post("/platform/proposal/common/listUnderTake").then((res) => {
if (res.code === 0) {
this.underTakeOptions = res.data
}
})
},
pageData() {
// 自定义统计查询执行期间显示表格加载动画,异常时也能正常关闭。
this.$set(this, "tableLoading", true)
this.$axios.post(loc() + "/data", this.pageForm).then((res) => {
if (res.code === 0) {
this.tableData = res.data.tableData
this.$set(this, "slaveNeedReply", res.data.slaveNeedReply)
this.syncSlaveReplyColumns(res.data.slaveNeedReply)
}
}).finally(() => {
this.$set(this, "tableLoading", false)
})
}
},
created() {
this.listSession()
this.listUnderTake()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,137 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app" v-cloak>
<el-card shadow="never">
<search @search="doSearch">
<search-item label="教代会">
<el-select @change="meetingChange" clearable filterable placeholder="所属教代会"
v-model="pageForm.sessionId">
<el-option :key="item.id" :label="item.fullName" :value="item.id"
v-for="item in sessionOptions"></el-option>
</el-select>
</search-item>
<search-item label="承办单位">
<el-select clearable filterable placeholder="承办单位" v-model="pageForm.undertakeUnitId">
<el-option :key="item.code" :label="item.name" :value="item.id"
v-for="item in underTakeOptions"></el-option>
</el-select>
</search-item>
</search>
</el-card>
<el-card shadow="never">
<table-tool :columns="tableColumns" @update:columns="handleTableColumnsChange">
<el-button type="primary" size="small" @click="exportCustomAsExcel">自定义导出</el-button>
</table-tool>
<el-table v-loading="tableLoading" :data="tableData" :key="tableKey" ref="tableRef" @sort-change="pageOrder">
<el-table-column label="序号" type="index" width="50"></el-table-column>
<el-table-column v-for="column in tableColumns" v-if="column.visible !== false" :key="column.prop"
:label="column.label" :prop="column.prop" :width="column.width"
sortable="custom" show-overflow-tooltip></el-table-column>
</el-table>
</el-card>
</div>
<script nonce="${cspNonce!}">
<!--#include("../../common/info.js"){}#-->
new Vue({
el: "#app",
mixins: [initTableMixins],
dicts: ['PROPOSAL_FEEDBACK'],
components: {
"proposal-info": PROPOSAL_INFO
},
data() {
return {
tableColumns: [
{label: "单位名称", prop: "unitName", width: "400"},
{label: "提案总数", prop: "sum"},
{label: "主办提案数", prop: "masterSum"},
{label: "协办提案数", prop: "slaveSum"}
],
sessionOptions: [],
underTakeOptions: [],
}
},
methods: {
/** 应用列设置后重新计算动态满意度列的表格布局。 */
handleTableColumnsChange(columns) {
this.$set(this, "tableColumns", columns)
this.$set(this, "tableKey", new Date().getTime())
this.$nextTick(() => {
if (this.$refs.tableRef) {
this.$refs.tableRef.doLayout()
}
})
},
/** 从后端字典生成满意度列,列设置与统计接口使用同一组字段编码。 */
setFeedbackTableColumns() {
this.$businessTool.getDictOptions("PROPOSAL_FEEDBACK").then((data) => {
var fixedColumns = this.tableColumns.filter((column) => ["unitName", "sum", "masterSum", "slaveSum"].includes(column.prop))
data.forEach((item) => {
fixedColumns.push({label: item.name, prop: item.code})
})
this.$set(this, "tableColumns", fixedColumns)
})
},
/** 按当前筛选条件和可见字段导出承办单位满意度统计。 */
exportCustomAsExcel() {
var exportColumns = this.tableColumns.filter((column) => column.visible !== false)
if (!exportColumns.length) {
this.$message.warning("请至少选择一个导出字段")
return
}
this.$downLoad(loc() + "/exportCustomAsExcel", {
pageForm: JSON.stringify(this.pageForm),
sessionId: this.pageForm.sessionId,
undertakeUnitId: this.pageForm.undertakeUnitId,
tableColumns: JSON.stringify(exportColumns)
})
},
meetingChange() {
this.doSearch()
},
listSession() {
this.$axios.post("/platform/proposal/common/listSession").then((res) => {
if (res.code === 0) {
this.sessionOptions = res.data
if (this.sessionOptions) {
this.$set(this.pageForm, "sessionId", this.sessionOptions[0].id)
this.pageData()
}
}
})
},
listUnderTake() {
this.$axios.post("/platform/proposal/common/listUnderTake").then((res) => {
if (res.code === 0) {
this.underTakeOptions = res.data
}
})
},
pageData() {
// 自定义统计查询执行期间显示表格加载动画,异常时也能正常关闭。
this.$set(this, "tableLoading", true)
this.$axios.post(loc() + "/data", this.pageForm).then((res) => {
if (res.code === 0) {
this.tableData = res.data
}
}).finally(() => {
this.$set(this, "tableLoading", false)
})
}
},
created() {
this.listSession()
this.listUnderTake()
this.setFeedbackTableColumns()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,263 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style>
.el-tag {
cursor: pointer;
}
</style>
<div id="app" v-cloak>
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="教代会">
<el-select @change="meetingChange" clearable filterable placeholder="所属教代会" v-model="pageForm.sessionId">
<el-option :key="item.id" :label="item.fullName" :value="item.id" v-for="item in sessionOptions"></el-option>
</el-select>
</search-item>
<search-item label="名称/编号">
<el-input @keyup.enter.native="doSearch" clearable placeholder="请输入内容"
v-model="pageForm.proposalKeyword">
<el-select slot="prepend" style="width: 110px" v-model="pageForm.proposalSearchField">
<el-option label="提案名称" value="name"></el-option>
<el-option label="提案编号" value="code"></el-option>
<el-option label="立案编号" value="caseFilingCode"></el-option>
</el-select>
</el-input>
</search-item>
<search-item label="姓名/工号">
<el-input @keyup.enter.native="doSearch" clearable placeholder="请输入姓名或工号"
v-model="pageForm.createUserKeyword"></el-input>
</search-item>
<search-item label="代表团">
<el-select clearable filterable placeholder="所属代表团" v-model="pageForm.delegationId">
<el-option :key="item.id" :label="item.name" :value="item.id" v-for="item in delegationOptions"></el-option>
</el-select>
</search-item>
<search-item label="提案分工会">
<el-select clearable filterable placeholder="分工会" v-model="pageForm.unionId" @change="pageForm.unitId=null;listUnit();">
<el-option :key="item.id" :label="item.name" :value="item.id" v-for="item in unionOptions"></el-option>
</el-select>
</search-item>
<search-item label="提案单位">
<el-select clearable filterable placeholder="提案单位" v-model="pageForm.unitId">
<el-option :key="item.id" :label="item.name" :value="item.id" v-for="item in unitOptions"></el-option>
</el-select>
</search-item>
<search-item label="承办单位">
<el-select clearable filterable placeholder="承办单位" v-model="pageForm.underTakeUnitId">
<el-option :key="item.code" :label="item.name" :value="item.code" v-for="item in underTakeOptions"></el-option>
</el-select>
</search-item>
<search-item label="提案类别">
<el-select clearable filterable multiple placeholder="提案类别" v-model="pageForm.typeIds">
<el-option :key="item.id" :label="item.name" :value="item.id" v-for="item in typeOptions"></el-option>
</el-select>
</search-item>
<search-item label="立案结果">
<el-select clearable filterable multiple placeholder="立案结果" v-model="pageForm.caseFilingResults">
<el-option :key="item.code" :label="item.label" :value="item.code" v-for="item in dict.type.PROPOSAL_CASE_FILING_RESULT"></el-option>
</el-select>
</search-item>
</search>
</el-card>
<el-card shadow="never">
<table-tool>
<el-button type="primary" size="small" @click="exportYearReport">导出提案报告</el-button>
</table-tool>
<el-table v-loading="tableLoading" :data="tableData" @sort-change="pageOrder" header-align="center" style="width: 100%" row-key="id">
<el-table-column label="序号" width="50" type="index" :index="indexMethod"></el-table-column>
<el-table-column label="提案编号" prop="code" sortable="custom" width="100px" show-overflow-tooltip></el-table-column>
<el-table-column label="立案编号" prop="caseFilingCode" sortable="custom" width="100px" show-overflow-tooltip></el-table-column>
<el-table-column label="提案名称" prop="name" sortable="custom" show-overflow-tooltip></el-table-column>
<el-table-column label="提案人" prop="createUserName" sortable="custom"></el-table-column>
<el-table-column label="提案类别" prop="typeName" sortable="custom"></el-table-column>
<el-table-column label="代表团" prop="delegationName" sortable="custom"></el-table-column>
<el-table-column label="立案结果" prop="caseFilingResult" sortable="custom">
<template scope="{row}">
<dict-tag :options="dict.type.PROPOSAL_CASE_FILING_RESULT" :value="row.caseFilingResult"></dict-tag>
</template>
</el-table-column>
<el-table-column label="是否并案" prop="isConsolidation" sortable="custom" width="100">
<template scope="{row}">
<el-tag size="mini" v-if="row.isConsolidation" type="success"></el-tag>
<el-tag size="mini" v-else type="danger"></el-tag>
</template>
</el-table-column>
<el-table-column label="承办单位" prop="undertakeUnits" sortable="custom" show-overflow-tooltip>
<template slot-scope="{row}">
{{ getUndertakeDisplay(row) }}
</template>
</el-table-column>
<el-table-column prop="curTaskName" label="当前节点" sortable="custom"></el-table-column>
<el-table-column prop="instanceState" label="流程状态" sortable="custom">
<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="200px">
<template scope="{row}">
<el-button size="mini" type="primary" @click="openView(row)">查看</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<template #view>
<proposal-info ref="infoRef"></proposal-info>
</template>
</guava>
</div>
<script nonce="${cspNonce!}">
<!--#include("../../common/info.js"){}#-->
new Vue({
el: "#app",
dicts: ["PROPOSAL_TYPE", "PROPOSAL_CASE_FILING_RESULT"],
store,
mixins: [initTableMixins],
components: {
"proposal-info": PROPOSAL_INFO
},
data() {
return {
sessionOptions: [],
typeOptions: [],
delegationOptions: [],
underTakeOptions: [],
unionOptions: [],
unitOptions: [],
pageForm: {
proposalSearchField: "name",
proposalKeyword: "",
typeIds: [],
caseFilingResults: [],
unionId: null,
unitId: null
}
}
},
methods: {
/**
* 年报查询列表里,把主办/协办与建议承办统一折叠成一个展示口径,
* 避免“作为建议”场景下仍显示主办/协办文案。
*/
getUndertakeDisplay(row) {
var masterUnitNames = this.formatUnitNames(row.masterUnitName)
var slaveUnitNames = this.formatUnitNames(row.slaveUnitNames)
if (row.caseFilingResult === "SUGGESTION") {
return masterUnitNames || slaveUnitNames
}
if (row.caseFilingResult === "CONFIRM_FILING") {
return [masterUnitNames ? "主办:" + masterUnitNames : "", slaveUnitNames ? "协办:" + slaveUnitNames : ""].filter(function(item) {
return item
}).join("")
}
return ""
},
formatUnitNames(unitNames) {
if (!unitNames) {
return ""
}
if (Array.isArray(unitNames)) {
return unitNames.filter(function(item) {
return item
}).join("")
}
return unitNames
},
openView(row) {
this.$refs.guava.view(() => {
this.$refs.infoRef.onOpen(row)
})
},
exportYearReport() {
this.$downLoad(loc() + "/exportYearReport", this.pageForm)
},
tagToggle(key, val) {
if (this.pageForm[key].includes(val)) {
this.pageForm[key].splice(this.pageForm[key].indexOf(val), 1)
} else {
this.pageForm[key].push(val)
}
this.doSearch()
},
listProposalType() {
this.$axios.post("/platform/proposal/common/listProposalType").then((res) => {
if (res.code === 0) {
this.typeOptions = res.data
}
})
},
async meetingChange(val) {
this.pageForm.delegationId = null
this.listDelegation()
},
listDelegation() {
this.$axios.post("/platform/proposal/common/listDelegation", { sessionId: this.pageForm.sessionId }).then((res) => {
if (res.code === 0) {
this.delegationOptions = res.data
}
})
},
listSession() {
this.$axios.post("/platform/proposal/common/listSession").then((res) => {
if (res.code === 0) {
this.sessionOptions = res.data
if (this.sessionOptions) {
this.$set(this.pageForm, "sessionId", this.sessionOptions[0].id)
this.listDelegation()
this.pageData()
}
}
})
},
listUnderTake() {
this.$axios.post("/platform/proposal/common/listUnderTake").then((res) => {
if (res.code === 0) {
this.underTakeOptions = res.data
}
})
},
listUnion() {
this.$businessTool.listUnion().then((res) => (this.unionOptions = res))
},
listUnit() {
this.$businessTool.listUnit(this.pageForm.unionId).then((res) => (this.unitOptions = res))
},
pageData() {
// 自定义查询覆盖了公共 mixin,请求期间手动维护表格加载状态。
this.$set(this, "tableLoading", true)
this.$axios
.post(loc() + "/pageData", {
pageForm: JSON.stringify(this.pageForm)
})
.then((res) => {
if (res.code === 0) {
this.tableData = res.data.list
this.pageForm.totalCount = res.data.totalCount
}
})
.finally(() => {
this.$set(this, "tableLoading", false)
})
}
},
created() {
this.listSession()
this.listUnderTake()
this.listUnion()
this.listUnit()
this.listProposalType()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,325 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style></style>
<div id="app" v-cloak>
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="教代会">
<el-select @change="meetingChange" clearable filterable placeholder="所属教代会"
v-model="pageForm.searchSessionId">
<el-option :key="item.id" :label="item.fullName" :value="item.id"
v-for="item in sessionOptions"></el-option>
</el-select>
</search-item>
<search-item label="名称/编号">
<el-input @keyup.enter.native="doSearch" clearable placeholder="请输入内容"
v-model="pageForm.proposalKeyword">
<el-select slot="prepend" style="width: 110px" v-model="pageForm.proposalSearchField">
<el-option label="提案名称" value="name"></el-option>
<el-option label="提案编号" value="code"></el-option>
<el-option label="立案编号" value="caseFilingCode"></el-option>
</el-select>
</el-input>
</search-item>
<search-item label="姓名/工号">
<el-input @keyup.enter.native="doSearch" clearable placeholder="请输入姓名或工号"
v-model="pageForm.createUserKeyword"></el-input>
</search-item>
<search-item label="代表团">
<el-select clearable filterable placeholder="所属代表团" v-model="pageForm.delegationId">
<el-option :key="item.id" :label="item.name" :value="item.id"
v-for="item in delegationOptions"></el-option>
</el-select>
</search-item>
<search-item label="提案分工会">
<el-select clearable filterable placeholder="分工会" v-model="pageForm.unionId"
@change="pageForm.unitId=null;listUnit();">
<el-option :key="item.id" :label="item.name" :value="item.id"
v-for="item in unionOptions"></el-option>
</el-select>
</search-item>
<search-item label="提案单位">
<el-select clearable filterable placeholder="提案单位" v-model="pageForm.unitId">
<el-option :key="item.id" :label="item.name" :value="item.id"
v-for="item in unitOptions"></el-option>
</el-select>
</search-item>
</search>
</el-card>
<el-card shadow="never">
<table-tool></table-tool>
<el-table v-loading="tableLoading" :data="tableData" @sort-change="pageOrder" header-align="center" style="width: 100%" row-key="id">
<el-table-column label="序号" width="50" type="index" :index="indexMethod"></el-table-column>
<el-table-column label="提案编号" prop="code" sortable="custom" width="100px" show-overflow-tooltip></el-table-column>
<el-table-column label="立案编号" prop="caseFilingCode" width="100px" show-overflow-tooltip></el-table-column>
<el-table-column label="提案名称" prop="name" sortable="custom" show-overflow-tooltip></el-table-column>
<el-table-column label="提案人" prop="createUserName" sortable="custom"></el-table-column>
<el-table-column label="提案类别" prop="typeName" sortable="custom"></el-table-column>
<el-table-column label="代表团" prop="delegationName" sortable="custom"></el-table-column>
<el-table-column label="立案结果" prop="caseFilingResult" sortable="custom">
<template scope="{row}">
<dict-tag :options="dict.type.PROPOSAL_CASE_FILING_RESULT"
:value="row.caseFilingResult"></dict-tag>
</template>
</el-table-column>
<el-table-column label="是否并案" prop="isConsolidation" sortable="custom" width="100">
<template scope="{row}">
<el-tag size="mini" v-if="row.isConsolidation" type="success"></el-tag>
<el-tag size="mini" v-else type="warning"></el-tag>
</template>
</el-table-column>
<el-table-column prop="curTaskName" label="当前节点" sortable="custom"></el-table-column>
<el-table-column prop="instanceState" label="流程状态" sortable="custom">
<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="200px">
<template scope="{row}">
<el-button size="mini" type="primary" @click="openView(row)">查看</el-button>
<el-button size="mini" type="primary" @click="onOpenEdit(row)">修改</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<template #view>
<proposal-info ref="infoRef"></proposal-info>
</template>
<template #edit>
<el-form :model="formData" ref="form" label-width="120px">
<el-row :gutter="20" type="flex">
<el-col :span="12">
<el-form-item label="代表姓名" prop="createUserName">
<el-input readonly v-model="formData.createUserName" disabled></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="提案时间" prop="createTime">
<el-input readonly v-model="formData.createTime" disabled></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20" type="flex">
<el-col :span="12">
<el-form-item label="提案编号" prop="code"
:rules="[{required:true,message:'请输入提案编号',trigger:'blur'}]">
<el-input maxlength="100" placeholder="提案编号" v-model="formData.code"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="立案编号" prop="caseFilingCode">
<el-input maxlength="100" placeholder="立案编号" v-model="formData.caseFilingCode"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20" type="flex">
<el-col :span="24">
<el-form-item label="提案名称" prop="name"
:rules="[{required:true,message:'请输入提案名称',trigger:'blur'}]">
<el-input maxlength="100" placeholder="提案名称" v-model="formData.name"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20" type="flex">
<el-col :span="12">
<el-form-item label="提案方式" prop="source">
<el-input :value="dict.type.PROPOSAL_SOURCE.find(v=>v.code === formData.source)?.name"
disabled></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="提案类别" prop="typeId">
<el-select v-model="formData.typeId" style="width: 100%">
<el-option :key="item.code" :label="item.name" :value="item.id"
v-for="item in typeOptions"></el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<!-- <el-form-item label="提案摘要" prop="excerpt">-->
<!-- <el-input-->
<!-- v-model="formData.excerpt"-->
<!-- type="textarea"-->
<!-- autosize-->
<!-- :autosize="{ minRows: 4, maxRows: 4}"-->
<!-- placeholder="提案摘要"-->
<!-- ></el-input>-->
<!-- </el-form-item>-->
<el-form-item label="建议承办单位" prop="suggestUnits">
<el-select v-model="formData.suggestUnits" multiple filterable style="width: 100%"
placeholder="请选择建议承办单位">
<el-option :key="item.id" :label="item.name" :value="item.name"
v-for="item in suggestUnitOptions"></el-option>
</el-select>
</el-form-item>
<el-form-item label="案由" prop="brief">
<text-editor v-model="formData.brief" key="brief" placeholder="案由"></text-editor>
</el-form-item>
<el-form-item label="建议措施" prop="measures">
<text-editor v-model="formData.measures" key="measures"
placeholder="建议措施"></text-editor>
</el-form-item>
<el-form-item label="附件上传" prop="files">
<file-upload
:value.sync="formData.files"
:upload_number="5"
upload_result_category="array"
upload_mode="drag"
complete_result
></file-upload>
</el-form-item>
</el-form>
<el-row type="flex" justify="end">
<el-button @click="$refs.guava.index()">取 消</el-button>
<el-button type="primary" @click="doUpdateBasic">确 定</el-button>
</el-row>
</template>
</guava>
</div>
<script nonce="${cspNonce!}">
<!--#include("/platform/zhgh/democratic/proposal/common/info.js"){}#-->
new Vue({
el: "#app",
dicts: ["PROPOSAL_CASE_FILING_RESULT", "PROPOSAL_SOURCE"],
store,
mixins: [initTableMixins],
components: {
"proposal-info": PROPOSAL_INFO
},
data() {
return {
sessionOptions: [],
typeOptions: [],
delegationOptions: [],
unionOptions: [],
unitOptions: [],
suggestUnitOptions: [],
pageForm: {
proposalSearchField: "name",
proposalKeyword: "",
types: [],
caseFilingResults: [],
unionId: null,
unitId: null
},
typeDialog: false,
formData: {
suggestUnits: []
}
}
},
methods: {
openView(row) {
this.$refs.guava.view(() => {
this.$refs.infoRef.onOpen(row)
})
},
onOpenEdit(row) {
this.$refs.guava.edit(() => {
let suggestUnits = []
try {
suggestUnits = JSON.parse(row.suggestUnits)
} catch (e) {
console.log(e)
}
this.formData = {
...row,
suggestUnits: suggestUnits
}
})
},
doUpdateBasic() {
this.$refs.form.validate((valid) => {
if (valid) {
this.$confirm("您确定要修改吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post("/platform/senior/basic/update", {
info: JSON.stringify(this.formData)
}).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.$refs.guava.index()
this.doSearch()
}
})
})
}
})
},
listProposalType() {
this.$axios.post("/platform/proposal/common/listProposalType").then((res) => {
if (res.code === 0) {
this.typeOptions = res.data
}
})
},
async meetingChange(val) {
this.pageForm.delegationId = null
this.listDelegation()
},
listDelegation() {
this.$axios.post("/platform/proposal/common/listDelegation", {sessionId: this.pageForm.searchSessionId}).then((res) => {
if (res.code === 0) {
this.delegationOptions = res.data
}
})
},
listSession() {
this.$axios.post("/platform/proposal/common/listSession").then((res) => {
if (res.code === 0) {
this.sessionOptions = res.data
if (this.sessionOptions) {
this.$set(this.pageForm, "searchSessionId", this.sessionOptions[0].id)
this.listDelegation()
this.pageData()
}
}
})
},
listUnion() {
this.$businessTool.listUnion().then((res) => (this.unionOptions = res))
},
listUnit() {
this.$businessTool.listUnit(this.pageForm.unionId).then((res) => (this.unitOptions = res))
},
// 建议承办单位
listSuggestUnit() {
this.$axios.post("/platform/proposal/common/listUnderTake").then((res) => {
if (res.code === 0) {
this.suggestUnitOptions = res.data
}
})
},
},
created() {
this.listSuggestUnit()
this.listSession()
this.listUnion()
this.listUnit()
this.listProposalType()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,175 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style></style>
<div id="app" v-cloak>
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="教代会">
<el-select @change="meetingChange" clearable filterable placeholder="所属教代会" v-model="pageForm.searchSessionId">
<el-option :key="item.id" :label="item.fullName" :value="item.id" v-for="item in sessionOptions"></el-option>
</el-select>
</search-item>
<search-item label="名称/编号">
<el-input @keyup.enter.native="doSearch" clearable placeholder="请输入内容"
v-model="pageForm.proposalKeyword">
<el-select slot="prepend" style="width: 110px" v-model="pageForm.proposalSearchField">
<el-option label="提案名称" value="name"></el-option>
<el-option label="提案编号" value="code"></el-option>
<el-option label="立案编号" value="caseFilingCode"></el-option>
</el-select>
</el-input>
</search-item>
<search-item label="姓名/工号">
<el-input @keyup.enter.native="doSearch" clearable placeholder="请输入姓名或工号"
v-model="pageForm.createUserKeyword"></el-input>
</search-item>
<search-item label="代表团">
<el-select clearable filterable placeholder="所属代表团" v-model="pageForm.delegationId">
<el-option :key="item.id" :label="item.name" :value="item.id" v-for="item in delegationOptions"></el-option>
</el-select>
</search-item>
<search-item label="提案分工会">
<el-select clearable filterable placeholder="分工会" v-model="pageForm.unionId" @change="pageForm.unitId=null;listUnit();">
<el-option :key="item.id" :label="item.name" :value="item.id" v-for="item in unionOptions"></el-option>
</el-select>
</search-item>
<search-item label="提案单位">
<el-select clearable filterable placeholder="提案单位" v-model="pageForm.unitId">
<el-option :key="item.id" :label="item.name" :value="item.id" v-for="item in unitOptions"></el-option>
</el-select>
</search-item>
</search>
</el-card>
<el-card shadow="never">
<table-tool></table-tool>
<el-table v-loading="tableLoading" :data="tableData" @sort-change="pageOrder" header-align="center" style="width: 100%" row-key="id">
<el-table-column label="序号" width="50" type="index" :index="indexMethod"></el-table-column>
<el-table-column label="提案编号" prop="code" sortable="custom" width="100px" show-overflow-tooltip></el-table-column>
<el-table-column label="立案编号" prop="caseFilingCode" sortable="custom" width="100px" show-overflow-tooltip></el-table-column>
<el-table-column label="提案名称" prop="name" sortable="custom" show-overflow-tooltip></el-table-column>
<el-table-column label="提案人" prop="createUserName" sortable="custom"></el-table-column>
<el-table-column label="提案类别" prop="typeName" sortable="custom"></el-table-column>
<el-table-column label="代表团" prop="delegationName" sortable="custom"></el-table-column>
<el-table-column label="立案结果" prop="caseFilingResult" sortable="custom">
<template scope="{row}">
<dict-tag :options="dict.type.PROPOSAL_CASE_FILING_RESULT" :value="row.caseFilingResult"></dict-tag>
</template>
</el-table-column>
<el-table-column label="是否并案" prop="isConsolidation" sortable="custom" width="100">
<template scope="{row}">
<el-tag size="mini" v-if="row.isConsolidation" type="success"></el-tag>
<el-tag size="mini" v-else type="danger"></el-tag>
</template>
</el-table-column>
<el-table-column prop="curTaskName" label="当前节点" sortable="custom"></el-table-column>
<el-table-column prop="instanceState" label="流程状态" sortable="custom">
<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="200px">
<template scope="{row}">
<el-button size="mini" type="primary" @click="openView(row)">查看</el-button>
<el-button size="mini" type="danger" @click="onDelete(row.id)">删除</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<template #view>
<proposal-info ref="infoRef"></proposal-info>
</template>
</guava>
</div>
<script nonce="${cspNonce!}">
<!--#include("../../common/info.js"){}#-->
new Vue({
el: "#app",
dicts: ["PROPOSAL_CASE_FILING_RESULT"],
store,
mixins: [initTableMixins],
components: {
"proposal-info": PROPOSAL_INFO
},
data() {
return {
sessionOptions: [],
typeOptions: [],
delegationOptions: [],
underTakeOptions: [],
unionOptions: [],
unitOptions: [],
pageForm: {
proposalSearchField: "name",
proposalKeyword: "",
types: [],
caseFilingResults: [],
unionId: null,
unitId: null
}
}
},
methods: {
openView(row) {
this.$refs.guava.view(() => {
this.$refs.infoRef.onOpen(row)
})
},
onDelete(id) {
this.$confirm("您确定删除该提案吗?", "提示", {
type: "warning"
}).then(() => {
this.$axios.post("/platform/senior/delete/delete", { id: id }).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.doSearch()
}
})
})
},
async meetingChange(val) {
this.pageForm.delegationId = null
this.listDelegation()
},
listDelegation() {
this.$axios.post("/platform/proposal/common/listDelegation", { sessionId: this.pageForm.searchSessionId }).then((res) => {
if (res.code === 0) {
this.delegationOptions = res.data
}
})
},
listSession() {
this.$axios.post("/platform/proposal/common/listSession").then((res) => {
if (res.code === 0) {
this.sessionOptions = res.data
if (this.sessionOptions) {
this.$set(this.pageForm, "searchSessionId", this.sessionOptions[0].id)
this.listDelegation()
this.pageData()
}
}
})
},
listUnion() {
this.$businessTool.listUnion().then((res) => (this.unionOptions = res))
},
listUnit() {
this.$businessTool.listUnit(this.pageForm.unionId).then((res) => (this.unitOptions = res))
}
},
created() {
this.listSession()
this.listUnion()
this.listUnit()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,229 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app">
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="教代会">
<el-select @change="meetingChange" clearable filterable placeholder="请选择所属教代会"
v-model="pageForm.sessionId">
<el-option :key="item.id" :label="item.fullName" :value="item.id"
v-for="item in sessionOptions"></el-option>
</el-select>
</search-item>
<search-item label="名称/编号">
<el-input @keyup.enter.native="doSearch" clearable placeholder="请输入内容"
v-model="pageForm.proposalKeyword">
<el-select slot="prepend" style="width: 110px" v-model="pageForm.proposalSearchField">
<el-option label="提案名称" value="name"></el-option>
<el-option label="提案编号" value="code"></el-option>
<el-option label="立案编号" value="caseFilingCode"></el-option>
</el-select>
</el-input>
</search-item>
<search-item label="姓名/工号">
<el-input @keyup.enter.native="doSearch" clearable placeholder="请输入姓名或工号"
v-model="pageForm.createUserKeyword"></el-input>
</search-item>
</search>
</el-card>
<el-card shadow="never">
<table-tool label="未答复列表">
<el-button type="primary" size="small" @click="onBatchHandle">
<i class="el-icon-s-promotion"></i>
批量催办
</el-button>
</table-tool>
<el-table v-loading="tableLoading" :data="tableData" @sort-change="pageOrder" style="width: 100%"
@selection-change="handleSelectionChange" row-key="id">
<el-table-column type="selection" reserve-selection width="55"></el-table-column>
<el-table-column label="序号" width="50" type="index" :index="indexMethod"></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:key="column.prop"
:width="column.width"
sortable="custom"
align="center"
header-align="center"
show-overflow-tooltip
v-for="column in tableColumns"
>
<template v-slot="{ row }" v-if="column.prop === 'caseFilingResult'">
<dict-tag :options="dict.type.PROPOSAL_CASE_FILING_RESULT" :value="row.caseFilingResult"></dict-tag>
</template>
<template v-slot="{ row }" v-else-if="column.prop === 'instanceState'">
<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="openView(row)" size="mini" type="primary">查看</el-button>
<el-button @click="onHandle(row)" size="mini" type="primary">催办</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<template #view>
<proposal-info ref="proposalInfoRef"></proposal-info>
</template>
<template #edit>
<div class="process-title">所选提案列表</div>
<el-table v-loading="tableLoading" :data="chooseTableData" style="width: 100%" max-height="600">
<el-table-column label="序号" width="50" type="index" :index="indexMethod"></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:key="column.prop"
:width="column.width"
sortable="custom"
align="center"
header-align="center"
show-overflow-tooltip
v-for="column in tableColumns"
>
<template v-slot="{ row }" v-if="column.prop === 'caseFilingResult'">
<dict-tag :options="dict.type.PROPOSAL_CASE_FILING_RESULT" :value="row.caseFilingResult"></dict-tag>
</template>
<template v-slot="{ row }" v-else-if="column.prop === 'instanceState'">
<enum-tag :value="row.instanceState" name="ProcessInstanceStateEnum" label_key="message"
size="small"></enum-tag>
</template>
</el-table-column>
</el-table>
<div class="process-title">催办内容</div>
<el-input v-model="content" type="textarea" :rows="4" placeholder="请输入催办内容" max="500"></el-input>
<el-row type="flex" justify="end" class="mt20">
<el-button @click="$refs.guava.index()">取消</el-button>
<el-button @click="onSubmit" type="primary">提交</el-button>
</el-row>
</template>
</guava>
</div>
<script nonce="${cspNonce!}">
<!--#include('../../common/info.js'){}#-->
new Vue({
el: "#app",
store,
dicts: ["PROPOSAL_CASE_FILING_RESULT","PROPOSAL_REPLY_IMPLEMENT"],
mixins: [initTableMixins],
components: {
"proposal-info": PROPOSAL_INFO
},
data() {
return {
pageForm: {
proposalSearchField: "name",
proposalKeyword: ""
},
formData: {},
sessionOptions: [],
delegationOptions: [],
tableColumns: [
{prop: 'code', label: '提案编号'},
{prop: 'caseFilingCode', label: '立案编号'},
{prop: 'name', label: '提案名称'},
{prop: 'typeName', label: '提案类别'},
{prop: 'delegationName', label: '代表团'},
{prop: 'caseFilingResult', label: '立案结果'},
{prop: 'curTaskName', label: '当前节点'},
{prop: 'underTakeName', label: '承办单位'},
{prop: 'taskName', label: '承办类型'},
{prop: 'actorName', label: '负责人'},
{prop: 'instanceState', label: '流程状态'},
],
chooseTableData: [],
multipleSelection: [],
content: '',
}
},
methods: {
onSubmit() {
if(!this.content) {
this.$message.warning('请输入催办内容')
return
}
this.$confirm("您选择了" + this.chooseTableData.length + "条提案,确定要催办吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post("/platform/senior/expediting/submit", {
taskIds: JSON.stringify(this.chooseTableData.map(o => o.taskId)),
content: this.content
}).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.pageData()
}
})
})
},
onBatchHandle() {
if(this.multipleSelection.length === 0) {
this.$message.warning('请先选择需要催办的提案')
return
}
this.chooseTableData = []
this.chooseTableData = clone(this.multipleSelection)
this.$refs.guava.edit()
},
onHandle(row) {
this.chooseTableData = []
this.chooseTableData.push(row)
this.$refs.guava.edit()
},
handleSelectionChange(val) {
this.multipleSelection = val
},
openView(row) {
this.$refs.guava.view(() => {
this.$refs.proposalInfoRef.onOpen(row)
})
},
// 教代会
async meetingChange(val) {
this.doSearch()
},
listDelegation() {
this.$axios.post("/platform/proposal/common/listDelegation", {sessionId: this.pageForm.sessionId}).then((res) => {
if (res.code === 0) {
this.delegationOptions = res.data
}
})
},
// 查询开启的教代会
listOpenSession() {
this.$axios.post("/platform/proposal/common/listOpenSession").then((res) => {
if (res.code === 0) {
this.sessionOptions = res.data
if (this.sessionOptions) {
this.$set(this.pageForm, "sessionId", this.sessionOptions[0].id)
this.pageData()
this.listDelegation()
}
}
})
}
},
created() {
this.pageData()
this.listOpenSession()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,266 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style></style>
<div id="app" v-cloak>
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="教代会">
<el-select @change="meetingChange" clearable filterable placeholder="所属教代会"
v-model="pageForm.searchSessionId">
<el-option :key="item.id" :label="item.fullName" :value="item.id"
v-for="item in sessionOptions"></el-option>
</el-select>
</search-item>
<search-item label="名称/编号">
<el-input @keyup.enter.native="doSearch" clearable placeholder="请输入内容"
v-model="pageForm.proposalKeyword">
<el-select slot="prepend" style="width: 110px" v-model="pageForm.proposalSearchField">
<el-option label="提案名称" value="name"></el-option>
<el-option label="提案编号" value="code"></el-option>
<el-option label="立案编号" value="caseFilingCode"></el-option>
</el-select>
</el-input>
</search-item>
<search-item label="姓名/工号">
<el-input @keyup.enter.native="doSearch" clearable placeholder="请输入姓名或工号"
v-model="pageForm.createUserKeyword"></el-input>
</search-item>
<search-item label="代表团">
<el-select clearable filterable placeholder="所属代表团" v-model="pageForm.delegationId">
<el-option :key="item.id" :label="item.name" :value="item.id"
v-for="item in delegationOptions"></el-option>
</el-select>
</search-item>
<search-item label="提案分工会">
<el-select clearable filterable placeholder="分工会" v-model="pageForm.unionId"
@change="pageForm.unitId=null;listUnit();">
<el-option :key="item.id" :label="item.name" :value="item.id"
v-for="item in unionOptions"></el-option>
</el-select>
</search-item>
<search-item label="提案单位">
<el-select clearable filterable placeholder="提案单位" v-model="pageForm.unitId">
<el-option :key="item.id" :label="item.name" :value="item.id"
v-for="item in unitOptions"></el-option>
</el-select>
</search-item>
</search>
</el-card>
<el-card shadow="never">
<table-tool></table-tool>
<el-table v-loading="tableLoading" :data="tableData" @sort-change="pageOrder" header-align="center" style="width: 100%" row-key="id">
<el-table-column label="序号" width="50" type="index" :index="indexMethod"></el-table-column>
<el-table-column label="提案编号" prop="code" sortable="custom" width="100px" show-overflow-tooltip></el-table-column>
<el-table-column label="立案编号" prop="caseFilingCode" sortable="custom" width="100px" show-overflow-tooltip></el-table-column>
<el-table-column label="提案名称" prop="name" sortable="custom" show-overflow-tooltip></el-table-column>
<el-table-column label="提案人" prop="createUserName" sortable="custom"></el-table-column>
<el-table-column label="提案类别" prop="typeName" sortable="custom"></el-table-column>
<el-table-column label="代表团" prop="delegationName" sortable="custom"></el-table-column>
<el-table-column label="立案结果" prop="caseFilingResult" sortable="custom">
<template scope="{row}">
<dict-tag :options="dict.type.PROPOSAL_CASE_FILING_RESULT"
:value="row.caseFilingResult"></dict-tag>
</template>
</el-table-column>
<el-table-column label="是否并案" prop="isConsolidation" sortable="custom" width="100">
<template scope="{row}">
<el-tag size="mini" v-if="row.isConsolidation" type="success"></el-tag>
<el-tag size="mini" v-else type="warning"></el-tag>
</template>
</el-table-column>
<el-table-column prop="curTaskName" label="当前节点" sortable="custom"></el-table-column>
<el-table-column prop="instanceState" label="流程状态" sortable="custom">
<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="反馈评价" prop="tf_feedback" sortable="custom" width="150px">
<template slot-scope="{row}">
<dict-tag :options="dict.type.PROPOSAL_FEEDBACK" :value="row.tf_feedback"></dict-tag>
</template>
</el-table-column>
<el-table-column label="操作" fixed="right" width="200px">
<template scope="{row}">
<el-button size="mini" type="primary" @click="openView(row)">查看</el-button>
<el-button size="mini" type="primary" @click="onOpenEdit(row.instanceId)">修改</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<template #view>
<proposal-info ref="infoRef"></proposal-info>
</template>
<el-dialog title="修改反馈评价" :visible.sync="editDialogVisible" width="50%">
<template v-for="task in tasks">
<el-descriptions border class="flow-task-form" :column="2" :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="办理结果" :span="2">
<el-radio-group v-model="task.taskFormData.tf_feedback" size="small">
<el-radio v-for="item in dict.type.PROPOSAL_FEEDBACK" :key="item.code"
:label="item.code" border>{{item.label}}
</el-radio>
</el-radio-group>
</el-descriptions-item>
<el-descriptions-item label="办理意见" :span="2" v-if="!task.ext.isFirstTaskNode">
<el-input
v-model="task.taskFormData.tf_opinion"
type="textarea"
:rows="3"
placeholder="请输入您的办理意见"
></el-input>
</el-descriptions-item>
</el-descriptions>
</template>
<el-row type="flex" justify="end" slot="footer">
<el-button @click="editDialogVisible=false">取 消</el-button>
<el-button type="primary" @click="onSubmit">确 定</el-button>
</el-row>
</el-dialog>
</guava>
</div>
<script nonce="${cspNonce!}">
<!--#include("/platform/zhgh/democratic/proposal/common/info.js"){}#-->
new Vue({
el: "#app",
store,
dicts: ['PROPOSAL_CASE_FILING_RESULT', 'PROCESS_TASK_SUBMIT_TYPE', 'PROPOSAL_FEEDBACK'],
mixins: [initTableMixins],
components: {
"proposal-info": PROPOSAL_INFO
},
data() {
return {
sessionOptions: [],
typeOptions: [],
delegationOptions: [],
unionOptions: [],
unitOptions: [],
pageForm: {
proposalSearchField: "name",
proposalKeyword: "",
types: [],
caseFilingResults: [],
unionId: null,
unitId: null
},
tasks: [],
editDialogVisible: false
}
},
methods: {
openView(row) {
this.$refs.guava.view(() => {
this.$refs.infoRef.onOpen(row)
})
},
onOpenEdit(instanceId) {
this.$axios.post('/platform/senior/feedback/info', {instanceId}).then(res => {
if (res.code === 0) {
this.tasks = res.data
if (this.tasks && this.tasks.length > 0) {
this.editDialogVisible = true
} else {
this.$message.warning("当前无法修改反馈评价")
}
}
})
},
onSubmit() {
const params = this.tasks.map(v => {
return {
id: v.id,
opinion: v?.taskFormData?.tf_opinion,
feedback: v?.taskFormData?.tf_feedback
}
})
this.$axios.post('/platform/senior/feedback/update', {data: JSON.stringify(params)}).then(res => {
if (res.code === 0) {
this.$message.success(res.msg)
this.editDialogVisible = false
this.doSearch()
}
})
},
listProposalType() {
this.$axios.post("/platform/proposal/common/listProposalType").then((res) => {
if (res.code === 0) {
this.typeOptions = res.data
}
})
},
async meetingChange(val) {
this.pageForm.delegationId = null
this.listDelegation()
},
listDelegation() {
this.$axios.post("/platform/proposal/common/listDelegation", {sessionId: this.pageForm.searchSessionId}).then((res) => {
if (res.code === 0) {
this.delegationOptions = res.data
}
})
},
listSession() {
this.$axios.post("/platform/proposal/common/listSession").then((res) => {
if (res.code === 0) {
this.sessionOptions = res.data
if (this.sessionOptions) {
this.$set(this.pageForm, "searchSessionId", this.sessionOptions[0].id)
this.listDelegation()
this.pageData()
}
}
})
},
listUnion() {
this.$businessTool.listUnion().then((res) => (this.unionOptions = res))
},
listUnit() {
this.$businessTool.listUnit(this.pageForm.unionId).then((res) => (this.unitOptions = res))
},
pageData() {
// 自定义查询覆盖了公共 mixin,请求期间手动维护表格加载状态。
this.$set(this, "tableLoading", true)
this.$axios
.post(loc() + "/pageData", {
pageForm: JSON.stringify(this.pageForm)
})
.then((res) => {
if (res.code === 0) {
this.tableData = res.data.list
this.pageForm.totalCount = res.data.totalCount
}
})
.finally(() => {
this.$set(this, "tableLoading", false)
})
}
},
created() {
this.listSession()
this.listUnion()
this.listUnit()
this.listProposalType()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,219 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style></style>
<div id="app" v-cloak>
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="教代会">
<el-select @change="meetingChange" clearable filterable placeholder="所属教代会" v-model="pageForm.searchSessionId">
<el-option :key="item.id" :label="item.fullName" :value="item.id" v-for="item in sessionOptions"></el-option>
</el-select>
</search-item>
<search-item label="名称/编号">
<el-input @keyup.enter.native="doSearch" clearable placeholder="请输入内容"
v-model="pageForm.proposalKeyword">
<el-select slot="prepend" style="width: 110px" v-model="pageForm.proposalSearchField">
<el-option label="提案名称" value="name"></el-option>
<el-option label="提案编号" value="code"></el-option>
<el-option label="立案编号" value="caseFilingCode"></el-option>
</el-select>
</el-input>
</search-item>
<search-item label="姓名/工号">
<el-input @keyup.enter.native="doSearch" clearable placeholder="请输入姓名或工号"
v-model="pageForm.createUserKeyword"></el-input>
</search-item>
<search-item label="代表团">
<el-select clearable filterable placeholder="所属代表团" v-model="pageForm.delegationId">
<el-option :key="item.id" :label="item.name" :value="item.id" v-for="item in delegationOptions"></el-option>
</el-select>
</search-item>
<search-item label="提案分工会">
<el-select clearable filterable placeholder="分工会" v-model="pageForm.unionId" @change="pageForm.unitId=null;listUnit();">
<el-option :key="item.id" :label="item.name" :value="item.id" v-for="item in unionOptions"></el-option>
</el-select>
</search-item>
<search-item label="提案单位">
<el-select clearable filterable placeholder="提案单位" v-model="pageForm.unitId">
<el-option :key="item.id" :label="item.name" :value="item.id" v-for="item in unitOptions"></el-option>
</el-select>
</search-item>
</search>
</el-card>
<el-card shadow="never">
<table-tool></table-tool>
<el-table v-loading="tableLoading" :data="tableData" @sort-change="pageOrder" header-align="center" style="width: 100%" row-key="id">
<el-table-column label="序号" width="50" type="index" :index="indexMethod"></el-table-column>
<el-table-column label="提案编号" prop="code" sortable="custom" width="100px" show-overflow-tooltip></el-table-column>
<el-table-column label="立案编号" prop="caseFilingCode" sortable="custom" width="100px" show-overflow-tooltip></el-table-column>
<el-table-column label="提案名称" prop="name" sortable="custom" show-overflow-tooltip></el-table-column>
<el-table-column label="提案人" prop="createUserName" sortable="custom"></el-table-column>
<el-table-column label="提案类别" prop="typeName" sortable="custom"></el-table-column>
<el-table-column label="代表团" prop="delegationName" sortable="custom"></el-table-column>
<el-table-column label="立案结果" prop="caseFilingResult" sortable="custom">
<template scope="{row}">
<dict-tag :options="dict.type.PROPOSAL_CASE_FILING_RESULT" :value="row.caseFilingResult"></dict-tag>
</template>
</el-table-column>
<el-table-column label="是否并案" prop="isConsolidation" sortable="custom" width="100">
<template scope="{row}">
<el-tag size="mini" v-if="row.isConsolidation" type="success"></el-tag>
<el-tag size="mini" v-else type="danger"></el-tag>
</template>
</el-table-column>
<el-table-column prop="curTaskName" label="当前节点" sortable="custom"></el-table-column>
<el-table-column prop="instanceState" label="流程状态" sortable="custom">
<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="200px">
<template scope="{row}">
<el-button size="mini" type="primary" @click="onOpen(row)">查看</el-button>
<el-button size="mini" type="primary" @click="onOpenEdit(row)">修改</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<template #view>
<proposal-info ref="infoRef"></proposal-info>
</template>
</guava>
<el-dialog title="修改提案类型" :close-on-click-modal="false" width="40%" :visible.sync="typeDialog">
<el-form :model="formData" ref="form" label-width="120px">
<el-form-item prop="oldTypeName" label="原类型">
<el-input disabled :value="formData.oldTypeName" type="text"></el-input>
</el-form-item>
<el-form-item prop="typeId" label="更改类型" :rules="[{required:true,message:'请选择类型',trigger:'blur'}]">
<el-select v-model="formData.typeId" style="width: 100%">
<el-option :key="item.code" :label="item.name" :value="item.id" v-for="item in typeOptions"></el-option>
</el-select>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="typeDialog=false">取 消</el-button>
<el-button type="primary" @click="doUpdateType">确 定</el-button>
</span>
</el-dialog>
</div>
<script nonce="${cspNonce!}">
<!--#include("../../common/info.js"){}#-->
new Vue({
el: "#app",
dicts: ["PROPOSAL_CASE_FILING_RESULT"],
store,
mixins: [initTableMixins],
components: {
"proposal-info": PROPOSAL_INFO
},
data() {
return {
typeOptions: [],
sessionOptions: [],
delegationOptions: [],
unionOptions: [],
unitOptions: [],
pageForm: {
proposalSearchField: "name",
proposalKeyword: "",
types: [],
caseFilingResults: [],
unionId: null,
unitId: null
},
typeDialog: false
}
},
methods: {
onOpen(row) {
this.$refs.guava.view(() => {
this.$refs.infoRef.onOpen(row)
})
},
onOpenEdit(row) {
this.typeDialog = true
this.$nextTick(() => {
this.formData = {
id: row.id,
oldTypeName: this.typeOptions.find((item) => item.id === row.typeId)?.name,
typeId: null
}
})
},
doUpdateType() {
this.$refs.form.validate((valid) => {
if (valid) {
this.$confirm("您确定要修改吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post("/platform/senior/type/update", this.formData).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.typeDialog = false
this.doSearch()
}
})
})
}
})
},
listProposalType() {
this.$axios.post("/platform/proposal/common/listProposalType").then((res) => {
if (res.code === 0) {
this.typeOptions = res.data
}
})
},
async meetingChange(val) {
this.pageForm.delegationId = null
this.listDelegation()
},
listDelegation() {
this.$axios.post("/platform/proposal/common/listDelegation", { sessionId: this.pageForm.searchSessionId }).then((res) => {
if (res.code === 0) {
this.delegationOptions = res.data
}
})
},
listSession() {
this.$axios.post("/platform/proposal/common/listSession").then((res) => {
if (res.code === 0) {
this.sessionOptions = res.data
if (this.sessionOptions) {
this.$set(this.pageForm, "searchSessionId", this.sessionOptions[0].id)
this.listDelegation()
this.pageData()
}
}
})
},
listUnion() {
this.$businessTool.listUnion().then((res) => (this.unionOptions = res))
},
listUnit() {
this.$businessTool.listUnit(this.pageForm.unionId).then((res) => (this.unitOptions = res))
}
},
created() {
this.listSession()
this.listUnion()
this.listUnit()
this.listProposalType()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,121 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app" v-cloak>
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="教代会">
<el-select @change="meetingChange" clearable filterable placeholder="所属教代会"
v-model="pageForm.sessionId">
<el-option :key="item.id" :label="item.fullName" :value="item.id"
v-for="item in sessionOptions"></el-option>
</el-select>
</search-item>
<search-item label="提案名称">
<el-input v-model="pageForm.name" placeholder="提案名称" @keyup.enter.native="doSearch" clearable
style="width: 100%"></el-input>
</search-item>
<search-item label="姓名/工号">
<el-input placeholder="请输入姓名或工号" clearable v-model="pageForm.createUserKeyword"></el-input>
</search-item>
</search>
</el-card>
<el-card shadow="never">
<table-tool :columns.sync="tableColumns">
</table-tool>
<el-table v-loading="tableLoading" :data="tableData" @sort-change="pageOrder" style="width: 100%">
<el-table-column label="序号" width="50" type="index" :index="indexMethod"
fixed="left"></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:key="column.key"
:min-width="column.width"
:fixed="column.fixed"
sortable="custom"
show-overflow-tooltip
v-for="column in tableColumns"
v-if="column.visible !== false"
>
<template v-if="column.prop === 'instanceState'" 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="100px">
<template slot-scope="{row}">
<el-button @click="openView(row)" size="mini" type="primary">查看</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<template #edit>
<proposal-info ref="proposalInfoRef">
</proposal-info>
</template>
</guava>
</div>
<script nonce="${cspNonce!}">
<!--#include('../../common/info.js'){}#-->
new Vue({
el: "#app",
store,
mixins: [initTableMixins],
components: {
"proposal-info": PROPOSAL_INFO
},
data() {
return {
tableColumns: [
{label: "提案编号", prop: "code"},
{label: "提案名称", prop: "name", width: "200px"},
{label: "提案人", prop: "createUserName", width: "80px"},
{label: "提案类别", prop: "typeName"},
{label: "届次", prop: "sessionName"},
{label: "代表团", prop: "delegationName"},
{label: "流程状态", prop: "instanceState"}
],
pageForm: {
approval: false
},
showApprovalForm: false,
sessionOptions:[]
}
},
created() {
this.pageData()
this.listOpenSession()
},
methods: {
// 教代会
async meetingChange(val) {
this.doSearch()
},
openView(row) {
this.$refs.guava.edit(() => {
this.showApprovalForm = false
this.$refs.proposalInfoRef.onOpen(row)
})
},
// 查询开启的教代会
listOpenSession() {
this.$axios.post("/platform/proposal/common/listOpenSession").then((res) => {
if (res.code === 0) {
this.sessionOptions = res.data
if (this.sessionOptions) {
this.$set(this.pageForm, "sessionId", this.sessionOptions[0].id)
this.pageData()
this.listDelegation()
}
}
})
},
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,335 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app" v-cloak>
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="教代会">
<el-select @change="meetingChange" clearable filterable placeholder="所属教代会"
v-model="pageForm.sessionId">
<el-option :key="item.id" :label="item.fullName" :value="item.id"
v-for="item in sessionOptions"></el-option>
</el-select>
</search-item>
<search-item label="代表团">
<el-select clearable filterable placeholder="所属代表团" v-model="pageForm.delegationId">
<el-option :key="item.id" :label="item.name" :value="item.id"
v-for="item in delegationOptions"></el-option>
</el-select>
</search-item>
<search-item label="工会">
<el-select clearable filterable placeholder="所属工会" 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-item label="提案名称">
<el-input v-model="pageForm.name" placeholder="提案名称" @keyup.enter.native="doSearch" clearable
style="width: 100%"></el-input>
</search-item>
<search-item label="姓名/工号">
<el-input placeholder="请输入姓名或工号" clearable v-model="pageForm.createUserKeyword"></el-input>
</search-item>
</search>
</el-card>
<el-card shadow="never">
<table-tool :columns.sync="tableColumns">
<el-button type="primary" size="small" @click="exportList">导出</el-button>
<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 v-loading="tableLoading" :data="tableData" @sort-change="pageOrder" style="width: 100%">
<el-table-column label="序号" width="50" type="index" :index="indexMethod" fixed="left"></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:key="column.key"
:min-width="column.width"
:fixed="column.fixed"
sortable="custom"
show-overflow-tooltip
v-for="column in tableColumns"
v-if="column.visible !== false"
>
<template v-if="column.prop === 'instanceState'" 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="200px">
<template slot-scope="{row}">
<el-button @click="openView(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>
<proposal-info ref="proposalInfoRef">
<div v-if="showApprovalForm">
<div class="process-title">
{{formData.taskName}}
</div>
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="150px" label-suffix="">
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="审核人" proop="tf_username">
<el-input readonly v-model="formData.tf_username"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="审核时间">
<el-input readonly v-model="formData.tf_auditTime"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-form-item label="二次答复" prop="tf_caseCheckNeedSecondReply">
<el-radio-group v-model="formData.tf_caseCheckNeedSecondReply">
<el-radio :label="0" border>
无需二次答复
</el-radio>
<el-radio :label="1" border>
需要二次答复
</el-radio>
</el-radio-group>
<span class="text-primary ml10" v-if="formData.tf_caseCheckNeedSecondReply">
(请选择需要进入二次答复的办理单位,可多选)
</span>
</el-form-item>
<el-form-item
label="答复单位"
prop="tf_secondReplyUnitIds"
v-if="formData.tf_caseCheckNeedSecondReply"
:rules="[{required:formData.tf_caseCheckNeedSecondReply === 1,message:'请选择需要二次答复的办理单位',trigger:['change','blur']}]"
>
<el-select v-model="formData.tf_secondReplyUnitIds" clearable filterable multiple style="width: 100%">
<el-option
v-for="item in replyUnitOptions"
:key="item.unitId"
:label="item.unitName + '' + (item.isMaster ? '主办' : '协办') + ''"
:value="item.unitId"
></el-option>
</el-select>
</el-form-item>
<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(1)" size="small" type="primary">同意</el-button>
<!-- <el-button @click="handleTaskAction(2)" size="small" type="danger">不同意</el-button>-->
<!-- <el-button @click="handleTaskAction(6)" size="small" type="info">退回到提案人</el-button>-->
<el-button @click="$refs.guava.index()" size="small">返回</el-button>
</el-row>
</div>
</proposal-info>
</template>
</guava>
</div>
<script nonce="${cspNonce!}">
<!--#include('../../common/info.js'){}#-->
new Vue({
el: "#app",
store,
mixins: [initTableMixins],
components: {
"proposal-info": PROPOSAL_INFO
},
data() {
return {
tableColumns: [
{label: "提案编号", prop: "code"},
{label: "立案编号", prop: "caseFilingCode"},
{label: "提案名称", prop: "name", width: "200px"},
{label: "提案人", prop: "createUserName", width: "80px"},
{label: "提案类别", prop: "typeName"},
{label: "届次", prop: "sessionName"},
{label: "代表团", prop: "delegationName"},
{label: "当前节点", prop: "curTaskName"},
{label: "流程状态", prop: "instanceState"},
{label: "办理时间", prop: "finishTime"}
],
pageForm: {
approval: false
},
showApprovalForm: false,
replyUnitOptions: [],
sessionOptions: [],
delegationOptions: [],
unionOptions: [],
}
},
created() {
this.pageData()
this.listOpenSession()
this.listUnion()
},
methods: {
exportList() {
this.$downLoad(loc() + "/exportList", {
pageForm: JSON.stringify(this.pageForm),
approval: this.pageForm.approval,
tableColumns: JSON.stringify(this.tableColumns.filter(function (item) {
return item.visible !== false
}))
})
},
openView(row) {
this.$refs.guava.edit(() => {
this.showApprovalForm = false
this.$refs.proposalInfoRef.onOpen(row)
})
},
openAudit(row) {
this.loadReplyUnits(row.id)
this.$refs.guava.edit(() => {
this.showApprovalForm = true
this.formData = {
proposalId: row.id,
processTaskId: row.taskId,
taskName: row.curTaskName,
tf_auditTime: this.$moment().format('YYYY-MM-DD'),
tf_username: this.$store.state.user.username,
tf_caseCheckNeedSecondReply: 0,
tf_secondReplyUnitIds: []
}
this.$refs.proposalInfoRef.onOpen(row)
})
},
/**
* 教代会切换后需要同步刷新代表团下拉,避免上一届次代表团条件残留。
*/
meetingChange() {
this.listDelegation()
this.doSearch()
},
/**
* 根据当前教代会加载代表团筛选项,没有选教代会时代表团下拉置空。
*/
listDelegation() {
this.delegationOptions = []
this.$set(this.pageForm, "delegationId", null)
if (!this.pageForm.sessionId) {
return
}
this.$axios.post("/platform/proposal/common/listDelegation", {
sessionId: this.pageForm.sessionId
}).then((res) => {
if (res.code === 0) {
this.delegationOptions = res.data
}
})
},
/**
* 工会下拉按系统分工会列表加载,用于按提案人所属工会筛选当前页面列表。
*/
listUnion() {
this.$businessTool.listUnion().then((res) => {
this.unionOptions = res
})
},
// 查询开启的教代会
listOpenSession() {
this.$axios.post("/platform/proposal/common/listOpenSession").then((res) => {
if (res.code === 0) {
this.sessionOptions = res.data
if (this.sessionOptions) {
this.$set(this.pageForm, "sessionId", this.sessionOptions[0].id)
this.listDelegation()
this.pageData()
}
}
})
},
// 二次答复只能选择当前提案已配置的办理单位,避免误选到别的单位。
loadReplyUnits(proposalId) {
this.$axios.post("/platform/proposal/case/check/listReplyUnits", { proposalId: proposalId }).then((res) => {
if (res.code === 0) {
this.replyUnitOptions = res.data || []
}
})
},
handleTaskAction(val) {
this.$refs.formRef.validate(valid => {
if (!valid) return
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
let submitData = Object.assign({}, this.formData)
if (submitData.tf_caseCheckNeedSecondReply === 1) {
let secondReplyUnits = this.replyUnitOptions.filter(item => submitData.tf_secondReplyUnitIds.indexOf(item.unitId) > -1)
let masterUnitIds = secondReplyUnits.filter(item => item.isMaster).map(item => item.unitId)
let slaveUnitIds = secondReplyUnits.filter(item => !item.isMaster).map(item => item.unitId)
let masterUnitNames = secondReplyUnits.filter(item => item.isMaster).map(item => item.unitName)
let slaveUnitNames = secondReplyUnits.filter(item => !item.isMaster).map(item => item.unitName)
submitData.tf_masterUnitIds = masterUnitIds
submitData.tf_masterUnitId = masterUnitIds.length ? masterUnitIds[0] : ""
submitData.tf_masterUnitName = masterUnitNames.length ? masterUnitNames[0] : ""
submitData.tf_masterUnitNames = masterUnitNames
submitData.tf_masterUnitNameStr = masterUnitNames.join(",")
submitData.tf_slaveUnitIds = slaveUnitIds
submitData.tf_slaveUnitNames = slaveUnitNames
submitData.tf_slaveUnitNameStr = slaveUnitNames.join(",")
} else {
submitData.tf_secondReplyUnitIds = []
submitData.tf_masterUnitIds = []
submitData.tf_masterUnitId = ""
submitData.tf_masterUnitName = ""
submitData.tf_masterUnitNames = []
submitData.tf_masterUnitNameStr = ""
submitData.tf_slaveUnitIds = []
submitData.tf_slaveUnitNames = []
submitData.tf_slaveUnitNameStr = ""
}
this.$axios.post("/flow/common/executeTask", {
data: JSON.stringify({
...submitData,
submitType: val
})
}).then((res) => {
if (res.code === 0) {
this.$refs.guava.index()
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()
}
})
})
},
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,220 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app">
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="教代会">
<el-select @change="meetingChange" clearable filterable placeholder="所属教代会"
v-model="pageForm.sessionId">
<el-option :key="item.id" :label="item.fullName" :value="item.id"
v-for="item in sessionOptions"></el-option>
</el-select>
</search-item>
<search-item label="提案编号">
<el-input v-model="pageForm.code" placeholder="提案编号" @keyup.enter.native="doSearch" clearable
style="width: 100%"></el-input>
</search-item>
<search-item label="提案名称">
<el-input v-model="pageForm.name" placeholder="提案名称" @keyup.enter.native="doSearch" clearable
style="width: 100%"></el-input>
</search-item>
<search-item label="姓名/工号">
<el-input placeholder="请输入姓名或工号" clearable
v-model="pageForm.createUserKeyword"></el-input>
</search-item>
</search>
</el-card>
<el-card shadow="never">
<table-tool :columns.sync="tableColumns">
<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 v-loading="tableLoading" :data="tableData" @sort-change="pageOrder" ref="tableRef" row-key="id" style="width: 100%">
<el-table-column label="序号" width="50" type="index" :index="indexMethod"
fixed="left"></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:key="column.key"
:min-width="column.width"
:fixed="column.fixed"
sortable="custom"
show-overflow-tooltip
v-for="column in tableColumns"
v-if="column.visible !== false"
>
<template v-if="column.prop === 'caseFilingResult'" scope="{row}">
<dict-tag :options="dict.type.PROPOSAL_CASE_FILING_RESULT"
:value="row.caseFilingResult"></dict-tag>
</template>
<template v-else-if="column.prop === 'merge'" scope="{row}">
<el-tag v-if="row.merge" size="small"></el-tag>
</template>
<template v-else-if="column.prop === 'instanceState'" 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="200px">
<template slot-scope="{row}">
<el-button @click="openView(row)" size="mini" type="primary">查看</el-button>
<el-button v-if="!row.pcoId" @click="openAudit(row)" size="mini" type="primary">审核</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<template #edit>
<proposal-info ref="proposalInfoRef">
<div v-if="showApprovalForm">
<div class="process-title">
提案委员会成员意见
</div>
<el-form :model="formData" ref="formRef" label-width="120px" :rules="formRules" label-suffix="">
<el-form-item label="立案结果" prop="caseFilingResult"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<el-radio-group v-model="formData.caseFilingResult" size="small">
<el-radio v-for="item in dict.type.PROPOSAL_CASE_FILING_RESULT" :label="item.code"
border>{{item.label}}
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item v-if="['CONFIRM_FILING'].includes(formData.caseFilingResult)" label="立案类型"
prop="caseFilingType"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<el-radio-group v-model="formData.caseFilingType" size="small">
<el-radio v-for="item in dict.type.PROPOSAL_CASE_FILING_TYPE" :label="item.code" border>
{{item.label}}
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="审核意见" prop="opinion"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<user-opinion-textarea v-model="formData.opinion"></user-opinion-textarea>
</el-form-item>
</el-form>
<el-row type="flex" justify="end">
<el-button @click="doSubmit" size="small" type="primary">提交</el-button>
<el-button @click="$refs.guava.index()" size="small">返回</el-button>
</el-row>
</div>
</proposal-info>
</template>
</guava>
</div>
<script nonce="${cspNonce!}">
<!--#include('../../common/info.js'){}#-->
new Vue({
el: "#app",
store,
dicts: ["PROPOSAL_CASE_FILING_RESULT", "PROPOSAL_CASE_FILING_TYPE"],
mixins: [initTableMixins],
components: {
"proposal-info": PROPOSAL_INFO
},
data() {
return {
tableColumns: [
{label: "提案编号", prop: "code"},
{label: "提案名称", prop: "name", width: "200px"},
{label: "提案类别", prop: "typeName"},
{label: "届次", prop: "sessionName"},
{label: "代表团", prop: "delegationName"},
{label: "立案票数", prop: "CONFIRM_FILING_COUNT"},
{label: "作为建议票数", prop: "SUGGESTION_COUNT"},
{label: "不予立案票数", prop: "NOT_COUNT"},
{label: "当前节点", prop: "taskName"},
{label: "流程状态", prop: "instanceState"}
],
pageForm: {
approval: false
},
formData: {
tf_masterUnitId: null,
tf_slaveUnitIds: []
},
showApprovalForm: false,
sessionOptions: [],
delegationOptions: [],
underTakeOptions: []
}
},
methods: {
openView(row) {
this.$refs.guava.edit(() => {
this.showApprovalForm = false
this.$refs.proposalInfoRef.onOpen(row)
})
},
// 审批
openAudit(row) {
this.$refs.guava.edit(() => {
this.showApprovalForm = true
this.formData = {
proposalId: row.id,
caseFilingResult: null,
caseFilingType: null,
opinion: null
}
this.$refs.proposalInfoRef.onOpen(row)
})
},
doSubmit() {
this.$refs.formRef.validate(async (valid) => {
if (!valid) return
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post('/platform/proposal/commissioner/doApproval', this.formData).then(res => {
if (res.code === 0) {
this.$message.success(res.msg)
this.doSearch()
this.$refs.guava.index()
}
})
})
})
},
// 教代会
async meetingChange(val) {
this.doSearch()
},
// 查询开启的教代会
listOpenSession() {
this.$axios.post("/platform/proposal/common/listOpenSession").then((res) => {
if (res.code === 0) {
this.sessionOptions = res.data
if (this.sessionOptions) {
this.$set(this.pageForm, "sessionId", this.sessionOptions[0].id)
this.pageData()
}
}
})
},
},
created() {
this.pageData()
this.listOpenSession()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,507 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app">
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="教代会">
<el-select @change="meetingChange" clearable filterable placeholder="所属教代会"
v-model="pageForm.sessionId">
<el-option :key="item.id" :label="item.fullName" :value="item.id"
v-for="item in sessionOptions"></el-option>
</el-select>
</search-item>
<search-item label="代表团">
<el-select clearable filterable placeholder="所属代表团" v-model="pageForm.delegationId">
<el-option :key="item.id" :label="item.name" :value="item.id"
v-for="item in delegationOptions"></el-option>
</el-select>
</search-item>
<search-item label="工会">
<el-select clearable filterable placeholder="所属工会" 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-item label="提案编号">
<el-input v-model="pageForm.code" placeholder="提案编号" @keyup.enter.native="doSearch" clearable
style="width: 100%"></el-input>
</search-item>
<search-item label="提案名称">
<el-input v-model="pageForm.name" placeholder="提案名称" @keyup.enter.native="doSearch" clearable
style="width: 100%"></el-input>
</search-item>
<search-item label="姓名/工号">
<el-input placeholder="请输入姓名或工号" clearable v-model="pageForm.createUserKeyword"></el-input>
</search-item>
<!-- <search-item label="提案人姓名">-->
<!-- <el-input-->
<!-- @keyup.enter.native="doSearch"-->
<!-- clearable-->
<!-- placeholder="请输入提案人姓名"-->
<!-- v-model="pageForm.createUserName"-->
<!-- style="width: 100%"-->
<!-- ></el-input>-->
<!-- </search-item>-->
<!-- <search-item label="提案人工号">-->
<!-- <el-input-->
<!-- @keyup.enter.native="doSearch"-->
<!-- clearable-->
<!-- placeholder="请输入提案人工号"-->
<!-- v-model="pageForm.createUserLoginName"-->
<!-- style="width: 100%"-->
<!-- ></el-input>-->
<!-- </search-item>-->
</search>
</el-card>
<el-card shadow="never">
<table-tool :columns.sync="tableColumns">
<el-button type="primary" size="small" @click="exportList">导出</el-button>
<el-button type="primary" icon="el-icon-plus" size="small" @click="openMerge">并案审核</el-button>
<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 :data="tableData" @sort-change="pageOrder" ref="tableRef" row-key="id" style="width: 100%" v-loading="tableLoading">
<el-table-column type="selection" width="50" fixed="left" v-if="!pageForm.approval"></el-table-column>
<el-table-column label="序号" width="50" type="index" :index="indexMethod"
fixed="left"></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:key="column.key"
:min-width="column.width"
:fixed="column.fixed"
sortable="custom"
show-overflow-tooltip
v-for="column in tableColumns"
v-if="column.visible !== false"
>
<template v-if="column.prop === 'caseFilingResult'" scope="{row}">
<dict-tag
:options="dict.type.PROPOSAL_CASE_FILING_RESULT"
:value="JSON.parse(row.taskVariable)?.tf_caseFilingResult"></dict-tag>
</template>
<template v-else-if="column.prop === 'merge'" scope="{row}">
<el-tag v-if="row.merge" size="small"></el-tag>
</template>
<template v-else-if="column.prop === 'instanceState'" 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="openView(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>
<proposal-info ref="proposalInfoRef">
<div v-if="showApprovalForm">
<div class="process-title">
{{formData.taskName}}
</div>
<el-form :model="formData" ref="formRef" label-width="120px" :rules="formRules" label-suffix="">
<el-form-item label="立案结果" prop="tf_caseFilingResult"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<el-radio-group v-model="formData.tf_caseFilingResult" size="small" @change="handleCaseFilingResultChange">
<el-radio v-for="item in dict.type.PROPOSAL_CASE_FILING_RESULT" :label="item.code"
border>{{item.label}}
</el-radio>
</el-radio-group>
</el-form-item>
<!-- 普通提案/重点提案暂不展示,保留原字段和处理逻辑,便于兼容历史流程数据。 -->
<el-form-item v-if="false" label="立案类型"
prop="tf_caseFilingType"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<el-radio-group v-model="formData.tf_caseFilingType" size="small">
<el-radio v-for="item in dict.type.PROPOSAL_CASE_FILING_TYPE" :label="item.code" border>
{{item.label}}
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item
:label="formData.tf_caseFilingResult === 'SUGGESTION' ? '办理单位' : '主办单位'"
v-if="['CONFIRM_FILING','SUGGESTION'].includes(formData.tf_caseFilingResult)"
:rules="[{required:['CONFIRM_FILING','SUGGESTION'].includes(formData.tf_caseFilingResult),message:formData.tf_caseFilingResult === 'SUGGESTION' ? '请选择办理单位' : '请选择主办单位',trigger:['change','blur']}]"
prop="tf_masterUnitIds"
>
<el-select v-model="formData.tf_masterUnitIds" filterable clearable multiple
@change="updateFilingOpinion"
style="width: 100%">
<el-option
v-for="item in underTakeOptions"
:label="item.name"
:value="item.id"
:key="item.id"
:disabled="formData && formData.tf_slaveUnitIds.includes(item.id)"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="协办单位"
v-if="formData.tf_caseFilingResult === 'CONFIRM_FILING'"
prop="tf_slaveUnitIds"
>
<el-select v-model="formData.tf_slaveUnitIds" filterable clearable multiple
@change="updateFilingOpinion"
style="width: 100%">
<el-option
v-for="item in underTakeOptions"
:label="item.name"
:value="item.id"
:key="item.id"
:disabled="formData && formData.tf_masterUnitIds.includes(item.id)"
></el-option>
</el-select>
</el-form-item>
<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(1)" size="small" type="primary">提交</el-button>
<el-button @click="handleTaskAction(4)" size="small" type="info">退回到提案人(不审核)</el-button>
<el-button @click="handleTaskAction(6)" size="small" type="info">退回到提案人(审核)</el-button>
<el-button @click="$refs.guava.index()" size="small">返回</el-button>
</el-row>
</div>
</proposal-info>
</template>
<template #public>
<merge ref="mergeRef" @close="handleMergeClose"></merge>
</template>
</guava>
</div>
<script nonce="${cspNonce!}">
<!--#include("../../common/info.js"){}#-->
<!--#include('merge.js'){}#-->
new Vue({
el: "#app",
store,
dicts: ["PROPOSAL_CASE_FILING_RESULT", "PROPOSAL_CASE_FILING_TYPE"],
mixins: [initTableMixins],
components: {
"proposal-info": PROPOSAL_INFO,
merge
},
data() {
return {
tableColumns: [
{ label: "提案编号", prop: "code" },
{ label: "立案编号", prop: "caseFilingCode" },
{ label: "提案名称", prop: "name", width: "200px" },
{ label: "提案类别", prop: "typeName" },
{ label: "届次", prop: "sessionName" },
{ label: "立案结果", prop: "caseFilingResult" },
{ label: "代表团", prop: "delegationName" },
{ label: "当前节点", prop: "curTaskName" },
{ label: "流程状态", prop: "instanceState" }
],
pageForm: {
approval: false
},
formData: {
tf_masterUnitIds: [],
tf_slaveUnitIds: []
},
formRules: {
tf_caseFilingResult: [{ required: true, message: "请选择立案结果", trigger: ["blur", "change"] }],
tf_caseFilingType: [{ required: true, message: "请选择立案类型", trigger: ["blur", "change"] }],
tf_masterUnitIds: [{ required: true, message: "请选择主办单位", trigger: "blur" }],
approvalOpinion: [{ required: true, message: "请填写审核意见", trigger: "blur" }]
},
showApprovalForm: false,
sessionOptions: [],
delegationOptions: [],
unionOptions: [],
underTakeOptions: []
}
},
methods: {
exportList() {
this.$downLoad(loc() + "/exportList", {
pageForm: JSON.stringify(this.pageForm),
approval: this.pageForm.approval,
tableColumns: JSON.stringify(this.tableColumns.filter(function (item) {
return item.visible !== false
}))
})
},
/**
* “作为建议”不再区分主办/协办,只保留办理单位;
* 切到“不予立案”等结果时,同时清空已选单位,避免旧值被误提交。
* 每次切换立案结果时同步写入对应的默认审核意见,审核人仍可在提交前修改。
* @param caseFilingResult 当前选择的立案结果编码
*/
handleCaseFilingResultChange(caseFilingResult) {
const opinionMap = {
CONFIRM_FILING: "经提案委员会审理,该提案确定立案。",
SUGGESTION: "经提案委员会审理,该提案作为意见建议。",
NOT: "经提案委员会审理,该提案不予立案。"
}
this.$set(this.formData, "tf_opinion", opinionMap[caseFilingResult] || "")
if (caseFilingResult !== "CONFIRM_FILING") {
this.$set(this.formData, "tf_caseFilingType", "")
}
if (caseFilingResult === "SUGGESTION") {
this.$set(this.formData, "tf_slaveUnitIds", [])
this.updateFilingOpinion()
return
}
if (caseFilingResult !== "CONFIRM_FILING") {
this.$set(this.formData, "tf_masterUnitIds", [])
this.$set(this.formData, "tf_slaveUnitIds", [])
}
this.updateFilingOpinion()
},
/**
* 确定立案时根据主办、协办单位生成标准审核意见;
* 工作建议根据办理单位自动补充“此提案建议由XX办理”。
*/
updateFilingOpinion() {
const caseFilingResult = this.formData.tf_caseFilingResult
if (!["CONFIRM_FILING", "SUGGESTION"].includes(caseFilingResult)) {
return
}
const masterUnitIds = this.formData.tf_masterUnitIds || []
const slaveUnitIds = this.formData.tf_slaveUnitIds || []
const masterUnitNames = masterUnitIds.map((unitId) => {
const unit = this.underTakeOptions.find((item) => item.id === unitId)
return unit ? unit.name : ""
}).filter((unitName) => unitName)
const slaveUnitNames = slaveUnitIds.map((unitId) => {
const unit = this.underTakeOptions.find((item) => item.id === unitId)
return unit ? unit.name : ""
}).filter((unitName) => unitName)
if (caseFilingResult === "SUGGESTION") {
let suggestionOpinion = "经提案委员会审理,该提案作为意见建议。"
if (masterUnitNames.length) {
suggestionOpinion = "经提案委员会审理,该提案作为意见建议,此提案建议由"
+ masterUnitNames.join("、") + "办理。"
}
this.$set(this.formData, "tf_opinion", suggestionOpinion)
return
}
let opinion = "经提案工作委员会研究,符合提案立案条件,予以立案。"
if (masterUnitNames.length) {
opinion = "经提案工作委员会研究,符合提案立案条件,予以立案,此提案建议由"
+ masterUnitNames.join("、") + "办理,"
+ (slaveUnitNames.length ? "由" + slaveUnitNames.join("、") + "协办。" : "暂无协办。")
}
this.$set(this.formData, "tf_opinion", opinion)
},
openView(row) {
this.$refs.guava.edit(() => {
this.showApprovalForm = false
this.$refs.proposalInfoRef.onOpen(row)
})
},
openAudit(row) {
this.$refs.guava.edit(() => {
this.showApprovalForm = true
this.formData = {
processTaskId: row.taskId,
taskName: row.curTaskName,
taskKey: row.taskKey,
tf_masterUnitIds: [],
tf_slaveUnitIds: []
}
this.$refs.proposalInfoRef.onOpen(row)
})
},
handleTaskAction(val) {
this.$refs.formRef.validate(valid => {
if (valid) {
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
// “作为建议”统一按办理单位处理,提交时不再携带协办单位数据。
const masterUnitIds = this.formData.tf_masterUnitIds || []
const slaveUnitIds = this.formData.tf_caseFilingResult === "CONFIRM_FILING" ? (this.formData.tf_slaveUnitIds || []) : []
// 是否有协办单位
let tf_helpunitreply
if (slaveUnitIds.length > 0) {
tf_helpunitreply = "HAS_HELP_UNIT"
} else {
tf_helpunitreply = "NO_HELP_UNIT"
}
const params = {
...this.formData,
tf_masterUnitIds: masterUnitIds,
tf_slaveUnitIds: slaveUnitIds,
submitType: val,
taskName: "startTask",
// 兼容旧流程仍按单个主办单位字段取值的场景,这里保留第一个主办单位ID和名称。
tf_masterUnitId: masterUnitIds.length ? masterUnitIds[0] : "",
tf_masterUnitName: masterUnitIds.length ? this.underTakeOptions.find(v => v.id === masterUnitIds[0])?.name : "",
tf_masterUnitNames: masterUnitIds.map(v => this.underTakeOptions.find(v2 => v2.id === v)?.name),
tf_masterUnitNameStr: masterUnitIds.map(v => this.underTakeOptions.find(v2 => v2.id === v)?.name).join(","),
tf_slaveUnitNames: slaveUnitIds.map(v => this.underTakeOptions.find(v2 => v2.id === v)?.name),
tf_slaveUnitNameStr: slaveUnitIds.map(v => this.underTakeOptions.find(v2 => v2.id === v)?.name).join(","),
tf_helpunitreply: tf_helpunitreply
}
// 不审核退回时记录来源节点,提案人重新提交后由 WF 直接跳回当前审核节点。
if (val === 4) {
params.tf_sourceTaskKey = this.formData.taskKey
params.tf_audit = false
}
const loading = createLoading("提交中")
this.$axios.post("/platform/proposal/committeeFiling/executeTask", {
data: JSON.stringify(params)
}).then((res) => {
if (res.code === 0) {
this.$refs.guava.index()
this.$message.success(res.msg)
this.doSearch()
}
}).finally(() => {
loading.close()
})
})
}
})
},
// 打开并案审核
openMerge() {
const selection = this.$refs.tableRef.selection
if (selection.length < 2) {
this.$message.warning("请先勾选需要并案审核的提案,至少需要两条提案")
return
}
this.$refs.guava.public(() => {
this.$refs.mergeRef.onOpen(selection, {
processTaskIds: selection.map(v => v.taskId),
taskName: selection[0].curTaskName,
taskKey: selection[0].taskKey,
tf_masterUnitIds: [],
tf_slaveUnitIds: []
})
})
},
/**
* 并案审核完成后由父页面统一收口处理:
* 1. 关闭弹层
* 2. 清空左侧勾选框
* 3. 刷新父列表,避免仍显示审核前数据
*/
handleMergeClose() {
this.$refs.guava.index()
this.$nextTick(() => {
if (this.$refs.tableRef) {
this.$refs.tableRef.clearSelection()
}
})
this.doSearch()
},
onRevoke(row) {
this.$confirm("您确定要撤回吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "info"
}).then(() => {
// 提委会立案撤回需要走专用接口,确保并案提案会整组一起撤回。
this.$axios.post("/platform/proposal/committeeFiling/revokeTask", { taskId: row.taskId, proposalId: row.id }).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.doSearch()
}
})
})
},
/**
* 教代会切换后重新加载当前届次代表团,并清空旧的代表团筛选条件,
* 避免跨届次继续沿用旧代表团数据。
*/
meetingChange() {
this.listDelegation()
this.doSearch()
},
/**
* 代表团下拉按教代会联动查询,没有选教代会时保持空列表。
*/
listDelegation() {
this.delegationOptions = []
this.$set(this.pageForm, "delegationId", null)
if (!this.pageForm.sessionId) {
return
}
this.$axios.post("/platform/proposal/common/listDelegation", {
sessionId: this.pageForm.sessionId
}).then((res) => {
if (res.code === 0) {
this.delegationOptions = res.data
}
})
},
/**
* 工会下拉按系统分工会列表加载,用于按提案人所属工会筛选当前页面列表。
*/
listUnion() {
this.$businessTool.listUnion().then((res) => {
this.unionOptions = res
})
},
// 查询开启的教代会
listOpenSession() {
this.$axios.post("/platform/proposal/common/listOpenSession").then((res) => {
if (res.code === 0) {
this.sessionOptions = res.data
if (this.sessionOptions) {
this.$set(this.pageForm, "sessionId", this.sessionOptions[0].id)
this.listDelegation()
this.pageData()
}
}
})
},
// 查询办理单位
listUnderTake() {
this.$axios.post("/platform/proposal/common/listUnderTake").then((res) => {
if (res.code === 0) {
this.underTakeOptions = res.data
this.updateFilingOpinion()
}
})
}
},
created() {
this.pageData()
this.listOpenSession()
this.listUnion()
this.listUnderTake()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,257 @@
const merge = {
template: /*language=HTML*/ `
<div>
<div class="process-title">
预选并案提案
</div>
<el-table v-loading="tableLoading" :data="selection" ref="tableRef" row-key="id" style="width: 100%">
<el-table-column label="序号" width="50" type="index"></el-table-column>
<el-table-column label="提案编号" prop="code"></el-table-column>
<el-table-column label="提案名称" prop="name" show-overflow-tooltip></el-table-column>
<el-table-column label="提案类别" prop="typeName"></el-table-column>
<el-table-column label="届次" prop="sessionName"></el-table-column>
<el-table-column label="代表团" prop="delegationName"></el-table-column>
<el-table-column label="操作" fixed="right" width="100px">
<template scope="scope">
<el-button @click="onRemove(scope.$index)" size="mini" type="danger">移除</el-button>
</template>
</el-table-column>
</el-table>
<div>
<div class="process-title">
{{formData.taskName}}
</div>
<el-form :model="formData" ref="formRef" label-width="120px" :rules="formRules" label-suffix="">
<el-form-item label="立案结果" prop="tf_caseFilingResult"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<el-radio-group v-model="formData.tf_caseFilingResult" size="small" @change="handleCaseFilingResultChange">
<el-radio v-for="item in dict.type.PROPOSAL_CASE_FILING_RESULT" :label="item.code"
border>{{item.label}}
</el-radio>
</el-radio-group>
</el-form-item>
<!-- 普通提案/重点提案暂不展示,保留原字段和处理逻辑,便于兼容历史流程数据。 -->
<el-form-item v-if="false" label="立案类型"
prop="tf_caseFilingType"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<el-radio-group v-model="formData.tf_caseFilingType" size="small">
<el-radio v-for="item in dict.type.PROPOSAL_CASE_FILING_TYPE" :label="item.code" border>
{{item.label}}
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item
:label="formData.tf_caseFilingResult === 'SUGGESTION' ? '办理单位' : '主办单位'"
v-if="['CONFIRM_FILING','SUGGESTION'].includes(formData.tf_caseFilingResult)"
:rules="[{required:['CONFIRM_FILING','SUGGESTION'].includes(formData.tf_caseFilingResult),message:formData.tf_caseFilingResult === 'SUGGESTION' ? '请选择办理单位' : '请选择主办单位',trigger:['change','blur']}]"
prop="tf_masterUnitIds"
>
<el-select v-model="formData.tf_masterUnitIds" filterable clearable multiple
@change="updateFilingOpinion" style="width: 100%">
<el-option
v-for="item in underTakeOptions"
:label="item.name"
:value="item.id"
:key="item.id"
:disabled="formData && formData.tf_slaveUnitIds.includes(item.id)"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="协办单位"
v-if="formData.tf_caseFilingResult === 'CONFIRM_FILING'"
prop="tf_slaveUnitIds"
>
<el-select v-model="formData.tf_slaveUnitIds" filterable clearable multiple
@change="updateFilingOpinion"
style="width: 100%">
<el-option
v-for="item in underTakeOptions"
:label="item.name"
:value="item.id"
:key="item.id"
:disabled="formData && formData.tf_masterUnitIds.includes(item.id)"
></el-option>
</el-select>
</el-form-item>
<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(1)" size="small" type="primary">提交</el-button>
<el-button @click="handleTaskAction(4)" size="small" type="info">退回到提案人(不审核)</el-button>
<el-button @click="handleTaskAction(6)" size="small" type="info">退回到提案人(审核)</el-button>
<el-button @click="$emit('close')" size="small">返回</el-button>
</el-row>
</div>
</div>
`,
dicts: ["PROPOSAL_CASE_FILING_RESULT", "PROPOSAL_CASE_FILING_TYPE"],
data() {
return {
tableLoading: false,
selection: [],
formData: {
tf_masterUnitIds: [],
tf_slaveUnitIds: []
},
formRules: {
tf_caseFilingResult: [{ required: true, message: "请选择立案结果", trigger: ["blur", "change"] }],
tf_caseFilingType: [{ required: true, message: "请选择立案类型", trigger: ["blur", "change"] }],
tf_masterUnitIds: [{ required: true, message: "请选择主办单位", trigger: "blur" }],
tf_opinion: [{ required: true, message: "请填写审核意见", trigger: "blur" }],
},
underTakeOptions: []
}
},
methods: {
/**
* 并案审核与单案审核保持同一口径:
* “作为建议”只录入办理单位,不再区分协办单位。
* 每次切换立案结果时同步写入对应的默认审核意见,审核人仍可在提交前修改。
* @param caseFilingResult 当前选择的立案结果编码
*/
handleCaseFilingResultChange(caseFilingResult) {
const opinionMap = {
CONFIRM_FILING: "经提案委员会审理,该提案确定立案。",
SUGGESTION: "经提案委员会审理,该提案作为意见建议。",
NOT: "经提案委员会审理,该提案不予立案。"
}
this.$set(this.formData, "tf_opinion", opinionMap[caseFilingResult] || "")
if (caseFilingResult !== "CONFIRM_FILING") {
this.$set(this.formData, "tf_caseFilingType", "")
}
if (caseFilingResult === "SUGGESTION") {
this.$set(this.formData, "tf_slaveUnitIds", [])
this.updateFilingOpinion()
return
}
if (caseFilingResult !== "CONFIRM_FILING") {
this.$set(this.formData, "tf_masterUnitIds", [])
this.$set(this.formData, "tf_slaveUnitIds", [])
}
this.updateFilingOpinion()
},
/**
* 并案审核根据确定立案的主协办单位或工作建议的办理单位生成标准审核意见。
*/
updateFilingOpinion() {
const caseFilingResult = this.formData.tf_caseFilingResult
if (!["CONFIRM_FILING", "SUGGESTION"].includes(caseFilingResult)) {
return
}
const masterUnitIds = this.formData.tf_masterUnitIds || []
const slaveUnitIds = this.formData.tf_slaveUnitIds || []
const masterUnitNames = masterUnitIds.map((unitId) => {
const unit = this.underTakeOptions.find((item) => item.id === unitId)
return unit ? unit.name : ""
}).filter((unitName) => unitName)
const slaveUnitNames = slaveUnitIds.map((unitId) => {
const unit = this.underTakeOptions.find((item) => item.id === unitId)
return unit ? unit.name : ""
}).filter((unitName) => unitName)
if (caseFilingResult === "SUGGESTION") {
let suggestionOpinion = "经提案委员会审理,该提案作为意见建议。"
if (masterUnitNames.length) {
suggestionOpinion = "经提案委员会审理,该提案作为意见建议,此提案建议由"
+ masterUnitNames.join("、") + "办理。"
}
this.$set(this.formData, "tf_opinion", suggestionOpinion)
return
}
let opinion = "经提案工作委员会研究,符合提案立案条件,予以立案。"
if (masterUnitNames.length) {
opinion = "经提案工作委员会研究,符合提案立案条件,予以立案,此提案建议由"
+ masterUnitNames.join("、") + "办理,"
+ (slaveUnitNames.length ? "由" + slaveUnitNames.join("、") + "协办。" : "暂无协办。")
}
this.$set(this.formData, "tf_opinion", opinion)
},
onOpen(selection, formData) {
this.selection = selection
this.formData = formData
this.listUnderTake()
},
// 移除
onRemove(index) {
if (this.selection.length === 2) {
this.$message.warning("并案审核至少两条提案")
return
}
this.selection.splice(index, 1)
},
// 查询办理单位
listUnderTake() {
// 并案弹窗初始化期间同步遮罩预选提案表格,避免辅助数据未就绪时继续操作。
this.$set(this, "tableLoading", true)
this.$axios.post("/platform/proposal/common/listUnderTake").then((res) => {
if (res.code === 0) {
this.underTakeOptions = res.data
this.updateFilingOpinion()
}
}).finally(() => {
this.$set(this, "tableLoading", false)
})
},
handleTaskAction(val) {
this.$refs.formRef.validate(valid => {
if (valid) {
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
// 并案审核提交参数与单案立案页保持一致,避免两个入口的流程变量不一致。
const masterUnitIds = this.formData.tf_masterUnitIds || []
const slaveUnitIds = this.formData.tf_caseFilingResult === "CONFIRM_FILING" ? (this.formData.tf_slaveUnitIds || []) : []
// 是否有协办单位
let tf_helpunitreply
if (slaveUnitIds.length > 0) {
tf_helpunitreply = "HAS_HELP_UNIT"
} else {
tf_helpunitreply = "NO_HELP_UNIT"
}
const params = {
...this.formData,
tf_masterUnitIds: masterUnitIds,
tf_slaveUnitIds: slaveUnitIds,
proposalIds: this.selection.map(v => v.id),
submitType: val,
taskName: "startTask",
// 兼容旧流程仍按单个主办单位字段取值的场景,这里保留第一个主办单位ID和名称。
tf_masterUnitId: masterUnitIds.length ? masterUnitIds[0] : "",
tf_masterUnitName: masterUnitIds.length ? this.underTakeOptions.find(v => v.id === masterUnitIds[0])?.name : "",
tf_masterUnitNames: masterUnitIds.map(v => this.underTakeOptions.find(v2 => v2.id === v)?.name),
tf_masterUnitNameStr: masterUnitIds.map(v => this.underTakeOptions.find(v2 => v2.id === v)?.name).join(','),
tf_slaveUnitNames: slaveUnitIds.map(v => this.underTakeOptions.find(v2 => v2.id === v)?.name),
tf_slaveUnitNameStr: slaveUnitIds.map(v => this.underTakeOptions.find(v2 => v2.id === v)?.name).join(','),
tf_helpunitreply: tf_helpunitreply
}
// 不审核退回时记录来源节点,提案人重新提交后由 WF 直接跳回当前审核节点。
if (val === 4) {
params.tf_sourceTaskKey = this.formData.taskKey
params.tf_audit = false
}
const loading = createLoading('提交中')
this.$axios.post("/platform/proposal/committeeFiling/merge", {
data: JSON.stringify(params)
}).then((res) => {
if (res.code === 0) {
this.$emit('close')
this.$message.success(res.msg)
}
}).finally(() => {
loading.close()
})
})
}
})
}
}
}
@@ -0,0 +1,530 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app">
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="教代会">
<el-select @change="meetingChange" clearable filterable placeholder="所属教代会"
v-model="pageForm.sessionId">
<el-option :key="item.id" :label="item.fullName" :value="item.id"
v-for="item in sessionOptions"></el-option>
</el-select>
</search-item>
<search-item label="代表团">
<el-select clearable filterable placeholder="所属代表团" v-model="pageForm.delegationId">
<el-option :key="item.id" :label="item.name" :value="item.id"
v-for="item in delegationOptions"></el-option>
</el-select>
</search-item>
<search-item label="工会">
<el-select clearable filterable placeholder="所属工会" 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-item label="提案编号">
<el-input v-model="pageForm.code" placeholder="提案编号" @keyup.enter.native="doSearch" clearable
style="width: 100%"></el-input>
</search-item>
<search-item label="提案名称">
<el-input v-model="pageForm.name" placeholder="提案名称" @keyup.enter.native="doSearch" clearable
style="width: 100%"></el-input>
</search-item>
<search-item label="姓名/工号">
<el-input placeholder="请输入姓名或工号" clearable v-model="pageForm.createUserKeyword"></el-input>
</search-item>
<!-- <search-item label="提案人姓名">-->
<!-- <el-input-->
<!-- @keyup.enter.native="doSearch"-->
<!-- clearable-->
<!-- placeholder="请输入提案人姓名"-->
<!-- v-model="pageForm.createUserName"-->
<!-- style="width: 100%"-->
<!-- ></el-input>-->
<!-- </search-item>-->
<!-- <search-item label="提案人工号">-->
<!-- <el-input-->
<!-- @keyup.enter.native="doSearch"-->
<!-- clearable-->
<!-- placeholder="请输入提案人工号"-->
<!-- v-model="pageForm.createUserLoginName"-->
<!-- style="width: 100%"-->
<!-- ></el-input>-->
<!-- </search-item>-->
</search>
</el-card>
<el-card shadow="never">
<table-tool :columns.sync="tableColumns">
<el-button type="primary" size="small" @click="exportList">导出</el-button>
<!-- <el-button type="primary" icon="el-icon-plus" size="small" @click="openMerge">并案审核</el-button>-->
<!-- <el-button type="primary" icon="el-icon-plus" size="small" @click="doUpData">更新</el-button>-->
<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 v-loading="tableLoading" :data="tableData" @sort-change="pageOrder" ref="tableRef" row-key="id" style="width: 100%">
<el-table-column type="selection" width="50" fixed="left" v-if="!pageForm.approval"></el-table-column>
<el-table-column label="序号" width="50" type="index" :index="indexMethod"
fixed="left"></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:key="column.key"
:min-width="column.width"
:fixed="column.fixed"
sortable="custom"
show-overflow-tooltip
v-for="column in tableColumns"
v-if="column.visible !== false"
>
<template v-if="column.prop === 'caseFilingResult'" scope="{row}">
<dict-tag
:options="dict.type.PROPOSAL_CASE_FILING_RESULT"
:value="JSON.parse(row.taskVariable)?.tf_caseFilingResult"></dict-tag>
</template>
<template v-else-if="column.prop === 'merge'" scope="{row}">
<el-tag v-if="row.merge" size="small"></el-tag>
</template>
<template v-else-if="column.prop === 'instanceState'" 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="openView(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>
<proposal-info ref="proposalInfoRef" @done-tasks="doneTasks">
<div v-if="showApprovalForm">
<div class="process-title">
{{formData.taskName}}
</div>
<el-form :model="formData" ref="formRef" label-width="120px" :rules="formRules" label-suffix="">
<el-form-item label="立案结果" prop="tf_caseFilingResult"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<el-radio-group v-model="formData.tf_caseFilingResult" size="small" @change="handleCaseFilingResultChange">
<el-radio v-for="item in dict.type.PROPOSAL_CASE_FILING_RESULT" :label="item.code"
border>{{item.label}}
</el-radio>
</el-radio-group>
</el-form-item>
<!-- <el-form-item v-if="['CONFIRM_FILING'].includes(formData.tf_caseFilingResult)" label="立案类型"
prop="tf_caseFilingType"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<el-radio-group v-model="formData.tf_caseFilingType" size="small">
<el-radio v-for="item in dict.type.PROPOSAL_CASE_FILING_TYPE" :label="item.code" border>
{{item.label}}
</el-radio>
</el-radio-group>
</el-form-item>-->
<el-form-item
:label="formData.tf_caseFilingResult === 'SUGGESTION' ? '办理单位' : '主办单位'"
v-if="['CONFIRM_FILING','SUGGESTION'].includes(formData.tf_caseFilingResult)"
:rules="[{required:['CONFIRM_FILING','SUGGESTION'].includes(formData.tf_caseFilingResult),message:formData.tf_caseFilingResult === 'SUGGESTION' ? '请选择办理单位' : '请选择主办单位',trigger:['change','blur']}]"
prop="tf_masterUnitIds"
>
<el-select v-model="formData.tf_masterUnitIds" filterable clearable multiple
@change="updateFilingOpinion"
style="width: 100%">
<el-option
v-for="item in underTakeOptions"
:label="item.name"
:value="item.id"
:key="item.id"
:disabled="formData && formData.tf_slaveUnitIds.includes(item.id)"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="协办单位"
v-if="formData.tf_caseFilingResult === 'CONFIRM_FILING'"
prop="tf_slaveUnitIds"
>
<el-select v-model="formData.tf_slaveUnitIds" filterable clearable multiple
@change="updateFilingOpinion"
style="width: 100%">
<el-option
v-for="item in underTakeOptions"
:label="item.name"
:value="item.id"
:key="item.id"
:disabled="formData && formData.tf_masterUnitIds.includes(item.id)"
></el-option>
</el-select>
</el-form-item>
<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(1)" size="small" type="primary">提交</el-button>
<el-button @click="handleTaskAction(4)" size="small" type="info">退回到提案人(不审核)</el-button>
<el-button @click="handleTaskAction(6)" size="small" type="info">退回到提案人(审核)</el-button>
<el-button @click="$refs.guava.index()" size="small">返回</el-button>
</el-row>
</div>
</proposal-info>
</template>
<template #public>
<merge ref="mergeRef" @close="$refs.guava.index()"></merge>
</template>
</guava>
</div>
<script nonce="${cspNonce!}">
<!--#include('../../common/info.js'){}#-->
<!--#include('../committeeFiling/merge.js'){}#-->
new Vue({
el: "#app",
store,
dicts: ["PROPOSAL_CASE_FILING_RESULT", "PROPOSAL_CASE_FILING_TYPE"],
mixins: [initTableMixins],
components: {
"proposal-info": PROPOSAL_INFO,
merge
},
data() {
return {
tableColumns: [
{label: "提案编号", prop: "code"},
{label: "立案编号", prop: "caseFilingCode"},
{label: "提案名称", prop: "name", width: "200px"},
{label: "提案类别", prop: "typeName"},
{label: "届次", prop: "sessionName"},
{label: "立案结果", prop: "caseFilingResult"},
{label: "代表团", prop: "delegationName"},
{label: "当前节点", prop: "curTaskName"},
{label: "流程状态", prop: "instanceState"}
],
pageForm: {
approval: false
},
formData: {
tf_masterUnitIds: [],
tf_slaveUnitIds: []
},
showApprovalForm: false,
sessionOptions: [],
delegationOptions: [],
unionOptions: [],
underTakeOptions: [],
}
},
methods: {
exportList() {
this.$downLoad(loc() + "/exportList", {
pageForm: JSON.stringify(this.pageForm),
approval: this.pageForm.approval,
tableColumns: JSON.stringify(this.tableColumns.filter(function (item) {
return item.visible !== false
}))
})
},
/**
* “作为建议”场景下只保留办理单位,其他结果继续清理不适用的单位字段。
* 每次切换立案结果时同步写入对应的默认审核意见,审核人仍可在提交前修改。
* @param caseFilingResult 当前选择的立案结果编码
*/
handleCaseFilingResultChange(caseFilingResult) {
const opinionMap = {
CONFIRM_FILING: "经提案委员会审理,该提案确定立案。",
SUGGESTION: "经提案委员会审理,该提案作为意见建议。",
NOT: "经提案委员会审理,该提案不予立案。"
}
this.$set(this.formData, "tf_opinion", opinionMap[caseFilingResult] || "")
if (caseFilingResult !== "CONFIRM_FILING") {
this.$set(this.formData, "tf_caseFilingType", "")
}
if (caseFilingResult === "SUGGESTION") {
this.$set(this.formData, "tf_slaveUnitIds", [])
this.updateFilingOpinion()
return
}
if (caseFilingResult !== "CONFIRM_FILING") {
this.$set(this.formData, "tf_masterUnitIds", [])
this.$set(this.formData, "tf_slaveUnitIds", [])
}
this.updateFilingOpinion()
},
/**
* 确认承办单位时,根据确定立案的主协办单位或工作建议的办理单位生成审核意见。
* 单位数据尚未加载完成时保留默认意见,加载完成后再次补充实际单位名称。
*/
updateFilingOpinion() {
const caseFilingResult = this.formData.tf_caseFilingResult
if (!["CONFIRM_FILING", "SUGGESTION"].includes(caseFilingResult)) {
return
}
const masterUnitIds = this.formData.tf_masterUnitIds || []
const slaveUnitIds = this.formData.tf_slaveUnitIds || []
const masterUnitNames = masterUnitIds.map((unitId) => {
const unit = this.underTakeOptions.find((item) => item.id === unitId)
return unit ? unit.name : ""
}).filter((unitName) => unitName)
const slaveUnitNames = slaveUnitIds.map((unitId) => {
const unit = this.underTakeOptions.find((item) => item.id === unitId)
return unit ? unit.name : ""
}).filter((unitName) => unitName)
if (caseFilingResult === "SUGGESTION") {
let suggestionOpinion = "经提案委员会审理,该提案作为意见建议。"
if (masterUnitNames.length) {
suggestionOpinion = "经提案委员会审理,该提案作为意见建议,此提案建议由"
+ masterUnitNames.join("、") + "办理。"
}
this.$set(this.formData, "tf_opinion", suggestionOpinion)
return
}
let opinion = "经提案工作委员会研究,符合提案立案条件,予以立案。"
if (masterUnitNames.length) {
opinion = "经提案工作委员会研究,符合提案立案条件,予以立案,此提案建议由"
+ masterUnitNames.join("、") + "办理,"
+ (slaveUnitNames.length ? "由" + slaveUnitNames.join("、") + "协办。" : "暂无协办。")
}
this.$set(this.formData, "tf_opinion", opinion)
},
doUpData(){
this.$.axios.post(loc()+"/doUpData")
},
// 兼容流程变量返回数组、JSON 字符串、逗号分隔字符串三种情况,统一转成下拉框需要的数组。
normalizeUnitIds(unitIds) {
if (!unitIds) {
return []
}
if (Array.isArray(unitIds)) {
return unitIds
}
if (typeof unitIds === "string") {
var value = unitIds.trim()
if (!value) {
return []
}
if (value.indexOf("[") === 0) {
try {
var parsedValue = JSON.parse(value)
return Array.isArray(parsedValue) ? parsedValue : []
} catch (e) {
return []
}
}
return value.split(",").filter(function(item) {
return item && item.trim()
}).map(function(item) {
return item.trim()
})
}
return []
},
openView(row) {
this.$refs.guava.edit(() => {
this.showApprovalForm = false
this.$refs.proposalInfoRef.onOpen(row)
})
},
doneTasks(val) {
if (!val || !val.length) {
return
}
// 当前页面需要回显上一环节“提案委员会立案”保存的主办/协办单位或办理单位。
var data = val[val.length - 1]
this.$set(this.formData, "tf_caseFilingResult", data.ext.tf_caseFilingResult)
this.$set(this.formData, "tf_caseFilingType", data.ext.tf_caseFilingType)
this.$set(this.formData, "tf_masterUnitIds", this.normalizeUnitIds(data.ext.tf_masterUnitIds))
this.$set(this.formData, "tf_slaveUnitIds", this.normalizeUnitIds(data.ext.tf_slaveUnitIds))
this.handleCaseFilingResultChange(this.formData.tf_caseFilingResult)
},
openAudit(row) {
this.$refs.guava.edit(() => {
this.showApprovalForm = true
this.formData = {
proposalId: row.id,
processTaskId: row.taskId,
taskName: row.curTaskName,
taskKey: row.taskKey,
tf_masterUnitIds: [],
tf_slaveUnitIds: []
}
this.$refs.proposalInfoRef.onOpen(row)
})
},
handleTaskAction(val) {
this.$refs.formRef.validate(valid => {
if (!valid) return
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
// “作为建议”统一按办理单位处理,提交时不再携带协办单位数据。
const masterUnitIds = this.formData.tf_masterUnitIds || []
const slaveUnitIds = this.formData.tf_caseFilingResult === "CONFIRM_FILING" ? (this.formData.tf_slaveUnitIds || []) : []
// 是否有协办单位
let tf_helpunitreply;
if (slaveUnitIds.length > 0) {
tf_helpunitreply = 'HAS_HELP_UNIT'
} else {
tf_helpunitreply = 'NO_HELP_UNIT'
}
const params = {
...this.formData,
tf_masterUnitIds: masterUnitIds,
tf_slaveUnitIds: slaveUnitIds,
submitType: val,
taskName: "startTask",
// 兼容旧流程仍按单个主办单位字段取值的场景,这里保留第一个主办单位ID和名称。
tf_masterUnitId: masterUnitIds.length ? masterUnitIds[0] : "",
tf_masterUnitName: masterUnitIds.length ? this.underTakeOptions.find(v => v.id === masterUnitIds[0])?.name : "",
tf_masterUnitNames: masterUnitIds.map(v => this.underTakeOptions.find(v2 => v2.id === v)?.name),
tf_masterUnitNameStr: masterUnitIds.map(v => this.underTakeOptions.find(v2 => v2.id === v)?.name).join(','),
tf_slaveUnitNames: slaveUnitIds.map(v => this.underTakeOptions.find(v2 => v2.id === v)?.name),
tf_slaveUnitNameStr: slaveUnitIds.map(v => this.underTakeOptions.find(v2 => v2.id === v)?.name).join(','),
tf_helpunitreply: tf_helpunitreply
}
// 不审核退回时记录来源节点,提案人重新提交后由 WF 直接跳回当前审核节点。
if (val === 4) {
params.tf_sourceTaskKey = this.formData.taskKey
params.tf_audit = false
}
const loading = createLoading('提交中')
this.$axios.post("/platform/proposal/committeeFilingUnit/executeTask", {
data: JSON.stringify(params)
}).then((res) => {
if (res.code === 0) {
this.$refs.guava.index()
this.$message.success(res.msg)
this.doSearch()
}
}).finally(() => {
loading.close()
})
})
})
},
// 打开并案审核
openMerge() {
const selection = this.$refs.tableRef.selection
if (selection.length < 2) {
this.$message.warning('请先勾选需要并案审核的提案,至少需要两条提案')
return
}
this.$refs.guava.public(() => {
this.$refs.mergeRef.onOpen(selection, {
processTaskIds: selection.map(v => v.taskId),
taskName: selection[0].curTaskName,
taskKey: selection[0].taskKey,
tf_masterUnitIds: [],
tf_slaveUnitIds: []
})
})
},
onRevoke(row) {
this.$confirm("您确定要撤回吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "info"
}).then(() => {
this.$axios.post("/platform/proposal/committeeFilingUnit/revokeTask", {
taskId: row.taskId,
proposalId: row.id
}).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.doSearch()
}
})
})
},
/**
* 教代会变更后,按当前届次联动刷新代表团下拉并清空旧值,
* 避免查询条件串到其他届次。
*/
meetingChange() {
this.listDelegation()
this.doSearch()
},
/**
* 根据教代会查询代表团列表,未选教代会时不加载代表团数据。
*/
listDelegation() {
this.delegationOptions = []
this.$set(this.pageForm, "delegationId", null)
if (!this.pageForm.sessionId) {
return
}
this.$axios.post("/platform/proposal/common/listDelegation", {
sessionId: this.pageForm.sessionId
}).then((res) => {
if (res.code === 0) {
this.delegationOptions = res.data
}
})
},
/**
* 工会下拉按系统分工会列表加载,用于按提案人所属工会筛选当前页面列表。
*/
listUnion() {
this.$businessTool.listUnion().then((res) => {
this.unionOptions = res
})
},
// 查询开启的教代会
listOpenSession() {
this.$axios.post("/platform/proposal/common/listOpenSession").then((res) => {
if (res.code === 0) {
this.sessionOptions = res.data
if (this.sessionOptions) {
this.$set(this.pageForm, "sessionId", this.sessionOptions[0].id)
this.listDelegation()
this.pageData()
}
}
})
},
// 查询办理单位
listUnderTake() {
this.$axios.post("/platform/proposal/common/listUnderTake").then((res) => {
if (res.code === 0) {
this.underTakeOptions = res.data
this.updateFilingOpinion()
}
})
}
},
created() {
this.pageData()
this.listOpenSession()
this.listUnion()
this.listUnderTake()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,196 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app" v-cloak>
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="教代会">
<el-select @change="doSearch" clearable filterable placeholder="所属教代会" v-model="pageForm.sessionId">
<el-option :key="item.id" :label="item.fullName" :value="item.id" v-for="item in sessionOptions"></el-option>
</el-select>
</search-item>
<search-item label="名称/编号">
<el-input @keyup.enter.native="doSearch" clearable placeholder="请输入内容"
v-model="pageForm.proposalKeyword">
<el-select slot="prepend" style="width: 110px" v-model="pageForm.proposalSearchField">
<el-option label="提案名称" value="name"></el-option>
<el-option label="提案编号" value="code"></el-option>
<el-option label="立案编号" value="caseFilingCode"></el-option>
</el-select>
</el-input>
</search-item>
<search-item label="姓名/工号">
<el-input placeholder="请输入姓名或工号" clearable v-model="pageForm.createUserKeyword"></el-input>
</search-item>
</search>
</el-card>
<el-card shadow="never">
<table-tool :columns.sync="tableColumns"></table-tool>
<el-table v-loading="tableLoading" :data="tableData" @sort-change="pageOrder" style="width: 100%">
<el-table-column label="序号" width="50" type="index" :index="indexMethod" fixed="left"></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:key="column.prop"
:min-width="column.width"
:fixed="column.fixed"
sortable="custom"
show-overflow-tooltip
v-for="column in tableColumns"
v-if="column.visible !== false"
>
<template v-if="column.prop === 'instanceState'" 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="220px">
<template slot-scope="{row}">
<el-button @click="openView(row)" size="mini" type="primary">查看</el-button>
<el-button @click="openJumpDialog(row)" size="mini" type="warning">跳转节点</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<template #edit>
<proposal-info ref="proposalInfoRef"></proposal-info>
</template>
<el-dialog title="跳转节点" width="480px" :visible.sync="jumpDialogVisible" append-to-body>
<el-form :model="jumpForm" ref="jumpFormRef" label-width="90px">
<el-form-item
label="目标节点"
prop="targetTaskName"
:rules="[{required: true, message: '请选择目标节点', trigger: 'change'}]"
>
<el-select v-model="jumpForm.targetTaskName" placeholder="请选择节点" filterable style="width: 100%">
<el-option v-for="item in jumpNodeOptions" :key="item.value" :label="item.label" :value="item.value"></el-option>
</el-select>
</el-form-item>
</el-form>
<span slot="footer">
<el-button size="small" @click="jumpDialogVisible = false">返回</el-button>
<el-button size="small" type="primary" @click="doJump">确定</el-button>
</span>
</el-dialog>
</guava>
</div>
<script nonce="${cspNonce!}">
<!--#include('../../common/info.js'){}#-->
new Vue({
el: "#app",
store,
mixins: [initTableMixins],
components: {
"proposal-info": PROPOSAL_INFO
},
data() {
return {
tableColumns: [
{label: "提案编号", prop: "code"},
{label: "立案编号", prop: "caseFilingCode"},
{label: "提案名称", prop: "name", width: "220px"},
{label: "提案人", prop: "createUserName", width: "90px"},
{label: "提案类别", prop: "typeName"},
{label: "届次", prop: "sessionName"},
{label: "代表团", prop: "delegationName"},
{label: "当前节点", prop: "curTaskName"},
{label: "流程状态", prop: "instanceState"}
],
pageForm: {
proposalSearchField: "name",
proposalKeyword: ""
},
jumpDialogVisible: false,
jumpNodeOptions: [],
jumpCurrentRow: null,
jumpForm: {
targetTaskName: "",
tf_audit: true
},
sessionOptions:[],
}
},
created() {
// 默认届次确定后再加载表格,避免无届次请求覆盖已按届次筛选的结果。
this.listOpenSession()
},
methods: {
openView(row) {
this.$refs.guava.edit(() => {
this.$refs.proposalInfoRef.onOpen(row)
})
},
openJumpDialog(row) {
this.jumpCurrentRow = row
this.jumpForm = {
targetTaskName: "",
tf_audit: true
}
this.jumpDialogVisible = true
this.$axios.post('/platform/proposal/control/jumpNodes', {instanceId: row.instanceId}).then(res => {
if (res.code === 0) {
const nodeList = res.data || []
const currentNode = nodeList.find(item => item.value === row.taskKey)
const currentSeq = currentNode ? Number(currentNode.seq) : Number.MAX_SAFE_INTEGER
this.jumpNodeOptions = nodeList.filter(item => item.value !== row.taskKey && Number(item.seq) < currentSeq)
}
})
},
doJump() {
this.$refs.jumpFormRef.validate(valid => {
if (!valid || !this.jumpCurrentRow) return
this.$confirm("您确定要跳转到该节点吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
const params = {
processTaskId: this.jumpCurrentRow.taskId,
submitType: 4,
taskName: this.jumpForm.targetTaskName,
tf_sourceTaskKey: this.jumpCurrentRow.taskKey,
tf_audit: true
}
this.$axios.post("/flow/common/executeTask", {
data: JSON.stringify(params)
}).then((res) => {
if (res.code === 0) {
this.jumpDialogVisible = false
this.$message.success(res.msg)
this.doSearch()
}
})
})
})
},
listOpenSession() {
this.$axios.post("/platform/proposal/common/listOpenSession").then((res) => {
if (res.code === 0) {
this.sessionOptions = res.data || []
if (this.sessionOptions && this.sessionOptions.length) {
this.$set(this.pageForm, "sessionId", this.sessionOptions[0].id)
this.pageData()
} else {
// 没有开启的教代会时保持空列表,避免发起无届次的全量流程查询。
this.tableData = []
this.$set(this.pageForm, "totalCount", 0)
}
}
})
}
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,219 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app">
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="教代会">
<el-select @change="meetingChange" clearable filterable placeholder="所属教代会"
v-model="pageForm.sessionId">
<el-option :key="item.id" :label="item.fullName" :value="item.id"
v-for="item in sessionOptions"></el-option>
</el-select>
</search-item>
<search-item label="提案名称">
<el-input v-model="pageForm.name" placeholder="提案名称" @keyup.enter.native="doSearch" clearable
style="width: 100%"></el-input>
</search-item>
<search-item label="姓名/工号">
<el-input placeholder="请输入姓名或工号" clearable v-model="pageForm.createUserKeyword"></el-input>
</search-item>
</search>
</el-card>
<el-card shadow="never">
<table-tool :columns.sync="tableColumns">
<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 v-loading="tableLoading" :data="tableData" @sort-change="pageOrder" style="width: 100%">
<el-table-column label="序号" width="50" type="index" :index="indexMethod" fixed="left"></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:key="column.key"
:min-width="column.width"
:fixed="column.fixed"
sortable="custom"
show-overflow-tooltip
v-for="column in tableColumns"
v-if="column.visible !== false"
>
<template v-if="column.prop === 'caseFilingResult'" scope="{row}">
<dict-tag :options="dict.type.PROPOSAL_CASE_FILING_RESULT"
:value="row.caseFilingResult"></dict-tag>
</template>
<template v-else-if="column.prop === 'merge'" scope="{row}">
<el-tag v-if="row.merge" size="small"></el-tag>
</template>
<template v-else-if="column.prop === 'instanceState'" 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="openView(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>
<proposal-info ref="proposalInfoRef">
<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(1)" size="small" type="primary">同意</el-button>
<el-button @click="handleTaskAction(2)" size="small" type="danger">不同意</el-button>
<el-button @click="handleTaskAction(6)" size="small" type="info">退回到提案人</el-button>
<el-button @click="$refs.guava.index()" size="small">返回</el-button>
</el-row>
</div>
</proposal-info>
</template>
</guava>
</div>
<script nonce="${cspNonce!}">
<!--#include('../../common/info.js'){}#-->
new Vue({
el: "#app",
store,
mixins: [initTableMixins],
components: {
"proposal-info": PROPOSAL_INFO
},
data() {
return {
tableColumns: [
{label: "提案编号", prop: "code"},
{label: "立案编号", prop: "caseFilingCode"},
{label: "提案名称", prop: "name", width: "200px"},
{label: "提案人", prop: "createUserName", width: "80px"},
{label: "提案类别", prop: "typeName"},
{label: "届次", prop: "sessionName"},
{label: "代表团", prop: "delegationName"},
{label: "当前节点", prop: "curTaskName"},
{label: "流程状态", prop: "instanceState"}
],
pageForm: {
approval: false
},
showApprovalForm: false
}
},
methods: {
openView(row) {
this.$refs.guava.edit(() => {
this.showApprovalForm = false
this.$refs.proposalInfoRef.onOpen(row)
})
},
openAudit(row) {
this.$refs.guava.edit(() => {
this.showApprovalForm = true
this.formData = {
processTaskId: row.taskId,
taskName: row.curTaskName
}
this.$refs.proposalInfoRef.onOpen(row)
})
},
handleTaskAction(val) {
this.$refs.formRef.validate(valid => {
if (!valid) return
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post("/flow/common/executeTask", {
data: JSON.stringify({
...this.formData,
submitType: val
})
}).then((res) => {
if (res.code === 0) {
this.$refs.guava.index()
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()
}
})
})
},
// 教代会
async meetingChange(val) {
this.formData.delegationId = null
this.formData.committeeId = null
this.doSearch()
},
listDelegation() {
this.$axios.post("/platform/proposal/common/listDelegation", {sessionId: this.pageForm.sessionId}).then((res) => {
if (res.code === 0) {
this.delegationOptions = res.data
}
})
},
// 查询开启的教代会
listOpenSession() {
this.$axios.post("/platform/proposal/common/listOpenSession").then((res) => {
if (res.code === 0) {
this.sessionOptions = res.data
if (this.sessionOptions) {
this.$set(this.pageForm, "sessionId", this.sessionOptions[0].id)
this.pageData()
this.listDelegation()
}
}
})
}
},
created() {
this.pageData()
this.listOpenSession()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,240 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app">
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="教代会">
<el-select @change="meetingChange" clearable filterable placeholder="所属教代会"
v-model="pageForm.sessionId">
<el-option :key="item.id" :label="item.fullName" :value="item.id"
v-for="item in sessionOptions"></el-option>
</el-select>
</search-item>
<search-item label="提案编号">
<el-input v-model="pageForm.code" placeholder="提案编号" @keyup.enter.native="doSearch" clearable
style="width: 100%"></el-input>
</search-item>
<search-item label="提案名称">
<el-input v-model="pageForm.name" placeholder="提案名称" @keyup.enter.native="doSearch" clearable
style="width: 100%"></el-input>
</search-item>
</search>
</el-card>
<el-card shadow="never">
<table-tool :columns.sync="tableColumns">
<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 v-loading="tableLoading" :data="tableData" @sort-change="pageOrder" style="width: 100%">
<el-table-column label="序号" width="50" type="index" :index="indexMethod"></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:key="column.key"
:min-width="column.width"
:fixed="column.fixed"
sortable="custom"
show-overflow-tooltip
v-for="column in tableColumns"
v-if="column.visible !== false"
>
<template v-if="column.prop === 'caseFilingResult'" scope="{row}">
<dict-tag :options="dict.type.PROPOSAL_CASE_FILING_RESULT"
:value="row.caseFilingResult"></dict-tag>
</template>
<template v-else-if="column.prop === 'merge'" scope="{row}">
<el-tag v-if="row.merge" size="small"></el-tag>
<el-tag v-else type="warning" size="small"></el-tag>
</template>
<template v-else-if="column.prop === 'underTakeIsMaster'" scope="{row}">
<el-tag v-if="row.underTakeIsMaster" size="small">主办</el-tag>
<el-tag v-else type="warning" size="small">协办</el-tag>
</template>
<template v-else-if="column.prop === 'instanceState'" 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="openView(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>
<proposal-info ref="proposalInfoRef">
<div v-if="showApprovalForm">
<div class="process-title">
{{formData.taskName}}
</div>
<el-form :model="formData" ref="formRef" label-width="120px" :rules="formRules" label-suffix="">
<el-form-item label="满意度" prop="tf_feedback"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<el-radio-group v-model="formData.tf_feedback" size="small">
<el-radio v-for="item in dict.type.PROPOSAL_FEEDBACK" :key="item.code"
:label="item.code" border>{{item.label}}
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="反馈意见" prop="tf_opinion"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<user-opinion-textarea
v-model="formData.tf_opinion"
:show-common-opinion="false">
</user-opinion-textarea>
</el-form-item>
</el-form>
<el-row type="flex" justify="end">
<el-button @click="handleTaskAction(1)" size="small" type="primary">提交</el-button>
<el-button @click="$refs.guava.index()" size="small">返回</el-button>
</el-row>
</div>
</proposal-info>
</template>
</guava>
</div>
<script nonce="${cspNonce!}">
<!--#include('../../common/info.js'){}#-->
new Vue({
el: "#app",
store,
dicts: ["PROPOSAL_FEEDBACK"],
mixins: [initTableMixins],
components: {
"proposal-info": PROPOSAL_INFO
},
data() {
return {
tableColumns: [
{label: "提案编号", prop: "code"},
{label: "立案编号", prop: "caseFilingCode"},
{label: "提案名称", prop: "name", width: "200px"},
{label: "提案类别", prop: "typeName"},
{label: "是否并案", prop: "merge"},
{label: "当前节点", prop: "curTaskName"},
{label: "流程状态", prop: "instanceState"}
],
pageForm: {
approval: false
},
formData: {},
showApprovalForm: false,
sessionOptions: [],
delegationOptions: [],
}
},
methods: {
openView(row) {
this.$refs.guava.edit(() => {
this.showApprovalForm = false
this.$refs.proposalInfoRef.onOpen(row)
})
},
openAudit(row) {
this.$refs.guava.edit(() => {
this.showApprovalForm = true
this.formData = {
processTaskId: row.taskId,
taskKey: row.taskKey,
taskName: row.taskName,
instanceId: row.instanceId
}
this.$refs.proposalInfoRef.onOpen(row)
})
},
handleTaskAction(val) {
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(async () => {
const formData = {
...this.formData,
submitType: val
}
// 不满意
if (this.formData.tf_feedback === 'DISSATISFIED') {
const caseInfo = await this.getCaseInfo(this.formData.instanceId)
formData.tf_masterUnitId = caseInfo.tf_masterUnitId
}
this.$axios.post("/flow/common/executeTask", {
data: JSON.stringify(formData)
}).then((res) => {
if (res.code === 0) {
this.$refs.guava.index()
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()
}
})
})
},
// 获取立案信息并返回 Promise,供表单初始化按原顺序等待结果。
getCaseInfo(instId) {
return this.$axios.post('/platform/proposal/feedbackEvaluation/caseInfo', {instId}).then((res) => {
if (res.code === 0) {
return res.data
}
})
},
// 教代会
async meetingChange(val) {
this.doSearch()
},
// 查询开启的教代会
listOpenSession() {
this.$axios.post("/platform/proposal/common/listOpenSession").then((res) => {
if (res.code === 0) {
this.sessionOptions = res.data
if (this.sessionOptions) {
this.$set(this.pageForm, "sessionId", this.sessionOptions[0].id)
this.pageData()
}
}
})
}
},
created() {
this.pageData()
this.listOpenSession()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,159 @@
<div id="proposal-transact-apply-form">
<div>
<el-row type="flex" style="column-gap: 10px">
<el-col :span="6">
<el-input v-model="pageForm.searchKeyword" placeholder="请输入工号或者姓名查询" clearable></el-input>
</el-col>
<el-col :span="6">
<el-select clearable filterable placeholder="所属代表团" v-model="pageForm.delegationId">
<el-option :key="item.id" :label="item.name" :value="item.id" v-for="item in delegationOptions"></el-option>
</el-select>
</el-col>
<el-col :span="4">
<el-button icon="el-icon-search" type="primary" @click="doSearch">查询</el-button>
</el-col>
</el-row>
<el-divider class="mt10 mb10"></el-divider>
<table-tool>
<el-radio-group v-model="pageForm.isInvite" @change="doSearch" size="small" style="margin-left: 5px">
<el-radio-button :label="true">已邀请</el-radio-button>
<el-radio-button :label="false">可邀请</el-radio-button>
</el-radio-group>
</table-tool>
<el-table
v-loading="tableLoading"
:data="tableData"
ref="tableRef"
@sort-change="pageOrder"
size="small"
header-align="center"
style="width: 100%"
:row-key="getRowKey"
>
<el-table-column type="selection" reserve-selection v-if="!pageForm.isInvite"></el-table-column>
<el-table-column label="序号" type="index" :index="indexMethod"></el-table-column>
<el-table-column label="工号" prop="loginName"></el-table-column>
<el-table-column label="姓名" prop="userName"></el-table-column>
<el-table-column label="性别" prop="sex"></el-table-column>
<el-table-column label="代表团" prop="delegationName"></el-table-column>
<!-- <el-table-column label="操作" width="150px">-->
<!-- <template scope="{row}">-->
<!-- <el-button size="mini" type="primary" @click="invite(row)">邀请</el-button>-->
<!-- </template>-->
<!-- </el-table-column>-->
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</div>
<snaker-flow-task-form-action @task-action="handleTaskAction"></snaker-flow-task-form-action>
</div>
<script nonce="${cspNonce!}">
new Vue({
el: "#proposal-transact-apply-form",
store,
mixins: [initTableMixins],
data() {
return {
businessId: GetQueryString("businessId"),
sessionId: GetQueryString("sessionId"),
instanceId: GetQueryString("instanceId"),
secondedNum: 0,
pageForm: {
isInvite: false
},
config: {},
delegationOptions: []
}
},
methods: {
getRowKey(val) {
return val.loginName + this.pageForm.isInvite
},
// 数据查询
pageData() {
// 邀请人员查询为组件自定义逻辑,请求结束后统一关闭表格加载状态。
this.$set(this, "tableLoading", true)
this.$axios
.post("/platform/proposal/invite/listSeconder", {
...this.pageForm,
sessionId: this.sessionId,
proposalId: this.businessId
})
.then((res) => {
if (res.code === 0) {
this.tableData = res.data.list
this.pageForm.totalCount = res.data.totalCount
}
})
.finally(() => {
this.$set(this, "tableLoading", false)
})
},
//查询代表团
listDelegation() {
this.$axios.post("/platform/proposal/common/listDelegation", { sessionId: this.sessionId }).then((res) => {
if (res.code === 0) {
this.delegationOptions = res.data
}
})
},
// 获取配置
async getConfig() {
const { code, data } = await this.$axios.post("/platform/proposal/common/config")
if (code === 0) {
this.config = data
}
},
handleTaskAction(val) {
console.log(val)
this.invite(val)
},
// 邀请
invite(val) {
const selection = this.$refs.tableRef.selection
if (selection.length === 0) {
this.$message.warning("请先选择附议人后再提交")
return
}
const loginNames = selection.map((s) => s.loginName)
const userName = selection.map((s) => s.userName)
this.$confirm("您确定要邀请" + userName.join("、") + "代表附议吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "info"
}).then(() => {
this.$axios
.post("/flow/common/executeTask", {
data: JSON.stringify({
...val,
tf_nextNodeOperator: selection.map((s) => s.userId),
tf_proposalId: this.businessId,
tf_seconders: JSON.stringify(selection)
})
})
.then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
// 发送完成消息
window.GlobalBroadcastChannel.postMessage({
type: "task-complete",
payload: val
})
}
})
})
}
},
created() {
debugger
this.getConfig()
this.listDelegation()
this.pageData()
}
})
</script>
@@ -0,0 +1,88 @@
<!--#
layout("/layouts/platform.html"){
#-->
<guava ref="guava">
<div id="app">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="年度">
<el-date-picker v-model="pageForm.year" type="year" value-format="yyyy" placeholder="请选择年度" style="width: 100%"></el-date-picker>
</search-item>
<search-item label="标题">
<el-input v-model="pageForm.title" placeholder="请输入标题" clearable></el-input>
</search-item>
</search>
</el-card>
<el-card shadow="never">
<table-tool>
<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 v-loading="tableLoading" :data="tableData" @sort-change="pageOrder" style="width: 100%">
<el-table-column label="序号" width="50" type="index" :index="indexMethod"></el-table-column>
<el-table-column label="提案编号" prop="code" sortable="custom"></el-table-column>
<el-table-column label="提案名称" prop="name" sortable="custom" show-overflow-tooltip></el-table-column>
<el-table-column label="提案类别" prop="typeName" sortable="custom"></el-table-column>
<el-table-column label="届次" prop="sessionName" sortable="custom"></el-table-column>
<el-table-column label="代表团" prop="delegationName" sortable="custom"></el-table-column>
<el-table-column prop="curTaskName" label="当前节点" sortable="custom"></el-table-column>
<el-table-column prop="instanceState" label="流程状态" sortable="custom">
<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="openView(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>
</div>
</guava>
<script nonce="${cspNonce!}">
new Vue({
el: "#app",
store,
mixins: [initTableMixins],
data() {
return {
pageDataUrl: "/platform/proposal/invite/pageData",
pageForm: {
approval: false
}
}
},
methods: {
openView(row) {
window.open(
"/flow/common/approval/form?taskId=" +
row.taskId +
"&instanceId=" +
row.instanceId +
"&businessId=" +
row.businessNo +
"&sessionId=" +
row.sessionId
)
},
onRevoke(row) {
console.log(row)
}
},
created() {
this.pageData()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,401 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style></style>
<div id="app" v-cloak>
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="教代会">
<el-select @change="meetingChange" clearable filterable placeholder="所属教代会"
v-model="pageForm.sessionId">
<el-option :key="item.id" :label="item.fullName" :value="item.id"
v-for="item in sessionOptions"></el-option>
</el-select>
</search-item>
<search-item label="提案名称">
<el-input v-model="pageForm.name" placeholder="提案名称" @keyup.enter.native="doSearch" clearable
style="width: 100%"></el-input>
</search-item>
</search>
</el-card>
<el-card shadow="never">
<table-tool :columns.sync="tableColumns">
<el-button class="ml5" icon="el-icon-upload2" type="primary" size="small"
@click="openImport">导入提案
</el-button>
</table-tool>
<el-table v-loading="tableLoading" :data="tableData" @sort-change="pageOrder" header-align="center" style="width: 100%" row-key="id">
<el-table-column label="序号" width="50" type="index" :index="indexMethod" fixed="left"></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:key="column.key"
:min-width="column.width"
:fixed="column.fixed"
sortable="custom"
show-overflow-tooltip
v-for="column in tableColumns"
v-if="column.visible !== false"
>
<template v-if="column.prop === 'caseFilingResult'" scope="{row}">
<dict-tag :options="dict.type.PROPOSAL_CASE_FILING_RESULT"
:value="row.caseFilingResult"></dict-tag>
</template>
<template v-else-if="column.prop === 'merge'" scope="{row}">
<el-tag v-if="row.merge" size="small"></el-tag>
</template>
<template v-else-if="column.prop === 'taskName'" scope="{row}">
<span>{{ (row.startTaskId) ? row.taskName : '待提交' }}</span>
</template>
<template v-else-if="column.prop === 'instanceState'" scope="{row}">
<span v-if="row.instanceState">
<enum-tag :value="row.instanceState" name="ProcessInstanceStateEnum" label_key="message"
size="small"></enum-tag>
</span>
<span v-else>未提交</span>
</template>
</el-table-column>
<el-table-column label="操作" fixed="right" width="400px">
<template scope="{row}">
<el-button size="mini" type="primary" @click="openView(row)">查看</el-button>
<el-button v-if="row.taskKey === 'startTask' || !row.instanceId" size="mini" type="primary"
@click="openEdit(row)">
编辑提案
</el-button>
<el-button
size="mini"
type="primary"
@click="onOpenInviteSeconder(row)"
v-if="row.taskKey === 'invite' || row.taskKey === 'second'"
>
邀请附议人
</el-button>
<el-button v-if="row.canRevoke" size="mini" type="danger" @click="openRevoke(row)">
撤回
</el-button>
<!-- v-if="row.taskKey === 'startTask' || !row.instanceId"-->
<el-button size="mini" type="danger" @click="del(row.id)">
删除
</el-button>
</template>
</el-table-column>
</el-table>
<el-dialog
title="提案导入"
:visible.sync="importVisible"
:close-on-click-modal="false"
width="50%"
>
<el-timeline-item timestamp="下载模板" placement="top">
<el-card>
<el-row :gutter="24">
<el-col :span="24">
<el-radio-group v-model="importTemplateType">
<el-radio :label="1">excel</el-radio>
<el-radio :label="2">word</el-radio>
</el-radio-group>
</el-col>
</el-row>
<el-row :gutter="24" style="margin-top: 20px;">
<el-col :span="24">
<el-button size="medium" type="" style="width: 200px"
@click="downloadTemplate"
icon="el-icon-download">下载模板
</el-button>
</el-col>
</el-row>
</el-card>
</el-timeline-item>
<el-timeline-item timestamp="上传文件" placement="top">
<el-card>
<el-upload
name="file"
ref="upload"
:on-remove="(file, fileList) => {
importData.fileList = fileHandleRemove(file, fileList)
}"
:on-change="(file, fileList) => {
if(this.importTemplateType === 2) {
importData.fileList = fileHandleChange(file, fileList,{type:['docx']})
} else {
importData.fileList = fileHandleChange(file, fileList,{type:['xlsx']})
}
}"
:auto-upload="false"
:limit="1"
:file-list="importData.fileList">
<el-button size="medium" type="" icon="el-icon-upload" style="width: 200px">选择文件
</el-button>
</el-upload>
</el-card>
</el-timeline-item>
<span slot="footer" class="dialog-footer">
<el-button @click="importVisible = false" :disabled="importLoading">取 消</el-button>
<el-button type="primary" @click="doImport" :loading="importLoading">确定</el-button>
</span>
</el-dialog>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<template #public>
<invite-seconder ref="inviteSeconderRef" @refresh="doSearch"></invite-seconder>
</template>
<template #view>
<proposal-info ref="infoRef"></proposal-info>
</template>
</guava>
</div>
<script type="text/x-template" id="proposal-invite-seconder-template">
<div>
<search @search="doSearch">
<search-item label="关键字">
<el-input v-model="pageForm.searchKeyword" placeholder="请输入工号或者姓名查询"
clearable></el-input>
</search-item>
<search-item label="代表团">
<el-select clearable filterable placeholder="所属代表团" v-model="pageForm.delegationId"
style="width: 100%">
<el-option :key="item.id" :label="item.name" :value="item.id"
v-for="item in delegationOptions"></el-option>
</el-select>
</search-item>
</search>
<div style="display: flex;column-gap: 50px;">
<div style="flex: 1">
<el-divider class="mt10 mb10"></el-divider>
<div>
<table-tool label="代表数据">
<el-radio-group v-model="pageForm.isInvite" @change="doSearch" size="small"
style="margin-left: 5px;">
<el-radio-button :label="true">已邀请</el-radio-button>
<el-radio-button :label="false">可邀请</el-radio-button>
</el-radio-group>
</table-tool>
<el-table v-loading="tableLoading" :data="tableData" ref="tableRef" @sort-change="pageOrder" header-align="center"
style="width: 100%" :row-key="getRowKey">
<el-table-column type="selection" reserve-selection
v-if="!pageForm.isInvite"></el-table-column>
<el-table-column label="序号" width="50px" type="index"
:index="indexMethod"></el-table-column>
<el-table-column label="工号" prop="loginName" sortable="custom"></el-table-column>
<el-table-column label="姓名" prop="userName" sortable="custom"></el-table-column>
<el-table-column label="性别" prop="sex" sortable="custom"></el-table-column>
<el-table-column label="单位" prop="unitName" sortable="custom"></el-table-column>
<el-table-column label="分工会" prop="unionName" sortable="custom"></el-table-column>
<el-table-column label="代表团" prop="delegationName" sortable="custom"></el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</div>
</div>
<div style="flex: 1">
<el-divider class="mt10 mb10"></el-divider>
<div v-if="$refs.tableRef">
<table-tool label="当前已选择"></table-tool>
<el-table v-loading="tableLoading" :data="$refs.tableRef.selection">
<el-table-column label="序号" width="50px" type="index"></el-table-column>
<el-table-column label="工号" prop="loginName" sortable></el-table-column>
<el-table-column label="姓名" prop="userName" sortable></el-table-column>
<el-table-column label="性别" prop="sex" sortable></el-table-column>
<el-table-column label="单位" prop="unitName" sortable></el-table-column>
<el-table-column label="分工会" prop="unionName" sortable></el-table-column>
<el-table-column label="代表团" prop="delegationName" sortable></el-table-column>
</el-table>
<el-row type="flex" justify="center" class="p10">
<el-button @click="">取消</el-button>
<el-button @click="invite" type="primary">邀请</el-button>
</el-row>
</div>
</div>
</div>
</div>
</script>
<script nonce="${cspNonce!}">
<!--#include("../../common/info.js"){}#-->
<!--#include("inviteSeconder.js"){}#-->
new Vue({
el: "#app",
store,
mixins: [initTableMixins],
components: {
"proposal-info": PROPOSAL_INFO,
"invite-seconder": PROPOSAL_INVITE_SECONDER_COMPONENT
},
data() {
return {
// 将 window.location 的引用存储在响应式数据中
location: window.location,
importTemplateType: 1,
importData: {},
importVisible: false,
importLoading: false,
sessionOptions: [],
businessNo: null,
tableColumns: [
{label: "提案编号", prop: "code"},
{label: "提案名称", prop: "name", width: "200px"},
{label: "提案时间", prop: "createTime"},
{label: "提案类型", prop: "typeName"},
{label: "提案方式", prop: "sourceName"},
{label: "届次", prop: "sessionName"},
{label: "提案状态", prop: "taskName"},
{label: "流程状态", prop: "instanceState"}
]
}
},
methods: {
openView(row) {
this.$refs.guava.view(() => {
this.$refs.infoRef.onOpen(row)
})
},
openEdit(row) {
commonUtil.pjaxPush('/platform/proposal/write?taskId=' + (row.startTaskId || '') + "&bizId=" + row.id)
},
openRevoke(row) {
this.$confirm("您确定要撤销申请吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post("/flow/common/revokeTask", {taskId: row.startTaskId}).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.pageData()
}
})
})
},
onOpenInviteSeconder(row) {
this.$axios.post(loc() + "/inviteCheck", {id: row.id}).then((res) => {
if (res.code === 0) {
this.$refs.guava.public(() => {
this.$refs.inviteSeconderRef.onOpen(row)
})
}
})
},
//教代会change
async meetingChange(val) {
this.doSearch()
//this.delegationOptions = await proposal.getDelegation(val)
//this.committeeOptions = await this.getInstitutions(val)
},
listSession() {
this.$axios.post("/platform/proposal/common/listSession").then((res) => {
if (res.code === 0) {
this.sessionOptions = res.data
}
})
},
withdraw({processInstId}) {
this.$confirm("您确定要撤回吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "info"
}).then(() => {
this.$axios.post(loc() + "/withdraw", {processInstId}).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.doSearch()
}
})
})
},
del(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()
}
})
})
},
// 检测操作
checkOperation() {
const operation = GetQueryString("operation")
const bizId = GetQueryString("bizId")
if (!operation) return
if (operation === "invite" && bizId) {
// 邀请附议人
this.$axios.post('/platform/proposal/mine/selectOne',{id: bizId}).then(res=>{
if (res.code === 0) {
this.onOpenInviteSeconder(res.data)
}
})
}
},
// 打开导入模板
async openImport() {
this.importData = {
fileList: []
}
this.importVisible = true;
},
downloadTemplate() {
let templateType = '.xlsx'
if(this.importTemplateType === 2) {
templateType = '.docx'
}
this.location.href='/platform/basics/downloadTemplate?filePath=proposal/proposal' + templateType + '&fileName=教职工代表大会提案表' + templateType
},
doImport() {
if (!this.importData.fileList.length) {
this.notifyWarning("请选择文件!")
return
}
const data = new FormData();
this.importData.fileList.forEach((val) => {
data.append("file", val.raw, val.raw.name);
});
this.importLoading = false
$.ajax({
url: loc() + "/importProposal?templateType=" + this.importTemplateType,
type: "post",
data: data,
processData: false,
contentType: false,
success: (data) => {
if (!data.code) {
this.pageData();
this.importVisible = false
} else {
this.notifyWarning(data.msg)
}
this.importLoading = false
},
error: (data) => {
this.notifyWarning("导入失败")
this.importLoading = false
}
});
},
},
created() {
this.listSession()
this.pageData()
this.checkOperation()
}
})
</script>
<style>
</style>
<!--#
}
#-->
@@ -0,0 +1,113 @@
const PROPOSAL_INVITE_SECONDER_COMPONENT = {
template: "#proposal-invite-seconder-template",
mixins: [initTableMixins],
data() {
return {
visible: false,
secondedNum: 0,
record: {},
pageForm: {
isInvite: false,
pageSize: 10
},
config: {},
delegationOptions: []
}
},
methods: {
getRowKey(val) {
return val.loginName + this.pageForm.isInvite
},
async onOpen(record) {
this.visible = true
this.record = record
await this.getConfig()
this.listDelegation()
this.pageData()
const {seconderNum} = this.config
this.$alert(
"1)请至少选择<span style='color: orange;font-weight: bold'>" +
seconderNum +
"</span>位以上(含" +
seconderNum +
"位)代表附议。<br>\n" +
"(2)邀请附议人后将不能再编辑提案,请确认提案内容后再邀请附议人。<br>",
{
title: "温馨提醒",
type: "warning",
dangerouslyUseHTMLString: true,
confirmButtonText: "确定",
callback: () => {
}
}
)
},
detail(id) {
},
invite() {
const selection = this.$refs.tableRef.selection
if (selection.length === 0) {
this.$message.warning("请先选择附议人后再邀请")
return
}
const loginNames = selection.map((s) => s.loginName)
const userName = selection.map((s) => s.userName)
this.$confirm("您确定要邀请" + userName.join("、") + "代表附议吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "info"
}).then(() => {
const loading = createLoading('邀请中...')
this.$axios.post("/platform/proposal/mine/inviteSeconder", {
proposalId: this.record.id,
seconders: JSON.stringify(loginNames)
}).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.$refs.tableRef.clearSelection()
this.pageData()
this.visible = false
this.$emit("refresh", null)
}
}).finally(() => loading.close())
})
},
pageData() {
// 附议人弹窗使用组件自己的加载状态,避免主列表与弹窗同时转圈。
this.$set(this, "tableLoading", true)
this.$axios.post("/platform/proposal/mine/listSeconder", {
...this.pageForm,
sessionId: this.record.sessionId,
proposalId: this.record.id
}).then((res) => {
if (res.code === 0) {
this.tableData = res.data.list
this.pageForm.totalCount = res.data.totalCount
}
}).finally(() => {
this.$set(this, "tableLoading", false)
})
},
//查询代表团
listDelegation() {
this.$axios.post("/platform/proposal/common/listDelegation", {sessionId: this.record.sessionId}).then((res) => {
if (res.code === 0) {
this.delegationOptions = res.data
}
})
},
// 加载附议人数配置,并返回 Promise 保证弹窗按原顺序初始化。
getConfig() {
return this.$axios.post("/platform/proposal/common/config").then((res) => {
if (res.code === 0) {
this.config = res.data
}
})
}
}
}
@@ -0,0 +1,266 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app" v-cloak>
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="教代会">
<el-select @change="meetingChange" clearable filterable placeholder="所属教代会"
v-model="pageForm.sessionId">
<el-option :key="item.id" :label="item.fullName" :value="item.id"
v-for="item in sessionOptions"></el-option>
</el-select>
</search-item>
<search-item label="代表团">
<el-select clearable filterable placeholder="所属代表团" v-model="pageForm.delegationId">
<el-option :key="item.id" :label="item.name" :value="item.id"
v-for="item in delegationOptions"></el-option>
</el-select>
</search-item>
<search-item label="工会">
<el-select clearable filterable placeholder="所属工会" 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-item label="提案名称">
<el-input v-model="pageForm.name" placeholder="提案名称" @keyup.enter.native="doSearch" clearable
style="width: 100%"></el-input>
</search-item>
<search-item label="姓名/工号">
<el-input placeholder="请输入姓名或工号" clearable v-model="pageForm.createUserKeyword"></el-input>
</search-item>
</search>
</el-card>
<el-card shadow="never">
<table-tool :columns.sync="tableColumns">
<el-button type="primary" size="small" @click="exportList">导出</el-button>
<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 v-loading="tableLoading" :data="tableData" @sort-change="pageOrder" style="width: 100%">
<el-table-column label="序号" width="50" type="index" :index="indexMethod" fixed="left"></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:key="column.key"
:min-width="column.width"
:fixed="column.fixed"
sortable="custom"
show-overflow-tooltip
v-for="column in tableColumns"
v-if="column.visible !== false"
>
<template v-if="column.prop === 'instanceState'" 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="openView(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>
<proposal-info ref="proposalInfoRef">
<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(1)" size="small" type="primary">同意</el-button>
<el-button @click="handleTaskAction(2)" size="small" type="danger">不同意</el-button>
<el-button @click="handleTaskAction(4)" size="small" type="info">退回到提案人(不审核)</el-button>
<el-button @click="handleTaskAction(6)" size="small" type="info">退回到提案人(审核)</el-button>
<el-button @click="$refs.guava.index()" size="small">返回</el-button>
</el-row>
</div>
</proposal-info>
</template>
</guava>
</div>
<script nonce="${cspNonce!}">
<!--#include('../../common/info.js'){}#-->
new Vue({
el: "#app",
store,
mixins: [initTableMixins],
components: {
"proposal-info": PROPOSAL_INFO
},
data() {
return {
tableColumns: [
{label: "提案编号", prop: "code"},
{label: "立案编号", prop: "caseFilingCode"},
{label: "提案名称", prop: "name", width: "200px"},
{label: "提案人", prop: "createUserName", width: "80px"},
{label: "提案类别", prop: "typeName"},
{label: "届次", prop: "sessionName"},
{label: "代表团", prop: "delegationName"},
{label: "当前节点", prop: "curTaskName"},
{label: "流程状态", prop: "instanceState"}
],
pageForm: {
approval: false
},
showApprovalForm: false,
sessionOptions: [],
delegationOptions: [],
unionOptions: []
}
},
created() {
this.pageData()
this.listOpenSession()
this.listUnion()
},
methods: {
exportList() {
this.$downLoad(loc() + "/exportList", {
pageForm: JSON.stringify(this.pageForm),
approval: this.pageForm.approval,
tableColumns: JSON.stringify(this.tableColumns.filter(function (item) {
return item.visible !== false
}))
})
},
openView(row) {
this.$refs.guava.edit(() => {
this.showApprovalForm = false
this.$refs.proposalInfoRef.onOpen(row)
})
},
openAudit(row) {
this.$refs.guava.edit(() => {
this.showApprovalForm = true
this.formData = {
processTaskId: row.taskId,
taskName: row.curTaskName,
taskKey: row.taskKey
}
this.$refs.proposalInfoRef.onOpen(row)
})
},
// 查询开启的教代会
listOpenSession() {
this.$axios.post("/platform/proposal/common/listOpenSession").then((res) => {
if (res.code === 0) {
this.sessionOptions = res.data
if (this.sessionOptions) {
this.$set(this.pageForm, "sessionId", this.sessionOptions[0].id)
this.listDelegation()
this.pageData()
}
}
})
},
/**
* 根据当前教代会加载代表团下拉,切换教代会时同步清空已选代表团,
* 避免把上一届教代会的代表团条件带到当前查询里。
*/
listDelegation() {
this.delegationOptions = []
this.$set(this.pageForm, "delegationId", null)
if (!this.pageForm.sessionId) {
return
}
this.$axios.post("/platform/proposal/common/listDelegation", {
sessionId: this.pageForm.sessionId
}).then((res) => {
if (res.code === 0) {
this.delegationOptions = res.data
}
})
},
/**
* 教代会切换后,先联动刷新代表团下拉,再按新的筛选条件重新查询列表。
*/
meetingChange() {
this.listDelegation()
this.doSearch()
},
/**
* 工会下拉按系统分工会列表加载,用于按提案人所属工会筛选当前页面列表。
*/
listUnion() {
this.$businessTool.listUnion().then((res) => {
this.unionOptions = res
})
},
handleTaskAction(val) {
this.$refs.formRef.validate(valid => {
if (!valid) return
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
const params = {
...this.formData,
submitType: val,
taskName: 'startTask'
}
if(val === 4) {
params.tf_sourceTaskKey = this.formData.taskKey
params.tf_audit = false
}
this.$axios.post("/flow/common/executeTask", {
data: JSON.stringify(params)
}).then((res) => {
if (res.code === 0) {
this.$refs.guava.index()
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()
}
})
})
},
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,330 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app">
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="教代会">
<el-select @change="meetingChange" clearable filterable placeholder="所属教代会"
v-model="pageForm.sessionId">
<el-option :key="item.id" :label="item.fullName" :value="item.id"
v-for="item in sessionOptions"></el-option>
</el-select>
</search-item>
<search-item label="代表团">
<el-select clearable filterable placeholder="所属代表团" v-model="pageForm.delegationId">
<el-option :key="item.id" :label="item.name" :value="item.id"
v-for="item in delegationOptions"></el-option>
</el-select>
</search-item>
<search-item label="工会">
<el-select clearable filterable placeholder="所属工会" 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-item label="提案编号">
<el-input v-model="pageForm.code" placeholder="提案编号" @keyup.enter.native="doSearch" clearable
style="width: 100%"></el-input>
</search-item>
<search-item label="提案名称">
<el-input v-model="pageForm.name" placeholder="提案名称" @keyup.enter.native="doSearch" clearable
style="width: 100%"></el-input>
</search-item>
<search-item label="姓名/工号">
<el-input placeholder="请输入姓名或工号" clearable v-model="pageForm.createUserKeyword"></el-input>
</search-item>
<!-- <search-item label="提案人姓名">-->
<!-- <el-input-->
<!-- @keyup.enter.native="doSearch"-->
<!-- clearable-->
<!-- placeholder="请输入提案人姓名"-->
<!-- v-model="pageForm.createUserName"-->
<!-- style="width: 100%"-->
<!-- ></el-input>-->
<!-- </search-item>-->
<!-- <search-item label="提案人工号">-->
<!-- <el-input-->
<!-- @keyup.enter.native="doSearch"-->
<!-- clearable-->
<!-- placeholder="请输入提案人工号"-->
<!-- v-model="pageForm.createUserLoginName"-->
<!-- style="width: 100%"-->
<!-- ></el-input>-->
<!-- </search-item>-->
</search>
</el-card>
<el-card shadow="never">
<table-tool :columns.sync="tableColumns">
<el-button type="primary" size="small" @click="exportList">导出</el-button>
<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 v-loading="tableLoading" :data="tableData" @sort-change="pageOrder" style="width: 100%">
<el-table-column label="序号" width="50" type="index" :index="indexMethod" fixed="left"></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:key="column.key"
:min-width="column.width"
:fixed="column.fixed"
sortable="custom"
show-overflow-tooltip
v-for="column in tableColumns"
v-if="column.visible !== false"
>
<template v-if="column.prop === 'caseFilingResult'" scope="{row}">
<dict-tag :options="dict.type.PROPOSAL_CASE_FILING_RESULT"
:value="row.caseFilingResult"></dict-tag>
</template>
<template v-else-if="column.prop === 'merge'" scope="{row}">
<el-tag v-if="row.merge" size="small"></el-tag>
<el-tag v-else type="warning" size="small"></el-tag>
</template>
<template v-else-if="column.prop === 'undertakeUnits'" scope="{row}">
<div v-if="getUndertakeDisplay(row)" class="text-left">{{ getUndertakeDisplay(row) }}</div>
<span v-else>暂无</span>
</template>
<template v-else-if="column.prop === 'instanceState'" 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="openView(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>
<proposal-info ref="proposalInfoRef">
<div v-if="showApprovalForm">
<div class="process-title">
{{formData.taskName}}
</div>
<el-form :model="formData" ref="formRef" label-width="120px" :rules="formRules" label-suffix="">
<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('back')" size="small" type="danger">退回提委会立案</el-button>
<el-button @click="$refs.guava.index()" size="small">返回</el-button>
</el-row>
</div>
</proposal-info>
</template>
</guava>
</div>
<script nonce="${cspNonce!}">
<!--#include('../../common/info.js'){}#-->
new Vue({
el: "#app",
store,
dicts: ["PROPOSAL_CASE_FILING_RESULT"],
mixins: [initTableMixins],
components: {
"proposal-info": PROPOSAL_INFO
},
data() {
return {
tableColumns: [
{label: "提案编号", prop: "code"},
{label: "立案编号", prop: "caseFilingCode"},
{label: "提案名称", prop: "name", width: "200px"},
{label: "提案类别", prop: "typeName"},
{label: "办理单位", prop: "undertakeUnits", width: "260px"},
{label: "是否并案", prop: "merge"},
{label: "当前节点", prop: "curTaskName"},
{label: "审核人", prop: "auditUser"},
{label: "流程状态", prop: "instanceState"}
],
pageForm: {
approval: false
},
formData: {},
showApprovalForm: false,
sessionOptions: [],
delegationOptions: [],
unionOptions: [],
}
},
methods: {
exportList() {
this.$downLoad(loc() + "/exportList", {
pageForm: JSON.stringify(this.pageForm),
approval: this.pageForm.approval,
tableColumns: JSON.stringify(this.tableColumns.filter(function (item) {
return item.visible !== false
}))
})
},
/**
* 校领导审批列表需要按立案结果切换办理单位展示口径:
* 确定立案显示主办/协办,作为建议只显示办理单位。
*/
getUndertakeDisplay(row) {
var masterUnitNames = this.formatUnitNames(row.masterUnitName)
var slaveUnitNames = this.formatUnitNames(row.slaveUnitNames)
if (row.caseFilingResult === "SUGGESTION") {
return masterUnitNames || slaveUnitNames
}
if (row.caseFilingResult === "CONFIRM_FILING") {
return [masterUnitNames ? "主办:" + masterUnitNames : "", slaveUnitNames ? "协办:" + slaveUnitNames : ""].filter(function(item) {
return item
}).join("")
}
return ""
},
formatUnitNames(unitNames) {
if (!unitNames) {
return ""
}
if (Array.isArray(unitNames)) {
return unitNames.filter(function(item) {
return item
}).join("")
}
return unitNames
},
openView(row) {
this.$refs.guava.edit(() => {
this.showApprovalForm = false
this.$refs.proposalInfoRef.onOpen(row)
})
},
openAudit(row) {
this.$refs.guava.edit(() => {
this.showApprovalForm = true
this.formData = {
processTaskId: row.taskId,
taskKey: row.taskKey,
taskName: row.taskName,
proposalId: row.id
}
this.$refs.proposalInfoRef.onOpen(row)
})
},
handleTaskAction(val) {
this.$refs.formRef.validate(valid => {
if (!valid) return
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
const formData = {
...this.formData,
tf_approval: val
}
delete formData.taskKey
delete formData.taskName
this.$axios.post("/platform/proposal/schoolLeaderApproval/executeTask", {
data: JSON.stringify(formData)
}).then((res) => {
if (res.code === 0) {
this.$refs.guava.index()
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()
}
})
})
},
/**
* 教代会切换时重新联动查询代表团,并清空上一届次已选代表团,
* 保证列表始终按当前教代会范围查询。
*/
meetingChange() {
this.listDelegation()
this.doSearch()
},
/**
* 代表团下拉只展示当前教代会下的数据,未选教代会时保持空列表。
*/
listDelegation() {
this.delegationOptions = []
this.$set(this.pageForm, "delegationId", null)
if (!this.pageForm.sessionId) {
return
}
this.$axios.post("/platform/proposal/common/listDelegation", {
sessionId: this.pageForm.sessionId
}).then((res) => {
if (res.code === 0) {
this.delegationOptions = res.data
}
})
},
/**
* 工会下拉按系统分工会列表加载,用于按提案人所属工会筛选当前页面列表。
*/
listUnion() {
this.$businessTool.listUnion().then((res) => {
this.unionOptions = res
})
},
// 查询开启的教代会
listOpenSession() {
this.$axios.post("/platform/proposal/common/listOpenSession").then((res) => {
if (res.code === 0) {
this.sessionOptions = res.data
if (this.sessionOptions) {
this.$set(this.pageForm, "sessionId", this.sessionOptions[0].id)
this.listDelegation()
this.pageData()
}
}
})
}
},
created() {
this.pageData()
this.listOpenSession()
this.listUnion()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,251 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app">
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="教代会">
<el-select @change="meetingChange" clearable filterable placeholder="所属教代会"
v-model="pageForm.sessionId">
<el-option :key="item.id" :label="item.fullName" :value="item.id"
v-for="item in sessionOptions"></el-option>
</el-select>
</search-item>
<search-item label="提案名称">
<el-input v-model="pageForm.name" placeholder="提案名称" @keyup.enter.native="doSearch" clearable
style="width: 100%"></el-input>
</search-item>
</search>
</el-card>
<el-card shadow="never">
<table-tool :columns.sync="tableColumns">
<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 v-loading="tableLoading" :data="tableData" @sort-change="pageOrder" style="width: 100%">
<el-table-column label="序号" width="50" type="index" :index="indexMethod"
fixed="left"></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:key="column.key"
:min-width="column.width"
:fixed="column.fixed"
sortable="custom"
show-overflow-tooltip
v-for="column in tableColumns"
v-if="column.visible !== false"
>
<template v-if="column.prop === 'caseFilingResult'" scope="{row}">
<dict-tag :options="dict.type.PROPOSAL_CASE_FILING_RESULT"
:value="row.caseFilingResult"></dict-tag>
</template>
<template v-else-if="column.prop === 'merge'" scope="{row}">
<el-tag v-if="row.merge" size="small"></el-tag>
</template>
<template v-else-if="column.prop === 'instanceState'" 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="openView(row)" size="mini" type="primary">查看</el-button>
<el-button v-if="showSecondAction(row)"
@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>
<proposal-info ref="proposalInfoRef">
<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" v-if="row.curTaskCode ==='second'">
<el-button @click="handleTaskAction(1)" size="small" type="primary">同意</el-button>
<el-button @click="handleTaskAction(20)" size="small" type="danger">不同意</el-button>
<el-button @click="$refs.guava.index()" size="small">返回</el-button>
</el-row>
<el-row type="flex" justify="end" v-else>
<el-button @click="updateSecond(1)" size="small" type="primary">同意</el-button>
<el-button @click="updateSecond(2)" size="small" type="danger">不同意</el-button>
<el-button @click="$refs.guava.index()" size="small">返回</el-button>
</el-row>
</div>
</proposal-info>
</template>
</guava>
</div>
<script nonce="${cspNonce!}">
<!--#include('../../common/info.js'){}#-->
new Vue({
el: "#app",
store,
mixins: [initTableMixins],
components: {
"proposal-info": PROPOSAL_INFO
},
data() {
return {
tableColumns: [
{label: "提案编号", prop: "code"},
{label: "提案名称", prop: "name", width: "200px"},
{label: "提案人", prop: "createUserName"},
{label: "提案类别", prop: "typeName"},
{label: "代表团", prop: "delegationName"},
{label: "附议人", prop: "taskActorName"},
{label: "当前节点", prop: "curTaskName"},
{label: "流程状态", prop: "instanceState"}
],
pageForm: {
approval: false
},
showApprovalForm: false,
sessionOptions: [],
delegationOptions: [],
}
},
methods: {
// 附议按钮显示规则:
// 1. 当前任务进行中(taskState=10)时显示
// 2. 当前任务已废弃(taskState=99)时,仅 invite、second、delegation、committee 节点显示
showSecondAction(row) {
return row.taskState === 10 || (row.taskState === 99 && ["invite", "second", "delegation", "preAudit", "committee"].includes(row.taskKey))
},
openView(row) {
this.$refs.guava.edit(() => {
this.showApprovalForm = false
this.$refs.proposalInfoRef.onOpen(row)
})
},
openAudit(row) {
this.row = row
this.$refs.guava.edit(() => {
this.showApprovalForm = true
this.formData = {
processTaskId: row.taskId,
proposalId: row.id,
taskActorUserId: row.taskActorUserId,
taskName: row.curTaskName,
tf_opinion: "同意该提案"
}
this.$refs.proposalInfoRef.onOpen(row)
})
},
handleTaskAction(val) {
this.$refs.formRef.validate(valid => {
if (!valid) return
this.$confirm("提案一旦提交,后续将无法自行修改或撤回。请您在提交前仔细确认。", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post("/platform/proposal/seconded/executeTask", {
data: JSON.stringify({
...this.formData,
submitType: val
})
}).then((res) => {
if (res.code === 0) {
this.$refs.guava.index()
this.$message.success(res.msg)
this.doSearch()
}
})
})
})
},
updateSecond(submitType) {
this.$confirm("提案一旦提交,后续将无法自行修改或撤回。请您在提交前仔细确认。", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post("/platform/proposal/seconded/updateInfo", {
proposalId: this.row.id,
taskId: this.row.taskId,
taskActorUserId: this.row.taskActorUserId,
opinion: this.formData.tf_opinion,
submitType: submitType,
}).then((res) => {
if (res.code === 0) {
this.$refs.guava.index()
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()
}
})
})
},
// 教代会
async meetingChange(val) {
this.formData.delegationId = null
this.formData.committeeId = null
this.doSearch()
},
// 查询开启的教代会
listOpenSession() {
this.$axios.post("/platform/proposal/common/listOpenSession").then((res) => {
if (res.code === 0) {
this.sessionOptions = res.data
if (this.sessionOptions) {
this.$set(this.pageForm, "sessionId", this.sessionOptions[0].id)
this.pageData()
this.listDelegation()
}
}
})
}
},
created() {
this.pageData()
this.listOpenSession()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,321 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style>
/* 提案信息卡片样式 - OA风格 */
.proposal-info-card {
background: #ffffff;
border: 1px solid var(--border-color-lighter);
margin-bottom: 20px;
overflow: hidden;
}
.proposal-info-content {
padding: 16px;
background: #fafafa;
}
.info-item {
display: flex;
align-items: flex-start;
margin-bottom: 12px;
line-height: 1.6;
padding: 8px 12px;
background: #ffffff;
border-left: 3px solid var(--color-primary-2);
transition: all 0.2s ease;
}
.info-item:hover {
border-left-color: var(--color-primary);
}
.info-item:last-child {
margin-bottom: 0;
}
.info-item label {
color: var(--color-text-regular);
font-weight: 500;
min-width: 80px;
margin-right: 12px;
flex-shrink: 0;
font-size: 13px;
}
.info-item span {
color: var(--color-text-primary);
word-break: break-all;
flex: 1;
font-size: 13px;
}
</style>
<div id="app">
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="教代会">
<el-select @change="meetingChange" clearable filterable placeholder="所属教代会" style="width: 100%"
v-model="pageForm.sessionId">
<el-option :key="item.id" :label="item.fullName" :value="item.id"
v-for="item in sessionOptions"></el-option>
</el-select>
</search-item>
<search-item label="提案编号">
<el-input v-model="pageForm.code" placeholder="提案编号" @keyup.enter.native="doSearch" clearable
style="width: 100%"></el-input>
</search-item>
<search-item label="提案名称">
<el-input v-model="pageForm.name" placeholder="提案名称" @keyup.enter.native="doSearch" clearable
style="width: 100%"></el-input>
</search-item>
<search-item label="姓名/工号">
<el-input placeholder="请输入姓名或工号" clearable v-model="pageForm.createUserKeyword"></el-input>
</search-item>
<!-- <search-item label="提案人姓名">-->
<!-- <el-input-->
<!-- @keyup.enter.native="doSearch"-->
<!-- clearable-->
<!-- placeholder="请输入提案人姓名"-->
<!-- v-model="pageForm.createUserName"-->
<!-- style="width: 100%"-->
<!-- ></el-input>-->
<!-- </search-item>-->
<!-- <search-item label="提案人工号">-->
<!-- <el-input-->
<!-- @keyup.enter.native="doSearch"-->
<!-- clearable-->
<!-- placeholder="请输入提案人工号"-->
<!-- v-model="pageForm.createUserLoginName"-->
<!-- style="width: 100%"-->
<!-- ></el-input>-->
<!-- </search-item>-->
</search>
</el-card>
<el-card shadow="never">
<table-tool :columns.sync="tableColumns">
<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 v-loading="tableLoading" :data="tableData" @sort-change="pageOrder" style="width: 100%">
<el-table-column label="序号" width="50" type="index" :index="indexMethod" fixed="left"></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:key="column.key"
:min-width="column.width"
:fixed="column.fixed"
sortable="custom"
show-overflow-tooltip
v-for="column in tableColumns"
v-if="column.visible !== false"
>
<template v-if="column.prop === 'caseFilingResult'" scope="{row}">
<dict-tag :options="dict.type.PROPOSAL_CASE_FILING_RESULT"
:value="row.caseFilingResult"></dict-tag>
</template>
<template v-else-if="column.prop === 'instanceState'" scope="{row}">
<enum-tag :value="row.instanceState" name="ProcessInstanceStateEnum" label_key="message"
size="small"></enum-tag>
</template>
<template v-else-if="column.prop === 'suggestUnits'" scope="{row}">
{{ JSON.parse(row.suggestUnits)?.map(item => item).join('') || '' }}
</template>
<template v-else-if="column.prop === 'count'" scope="{ row }">
<el-link size="mini" type="primary" @click="openSuggestion(row)">{{ row.count }}</el-link>
</template>
</el-table-column>
<el-table-column label="操作" fixed="right" min-width="160px">
<template slot-scope="{row}">
<el-button @click="openView(row)" size="mini" type="primary">查看</el-button>
<el-button @click="openAudit(row)" size="mini" type="primary">反馈意见</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<template #edit>
<proposal-info ref="proposalInfoRef">
<div v-if="showApprovalForm">
<div class="process-title">
办理单位意见
</div>
<el-form :model="formData" ref="formRef" label-width="80px" :rules="formRules" label-suffix="">
<el-form-item label="承办意向" prop="result"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<el-radio-group v-model="formData.result" size="small">
<el-radio v-for="item in dict.type.UNDERTAKE_SUGGESTION" :label="item.code" border>
{{item.label}}
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="反馈意见" prop="opinion"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<text-editor v-model="formData.opinion"></text-editor>
</el-form-item>
</el-form>
<el-row type="flex" justify="end">
<el-button @click="onAudit()" size="small" type="primary">提交</el-button>
<el-button @click="$refs.guava.index()" size="small">返回</el-button>
</el-row>
</div>
</proposal-info>
</template>
<template #view>
<template v-for="item,index in suggestionList">
<div style="display: flex; justify-content: space-between; align-items: center">
<div class="left-span-label">意见{{ index + 1 }}</div>
<div>
<el-button @click="onDelete(item)" size="mini" type="danger">删除</el-button>
</div>
</div>
<el-descriptions :column="2" border>
<el-descriptions-item label="反馈人">{{ item.userName }}</el-descriptions-item>
<el-descriptions-item label="所属单位">{{ item.unitName }}</el-descriptions-item>
<el-descriptions-item label="反馈时间">{{ item.time }}</el-descriptions-item>
<el-descriptions-item label="反馈结果">{{ item.result }}</el-descriptions-item>
<el-descriptions-item label="反馈意见">
<span v-html="item.opinion"></span>
</el-descriptions-item>
</el-descriptions>
</template>
</template>
</guava>
</div>
<script nonce="${cspNonce!}">
<!--#include('../../common/info.js'){}#-->
new Vue({
el: "#app",
store,
dicts: ["UNDERTAKE_SUGGESTION"],
mixins: [initTableMixins],
components: {
"proposal-info": PROPOSAL_INFO
},
data() {
return {
tableColumns: [
{label: "提案编号", prop: "code"},
{label: "提案名称", prop: "name", width: "200px"},
{label: "提案类别", prop: "typeName"},
{label: "届次", prop: "sessionName"},
{label: "代表团", prop: "delegationName"},
{label: "建议办理单位", prop: "suggestUnits"},
{label: "意见数", prop: "count"},
{label: "当前节点", prop: "curTaskName"},
{label: "流程状态", prop: "instanceState"}
],
pageForm: {
approval: false
},
showApprovalForm: false,
formData: {},
sessionOptions: [],
suggestionList: [],
}
},
methods: {
openSuggestion(row) {
this.$axios.post('/platform/proposal/suggestion/selectSuggestion', {
proposalId: row.id,
}).then(res => {
if(res.code === 0) {
this.suggestionList = res.data
if(this.suggestionList.length === 0) {
this.$message.warning('暂无意见数')
return
}
this.$refs.guava.view()
} else {
this.$message.error(res.msg)
}
})
},
onDelete(row) {
this.$confirm("您确定要删除吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post('/platform/proposal/suggestion/delete', { id: row.id, })
.then(res => {
if(res.code === 0) {
this.$message.success(res.msg)
this.$refs.guava.index()
this.pageData()
} else {
this.$message.error(res.msg)
}
})
})
},
openView(row) {
this.$refs.guava.edit(() => {
this.showApprovalForm = false
this.$refs.proposalInfoRef.onOpen(row)
})
},
openAudit(row) {
this.$refs.guava.edit(() => {
this.showApprovalForm = true
this.formData = {
proposalId: row.id,
}
this.$refs.proposalInfoRef.onOpen(row)
})
},
onAudit() {
this.$refs.formRef.validate(valid => {
if (!valid) return
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post("/platform/proposal/suggestion/suggest", this.formData).then((res) => {
if (res.code === 0) {
this.$refs.guava.index()
this.$message.success(res.msg)
this.doSearch()
}
})
})
})
},
// 教代会
async meetingChange(val) {
this.doSearch()
},
// 查询开启的教代会
listOpenSession() {
this.$axios.post("/platform/proposal/common/listOpenSession").then((res) => {
if (res.code === 0) {
this.sessionOptions = res.data
if (this.sessionOptions) {
this.$set(this.pageForm, "sessionId", this.sessionOptions[0].id)
this.pageData()
}
}
})
}
},
created() {
this.pageData()
this.listOpenSession()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,162 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app">
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="教代会">
<el-select @change="meetingChange" clearable filterable placeholder="所属教代会"
v-model="pageForm.sessionId">
<el-option :key="item.id" :label="item.fullName" :value="item.id"
v-for="item in sessionOptions"></el-option>
</el-select>
</search-item>
<search-item label="名称/编号">
<el-input @keyup.enter.native="doSearch" clearable placeholder="请输入内容"
v-model="pageForm.searchKeyword">
<el-select placeholder="查询类型" slot="prepend" style="width: 110px;"
v-model="pageForm.searchName">
<el-option label="提案名称" value="proposalName"></el-option>
<el-option label="提案编号" value="proposalCode"></el-option>
</el-select>
</el-input>
</search-item>
<search-item label="提案人">
<el-input @keyup.enter.native="doSearch" clearable placeholder="请输入内容"
v-model="pageForm.searchKeyword2">
<el-select placeholder="查询类型" slot="prepend" style="width: 110px;"
v-model="pageForm.searchName2">
<el-option label="提案人" value="su.username"></el-option>
<!-- <el-option label="附议人" value="seconded.username"></el-option>-->
</el-select>
</el-input>
</search-item>
</search>
</el-card>
<el-card shadow="never">
<table-tool label="提案列表" :columns.sync="tableColumns"></table-tool>
<el-table v-loading="tableLoading" :data="tableData" @sort-change="pageOrder" style="width: 100%">
<el-table-column label="序号" width="50" type="index" :index="indexMethod" fixed="left"></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:key="column.key"
:min-width="column.width"
:fixed="column.fixed"
sortable="custom"
show-overflow-tooltip
v-for="column in tableColumns"
v-if="column.visible !== false"
>
<template v-if="column.prop === 'caseFilingResult'" scope="{row}">
<dict-tag :options="dict.type.PROPOSAL_CASE_FILING_RESULT"
:value="row.caseFilingResult"></dict-tag>
</template>
<template v-else-if="column.prop === 'merge'" scope="{row}">
<el-tag v-if="row.merge" size="small"></el-tag>
</template>
<template v-else-if="column.prop === 'instanceState'" 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="120px">
<template slot-scope="{row}">
<el-button @click="openView(row)" size="mini" type="primary">查看</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<template #edit>
<proposal-info ref="proposalInfoRef">
<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(1)" size="small" type="primary">同意</el-button>
<el-button @click="handleTaskAction(2)" size="small" type="danger">不同意</el-button>
<el-button @click="handleTaskAction(6)" size="small" type="info">退回到提案人</el-button>
<el-button @click="$refs.guava.index()" size="small">返回</el-button>
</el-row>
</div>
</proposal-info>
</template>
</guava>
</div>
<script nonce="${cspNonce!}">
<!--#include('../../common/info.js'){}#-->
new Vue({
el: "#app",
store,
mixins: [initTableMixins],
components: {
"proposal-info": PROPOSAL_INFO
},
data() {
return {
tableColumns: [
{label: "提案编号", prop: "proposalCode"},
{label: "提案名称", prop: "proposalName", width: "200px"},
{label: "提案人", prop: "username"},
{label: "联系方式", prop: "mobile"},
{label: "单位", prop: "unitName"},
{label: "代表团", prop: "delegationName"},
{label: "提案类型", prop: "typeName"},
{label: "提交方式", prop: "mannerName"},
{label: "附议人数量", prop: "secondedNum"},
{label: "已附议", prop: "secondedAgreeNum"},
{label: "团长审核", prop: "delegationAudit"},
],
pageForm: {
approval: false,
searchName: "proposalName",
searchName2: "su.username",
},
showApprovalForm: false,
sessionOptions: []
}
},
methods: {
// 查看
openView(row) {
this.$refs.guava.edit(() => {
this.showApprovalForm = false
this.$refs.proposalInfoRef.onOpen(row)
})
},
// 查询开启的教代会
listOpenSession() {
this.$axios.post("/platform/proposal/common/listOpenSession").then((res) => {
if (res.code === 0) {
this.sessionOptions = res.data
if (this.sessionOptions) {
this.$set(this.pageForm, "sessionId", this.sessionOptions[0].id)
this.pageData()
this.listDelegation()
}
}
})
}
},
created() {
this.pageData()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,257 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style></style>
<div id="app" v-cloak>
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="提案编号">
<el-input v-model="pageForm.code" placeholder="提案编号" @keyup.enter.native="doSearch" clearable style="width: 100%"></el-input>
</search-item>
<search-item label="提案名称">
<el-input v-model="pageForm.name" placeholder="提案名称" @keyup.enter.native="doSearch" clearable style="width: 100%"></el-input>
</search-item>
<search-item label="提案人姓名">
<el-input
@keyup.enter.native="doSearch"
clearable
placeholder="请输入提案人姓名"
v-model="pageForm.createUserName"
style="width: 100%"
></el-input>
</search-item>
<search-item label="提案人工号">
<el-input
@keyup.enter.native="doSearch"
clearable
placeholder="请输入提案人工号"
v-model="pageForm.createUserLoginName"
style="width: 100%"
></el-input>
</search-item>
<search-item label="教代会">
<el-select @change="meetingChange" clearable filterable placeholder="所属教代会" v-model="pageForm.sessionId">
<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-radio-group v-model="pageForm.approval" @change="doSearch" size="small" v-if="!pageForm.transfer" class="ml5">-->
<!-- <el-radio-button :label="true">已查阅</el-radio-button>-->
<!-- <el-radio-button :label="false">未查阅</el-radio-button>-->
<!-- </el-radio-group>-->
</table-tool>
<el-table
v-loading="tableLoading"
:data="tableData"
@sort-change="pageOrder"
header-align="center"
style="width: 100%"
:row-key="(val)=>{val.id + val.processInstanceTaskId}"
>
<el-table-column label="序号" width="50" type="index" :index="indexMethod"></el-table-column>
<el-table-column label="提案编号" prop="code" sortable="custom"></el-table-column>
<el-table-column label="提案名称" prop="name" sortable="custom" show-overflow-tooltip></el-table-column>
<el-table-column label="提案人" prop="createUserName" sortable="custom"></el-table-column>
<el-table-column label="代表团" prop="delegationName" sortable="custom"></el-table-column>
<el-table-column label="立案结果" prop="caseFilingResult" sortable="custom">
<template scope="{row}">
<dict-tag :options="dict.type.PROPOSAL_CASE_FILING_RESULT" :value="row.caseFilingResult"></dict-tag>
</template>
</el-table-column>
<el-table-column label="是否并案" prop="isConsolidation" sortable="custom" width="100">
<template scope="{row}">
<el-tag size="mini" v-if="row.isConsolidation" type="success"></el-tag>
<el-tag size="mini" v-else type="danger"></el-tag>
</template>
</el-table-column>
<el-table-column label="是否主办" prop="isMasterUnderTake" sortable="custom" width="100">
<template scope="{row}">
<el-tag v-if="row.isMasterUnderTake" size="mini" type="success"></el-tag>
<el-tag v-else size="mini" type="info"></el-tag>
</template>
</el-table-column>
<el-table-column label="办理单位" prop="underTakeName" show-overflow-tooltip></el-table-column>
<el-table-column label="当前节点" prop="processInstanceNodeName" show-overflow-tooltip></el-table-column>
<el-table-column label="操作" fixed="right" width="100px">
<template scope="{row}">
<el-button size="mini" type="primary" @click="onOpen(row)">查看</el-button>
<!-- <el-button v-if="row.processInstanceTaskStatus==='ACTIVE'" @click="openApproval(row)" size="mini" type="primary">-->
<!-- 查阅-->
<!-- </el-button>-->
<!-- <el-button-->
<!-- v-if="row.processInstanceTaskStatus==='COMPLETE' && !row.nextTaskIsComplete"-->
<!-- @click="openRevoke(row.processInstanceTaskId)"-->
<!-- size="mini"-->
<!-- type="danger"-->
<!-- >-->
<!-- 撤回-->
<!-- </el-button>-->
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<template #public>
<proposal-info ref="infoRef"></proposal-info>
<div v-if="showApprovalForm">
<div class="process-title">{{formData.processInstanceNodeName}}</div>
<el-alert v-if="formData.isConsolidation" type="success" title="提醒:本提案已初步并案,您只需审批一次即可!"></el-alert>
<el-divider></el-divider>
<el-form :model="formData" ref="approvalFormRef" label-position="left" label-width="80px">
<el-form-item label="办理单位">
<el-input :value="formData.underTakeName" disabled></el-input>
</el-form-item>
<el-form-item label="能否承办" prop="canTake" :rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<el-radio-group v-model="formData.canTake" size="small">
<el-radio label="可以承办" border>可以承办</el-radio>
<el-radio label="无法承办" border>无法承办</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="初步阅览意见" prop="approvalOpinion" :rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<el-input
v-model="formData.approvalOpinion"
autosize
:autosize="{ minRows: 4}"
type="textarea"
placeholder="请输入初步阅览意见"
></el-input>
</el-form-item>
<!-- <el-form-item label="电子签名" prop="approvalSignature" :rules="[{required:true,message:'必填',trigger:['change','blur']}]">-->
<!-- <pc-signature v-model="formData.approvalSignature"></pc-signature>-->
<!-- </el-form-item>-->
</el-form>
<el-row type="flex" justify="end">
<el-button type="primary" @click="doApproval('DYNAMIC')">提交</el-button>
<el-button plain @click="$refs.guava.index()">返回</el-button>
</el-row>
</div>
</template>
</guava>
</div>
<script nonce="${cspNonce!}">
<!--#include("../../common/info.js"){}#-->
new Vue({
el: "#app",
dicts: ["PROPOSAL_CASE_FILING_RESULT"],
store,
mixins: [initTableMixins],
components: {
"proposal-info": PROPOSAL_INFO_COMPONENT
},
data() {
return {
sessionOptions: [],
delegationOptions: [],
pageForm: {
approval: false,
transfer: false
},
showApprovalForm: false,
transferFormData: {},
transferDialogVisible: false,
transferUserOptions: []
}
},
methods: {
onOpen(row) {
this.$refs.guava.public(() => {
this.$refs.infoRef.onOpen(row.id)
this.showApprovalForm = false
})
},
openApproval(row) {
this.$refs.guava.public(() => {
this.$refs.infoRef.onOpen(row.id)
this.formData = row.approvalParam
this.$set(this.formData, "implementState", null)
this.$set(this.formData, "approvalOpinion", null)
this.formData.isConsolidation = row.isConsolidation
this.formData.underTakeName = row.underTakeName
this.formData.underTakeId = row.underTakeId
this.showApprovalForm = true
})
},
doApproval(approvalType) {
this.formData.bpmTaskApprovalType = approvalType
this.$refs.approvalFormRef.validate((valid) => {
if (valid) {
this.$axios
.post(loc() + "/approval", {
approval: JSON.stringify(this.formData)
})
.then((res) => {
if (res.code === 0) {
this.$refs.guava.index()
this.$message.success(res.msg)
this.doSearch()
}
})
}
})
},
openRevoke(taskId) {
this.$confirm("您确定要撤回吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "info"
}).then(() => {
this.$axios.post(loc() + "/revoke", { taskId }).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.doSearch()
}
})
})
},
//教代会change
async meetingChange(val) {
this.formData.delegationId = null
this.formData.committeeId = null
this.delegationOptions = await proposal.getDelegation(val)
this.committeeOptions = await this.getInstitutions(val)
},
listDelegation() {
this.$axios.post("/platform/proposal/common/listDelegation", { sessionId: this.pageForm.sessionId }).then((res) => {
if (res.code === 0) {
this.delegationOptions = res.data
}
})
},
listOpenSession() {
this.$axios.post("/platform/proposal/common/listOpenSession").then((res) => {
if (res.code === 0) {
this.sessionOptions = res.data
if (this.sessionOptions) {
this.$set(this.pageForm, "sessionId", this.sessionOptions[0].id)
this.pageData()
this.listDelegation()
}
}
})
},
del() {},
openView(id) {}
},
created() {
this.listOpenSession()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,545 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style>
/* 提案信息卡片样式 - OA风格 */
.proposal-info-card {
background: #ffffff;
border: 1px solid var(--border-color-lighter);
margin-bottom: 20px;
overflow: hidden;
}
.proposal-info-content {
padding: 16px;
background: #fafafa;
}
.info-item {
display: flex;
align-items: flex-start;
margin-bottom: 12px;
line-height: 1.6;
padding: 8px 12px;
background: #ffffff;
border-left: 3px solid var(--color-primary-2);
transition: all 0.2s ease;
}
.info-item:hover {
border-left-color: var(--color-primary);
}
.info-item:last-child {
margin-bottom: 0;
}
.info-item label {
color: var(--color-text-regular);
font-weight: 500;
min-width: 80px;
margin-right: 12px;
flex-shrink: 0;
font-size: 13px;
}
.info-item span {
color: var(--color-text-primary);
word-break: break-all;
flex: 1;
font-size: 13px;
}
</style>
<div id="app">
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="教代会">
<el-select @change="meetingChange" clearable filterable placeholder="所属教代会" style="width: 100%"
v-model="pageForm.sessionId">
<el-option :key="item.id" :label="item.fullName" :value="item.id"
v-for="item in sessionOptions"></el-option>
</el-select>
</search-item>
<search-item label="提案编号">
<el-input v-model="pageForm.code" placeholder="提案编号" @keyup.enter.native="doSearch" clearable
style="width: 100%"></el-input>
</search-item>
<search-item label="提案名称">
<el-input v-model="pageForm.name" placeholder="提案名称" @keyup.enter.native="doSearch" clearable
style="width: 100%"></el-input>
</search-item>
<search-item label="姓名/工号">
<el-input placeholder="请输入姓名或工号" clearable v-model="pageForm.createUserKeyword"></el-input>
</search-item>
<!-- <search-item label="提案人姓名">-->
<!-- <el-input-->
<!-- @keyup.enter.native="doSearch"-->
<!-- clearable-->
<!-- placeholder="请输入提案人姓名"-->
<!-- v-model="pageForm.createUserName"-->
<!-- style="width: 100%"-->
<!-- ></el-input>-->
<!-- </search-item>-->
<!-- <search-item label="提案人工号">-->
<!-- <el-input-->
<!-- @keyup.enter.native="doSearch"-->
<!-- clearable-->
<!-- placeholder="请输入提案人工号"-->
<!-- v-model="pageForm.createUserLoginName"-->
<!-- style="width: 100%"-->
<!-- ></el-input>-->
<!-- </search-item>-->
</search>
</el-card>
<el-card shadow="never">
<table-tool :columns.sync="tableColumns">
<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 v-loading="tableLoading" :data="tableData" @sort-change="pageOrder" style="width: 100%">
<el-table-column label="序号" width="50" type="index" :index="indexMethod" fixed="left"></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:key="column.key"
:min-width="column.width"
:fixed="column.fixed"
sortable="custom"
show-overflow-tooltip
v-for="column in tableColumns"
v-if="column.visible !== false"
>
<template v-if="column.prop === 'caseFilingResult'" scope="{row}">
<dict-tag :options="dict.type.PROPOSAL_CASE_FILING_RESULT"
:value="row.caseFilingResult"></dict-tag>
</template>
<template v-else-if="column.prop === 'merge'" scope="{row}">
<el-tag v-if="row.merge" size="small"></el-tag>
<el-tag v-else type="warning" size="small"></el-tag>
</template>
<template v-else-if="column.prop === 'underTakeIsMaster'" scope="{row}">
<!-- 工作建议不区分主办、协办,承办类型统一展示为“承办”。 -->
<el-tag v-if="row.caseFilingResult === 'SUGGESTION'" size="small">承办</el-tag>
<el-tag v-else-if="row.underTakeIsMaster" size="small">主办</el-tag>
<el-tag v-else type="warning" size="small">协办</el-tag>
</template>
<template v-else-if="column.prop === 'instanceState'" scope="{row}">
<enum-tag :value="row.instanceState" name="ProcessInstanceStateEnum" label_key="message"
size="small"></enum-tag>
</template>
</el-table-column>
<el-table-column label="转交" prop="transfer" sortable="custom"
v-if="pageForm.approval && $auth.hasRoleOr('SYSADMIN,PROPOSAL_UNIT_LEADER')">
<template slot-scope="{row}">
{{row.transferUserName}}
</template>
</el-table-column>
<el-table-column label="操作" fixed="right" min-width="320px">
<template slot-scope="{row}">
<el-button @click="openView(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="pageForm.approval && row.taskState === 20 && $auth.hasRole('SYSADMIN')"
@click="openReplyEdit(row)" size="mini" type="primary">编辑答复
</el-button>
<el-button v-if="row.canRevoke" @click="onRevoke(row)" size="mini" type="danger">撤回
</el-button>
<!--办理单位领导、超级管理员才能转办-->
<el-button v-if="!pageForm.approval && $auth.hasRoleOr('SYSADMIN,PROPOSAL_UNIT_LEADER')"
@click="openTransfer(row)" size="mini" type="primary">转交
</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<template #edit>
<proposal-info ref="proposalInfoRef">
<div v-if="showApprovalForm">
<div class="process-title">
{{formData.taskName}}
</div>
<el-form :model="formData" ref="formRef" label-width="80px" :rules="formRules" label-suffix="">
<el-form-item label="办理单位">
<el-input :value="formData.underTakeName" disabled></el-input>
</el-form-item>
<el-form-item label="落实情况" prop="tf_implementState"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<el-radio-group v-model="formData.tf_implementState" size="small">
<el-radio v-for="item in dict.type.PROPOSAL_REPLY_IMPLEMENT" :label="item.code" border>
{{item.label}}
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item prop="tf_attachment" label="附件">
<file-upload
:value.sync="formData.tf_attachment"
upload_mode="drag"
:upload_number="5"
upload_result_category="array"
complete_result
upload_mode="file"
></file-upload>
</el-form-item>
<el-form-item label="答复内容" prop="tf_opinion"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<text-editor v-model="formData.tf_opinion"></text-editor>
</el-form-item>
<el-form-item label="校领导" prop="tf_nextNodeOperator"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]"
v-if="supportCandidate && formData.underTakeIsMaster">
<el-select v-model="formData.tf_nextNodeOperator" placeholder="请选择校领导">
<el-option :key="item.id" :label="item.userName" :value="item.userId"
v-for="item in candidates"></el-option>
</el-select>
</el-form-item>
</el-form>
<el-row type="flex" justify="end">
<el-button @click="handleTaskAction(1)" size="small" type="primary">提交</el-button>
<!-- <el-button @click="handleTaskAction(6)" size="small" type="info">退回到发起人</el-button>-->
<el-button @click="$refs.guava.index()" size="small">返回</el-button>
</el-row>
</div>
</proposal-info>
</template>
</guava>
<el-dialog title="转交" :visible.sync="showTransferDialog" width="500px">
<!--展示提案基本信息 名称、编号等-->
<div class="proposal-info-card">
<div class="proposal-info-content">
<div class="info-item">
<label>提案编号:</label>
<span>{{ transferForm.code }}</span>
</div>
<div class="info-item">
<label>提案名称:</label>
<span>{{ transferForm.name }}</span>
</div>
<div class="info-item">
<label>代表团:</label>
<span>{{ transferForm.delegationName }}</span>
</div>
</div>
</div>
<el-form ref="transferFormRef" :model="transferForm" label-position="top">
<el-form-item label="转交给" prop="userId"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<el-select v-model="transferForm.userId"
placeholder="请选择转交用户"
filterable
remote
:remote-method="selectTransferUser"
style="width: 100%"
>
<el-option :key="item.id"
:label="item.username"
:value="item.id"
v-for="item in transferUserOptions"></el-option>
</el-select>
</el-form-item>
</el-form>
<el-row type="flex" justify="end">
<el-button @click="showTransferDialog = false" size="small">返回</el-button>
<el-button @click="handleTransfer" size="small" type="primary">提交</el-button>
</el-row>
</el-dialog>
<el-dialog title="编辑答复内容" :visible.sync="showReplyEditDialog" width="900px" append-to-body>
<el-form ref="replyEditFormRef" :model="replyEditForm" label-width="80px">
<el-form-item label="提案编号">
<el-input :value="replyEditForm.code" disabled></el-input>
</el-form-item>
<el-form-item label="提案名称">
<el-input :value="replyEditForm.name" disabled></el-input>
</el-form-item>
<el-form-item label="答复内容" prop="tf_opinion"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<text-editor v-model="replyEditForm.tf_opinion"></text-editor>
</el-form-item>
</el-form>
<el-row type="flex" justify="end">
<el-button @click="showReplyEditDialog = false" size="small">返回</el-button>
<el-button @click="handleReplyEdit" size="small" type="primary">保存</el-button>
</el-row>
</el-dialog>
</div>
<script nonce="${cspNonce!}">
<!--#include('../../common/info.js'){}#-->
new Vue({
el: "#app",
store,
dicts: ["PROPOSAL_CASE_FILING_RESULT", "PROPOSAL_REPLY_IMPLEMENT"],
mixins: [initTableMixins],
components: {
"proposal-info": PROPOSAL_INFO
},
data() {
return {
tableColumns: [
{label: "提案编号", prop: "code"},
{label: "立案编号", prop: "caseFilingCode"},
{label: "提案名称", prop: "name", width: "200px"},
{label: "提案类别", prop: "typeName"},
{label: "立案结果", prop: "caseFilingResult"},
{label: "是否并案", prop: "merge"},
{label: "办理单位", prop: "underTakeName"},
{label: "承办类型", prop: "underTakeIsMaster"},
{label: "当前节点", prop: "curTaskName"},
{label: "审核人", prop: "auditUser"},
{label: "流程状态", prop: "instanceState"}
],
pageForm: {
approval: false
},
formData: {},
showApprovalForm: false,
sessionOptions: [],
delegationOptions: [],
candidates: [],
supportCandidate: false,
// 转交
showTransferDialog: false,
transferForm: {},
transferUserOptions: [],
// 超级管理员编辑历史答复内容
showReplyEditDialog: false,
replyEditForm: {},
}
},
methods: {
openView(row) {
this.$refs.guava.edit(() => {
this.showApprovalForm = false
this.$refs.proposalInfoRef.onOpen(row)
})
},
async openAudit(row) {
this.loadCandidates(row.taskId)
try{
await this.$confirm("是否已与提案代表进行充分沟通?", "提示", {
confirmButtonText: "是",
cancelButtonText: "否",
type: "info"
})
} catch (e) {
console.log(e)
return
}
this.$refs.guava.edit(() => {
this.showApprovalForm = true
this.formData = {
processTaskId: row.taskId,
taskKey: row.taskKey,
taskName: row.taskName,
proposalId: row.id,
underTakeName: row.underTakeName,
underTakeIsMaster: row.underTakeIsMaster
}
this.$refs.proposalInfoRef.onOpen(row)
})
},
// 超级管理员编辑已答复任务的答复内容,仅回显和提交 tf_opinion 字段。
openReplyEdit(row) {
const loading = createLoading('加载中')
this.$axios.post("/platform/proposal/unitReply/getReplyOpinion", {taskId: row.taskId}).then((res) => {
if (res.code === 0) {
this.replyEditForm = {
taskId: row.taskId,
code: row.code,
name: row.name,
tf_opinion: res.data ? res.data.tf_opinion : ""
}
this.showReplyEditDialog = true
this.$nextTick(() => {
if (this.$refs.replyEditFormRef) {
this.$refs.replyEditFormRef.clearValidate()
}
})
}
}).finally(() => {
loading.close()
})
},
// 历史答复编辑只保存答复内容,不修改落实情况、附件等其他字段。
handleReplyEdit() {
this.$refs.replyEditFormRef.validate((valid) => {
if (!valid) return
this.$confirm("您确定要保存答复内容吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
const loading = createLoading('保存中')
this.$axios.post("/platform/proposal/unitReply/updateReplyOpinion", {
taskId: this.replyEditForm.taskId,
opinion: this.replyEditForm.tf_opinion
}).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.showReplyEditDialog = false
this.doSearch()
}
}).finally(() => {
loading.close()
})
})
})
},
handleTaskAction(val) {
if(val === 6) {
this.handleTaskConfirm(val)
}else {
this.$refs.formRef.validate(valid => {
if (!valid) return
this.handleTaskConfirm(val)
})
}
},
handleTaskConfirm(val) {
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
const loading = createLoading('提交中')
delete this.formData.underTakeIsMaster
delete this.formData.underTakeName
this.$axios.post("/platform/proposal/unitReply/executeTask", {
data: JSON.stringify({
...this.formData,
submitType: val
})
}).then((res) => {
if (res.code === 0) {
this.$refs.guava.index()
this.$message.success(res.msg)
this.doSearch()
}
}).finally(() => {
loading.close()
})
})
},
// 撤销
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()
}
})
})
},
// 加载候选人列表
loadCandidates(taskId) {
$.get("/flow/common/candidate", {taskId}).then((res) => {
if (res.code === 0) {
this.candidates = res.data.candidates
this.supportCandidate = res.data.support
}
})
},
// 打开转办
openTransfer(row) {
this.showTransferDialog = true
this.transferForm = {
taskId: row.taskId,
name: row.name,
code: row.code,
delegationName: row.delegationName
}
},
// 查询转办用户
selectTransferUser(keyword) {
this.$axios.post("/platform/proposal/unitReply/selectViceUser", {keyword}).then(res => {
if (res.code === 0) {
this.transferUserOptions = res.data
}
})
},
// 转办
handleTransfer() {
this.$refs.transferFormRef.validate(valid => {
if (!valid) return
const transferUserName = this.transferUserOptions.find(item => item.id === this.transferForm.userId)?.username
const name = this.transferForm.name
this.$confirm("您确定要将" + name + "提案转交给" + transferUserName + "办理吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "info"
}).then(() => {
this.$axios.post('/platform/proposal/unitReply/transfer', this.transferForm).then(res => {
if (res.code === 0) {
this.$message.success(res.msg)
this.showTransferDialog = false
this.doSearch()
}
})
})
})
},
// 教代会
async meetingChange(val) {
this.doSearch()
},
// 查询开启的教代会
listOpenSession() {
this.$axios.post("/platform/proposal/common/listOpenSession").then((res) => {
if (res.code === 0) {
this.sessionOptions = res.data
if (this.sessionOptions) {
this.$set(this.pageForm, "sessionId", this.sessionOptions[0].id)
this.pageData()
}
}
})
}
},
created() {
this.pageData()
this.listOpenSession()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,187 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app">
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="教代会">
<el-select @change="meetingChange" clearable filterable placeholder="所属教代会"
v-model="pageForm.sessionId">
<el-option :key="item.id" :label="item.fullName" :value="item.id"
v-for="item in sessionOptions"></el-option>
</el-select>
</search-item>
<search-item label="提案名称">
<el-input v-model="pageForm.name" placeholder="提案名称" @keyup.enter.native="doSearch" clearable
style="width: 100%"></el-input>
</search-item>
<search-item label="姓名/工号">
<el-input placeholder="请输入姓名或工号" clearable v-model="pageForm.createUserKeyword"></el-input>
</search-item>
</search>
</el-card>
<el-card shadow="never">
<table-tool :columns.sync="tableColumns">
<!-- <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 v-loading="tableLoading" :data="tableData" @sort-change="pageOrder" style="width: 100%">
<el-table-column
:label="column.label"
:prop="column.prop"
:key="column.key"
:min-width="column.width"
:fixed="column.fixed"
sortable="custom"
show-overflow-tooltip
v-for="column in tableColumns"
v-if="column.visible !== false"
>
<template v-if="column.prop === 'caseFilingResult'" scope="{row}">
<dict-tag :options="dict.type.PROPOSAL_CASE_FILING_RESULT"
:value="row.caseFilingResult"></dict-tag>
</template>
<template v-else-if="column.prop === 'merge'" scope="{row}">
<el-tag v-if="row.merge" size="small"></el-tag>
</template>
<template v-else-if="column.prop === 'instanceState'" 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="100px">
<template slot-scope="{row}">
<el-button @click="openView(row)" size="mini" type="primary">查看</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<template #edit>
<proposal-info ref="proposalInfoRef"></proposal-info>
</template>
</guava>
</div>
<script nonce="${cspNonce!}">
<!--#include('../../common/info.js'){}#-->
new Vue({
el: "#app",
store,
mixins: [initTableMixins],
components: {
"proposal-info": PROPOSAL_INFO
},
data() {
return {
tableColumns: [
{label: "提案编号", prop: "code"},
{label: "提案名称", prop: "name", width: "200px"},
{label: "提案类别", prop: "typeName"},
{label: "届次", prop: "sessionName"},
{label: "代表团", prop: "delegationName"},
{label: "当前节点", prop: "curTaskName"},
{label: "流程状态", prop: "instanceState"}
],
pageForm: {
approval: false
},
showApprovalForm: false
}
},
methods: {
openView(row) {
this.$refs.guava.edit(() => {
this.showApprovalForm = false
this.$refs.proposalInfoRef.onOpen(row)
})
},
openAudit(row) {
this.$refs.guava.edit(() => {
this.showApprovalForm = true
this.formData = {
processTaskId: row.taskId,
taskName: row.curTaskName
}
this.$refs.proposalInfoRef.onOpen(row)
})
},
handleTaskAction(val) {
this.$refs.formRef.validate(valid => {
if (!valid) return
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post("/flow/common/executeTask", {
data: JSON.stringify({
...this.formData,
submitType: val
})
}).then((res) => {
if (res.code === 0) {
this.$refs.guava.index()
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()
}
})
})
},
// 教代会
async meetingChange(val) {
this.formData.delegationId = null
this.formData.committeeId = null
this.doSearch()
},
// 查询开启的教代会
listOpenSession() {
this.$axios.post("/platform/proposal/common/listOpenSession").then((res) => {
if (res.code === 0) {
this.sessionOptions = res.data
if (this.sessionOptions) {
this.$set(this.pageForm, "sessionId", this.sessionOptions[0].id)
this.pageData()
this.listDelegation()
}
}
})
}
},
created() {
this.pageData()
this.listOpenSession()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,603 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style></style>
<div id="app" v-cloak>
<custom-card>
<snaker-start slot="header" label="撰写提案" define_key="JDHTA_NC">
<template slot="header-right-label">
<el-link type="primary" @click="openImport" v-if="!formData.id" style="margin-right: 15px">导入提案</el-link>
</template>
</snaker-start>
<el-form :model="formData" :rules="formRules" label-width="120px" ref="addForm">
<el-row :gutter="20" type="flex">
<el-col :span="12">
<el-form-item label="代表姓名" prop="createUserName">
<el-input readonly v-model="formData.createUserName" disabled></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="提案时间" prop="createTime">
<el-input readonly v-model="formData.createTime" disabled></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20" type="flex">
<el-col :span="12" v-if="false">
<el-form-item label="所属教代会" prop="sessionId">
<el-select
@change="meetingChange"
clearable
filterable
placeholder="所属教代会"
v-model="formData.sessionId"
style="width: 100%"
>
<el-option :key="item.id" :label="item.fullName" :value="item.id"
v-for="item in sessionOptions"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12" v-if="false">
<el-form-item label="所属代表团" prop="delegationId">
<el-select clearable filterable placeholder="所属代表团" v-model="formData.delegationId"
style="width: 100%" disabled>
<el-option :key="item.id" :label="item.name" :value="item.id"
v-for="item in delegationOptions"></el-option>
</el-select>
</el-form-item>
<el-form-item label="所属委员会" prop="committeeId" v-if="formData.mannerCode=='W03'">
<el-select clearable filterable placeholder="所属委员会" v-model="formData.committeeId"
style="width: 100%">
<el-option :key="item.id" :label="item.name" :value="item.id"
v-for="item in committeeOptions"></el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20" v-if="false">
<el-col :span="12">
<el-form-item label="单位" prop="unitName">
<el-input v-model="formData.unitName" disabled></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="联系电话" prop="mobile">
<el-input v-model="formData.mobile" clearable placeholder="联系电话"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20" type="flex">
<el-col :span="12">
<el-form-item label="提案名称" prop="name">
<el-input maxlength="100" placeholder="提案名称" v-model="formData.name"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="提案方式" prop="source">
<!-- <el-select v-model="formData.source" style="width: 100%">-->
<!-- <el-option :key="item.code" :label="item.name" :value="item.code"-->
<!-- v-for="item in sourceOptions"></el-option>-->
<!-- </el-select>-->
<el-radio :key="item.code" :label="item.code" border
size="medium"
v-for="item in sourceOptions" v-model="formData.source">
{{item.name}}
</el-radio>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20" type="flex">
<el-col :span="12">
<el-form-item label="提案类型" prop="typeId">
<el-select v-model="formData.typeId" style="width: 100%">
<el-option :key="item.id" :label="item.name" :value="item.id"
v-for="item in typeOptions"></el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<!-- <el-form-item label="提案摘要" prop="excerpt">-->
<!-- <span slot="label">-->
<!-- 提案摘要-->
<!-- <el-tooltip content="请简述提案内容和依据、改进建议和措施摘要" placement="right">-->
<!-- <i class="el-icon-question"></i>-->
<!-- </el-tooltip>-->
<!-- </span>-->
<!-- <el-input-->
<!-- v-model="formData.excerpt"-->
<!-- type="textarea"-->
<!-- autosize-->
<!-- :autosize="{ minRows: 4, maxRows: 4}"-->
<!-- placeholder="提案摘要"-->
<!-- ></el-input>-->
<!-- </el-form-item>-->
<!-- <el-form-item label="调研情况" prop="researchFindings">-->
<!-- <el-input-->
<!-- v-model="formData.researchFindings"-->
<!-- type="textarea"-->
<!-- autosize-->
<!-- :autosize="{ minRows: 4, maxRows: 4}"-->
<!-- placeholder="调研情况"-->
<!-- ></el-input>-->
<!-- </el-form-item>-->
<el-form-item label="建议办理单位" prop="suggestUnits" v-if="false">
<el-select v-model="formData.suggestUnits" multiple filterable style="width: 100%"
placeholder="请选择建议办理单位">
<el-option :key="item.id" :label="item.name" :value="item.name"
v-for="item in suggestUnitOptions"></el-option>
</el-select>
</el-form-item>
<el-form-item label="案由" prop="brief">
<text-editor v-model="formData.brief" key="brief" top-tip="(提案内容已进入深入调研,具备真实性、广泛性、代表性)"></text-editor>
</el-form-item>
<el-form-item label="建议措施" prop="measures">
<text-editor v-model="formData.measures" key="measures"
top-tip="(建议措施内容具体,具备科学性,可执行性)"></text-editor>
</el-form-item>
<el-form-item label="附件上传" prop="files">
<file-upload
:value.sync="formData.files"
:upload_number="5"
upload_result_category="array"
upload_mode="drag"
:limit_upload_size="false"
complete_result
></file-upload>
</el-form-item>
<!-- <el-form-item label="电子签名" prop="signature">-->
<!-- <pc-signature v-model="formData.signature"></pc-signature>-->
<!-- </el-form-item>-->
</el-form>
<template slot="footer" v-if="isWriteTime">
<el-button type="primary" @click="onSave" :loading="formLoading">保存</el-button>
<el-button type="primary" @click="onSubmit" v-if="!taskId" :loading="formLoading">提交</el-button>
<el-button type="primary" @click="onSubmitAgain" v-else :loading="formLoading">提交</el-button>
</template>
</custom-card>
<el-dialog title="提案撰写须知" :visible.sync="noticeDialogVisible" :show-close="false" width="50%">
<div v-html="proposalConfig.writeRemind" style="max-height: 50vh; overflow-y: auto"></div>
<div slot="footer">
<el-button type="primary" @click="noticeDialogVisible = false">我已知晓</el-button>
</div>
</el-dialog>
<el-dialog
title="提案导入"
:visible.sync="importVisible"
:close-on-click-modal="false"
width="50%"
>
<el-timeline>
<el-timeline-item timestamp="下载模板" placement="top">
<el-card>
<el-row :gutter="24">
<el-col :span="24">
<el-radio-group v-model="importTemplateType">
<el-radio :label="1">excel</el-radio>
<el-radio :label="2">word</el-radio>
</el-radio-group>
</el-col>
</el-row>
<el-row :gutter="24" style="margin-top: 20px;">
<el-col :span="24">
<el-button size="medium" type="" style="width: 200px"
@click="downloadTemplate"
icon="el-icon-download">下载模板
</el-button>
</el-col>
</el-row>
</el-card>
</el-timeline-item>
<el-timeline-item timestamp="上传文件" placement="top">
<el-card>
<el-upload
name="file"
ref="upload"
:on-remove="(file, fileList) => {
importData.fileList = fileHandleRemove(file, fileList)
}"
:on-change="(file, fileList) => {
if(this.importTemplateType === 2) {
importData.fileList = fileHandleChange(file, fileList,{type:['docx']})
} else {
importData.fileList = fileHandleChange(file, fileList,{type:['xlsx']})
}
}"
:auto-upload="false"
:limit="1"
:file-list="importData.fileList">
<el-button size="medium" type="" icon="el-icon-upload" style="width: 200px">选择文件
</el-button>
</el-upload>
</el-card>
</el-timeline-item>
</el-timeline>
<span slot="footer" class="dialog-footer">
<el-button @click="importVisible = false" :disabled="importLoading">取 消</el-button>
<el-button type="primary" @click="doImport" :loading="importLoading">确定</el-button>
</span>
</el-dialog>
</div>
<script nonce="${cspNonce!}">
const vue = new Vue({
el: "#app",
store,
mixins: [initTableMixins],
data() {
return {
bizId: GetQueryString("bizId"),
taskId: GetQueryString("taskId"),
// 将 window.location 的引用存储在响应式数据中
location: window.location,
importTemplateType: 1,
importData: {},
importVisible: false,
importLoading: false,
formData: {},
sessionOptions: [],
sourceOptions: [],
allSourceOptions: [],
delegationOptions: [],
committeeOptions: [],
typeOptions: [],
formRules: {
createUserName: [{required: true, message: "请填写提案人", trigger: ["blur", "change"]}],
createTime: [{required: true, message: "请填写提案时间", trigger: ["blur", "change"]}],
name: [{required: true, message: "请填写提案名称", trigger: ["blur", "change"]}],
source: [{required: true, message: "请选择提案方式", trigger: ["blur", "change"]}],
delegationId: [{required: true, message: "请选择所属代表团", trigger: ["blur", "change"]}],
sessionId: [{required: true, message: "请选择所属教代会", trigger: ["blur", "change"]}],
committeeId: [{required: true, message: "请选择所属委员会", trigger: ["blur", "change"]}],
typeId: [{required: true, message: "请选择提案类型", trigger: ["blur", "change"]}],
suggestUnits: [{required: true, message: "请选择建议办理单位", trigger: ["blur", "change"]}],
sign: [{required: true, message: "请扫描二维码进行签字", trigger: ["blur", "change"]}],
excerpt: [{required: true, message: "请填写", trigger: ["blur", "change"]}],
researchFindings: [{required: true, message: "请填写", trigger: ["blur", "change"]}],
brief: [{required: true, message: "请填写", trigger: ["blur", "change"]}],
measures: [{required: true, message: "请填写", trigger: ["blur", "change"]}],
unitName: [{required: true, message: "请填写", trigger: ["blur", "change"]}],
mobile: [{required: true, message: "请填写", trigger: ["blur", "change"]}],
signature: [{required: false, message: "请扫描二维码进行签字", trigger: ["blur", "change"]}]
},
proposalConfig: {},
noticeDialogVisible: false,
isWriteTime: true,
// 建议办理单位
suggestUnitOptions: []
}
},
methods: {
onSave() {
this.$refs["addForm"].validate((valid) => {
if (!valid) {
return
}
if (!this.formData.name || this.formData.name.trim().length < 1) {
this.$message.warning("请填写提案名称")
return
}
this.formLoading = true
this.$axios.post("/platform/proposal/write/save", {info: JSON.stringify(this.formData)}).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.formData = res.data
commonUtil.pjaxPush('/platform/proposal/mine')
}
}).finally(() => {
this.formLoading = false
})
})
},
// 提交
onSubmit() {
this.$refs["addForm"].validate((valid) => {
if (!valid) {
return
}
if (!this.formData.name || this.formData.name.trim().length < 1) {
this.$message.warning("请填写提案名称")
return
}
let brief = clone(this.formData.brief)
brief = removeHTMLTag(brief)
if (brief.length < this.proposalConfig.briefMinLength) {
this.$message.warning("提案内容和依据最少为" + this.proposalConfig.briefMinLength + "字")
return
}
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.formLoading = true
this.$axios.post('/platform/proposal/write/submit', {info: JSON.stringify(this.formData)}).then((res) => {
if (res.code === 0) {
this.$message.success("提交成功")
if (this.formData.source==="PERSONAL"){
this.$confirm("提交成功,是否立即去邀请附议人?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
commonUtil.pjaxPush('/platform/proposal/mine?bizId=' + res.data.id + "&operation=invite")
}).catch(() => {
this.$message.info("请到我的提案界面邀请附议人")
commonUtil.pjaxPush('/platform/proposal/mine')
})
}else{
commonUtil.pjaxPush('/platform/proposal/mine')
}
}
}).finally(() => {
this.formLoading = false
})
})
})
},
// 打开导入窗口
openImport() {
this.importData = {
fileList: []
}
this.importVisible = true;
},
// 下载导入模板
downloadTemplate() {
let templateType = '.xlsx'
if(this.importTemplateType === 2) {
templateType = '.docx'
}
this.location.href='/platform/basics/downloadTemplate?filePath=proposal/proposal' + templateType + '&fileName=教职工代表大会提案表' + templateType
},
// 开始导入数据
doImport() {
if (!this.importData.fileList.length) {
this.notifyWarning("请选择文件!")
return
}
const data = new FormData();
this.importData.fileList.forEach((val) => {
data.append("file", val.raw, val.raw.name);
});
this.importLoading = true
$.ajax({
url: loc() + "/importProposal?templateType=" + this.importTemplateType,
type: "post",
data: data,
processData: false,
contentType: false,
success: (data) => {
console.log(loc(), data)
if (!data.code) {
if(data.data) {
this.formData = { ...data.data }
}
this.importVisible = false
} else {
this.notifyWarning(data.msg)
}
},
error: () => {
this.notifyWarning("导入失败")
}
}).always(() => {
this.importLoading = false
})
},
// 重新提交
onSubmitAgain() {
this.$refs["addForm"].validate((valid) => {
if (!valid) {
return
}
if (!this.formData.name || this.formData.name.trim().length < 1) {
this.$message.warning("请填写提案名称")
return
}
let brief = clone(this.formData.brief)
brief = removeHTMLTag(brief)
if (brief.length < this.proposalConfig.briefMinLength) {
this.$message.warning("提案内容和依据最少为" + this.proposalConfig.briefMinLength + "字")
return
}
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.formLoading = true
this.$axios.post('/platform/proposal/write/submitAgain', {
info: JSON.stringify(this.formData),
taskId: GetQueryString("taskId")
}).then((res) => {
if (res.code === 0) {
this.$message.success("提交成功")
commonUtil.pjaxPush('/platform/proposal/mine')
}
}).finally(() => {
this.formLoading = false
})
})
})
},
// 根据当前教代会届次获取允许撰写的提案类型
listProposalType() {
if (!this.formData.sessionId) {
this.typeOptions = []
return Promise.resolve()
}
return this.$axios.post("/platform/proposal/write/listSessionProposalTypes", {
sessionId: this.formData.sessionId
}).then((res) => {
if (res.code === 0) {
this.typeOptions = res.data
}
})
},
// 获取配置
getProposalConfig() {
return this.$axios.post("/platform/proposal/common/config").then((res) => {
if (res.code === 0) {
this.proposalConfig = res.data
}
})
},
//教代会change
meetingChange(val) {
// 切换届次后,原提案类型不再有效,需按新届次重新选择
this.$set(this.formData, "typeId", null)
this.typeOptions = []
this.listProposalType()
this.formData.delegationId = null
this.formData.committeeId = null
this.listDelegation()
this.searchMineDelegation()
},
// 建议办理单位
listSuggestUnit() {
this.$axios.post("/platform/proposal/common/listUnderTake").then((res) => {
if (res.code === 0) {
this.suggestUnitOptions = res.data
}
})
},
// 获取代表团
listDelegation() {
return this.$axios.post("/platform/proposal/common/listDelegation", {sessionId: this.formData.sessionId}).then((res) => {
if (res.code === 0) {
this.delegationOptions = res.data
}
})
},
// 查询开启的教代会
listOpenSession(isModify = false) {
return this.$axios.post("/platform/proposal/common/listOpenSession").then((res) => {
if (res.code === 0) {
this.sessionOptions = res.data
let delegationPromise = Promise.resolve()
if (!isModify && this.sessionOptions) {
this.$set(this.formData, "sessionId", this.sessionOptions[0].id)
// 获取代表团
delegationPromise = this.searchMineDelegation().then(() => {
// 检查是否在撰写时间内
this.checkWriteTime()
})
}
return delegationPromise.then(() => this.listDelegation()).then(() => this.listProposalType())
}
})
},
//查询自己有权限的撰写方式
listSource() {
return this.$axios.post("/platform/proposal/write/listSource", {sessionId: this.formData.sessionId}).then((res) => {
if (res.code === 0) {
this.sourceOptions = res.data
}
})
},
// 查询字典 撰写方式
getDictByCode(code) {
return this.$axios.post("/platform/proposal/write/listSourceByCode", {code: code}).then((res) => {
return res.data
})
},
//查询自己有权限的代表团
searchMineDelegation() {
return this.$axios.post("/platform/proposal/write/searchMineDelegation", {sessionId: this.formData.sessionId}).then((res) => {
if (res.code === 0) {
this.$set(this.formData, "delegationId", res.data)
}
})
},
// 检查是否在撰写时间内
checkWriteTime() {
this.$axios.post("/platform/proposal/write/checkWriteTime", {sessionId: this.formData.sessionId}).then((res) => {
if (res.code === 0) {
if (!res.data) {
this.$message.warning("当前时间不在撰写时间段内")
this.isWriteTime = false
} else {
this.isWriteTime = true
}
}
})
},
init() {
if (this.bizId) {
this.$axios.post("/platform/proposal/write/detail", {id: this.bizId}).then((res) => {
if (res.code === 0) {
this.formData = res.data
this.listOpenSession(true)
}
})
} else {
this.noticeDialogVisible = true
this.listOpenSession(false)
this.$set(this.formData, "createUserId", this.$store.state.user.id)
this.$set(this.formData, "createUserName", this.$store.state.user.username)
this.$set(this.formData, "createUserLoginName", this.$store.state.user.loginname)
this.$set(this.formData, "createTime", this.$moment().format("YYYY-MM-DD"))
this.$set(this.formData, "mobile", this.$store.state.user.mobile)
this.$set(this.formData, "unitName", this.$store.state.user.unit?.name)
}
// 撰写方式
this.getDictByCode("PROPOSAL_SOURCE").then((data) => {
this.allSourceOptions = data
this.sourceOptions = data
})
}
},
created() {
this.init()
this.listSuggestUnit()
this.getProposalConfig()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,170 @@
<div id="proposal-view">
<!-- <el-form ref="formRef" label-width="0" label-suffix="" class="flow-task-form">-->
<el-descriptions :column="2" border class="flow-task-form">
<el-descriptions-item label="提案名称" :span="2">{{ viewData.name }}</el-descriptions-item>
<el-descriptions-item label="提案编号">{{ viewData.code }}</el-descriptions-item>
<el-descriptions-item label="提案人">{{viewData.createUserName }}</el-descriptions-item>
<el-descriptions-item label="提案时间">{{ viewData.createTime }}</el-descriptions-item>
<el-descriptions-item label="教代会届次">{{ viewData.sessionName || '暂无' }}</el-descriptions-item>
<el-descriptions-item label="提案人单位">{{ viewData.unitName }}</el-descriptions-item>
<el-descriptions-item :label="viewData.mannerCode!=='W03'?'代表团名称':'委员会名称'">
{{ viewData.mannerCode !== 'W03' ? viewData.delegationName : viewData.committeeName }}
</el-descriptions-item>
<el-descriptions-item label="提案类别">{{viewData.typeName}}</el-descriptions-item>
<el-descriptions-item label="立案结果" :span="2">
<dict-tag :options="dict.type.PROPOSAL_CASE_FILING_RESULT" :value="viewData.caseFilingResult"></dict-tag>
</el-descriptions-item>
<el-descriptions-item label="提案摘要" :span="2">
<div class="text-left">{{viewData.excerpt}}</div>
</el-descriptions-item>
<el-descriptions-item label="提案内容" :span="2">
<div class="text-left" v-html="viewData.brief"></div>
</el-descriptions-item>
<el-descriptions-item label="改进建议和措施" :span="2">
<div class="text-left" v-html="viewData.measures"></div>
</el-descriptions-item>
<el-descriptions-item label="附件" :span="2">
<file-preview :files="viewData.files" complete_result></file-preview>
</el-descriptions-item>
</el-descriptions>
<!-- <template v-for="task in doneTasks">-->
<!-- <div class="task-panel mt10">-->
<!-- <div class="task-panel-header">{{ task.displayName }}</div>-->
<!-- <el-descriptions border class="flow-task-form" :column="3" :key="task.id" v-if="task.ext.isFirstTaskNode">-->
<!-- <el-descriptions-item label="申请用户">{{ task.ext.initiatorName }}({{task.ext.initiatorAccount}})</el-descriptions-item>-->
<!-- <el-descriptions-item label="申请时间">{{ task.finishTime }}</el-descriptions-item>-->
<!-- <el-descriptions-item label="办理结果">-->
<!-- <dict-tag :options="dict.type.PROCESS_TASK_SUBMIT_TYPE" :value="task.ext.submitType"></dict-tag>-->
<!-- </el-descriptions-item>-->
<!-- </el-descriptions>-->
<!-- <el-descriptions border class="flow-task-form" :column="3" :key="task.id" v-else>-->
<!-- <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="办理结果">-->
<!-- <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>-->
<!-- 首先按 taskParentId 分组 -->
<template v-for="(group, parentId) in groupTasksByParentId(doneTasks)">
<div class="task-panel mt10" :key="parentId">
<!-- 显示主任务(parentId 为 0 或没有子任务的任务) -->
<template v-if="parentId === '0' || !group.children.length">
<div class="task-panel-header">{{ group.mainTask.displayName }}</div>
<el-descriptions border class="flow-task-form" :column="3">
<el-descriptions-item label="申请用户">
{{ group.mainTask.ext.initiatorName }}({{group.mainTask.ext.initiatorAccount}})
</el-descriptions-item>
<el-descriptions-item label="申请时间">{{ group.mainTask.finishTime }}</el-descriptions-item>
<el-descriptions-item label="办理结果">
<dict-tag :options="dict.type.PROCESS_TASK_SUBMIT_TYPE" :value="group.mainTask.ext.submitType"></dict-tag>
</el-descriptions-item>
</el-descriptions>
</template>
<!-- 显示子任务 -->
<template v-for="(task, index) in group.children">
<div class="task-panel-header" :key="task.id" v-if="index === 0 || task.displayName !== group.children[index-1].displayName">
{{ 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="办理结果">
<dict-tag :options="dict.type.PROCESS_TASK_SUBMIT_TYPE" :value="task.ext.submitType"></dict-tag>
</el-descriptions-item>
<el-descriptions-item label="办理意见">{{ task.taskFormData.opinion }}</el-descriptions-item>
</el-descriptions>
</template>
</div>
</template>
</div>
<script nonce="${cspNonce!}">
new Vue({
el: "#proposal-view",
store,
dicts: ["PROCESS_TASK_SUBMIT_TYPE"],
data() {
return {
businessId: GetQueryString("businessId"),
instanceId: GetQueryString("instanceId"),
viewData: {},
doneTasks: []
}
},
methods: {
info() {
this.$axios.post("/platform/proposal/view/info", { id: this.businessId }).then((res) => {
if (res.code === 0) {
this.viewData = res.data
}
})
},
getDoneTasks() {
this.$axios.post("/flow/common/doneTasks", { instanceId: this.instanceId }).then((res) => {
if (res.code === 0) {
this.doneTasks = res.data
}
})
},
groupTasksByParentId(tasks) {
const groups = {}
// 首先找出所有主任务(taskParentId 为 0 的任务)
tasks.forEach((task) => {
const parentId = task.taskParentId || "0"
if (!groups[parentId]) {
groups[parentId] = {
mainTask: null,
children: []
}
}
if (parentId === "0") {
groups[parentId].mainTask = task
} else {
// 如果是子任务,尝试找到对应的主任务
if (!groups[parentId].mainTask) {
const mainTask = tasks.find((t) => t.id === task.taskParentId)
if (mainTask) {
groups[parentId].mainTask = mainTask
}
}
groups[parentId].children.push(task)
}
})
return groups
}
},
created() {
this.info()
this.getDoneTasks()
}
})
</script>
<style>
.task-panel {
background: white;
border-radius: 4px;
overflow: hidden;
}
.task-panel-header {
background: rgb(250, 250, 250);
border: 1px solid rgb(228, 231, 237);
border-bottom: none;
padding: 12px 16px;
display: flex;
justify-content: space-between;
align-items: center;
}
</style>