Merge remote-tracking branch 'origin/feature_界面UI优化' into feature_界面UI优化
This commit is contained in:
-9
@@ -65,15 +65,6 @@ public class ProposalCaseCheckController {
|
||||
public void h5Index() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开提案委员会审查手机端详情及审核页。
|
||||
*/
|
||||
@At("/info/h5")
|
||||
@Ok("beetl:/platform/zhghh5/democratic/proposal/transact/caseCheck/info.html")
|
||||
@SaCheckPermission("h5.proposal.caseCheck")
|
||||
public void h5Info() {
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission(value = {"proposal.caseCheck", "h5.proposal.caseCheck"}, mode = SaMode.OR)
|
||||
@ApiOperation("分页列表")
|
||||
|
||||
-7
@@ -49,13 +49,6 @@ public class ProposalCommissionerController {
|
||||
public void h5Index() {
|
||||
}
|
||||
|
||||
@At("/info/h5")
|
||||
@Ok("beetl:/platform/zhghh5/democratic/proposal/transact/commissioner/info.html")
|
||||
@SaCheckPermission("h5.proposal.commissioner")
|
||||
public void h5Info() {
|
||||
}
|
||||
|
||||
|
||||
@At
|
||||
@SaCheckPermission("proposal.commissioner")
|
||||
public Result pageData(@Valid ProposalSearchParam pageForm, boolean approval) {
|
||||
|
||||
-7
@@ -67,13 +67,6 @@ public class ProposalDelegationController {
|
||||
public void h5Index() {
|
||||
}
|
||||
|
||||
@At("/info/h5")
|
||||
@Ok("beetl:/platform/zhghh5/democratic/proposal/transact/delegation/info.html")
|
||||
@SaCheckPermission("h5.proposal.delegation")
|
||||
public void h5Info() {
|
||||
}
|
||||
|
||||
|
||||
@At
|
||||
@SaCheckPermission("proposal.delegation")
|
||||
@ApiOperation("分页列表")
|
||||
|
||||
-7
@@ -54,13 +54,6 @@ public class ProposalFeedbackEvaluationController {
|
||||
public void h5Index() {
|
||||
}
|
||||
|
||||
@At("/info/h5")
|
||||
@Ok("beetl:/platform/zhghh5/democratic/proposal/transact/feedbackEvaluation/info.html")
|
||||
@SaCheckPermission("h5.proposal.feedbackEvaluation")
|
||||
public void h5Info() {
|
||||
}
|
||||
|
||||
|
||||
@At
|
||||
@SaCheckPermission("proposal.feedbackEvaluation")
|
||||
@ApiOperation("分页列表")
|
||||
|
||||
-6
@@ -107,12 +107,6 @@ public class ProposalMineController {
|
||||
public void h5Index() {
|
||||
}
|
||||
|
||||
@At("/info/h5")
|
||||
@Ok("beetl:/platform/zhghh5/democratic/proposal/transact/mine/info.html")
|
||||
@SaCheckPermission("h5.proposal.mine")
|
||||
public void h5Info() {
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("proposal.mine")
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
|
||||
-7
@@ -58,13 +58,6 @@ public class ProposalPreAuditController {
|
||||
public void h5Index() {
|
||||
}
|
||||
|
||||
@At("/info/h5")
|
||||
@Ok("beetl:/platform/zhghh5/democratic/proposal/transact/preAudit/info.html")
|
||||
@SaCheckPermission("h5.proposal.preAudit")
|
||||
public void h5Info() {
|
||||
}
|
||||
|
||||
|
||||
@At
|
||||
@SaCheckPermission("proposal.preAudit")
|
||||
@ApiOperation("分页列表")
|
||||
|
||||
-7
@@ -74,13 +74,6 @@ public class ProposalSchoolLeaderApprovalController {
|
||||
public void h5Index() {
|
||||
}
|
||||
|
||||
@At("/info/h5")
|
||||
@Ok("beetl:/platform/zhghh5/democratic/proposal/transact/schoolLeaderApproval/info.html")
|
||||
@SaCheckPermission("h5.proposal.schoolLeaderApproval")
|
||||
public void h5Info() {
|
||||
}
|
||||
|
||||
|
||||
@At
|
||||
@SaCheckPermission("proposal.schoolLeaderApproval")
|
||||
@ApiOperation("分页列表")
|
||||
|
||||
-6
@@ -88,12 +88,6 @@ public class ProposalSecondedController {
|
||||
public void h5Index() {
|
||||
}
|
||||
|
||||
@At("/info/h5")
|
||||
@Ok("beetl:/platform/zhghh5/democratic/proposal/transact/seconded/info.html")
|
||||
@SaCheckPermission("h5.proposal.seconded")
|
||||
public void h5Info() {
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("proposal.seconded")
|
||||
public Result pageData(@Valid ProposalSearchParam pageForm, boolean approval) {
|
||||
|
||||
-6
@@ -76,12 +76,6 @@ public class ProposalUnderTakeReplyController {
|
||||
public void h5Index() {
|
||||
}
|
||||
|
||||
@At("/info/h5")
|
||||
@Ok("beetl:/platform/zhghh5/democratic/proposal/transact/unitReply/info.html")
|
||||
@SaCheckPermission("h5.proposal.unitReply")
|
||||
public void h5Info() {
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("proposal.unitReply")
|
||||
@ApiOperation("分页列表")
|
||||
|
||||
-6
@@ -62,12 +62,6 @@ public class ProposalUndertakeSuggestionController {
|
||||
public void h5Index() {
|
||||
}
|
||||
|
||||
@At("/info/h5")
|
||||
@Ok("beetl:/platform/zhghh5/democratic/proposal/transact/suggestion/info.html")
|
||||
@SaCheckPermission("h5.proposal.suggestion")
|
||||
public void h5Info() {
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission(value = {"proposal.suggestion", "h5.proposal.suggestion"}, mode = SaMode.OR)
|
||||
@ApiOperation("分页列表")
|
||||
|
||||
-6
@@ -42,12 +42,6 @@ public class ProposalViceDelegationController {
|
||||
public void h5Index() {
|
||||
}
|
||||
|
||||
@At("/info/h5")
|
||||
@Ok("beetl:/platform/zhghh5/democratic/proposal/transact/viceDelegation/info.html")
|
||||
@SaCheckPermission("h5.proposal.vice.delegation")
|
||||
public void h5Info() {
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("proposal.vice.delegation")
|
||||
@ApiOperation("分页列表")
|
||||
|
||||
-6
@@ -19,10 +19,4 @@ public class H5ProposalQueryComprehensiveController {
|
||||
public void index() {
|
||||
}
|
||||
|
||||
@At("/info")
|
||||
@Ok("beetl:/platform/zhghh5/democratic/proposal/query/comprehensive/info.html")
|
||||
@SaCheckPermission("h5.proposal.query.comprehensive")
|
||||
public void info() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -166,7 +166,7 @@ layout("/layouts/platform_tour_signup_h5.html"){
|
||||
</style>
|
||||
|
||||
<div id="app" class="tour-signup-h5">
|
||||
<van-nav-bar title="疗休养报名" left-text="返回" left-arrow @click-left="historyBack" fixed placeholder></van-nav-bar>
|
||||
<van-nav-bar title="疗休养报名" left-text="返回" left-arrow @click-left="$pjaxReplace('/platform/h5/home')" fixed placeholder></van-nav-bar>
|
||||
|
||||
<div class="tour-signup-banner">
|
||||
<van-swipe class="tour-signup-swipe" :autoplay="3500" indicator-color="white">
|
||||
@@ -438,7 +438,7 @@ layout("/layouts/platform_tour_signup_h5.html"){
|
||||
if (this.readCountdown > 0) {
|
||||
return
|
||||
}
|
||||
window.location.href = "/platform/tour/signup/h5/signup"
|
||||
this.$pjaxReplace('/platform/tour/signup/h5/signup')
|
||||
}
|
||||
},
|
||||
created() {
|
||||
|
||||
@@ -9,6 +9,129 @@
|
||||
background: #f3f7fc;
|
||||
}
|
||||
|
||||
/* 提案 H5 列表统一使用全屏 Popup 承载详情和办理表单。 */
|
||||
.proposal-full-popup {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
background: #f3f7fc;
|
||||
}
|
||||
|
||||
.proposal-full-popup__page {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
padding-top: 46px;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.proposal-full-popup__page > .van-nav-bar {
|
||||
z-index: 20;
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
.proposal-full-popup__scroll {
|
||||
min-height: 0;
|
||||
overflow-y: auto;
|
||||
flex: 1;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
.proposal-full-popup__scroll .proposal-view-main {
|
||||
padding-top: 18px;
|
||||
}
|
||||
|
||||
.proposal-popup-form-actions {
|
||||
display: flex;
|
||||
padding: 10px 12px calc(12px + env(safe-area-inset-bottom));
|
||||
justify-content: space-between;
|
||||
column-gap: 10px;
|
||||
}
|
||||
|
||||
.proposal-action-icon {
|
||||
margin-right: 6px;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.reply-unit-popup {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.reply-unit-toolbar {
|
||||
display: grid;
|
||||
min-height: 48px;
|
||||
border-bottom: 1px solid #eee;
|
||||
grid-template-columns: 64px 1fr 64px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.reply-unit-toolbar button {
|
||||
height: 48px;
|
||||
padding: 0;
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.reply-unit-toolbar button:last-child {
|
||||
color: #1989fa;
|
||||
}
|
||||
|
||||
.reply-unit-toolbar-title {
|
||||
color: #222;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.reply-unit-list {
|
||||
overflow-y: auto;
|
||||
flex: 1;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
.reply-unit-empty {
|
||||
padding: 48px 16px;
|
||||
color: #999;
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.transfer-dialog {
|
||||
padding: 18px 16px 76px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.proposal-info-card {
|
||||
margin-bottom: 16px;
|
||||
padding: 16px;
|
||||
background: #fff;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.proposal-info-card .info-item {
|
||||
display: flex;
|
||||
margin-bottom: 10px;
|
||||
flex-direction: column;
|
||||
row-gap: 4px;
|
||||
}
|
||||
|
||||
.proposal-info-card .info-item label {
|
||||
color: #969799;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.proposal-full-popup__page > .button-group {
|
||||
display: flex;
|
||||
padding: 10px 16px calc(10px + env(safe-area-inset-bottom));
|
||||
background: #fff;
|
||||
column-gap: 10px;
|
||||
}
|
||||
|
||||
.proposal-view-main {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
@@ -45,6 +168,41 @@
|
||||
content: "";
|
||||
}
|
||||
|
||||
/* 审核、附议、反馈及答复输入框统一复用提案查询 Card 的视觉规范。 */
|
||||
.proposal-audit-card__required {
|
||||
margin-left: 4px;
|
||||
color: #ee0a24;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.proposal-view-card .van-field.proposal-audit-field {
|
||||
width: calc(100% - 28px);
|
||||
margin: 0 14px 14px;
|
||||
padding: 12px;
|
||||
border: 1px solid #c9d5e5;
|
||||
border-radius: 10px;
|
||||
background-color: #f7f9fd;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.proposal-view-card .van-field.proposal-audit-field .van-field__control {
|
||||
min-height: 150px;
|
||||
color: #253247;
|
||||
line-height: 22px;
|
||||
}
|
||||
|
||||
.proposal-view-card .van-field.proposal-audit-field .van-field__control::placeholder {
|
||||
color: #9aa7b8;
|
||||
}
|
||||
|
||||
.proposal-view-card .van-field.proposal-audit-field .van-field__word-limit {
|
||||
color: #718096;
|
||||
}
|
||||
|
||||
.proposal-view-card .van-field.proposal-audit-field::after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.proposal-view-card .van-cell-group {
|
||||
margin: 0;
|
||||
background: transparent;
|
||||
|
||||
@@ -210,6 +210,11 @@ const PROPOSAL_INFO = {
|
||||
bizId: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
// visible 表示承载详情的 Popup 是否打开;每次重新打开时都需要查询最新详情和流程记录。
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
dicts: ["PROPOSAL_TYPE", "PROPOSAL_SOURCE", "PROPOSAL_CASE_FILING_RESULT", "PROPOSAL_CASE_FILING_TYPE", "PROCESS_TASK_SUBMIT_TYPE", "PROPOSAL_FEEDBACK"],
|
||||
@@ -218,7 +223,8 @@ const PROPOSAL_INFO = {
|
||||
viewData: {},
|
||||
doneTasks: [],
|
||||
selectedTask: null,
|
||||
currentBizId: ""
|
||||
currentBizId: "",
|
||||
reloadPending: false
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@@ -227,12 +233,31 @@ const PROPOSAL_INFO = {
|
||||
handler(value) {
|
||||
if (!value) return
|
||||
this.$set(this, "currentBizId", value)
|
||||
this.getInfo()
|
||||
this.getDoneTasks()
|
||||
if (this.visible) this.queueReload()
|
||||
}
|
||||
},
|
||||
visible(value) {
|
||||
if (!value || !this.bizId) return
|
||||
this.$set(this, "currentBizId", this.bizId)
|
||||
this.queueReload()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* 合并同一轮 bizId 与 Popup 显示状态变化触发的刷新。
|
||||
* 无参数;组件可见且存在提案主键时调用详情和已办流程接口,无返回值。
|
||||
*/
|
||||
queueReload() {
|
||||
if (this.reloadPending) return
|
||||
this.$set(this, "reloadPending", true)
|
||||
this.$nextTick(() => {
|
||||
this.$set(this, "reloadPending", false)
|
||||
if (!this.visible || !this.currentBizId) return
|
||||
this.getInfo()
|
||||
this.getDoneTasks()
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取字典字段的展示文本。
|
||||
* options 为 PROPOSAL_SOURCE 等字典数组,value 为业务保存的字典 code;返回名称字符串,无匹配项时返回原值或 --。
|
||||
@@ -308,8 +333,7 @@ const PROPOSAL_INFO = {
|
||||
openView(row) {
|
||||
if (row && typeof row === 'object' && row.id) {
|
||||
this.$set(this, "currentBizId", row.id)
|
||||
this.getInfo()
|
||||
this.getDoneTasks()
|
||||
this.queueReload()
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
const PROPOSAL_TASK_POPUP = {
|
||||
template: /*language=HTML*/ `
|
||||
<van-popup v-model="visible" position="right" class="proposal-full-popup" :close-on-click-overlay="false" get-container="#app">
|
||||
<div class="proposal-full-popup__page">
|
||||
<van-nav-bar @click-left="close" left-arrow left-text="返回" :title="title" placeholder fixed></van-nav-bar>
|
||||
<div class="proposal-full-popup__scroll">
|
||||
<proposal-info v-if="bizId" :biz-id="bizId" :visible="visible">
|
||||
<div v-if="isApproval">
|
||||
<van-form ref="formRef">
|
||||
<template v-if="kind === 'delegation' || kind === 'preAudit' || kind === 'schoolLeaderApproval'">
|
||||
<section class="proposal-view-card">
|
||||
<h2 class="proposal-view-card__title">审批意见<span class="proposal-audit-card__required">*</span></h2>
|
||||
<van-field v-model="formData.tf_opinion" class="proposal-audit-field" name="tf_opinion" type="textarea" rows="6" label="" placeholder="请输入审批意见" :rules="[{required:true,message:'请填写审批意见'}]" required maxlength="100" show-word-limit></van-field>
|
||||
</section>
|
||||
</template>
|
||||
<template v-if="kind === 'feedbackEvaluation'">
|
||||
<van-field v-model="formData.tf_feedback_name" label="满意度" placeholder="请选择满意度" :rules="[{required:true,message:'请选择满意度'}]" required readonly is-link @click="openLayer('feedback-picker')"></van-field>
|
||||
<section class="proposal-view-card">
|
||||
<h2 class="proposal-view-card__title">审批意见<span class="proposal-audit-card__required">*</span></h2>
|
||||
<van-field v-model="formData.tf_opinion" class="proposal-audit-field" name="tf_opinion" type="textarea" rows="6" label="" placeholder="请输入审批意见" :rules="[{required:true,message:'请填写审批意见'}]" required maxlength="100" show-word-limit></van-field>
|
||||
</section>
|
||||
</template>
|
||||
<template v-if="kind === 'suggestion'">
|
||||
<van-field v-model="formData.result" label="承办意向" placeholder="请选择承办意向" :rules="[{required:true,message:'请选择承办意向'}]" required readonly is-link @click="openLayer('result-picker')"></van-field>
|
||||
<section class="proposal-view-card">
|
||||
<h2 class="proposal-view-card__title">反馈意见<span class="proposal-audit-card__required">*</span></h2>
|
||||
<van-field v-model="formData.opinion" class="proposal-audit-field" name="opinion" type="textarea" rows="6" label="" placeholder="请输入反馈意见" :rules="[{required:true,message:'请输入反馈意见'}]" required show-word-limit></van-field>
|
||||
</section>
|
||||
</template>
|
||||
<template v-if="kind === 'unitReply'">
|
||||
<van-field :value="formData.underTakeName" label="承办单位" readonly></van-field>
|
||||
<van-field v-model="formData.tf_implementStateName" label="落实情况" placeholder="请选择落实情况" :rules="[{required:true,message:'请选择落实情况'}]" required readonly is-link @click="openLayer('implement-picker')"></van-field>
|
||||
<section class="proposal-view-card">
|
||||
<h2 class="proposal-view-card__title">答复内容<span class="proposal-audit-card__required">*</span></h2>
|
||||
<van-field v-model="formData.tf_opinion" class="proposal-audit-field" name="tf_opinion" type="textarea" rows="6" label="" placeholder="请输入答复内容" :rules="[{required:true,message:'请填写答复内容'}]" required maxlength="100" show-word-limit></van-field>
|
||||
</section>
|
||||
<van-field v-if="supportCandidate && formData.underTakeIsMaster" v-model="formData.tf_nextNodeOperatorName" label="校领导" placeholder="请选择校领导" :rules="[{required:true,message:'请选择校领导'}]" required readonly is-link @click="openLayer('candidate-picker')"></van-field>
|
||||
</template>
|
||||
<template v-if="kind === 'caseCheck'">
|
||||
<van-field :value="formData.tf_username" label="审核人" readonly></van-field>
|
||||
<van-field :value="formData.tf_auditTime" label="审核时间" readonly></van-field>
|
||||
<van-field :value="formData.tf_caseCheckNeedSecondReply" label="二次答复" required :rules="[{validator:validateSecondReply,message:'请选择是否需要二次答复'}]">
|
||||
<template #input><van-radio-group v-model="formData.tf_caseCheckNeedSecondReply" direction="horizontal" @change="onSecondReplyChange"><van-radio :name="0">无需二次答复</van-radio><van-radio :name="1">需要二次答复</van-radio></van-radio-group></template>
|
||||
</van-field>
|
||||
<van-field v-if="formData.tf_caseCheckNeedSecondReply === 1" :value="selectedReplyUnitNames" label="答复单位" placeholder="请选择办理单位" readonly required is-link :rules="[{validator:validateSecondReplyUnits,message:'请选择需要二次答复的办理单位'}]" @click="openReplyUnitPicker"></van-field>
|
||||
<section class="proposal-view-card">
|
||||
<h2 class="proposal-view-card__title">审批意见<span class="proposal-audit-card__required">*</span></h2>
|
||||
<van-field v-model="formData.tf_opinion" class="proposal-audit-field" name="tf_opinion" type="textarea" rows="6" label="" placeholder="请输入审批意见" required maxlength="100" show-word-limit :rules="[{required:true,message:'请填写审批意见'}]"></van-field>
|
||||
</section>
|
||||
</template>
|
||||
</van-form>
|
||||
<div class="proposal-popup-form-actions" v-if="kind === 'delegation'">
|
||||
<van-button type="danger" block :loading="formLoading" @click="prepareSubmit(6)">退回</van-button><van-button type="danger" block :loading="formLoading" @click="prepareSubmit(2)">不同意</van-button><van-button type="primary" block :loading="formLoading" @click="prepareSubmit(1)">同意</van-button>
|
||||
</div>
|
||||
<div class="proposal-popup-form-actions" v-else-if="kind === 'preAudit'" style="display:grid;grid-template-columns:repeat(2,minmax(0,1fr))">
|
||||
<van-button type="warning" :loading="formLoading" @click="prepareSubmit(4)">退回(不审核)</van-button><van-button type="warning" :loading="formLoading" @click="prepareSubmit(6)">退回(审核)</van-button><van-button type="danger" :loading="formLoading" @click="prepareSubmit(2)">不同意</van-button><van-button type="primary" :loading="formLoading" @click="prepareSubmit(1)">同意</van-button>
|
||||
</div>
|
||||
<div class="proposal-popup-form-actions" v-else-if="kind === 'schoolLeaderApproval'"><van-button type="danger" block :loading="formLoading" @click="prepareSubmit('back')">退回答复</van-button><van-button type="primary" block :loading="formLoading" @click="prepareSubmit('agree')">同意答复</van-button></div>
|
||||
<div class="proposal-popup-form-actions" v-else><van-button block :disabled="formLoading" @click="close">取消</van-button><van-button type="primary" block :loading="formLoading" @click="prepareSubmit(1)">提交</van-button></div>
|
||||
</div>
|
||||
</proposal-info>
|
||||
</div>
|
||||
</div>
|
||||
<van-popup v-model="feedbackPickerVisible" position="bottom" :close-on-click-overlay="false"><van-picker show-toolbar :columns="dict.type.PROPOSAL_FEEDBACK.map((item) => ({text:item.label,value:item.code}))" @confirm="confirmFeedback" @cancel="closeLayer('feedback-picker')"></van-picker></van-popup>
|
||||
<van-popup v-model="resultPickerVisible" position="bottom" :close-on-click-overlay="false"><van-picker show-toolbar :columns="dict.type.UNDERTAKE_SUGGESTION.map((item) => item.code)" @confirm="confirmResult" @cancel="closeLayer('result-picker')"></van-picker></van-popup>
|
||||
<van-popup v-model="implementPickerVisible" position="bottom" :close-on-click-overlay="false"><van-picker show-toolbar :columns="dict.type.PROPOSAL_REPLY_IMPLEMENT.map((item) => ({text:item.label,value:item.code}))" @confirm="confirmImplement" @cancel="closeLayer('implement-picker')"></van-picker></van-popup>
|
||||
<van-popup v-model="candidatePickerVisible" position="bottom" :close-on-click-overlay="false"><van-picker show-toolbar :columns="candidates.map((item) => ({text:item.userName,value:item.userId}))" @confirm="confirmCandidate" @cancel="closeLayer('candidate-picker')"></van-picker></van-popup>
|
||||
<van-popup v-model="replyUnitPickerVisible" position="bottom" round :close-on-click-overlay="false" :style="{height:'70%'}">
|
||||
<div class="reply-unit-popup"><div class="reply-unit-toolbar"><button type="button" @click="closeLayer('reply-unit-picker')">取消</button><div class="reply-unit-toolbar-title">选择答复单位</div><button type="button" @click="confirmReplyUnits">确定</button></div>
|
||||
<div class="reply-unit-list" v-if="replyUnitOptions.length"><van-checkbox-group v-model="pendingReplyUnitIds"><van-cell v-for="item in replyUnitOptions" :key="item.unitId" clickable :title="item.unitName" :label="item.isMaster ? '主办单位' : '协办单位'" @click="toggleReplyUnit(item)"><template #right-icon><van-checkbox :name="item.unitId" @click.stop></van-checkbox></template></van-cell></van-checkbox-group></div>
|
||||
<div class="reply-unit-empty" v-else>暂无可选办理单位</div>
|
||||
</div>
|
||||
</van-popup>
|
||||
<van-dialog :value="confirmVisible" title="提示" message="您确定要提交吗?" show-cancel-button @confirm="submit" @cancel="closeLayer('submit-confirm')"></van-dialog>
|
||||
</van-popup>
|
||||
`,
|
||||
dicts: ["PROPOSAL_FEEDBACK", "UNDERTAKE_SUGGESTION", "PROPOSAL_REPLY_IMPLEMENT"],
|
||||
components: {"proposal-info": PROPOSAL_INFO},
|
||||
props: {kind: {type: String, required: true}, pageKey: {type: String, required: true}},
|
||||
data() { return {visible:false,bizId:"",action:"view",formData:{},formLoading:false,pendingSubmitType:1,feedbackPickerVisible:false,resultPickerVisible:false,implementPickerVisible:false,candidatePickerVisible:false,replyUnitPickerVisible:false,confirmVisible:false,supportCandidate:false,candidates:[],replyUnitOptions:[],pendingReplyUnitIds:[],unsubscribeHistoryLayer:null} },
|
||||
computed: {
|
||||
isApproval() { return this.action === "approval" },
|
||||
title() { const titles={delegation:"团长审核",preAudit:"校工会预审核",schoolLeaderApproval:"分管校领导审批",feedbackEvaluation:"反馈评价",suggestion:"承办单位意见",unitReply:"承办单位答复",caseCheck:"提案委员会审查"}; return this.isApproval ? titles[this.kind] : "提案详情" },
|
||||
selectedReplyUnitNames() { const ids=this.formData.tf_secondReplyUnitIds || []; return this.replyUnitOptions.filter((item) => ids.indexOf(item.unitId)>-1).map((item) => item.unitName+"("+(item.isMaster?"主办":"协办")+")").join("、") }
|
||||
},
|
||||
methods: {
|
||||
syncLayers(stack) { this.$set(this,"visible",stack.includes("detail")); this.$set(this,"feedbackPickerVisible",stack.includes("feedback-picker")); this.$set(this,"resultPickerVisible",stack.includes("result-picker")); this.$set(this,"implementPickerVisible",stack.includes("implement-picker")); this.$set(this,"candidatePickerVisible",stack.includes("candidate-picker")); this.$set(this,"replyUnitPickerVisible",stack.includes("reply-unit-picker")); this.$set(this,"confirmVisible",stack.includes("submit-confirm")) },
|
||||
openLayer(name) { window.h5HistoryLayerManager.open(name) }, closeLayer(name,callback) { window.h5HistoryLayerManager.close(name,callback) }, close() { this.closeLayer("detail") },
|
||||
/** row 提供详情主键和当前 WF 任务参数,action 为 view 或 approval。 */
|
||||
open(row,action) {
|
||||
const defaultTaskNames={delegation:"团长审核",preAudit:"校工会预审核",feedbackEvaluation:"反馈评价",unitReply:"承办单位答复",caseCheck:"提案委员会审查"}
|
||||
const taskName=this.kind === "unitReply" ? (row.taskName || defaultTaskNames[this.kind]) : (row.curTaskName || row.taskName || defaultTaskNames[this.kind] || "")
|
||||
this.$set(this,"bizId",row.id); this.$set(this,"action",action); this.$set(this,"formData",{proposalId:row.id,processTaskId:row.taskId || "",taskKey:row.taskKey || "",taskName:taskName,instanceId:row.instanceId || "",underTakeName:row.underTakeName || "",underTakeIsMaster:!!row.underTakeIsMaster,tf_opinion:"",opinion:""})
|
||||
if (action === "approval" && this.kind === "unitReply") this.loadCandidates(row.taskId || "")
|
||||
if (action === "approval" && this.kind === "caseCheck") { this.$set(this.formData,"tf_auditTime",moment().format("YYYY-MM-DD")); this.$set(this.formData,"tf_username",(this.$store.state.user && this.$store.state.user.username) || ""); this.$set(this.formData,"tf_caseCheckNeedSecondReply",0); this.$set(this.formData,"tf_secondReplyUnitIds",[]); this.loadReplyUnits(row.id) }
|
||||
this.openLayer("detail")
|
||||
},
|
||||
loadCandidates(taskId) { this.$axios.post("/flow/common/candidate",{taskId:taskId}).then((res) => { if (res.code === 0) { this.$set(this,"candidates",res.data.candidates || []); this.$set(this,"supportCandidate",res.data.support) } }) },
|
||||
confirmFeedback(value) { this.$set(this.formData,"tf_feedback_name",value.text); this.$set(this.formData,"tf_feedback",value.value); this.closeLayer("feedback-picker") },
|
||||
confirmResult(value) { this.$set(this.formData,"result",value); this.closeLayer("result-picker") },
|
||||
confirmImplement(value) { this.$set(this.formData,"tf_implementStateName",value.text); this.$set(this.formData,"tf_implementState",value.value); this.closeLayer("implement-picker") },
|
||||
confirmCandidate(value) { this.$set(this.formData,"tf_nextNodeOperatorName",value.text); this.$set(this.formData,"tf_nextNodeOperator",value.value); this.closeLayer("candidate-picker") },
|
||||
validateSecondReply(value) { return value === 0 || value === 1 },
|
||||
validateSecondReplyUnits() { return this.formData.tf_caseCheckNeedSecondReply !== 1 || (this.formData.tf_secondReplyUnitIds || []).length > 0 },
|
||||
onSecondReplyChange(value) { if (value !== 1) this.$set(this.formData,"tf_secondReplyUnitIds",[]) },
|
||||
loadReplyUnits(proposalId) { this.$axios.post("/platform/proposal/case/check/listReplyUnits",{proposalId:proposalId}).then((res) => { if (res && res.code === 0) this.$set(this,"replyUnitOptions",res.data || []) }) },
|
||||
openReplyUnitPicker() { this.$set(this,"pendingReplyUnitIds",[...(this.formData.tf_secondReplyUnitIds || [])]); this.openLayer("reply-unit-picker") },
|
||||
toggleReplyUnit(item) { const ids=[...this.pendingReplyUnitIds]; const index=ids.indexOf(item.unitId); if (index>-1) ids.splice(index,1); else ids.push(item.unitId); this.$set(this,"pendingReplyUnitIds",ids) },
|
||||
confirmReplyUnits() { this.$set(this.formData,"tf_secondReplyUnitIds",[...this.pendingReplyUnitIds]); this.closeLayer("reply-unit-picker") },
|
||||
buildCaseCheckData() { const data={...this.formData}; const units=data.tf_caseCheckNeedSecondReply === 1 ? this.replyUnitOptions.filter((item) => data.tf_secondReplyUnitIds.indexOf(item.unitId)>-1) : []; const masters=units.filter((item) => item.isMaster); const slaves=units.filter((item) => !item.isMaster); data.tf_masterUnitIds=masters.map((item) => item.unitId); data.tf_masterUnitId=data.tf_masterUnitIds[0] || ""; data.tf_masterUnitNames=masters.map((item) => item.unitName); data.tf_masterUnitName=data.tf_masterUnitNames[0] || ""; data.tf_masterUnitNameStr=data.tf_masterUnitNames.join(","); data.tf_slaveUnitIds=slaves.map((item) => item.unitId); data.tf_slaveUnitNames=slaves.map((item) => item.unitName); data.tf_slaveUnitNameStr=data.tf_slaveUnitNames.join(","); return data },
|
||||
prepareSubmit(value) { this.$refs.formRef.validate().then(() => { this.$set(this,"pendingSubmitType",value); this.openLayer("submit-confirm") }).catch(() => {}) },
|
||||
/** 根据页面类型保留原接口和参数分支,成功后清理全部弹层历史并通知列表刷新。 */
|
||||
submit() {
|
||||
this.$set(this,"formLoading",true)
|
||||
let request
|
||||
if (this.kind === "suggestion") request=this.$axios.post("/platform/proposal/suggestion/suggest",this.formData)
|
||||
else if (this.kind === "schoolLeaderApproval") { const data={...this.formData,tf_approval:this.pendingSubmitType}; delete data.taskKey; delete data.taskName; request=this.$axios.post("/platform/proposal/schoolLeaderApproval/executeTask",{data:JSON.stringify(data)}) }
|
||||
else {
|
||||
const data=this.kind === "caseCheck" ? {...this.buildCaseCheckData(),submitType:this.pendingSubmitType} : {...this.formData,submitType:this.pendingSubmitType}
|
||||
if (this.kind === "preAudit") { data.taskName="startTask"; if (this.pendingSubmitType === 4) { data.tf_sourceTaskKey=this.formData.taskKey; data.tf_audit=false } }
|
||||
if (this.kind === "unitReply") { delete data.underTakeIsMaster; delete data.underTakeName }
|
||||
if (this.kind === "feedbackEvaluation" && data.tf_feedback === "DISSATISFIED") request=this.$axios.post("/platform/proposal/feedbackEvaluation/caseInfo",{instId:data.instanceId}).then((res) => { if (res.code !== 0) return Promise.reject(new Error(res.msg || "查询立案信息失败")); data.tf_masterUnitId=res.data.tf_masterUnitId; return this.$axios.post("/flow/common/executeTask",{data:JSON.stringify(data)}) })
|
||||
else request=this.$axios.post("/flow/common/executeTask",{data:JSON.stringify(data)})
|
||||
}
|
||||
request.then((res) => { if (res && res.code === 0) { this.$toast.success(res.msg); window.h5HistoryLayerManager.closeAll(() => this.$emit("success")) } }).catch((error) => { if (error && error.message && error.message !== "cancel") this.$toast.fail(error.message) }).finally(() => { this.$set(this,"formLoading",false) })
|
||||
}
|
||||
},
|
||||
created() { window.h5HistoryLayerManager.ensureRegistered(this.pageKey); this.$set(this,"unsubscribeHistoryLayer",window.h5HistoryLayerManager.subscribe((stack) => this.syncLayers(stack))) },
|
||||
beforeDestroy() { if (this.unsubscribeHistoryLayer) this.unsubscribeHistoryLayer(); if (window.h5HistoryLayerManager.pageKey === this.pageKey) window.h5HistoryLayerManager.unregister(this.pageKey) }
|
||||
}
|
||||
+55
-5
@@ -1,8 +1,11 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_h5.html"){
|
||||
#-->
|
||||
<style>
|
||||
<!--#include("../../common/info.css"){}#-->
|
||||
</style>
|
||||
<div id="app" v-cloak>
|
||||
<van-nav-bar @click-left="historyBack" left-arrow left-text="返回" title="提案查询" placeholder fixed></van-nav-bar>
|
||||
<van-nav-bar @click-left="handlePageBack" left-arrow left-text="返回" title="提案查询" placeholder fixed></van-nav-bar>
|
||||
<van-sticky offset-top="46px">
|
||||
<van-search
|
||||
v-model="pageForm.name"
|
||||
@@ -49,7 +52,9 @@ layout("/layouts/platform_h5.html"){
|
||||
<van-cell title="代表团" :value="row.delegationName"></van-cell>
|
||||
<van-cell title="当前节点" :value="row.processInstanceNodeName"></van-cell>
|
||||
<van-cell class="table-card-footer">
|
||||
<van-button size="small" @click="openView(row)">查看</van-button>
|
||||
<van-button size="small" @click="openView(row)">
|
||||
<van-icon class="proposal-action-icon" name="eye-o"></van-icon>查看
|
||||
</van-button>
|
||||
</van-cell>
|
||||
</div>
|
||||
</div>
|
||||
@@ -57,11 +62,26 @@ layout("/layouts/platform_h5.html"){
|
||||
<van-empty v-else image="/assets/platform/plugins/vant-green/images/nodata/nodata.png" description="暂无数据"></van-empty>
|
||||
</div>
|
||||
|
||||
<van-popup v-model="detailVisible" class="proposal-full-popup" position="right"
|
||||
:close-on-click-overlay="false" safe-area-inset-bottom>
|
||||
<div class="proposal-full-popup__page">
|
||||
<van-nav-bar title="提案信息" left-arrow left-text="返回" fixed
|
||||
@click-left="closeHistoryLayer('detail')"></van-nav-bar>
|
||||
<div class="proposal-full-popup__scroll">
|
||||
<proposal-info v-if="detailVisible && detailBizId" :biz-id="detailBizId" :visible="detailVisible"></proposal-info>
|
||||
</div>
|
||||
</div>
|
||||
</van-popup>
|
||||
|
||||
</div>
|
||||
<script nonce="${cspNonce!}">
|
||||
<!--#include("../../common/info.js"){}#-->
|
||||
const vue = new Vue({
|
||||
el: "#app",
|
||||
store,
|
||||
components: {
|
||||
"proposal-info": PROPOSAL_INFO
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
pageForm: {
|
||||
@@ -89,11 +109,34 @@ layout("/layouts/platform_h5.html"){
|
||||
unitOptions: [],
|
||||
moreOptions: {},
|
||||
id: "",
|
||||
formValidSuccess: false
|
||||
formValidSuccess: false,
|
||||
detailVisible: false,
|
||||
detailBizId: "",
|
||||
historyLayerPageKey: "proposal-query-comprehensive-h5"
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
historyBack,
|
||||
registerHistoryLayers() {
|
||||
if (!window.h5HistoryLayerManager) return
|
||||
window.h5HistoryLayerManager.register(this.historyLayerPageKey, (stack) => {
|
||||
this.$set(this, "detailVisible", stack.includes("detail"))
|
||||
})
|
||||
},
|
||||
openHistoryLayer(layerName) {
|
||||
if (window.h5HistoryLayerManager && window.h5HistoryLayerManager.open(layerName)) return
|
||||
if (layerName === "detail") this.$set(this, "detailVisible", true)
|
||||
},
|
||||
closeHistoryLayer(layerName) {
|
||||
if (window.h5HistoryLayerManager && window.h5HistoryLayerManager.close(layerName)) return
|
||||
if (layerName === "detail") this.$set(this, "detailVisible", false)
|
||||
},
|
||||
handlePageBack() {
|
||||
if (window.h5HistoryLayerManager && window.h5HistoryLayerManager.stack.length) {
|
||||
window.h5HistoryLayerManager.close()
|
||||
return
|
||||
}
|
||||
historyBack()
|
||||
},
|
||||
sessionChange(val) {
|
||||
this.pageForm.delegationId = null
|
||||
if (this.pageForm.sessionId) {
|
||||
@@ -148,7 +191,8 @@ layout("/layouts/platform_h5.html"){
|
||||
},
|
||||
|
||||
openView(row) {
|
||||
this.$pjaxReplace("/platform/h5/proposal/query/comprehensive/info?bizId=" + encodeURIComponent(row.id))
|
||||
this.$set(this, "detailBizId", row.id)
|
||||
this.openHistoryLayer("detail")
|
||||
},
|
||||
|
||||
pageData() {
|
||||
@@ -176,8 +220,14 @@ layout("/layouts/platform_h5.html"){
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.registerHistoryLayers()
|
||||
this.pageData()
|
||||
this.listSession()
|
||||
},
|
||||
beforeDestroy() {
|
||||
if (window.h5HistoryLayerManager) {
|
||||
window.h5HistoryLayerManager.unregister(this.historyLayerPageKey)
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
-35
@@ -1,35 +0,0 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_h5.html"){
|
||||
#-->
|
||||
<style id="style-proposal-info-h5">
|
||||
<!--#include("../../common/info.css"){}#-->
|
||||
</style>
|
||||
<div id="app" v-cloak>
|
||||
<van-nav-bar @click-left="historyBack" left-arrow left-text="返回" title="提案信息" placeholder fixed></van-nav-bar>
|
||||
<proposal-info v-if="bizId" :biz-id="bizId"></proposal-info>
|
||||
</div>
|
||||
<script nonce="${cspNonce!}">
|
||||
<!--#include("../../common/info.js"){}#-->
|
||||
const vue = new Vue({
|
||||
el: "#app",
|
||||
store,
|
||||
components: {
|
||||
"proposal-info": PROPOSAL_INFO
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
bizId: ""
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
historyBack
|
||||
},
|
||||
created() {
|
||||
const params = new URLSearchParams(window.location.search)
|
||||
this.bizId = params.get("bizId") || ""
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
+12
-257
@@ -229,6 +229,9 @@ layout("/layouts/platform_h5.html"){
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style id="style-proposal-task-popup-h5">
|
||||
<!--#include("../../common/info.css"){}#-->
|
||||
</style>
|
||||
<div id="app" v-cloak>
|
||||
<div class="proposal-case-check-page">
|
||||
<van-nav-bar @click-left="historyBack" left-arrow left-text="返回" title="提案委员会审查" placeholder fixed></van-nav-bar>
|
||||
@@ -305,15 +308,15 @@ layout("/layouts/platform_h5.html"){
|
||||
</template>
|
||||
<template #actions="{index,row}">
|
||||
<div class="action-btn" @click="onView(row,index)">
|
||||
<i class="fa fa-eye"></i>
|
||||
<van-icon class="proposal-action-icon" name="eye-o"></van-icon>
|
||||
<span>查看</span>
|
||||
</div>
|
||||
<div class="action-btn" v-if="row.taskState === 10" @click="onApproval(row,index)">
|
||||
<i class="fa fa-edit"></i>
|
||||
<van-icon class="proposal-action-icon" name="edit"></van-icon>
|
||||
<span>审核</span>
|
||||
</div>
|
||||
<div class="action-btn delete" v-if="row.canRevoke" @click="onRevoke(row)">
|
||||
<i class="fa fa-reply"></i>
|
||||
<van-icon class="proposal-action-icon" name="revoke"></van-icon>
|
||||
<span>撤回</span>
|
||||
</div>
|
||||
</template>
|
||||
@@ -321,11 +324,15 @@ layout("/layouts/platform_h5.html"){
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
<proposal-task-popup ref="taskPopup" kind="caseCheck" page-key="proposal-case-check-task" @success="doSearch"></proposal-task-popup>
|
||||
</div>
|
||||
<script nonce="${cspNonce!}">
|
||||
<!--#include("../../common/info.js"){}#-->
|
||||
<!--#include("../../common/task-popup.js"){}#-->
|
||||
new Vue({
|
||||
el: "#app",
|
||||
store,
|
||||
components: {"proposal-task-popup": PROPOSAL_TASK_POPUP},
|
||||
data() {
|
||||
return {
|
||||
pageForm: {
|
||||
@@ -345,16 +352,10 @@ layout("/layouts/platform_h5.html"){
|
||||
{text: "未审核", value: "0"},
|
||||
{text: "已审核", value: "1"}
|
||||
],
|
||||
pendingListCache: null
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onReady() {
|
||||
if (this.pendingListCache) {
|
||||
this.restoreListCache()
|
||||
this.listSession(true)
|
||||
return
|
||||
}
|
||||
this.listSession(false)
|
||||
},
|
||||
|
||||
@@ -386,254 +387,11 @@ layout("/layouts/platform_h5.html"){
|
||||
},
|
||||
|
||||
onView(row, index) {
|
||||
this.saveListCache(row, index)
|
||||
this.$pjaxReplace("/platform/proposal/case/check/info/h5?bizId=" + encodeURIComponent(row.id) + "&action=view")
|
||||
this.$refs.taskPopup.open(row, "view")
|
||||
},
|
||||
|
||||
onApproval(row, index) {
|
||||
this.saveListCache(row, index)
|
||||
const params = new URLSearchParams()
|
||||
params.set("bizId", row.id)
|
||||
params.set("action", "approval")
|
||||
params.set("taskId", row.taskId)
|
||||
params.set("taskName", row.curTaskName || row.taskName || "提案委员会审查")
|
||||
this.$pjaxReplace("/platform/proposal/case/check/info/h5?" + params.toString())
|
||||
},
|
||||
|
||||
getListCacheKey() {
|
||||
return "proposal:case-check:h5:list-state"
|
||||
},
|
||||
|
||||
getListCacheTokenParam() {
|
||||
return "caseCheckListCacheToken"
|
||||
},
|
||||
|
||||
getCurrentListCacheToken() {
|
||||
return new URLSearchParams(window.location.search).get(this.getListCacheTokenParam()) || ""
|
||||
},
|
||||
|
||||
/**
|
||||
* 将委员会审查列表缓存标识绑定到当前历史记录。
|
||||
* PJAX 返回时仅恢复当前历史记录对应的筛选条件、分页数据和滚动快照。
|
||||
*/
|
||||
bindListCacheToken(token) {
|
||||
const currentUrl = new URL(window.location.href)
|
||||
currentUrl.searchParams.set(this.getListCacheTokenParam(), token)
|
||||
const currentState = window.history.state ? {...window.history.state} : null
|
||||
if (currentState && currentState.url) {
|
||||
currentState.url = currentUrl.toString()
|
||||
}
|
||||
window.history.replaceState(currentState, document.title, currentUrl.toString())
|
||||
if ($.pjax && $.pjax.state) {
|
||||
$.pjax.state.url = currentUrl.toString()
|
||||
}
|
||||
},
|
||||
|
||||
// 用户主动搜索、切换教代会或审核状态时使旧返回缓存失效。
|
||||
clearListCache() {
|
||||
const token = this.getCurrentListCacheToken()
|
||||
if (!token) return
|
||||
const currentUrl = new URL(window.location.href)
|
||||
currentUrl.searchParams.delete(this.getListCacheTokenParam())
|
||||
const currentState = window.history.state ? {...window.history.state} : null
|
||||
if (currentState && currentState.url) {
|
||||
currentState.url = currentUrl.toString()
|
||||
}
|
||||
window.history.replaceState(currentState, document.title, currentUrl.toString())
|
||||
if ($.pjax && $.pjax.state) {
|
||||
$.pjax.state.url = currentUrl.toString()
|
||||
}
|
||||
sessionStorage.removeItem(this.getListCacheKey())
|
||||
},
|
||||
|
||||
// platform_h5 的实际滚动区域是 page-wrapper,列表位置必须基于该容器保存和恢复。
|
||||
getListScrollContainer() {
|
||||
return document.querySelector(".page-wrapper") || document.scrollingElement || document.documentElement
|
||||
},
|
||||
|
||||
/**
|
||||
* 进入查看或审核详情前保存列表现场。
|
||||
* row 为当前 WF 任务,index 为已加载列表索引;当前任务和相邻锚点均使用唯一 taskId。
|
||||
*/
|
||||
saveListCache(row, index) {
|
||||
const tableList = this.$refs.tableListRef
|
||||
if (!tableList) return
|
||||
const cacheToken = Date.now() + "-" + Math.random().toString(36).slice(2)
|
||||
const tableState = typeof tableList.getListState === "function"
|
||||
? tableList.getListState()
|
||||
: {
|
||||
tableData: JSON.parse(JSON.stringify(tableList.tableData || [])),
|
||||
localPageForm: JSON.parse(JSON.stringify(tableList.localPageForm || this.pageForm)),
|
||||
tableFinished: !!tableList.tableFinished
|
||||
}
|
||||
const cards = document.querySelectorAll(".proposal-case-check-list .table-list-item")
|
||||
const currentCard = cards[index]
|
||||
const scrollContainer = this.getListScrollContainer()
|
||||
const cache = {
|
||||
time: Date.now(),
|
||||
token: cacheToken,
|
||||
pageForm: JSON.parse(JSON.stringify(this.pageForm)),
|
||||
tableState: tableState,
|
||||
completedTaskId: "",
|
||||
anchor: {
|
||||
taskId: row.taskId,
|
||||
previousTaskId: index > 0 && tableState.tableData[index - 1]
|
||||
? tableState.tableData[index - 1].taskId
|
||||
: "",
|
||||
nextTaskId: tableState.tableData[index + 1] ? tableState.tableData[index + 1].taskId : "",
|
||||
viewportTop: currentCard ? currentCard.getBoundingClientRect().top : 0,
|
||||
scrollTop: scrollContainer ? scrollContainer.scrollTop : 0
|
||||
}
|
||||
}
|
||||
try {
|
||||
sessionStorage.setItem(this.getListCacheKey(), JSON.stringify(cache))
|
||||
this.bindListCacheToken(cacheToken)
|
||||
} catch (error) {
|
||||
sessionStorage.removeItem(this.getListCacheKey())
|
||||
}
|
||||
},
|
||||
|
||||
// 仅恢复当前历史记录对应且十分钟内有效的委员会审查列表缓存。
|
||||
prepareListCache() {
|
||||
try {
|
||||
const cacheToken = this.getCurrentListCacheToken()
|
||||
if (!cacheToken) return
|
||||
const cacheText = sessionStorage.getItem(this.getListCacheKey())
|
||||
if (!cacheText) return
|
||||
const cache = JSON.parse(cacheText)
|
||||
if (!cache || cache.token !== cacheToken || !cache.tableState) return
|
||||
if (Date.now() - cache.time > 10 * 60 * 1000) {
|
||||
this.clearListCache()
|
||||
return
|
||||
}
|
||||
Object.keys(cache.pageForm || {}).forEach((key) => {
|
||||
this.$set(this.pageForm, key, cache.pageForm[key])
|
||||
})
|
||||
this.$set(this, "pendingListCache", cache)
|
||||
} catch (error) {
|
||||
sessionStorage.removeItem(this.getListCacheKey())
|
||||
}
|
||||
},
|
||||
|
||||
// 普通查看返回恢复旧快照;审核完成返回重新查询,避免未审核列表继续显示已处理任务。
|
||||
restoreListCache() {
|
||||
const cache = this.pendingListCache
|
||||
const tableList = this.$refs.tableListRef
|
||||
if (!cache || !tableList) return
|
||||
const anchor = cache.anchor || {}
|
||||
if (cache.completedTaskId) {
|
||||
this.refreshCompletedListCache(cache)
|
||||
return
|
||||
}
|
||||
this.applyListCache(cache.tableState, anchor.taskId, anchor)
|
||||
},
|
||||
|
||||
/**
|
||||
* 按离开前已加载页数重新获取审核后的列表。
|
||||
* 返回值转换为 TableList 状态,并优先定位下一任务,没有下一任务时定位上一任务。
|
||||
*/
|
||||
refreshCompletedListCache(cache) {
|
||||
const originalPageSize = Number(cache.pageForm.pageSize || 10)
|
||||
const loadedCount = Math.max(cache.tableState.tableData.length, originalPageSize)
|
||||
const loadedPageCount = Math.max(1, Math.ceil(loadedCount / originalPageSize))
|
||||
const requestForm = {
|
||||
...cache.pageForm,
|
||||
pageNumber: 1,
|
||||
pageSize: loadedPageCount * originalPageSize
|
||||
}
|
||||
const loading = createListLoading()
|
||||
this.$axios.post("/platform/proposal/case/check/pageData", requestForm, {h5SkeletonLoading: true})
|
||||
.then((res) => {
|
||||
if (res.code !== 0) {
|
||||
this.applyCompletedCacheFallback(cache)
|
||||
return
|
||||
}
|
||||
const freshState = {
|
||||
tableData: res.data.list || [],
|
||||
localPageForm: {
|
||||
...cache.pageForm,
|
||||
pageNumber: loadedPageCount,
|
||||
pageSize: originalPageSize,
|
||||
totalCount: res.data.totalCount
|
||||
},
|
||||
tableFinished: (res.data.list || []).length >= res.data.totalCount
|
||||
}
|
||||
const anchor = cache.anchor || {}
|
||||
this.applyListCache(freshState, anchor.nextTaskId || anchor.previousTaskId, anchor)
|
||||
})
|
||||
.catch(() => {
|
||||
this.applyCompletedCacheFallback(cache)
|
||||
})
|
||||
.finally(() => {
|
||||
loading.close()
|
||||
})
|
||||
},
|
||||
|
||||
// 审核后刷新失败时只处理已完成 taskId,避免误改其他流程记录。
|
||||
applyCompletedCacheFallback(cache) {
|
||||
const tableState = cache.tableState
|
||||
const completedIndex = tableState.tableData.findIndex((item) => String(item.taskId) === String(cache.completedTaskId))
|
||||
if (completedIndex >= 0 && cache.pageForm.approval === false) {
|
||||
tableState.tableData.splice(completedIndex, 1)
|
||||
if (tableState.localPageForm && tableState.localPageForm.totalCount > 0) {
|
||||
tableState.localPageForm.totalCount--
|
||||
}
|
||||
} else if (completedIndex >= 0) {
|
||||
this.$set(tableState.tableData[completedIndex], "taskState", 20)
|
||||
}
|
||||
const anchor = cache.anchor || {}
|
||||
this.applyListCache(tableState, anchor.nextTaskId || anchor.previousTaskId, anchor)
|
||||
},
|
||||
|
||||
/**
|
||||
* 恢复 TableList 数据并将目标任务卡片放回离开页面前的视口位置。
|
||||
* sticky 吸顶会改变一次布局,因此首次滚动后再执行一次位置校正。
|
||||
*/
|
||||
applyListCache(tableState, targetTaskId, anchor) {
|
||||
const tableList = this.$refs.tableListRef
|
||||
if (!tableList) return
|
||||
if (typeof tableList.restoreListState === "function") {
|
||||
if (!tableList.restoreListState(tableState)) return
|
||||
} else {
|
||||
this.$set(tableList, "tableData", tableState.tableData || [])
|
||||
this.$set(tableList, "localPageForm", {...tableList.localPageForm, ...(tableState.localPageForm || {})})
|
||||
this.$set(tableList, "tableFinished", !!tableState.tableFinished)
|
||||
this.$set(tableList, "tableLoading", false)
|
||||
this.$set(tableList, "tableRefreshing", false)
|
||||
tableList.$emit("update:page_form", {...tableList.localPageForm})
|
||||
}
|
||||
this.$set(this, "pendingListCache", null)
|
||||
this.$nextTick(() => {
|
||||
setTimeout(() => {
|
||||
const cards = Array.from(document.querySelectorAll(".proposal-case-check-list .table-list-item"))
|
||||
const scrollContainer = this.getListScrollContainer()
|
||||
if (!scrollContainer) return
|
||||
const candidateTaskIds = [targetTaskId, anchor.nextTaskId, anchor.previousTaskId]
|
||||
.filter((taskId) => taskId)
|
||||
.map((taskId) => String(taskId))
|
||||
.filter((taskId, index, values) => values.indexOf(taskId) === index)
|
||||
let targetIndex = -1
|
||||
candidateTaskIds.some((candidateTaskId) => {
|
||||
targetIndex = (tableState.tableData || [])
|
||||
.findIndex((item) => String(item.taskId) === candidateTaskId)
|
||||
return targetIndex >= 0
|
||||
})
|
||||
const targetCard = targetIndex >= 0 ? cards[targetIndex] : null
|
||||
if (targetCard) {
|
||||
const restoreTargetCard = () => {
|
||||
if (!targetCard.isConnected) return
|
||||
const targetTop = scrollContainer.scrollTop
|
||||
+ targetCard.getBoundingClientRect().top
|
||||
- Number(anchor.viewportTop || 0)
|
||||
scrollContainer.scrollTo(0, Math.max(0, targetTop))
|
||||
}
|
||||
restoreTargetCard()
|
||||
setTimeout(restoreTargetCard, 100)
|
||||
return
|
||||
}
|
||||
scrollContainer.scrollTo(0, Number(anchor.scrollTop || 0))
|
||||
}, 0)
|
||||
})
|
||||
this.$refs.taskPopup.open(row, "approval")
|
||||
},
|
||||
|
||||
onRevoke(row) {
|
||||
@@ -651,7 +409,6 @@ layout("/layouts/platform_h5.html"){
|
||||
},
|
||||
|
||||
doSearch() {
|
||||
this.clearListCache()
|
||||
this.$nextTick(() => {
|
||||
this.$set(this.pageForm, "pageNumber", 1)
|
||||
this.$set(this.pageForm, "totalCount", 0)
|
||||
@@ -660,8 +417,6 @@ layout("/layouts/platform_h5.html"){
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.prepareListCache()
|
||||
if (this.pendingListCache) return
|
||||
const tab = new URLSearchParams(window.location.search).get("tab")
|
||||
if (tab === "done") {
|
||||
this.$set(this.pageForm, "approval", true)
|
||||
|
||||
-363
@@ -1,363 +0,0 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_h5.html"){
|
||||
#-->
|
||||
<style id="style-proposal-info-h5">
|
||||
<!--#include("../../common/info.css"){}#-->
|
||||
</style>
|
||||
<style id="style-case-check-info-h5">
|
||||
.case-check-tip {
|
||||
margin: 0 16px 10px;
|
||||
padding: 10px 12px;
|
||||
color: #8c6a28;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
background: #fff8e8;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.case-check-actions {
|
||||
display: grid;
|
||||
grid-template-columns: 88px 1fr;
|
||||
gap: 12px;
|
||||
padding: 12px 16px calc(12px + env(safe-area-inset-bottom));
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
.case-check-actions .van-button {
|
||||
height: 40px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.reply-unit-popup {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.reply-unit-toolbar {
|
||||
display: grid;
|
||||
grid-template-columns: 64px 1fr 64px;
|
||||
align-items: center;
|
||||
min-height: 48px;
|
||||
border-bottom: 1px solid #eeeeee;
|
||||
}
|
||||
|
||||
.reply-unit-toolbar button {
|
||||
height: 48px;
|
||||
padding: 0;
|
||||
color: #666666;
|
||||
font-size: 14px;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.reply-unit-toolbar button:last-child {
|
||||
color: #1989fa;
|
||||
}
|
||||
|
||||
.reply-unit-toolbar-title {
|
||||
color: #222222;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.reply-unit-list {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
.reply-unit-empty {
|
||||
padding: 48px 16px;
|
||||
color: #999999;
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
<div id="app" v-cloak>
|
||||
<van-nav-bar @click-left="historyBack" left-arrow left-text="返回" :title="pageTitle" placeholder fixed></van-nav-bar>
|
||||
<proposal-info v-if="bizId" :biz-id="bizId">
|
||||
<div v-if="isApproval">
|
||||
<div class="process-title">{{formData.taskName}}</div>
|
||||
<van-form ref="formRef">
|
||||
<van-field :value="formData.tf_username" label="审核人" readonly></van-field>
|
||||
<van-field :value="formData.tf_auditTime" label="审核时间" readonly></van-field>
|
||||
<van-field
|
||||
:value="formData.tf_caseCheckNeedSecondReply"
|
||||
name="tf_caseCheckNeedSecondReply"
|
||||
label="二次答复"
|
||||
required
|
||||
:rules="[{ validator: validateSecondReply, message: '请选择是否需要二次答复' }]"
|
||||
>
|
||||
<template #input>
|
||||
<van-radio-group
|
||||
v-model="formData.tf_caseCheckNeedSecondReply"
|
||||
direction="horizontal"
|
||||
@change="onSecondReplyChange"
|
||||
>
|
||||
<van-radio :name="0">无需二次答复</van-radio>
|
||||
<van-radio :name="1">需要二次答复</van-radio>
|
||||
</van-radio-group>
|
||||
</template>
|
||||
</van-field>
|
||||
<div class="case-check-tip" v-if="formData.tf_caseCheckNeedSecondReply === 1">
|
||||
请选择需要进入二次答复的办理单位,可多选。
|
||||
</div>
|
||||
<van-field
|
||||
v-if="formData.tf_caseCheckNeedSecondReply === 1"
|
||||
:value="selectedReplyUnitNames"
|
||||
name="tf_secondReplyUnitIds"
|
||||
label="答复单位"
|
||||
placeholder="请选择办理单位"
|
||||
readonly
|
||||
required
|
||||
is-link
|
||||
:rules="[{ validator: validateSecondReplyUnits, message: '请选择需要二次答复的办理单位' }]"
|
||||
@click="openReplyUnitPicker"
|
||||
></van-field>
|
||||
<van-field
|
||||
v-model="formData.tf_opinion"
|
||||
name="tf_opinion"
|
||||
label="审批意见"
|
||||
type="textarea"
|
||||
rows="3"
|
||||
autosize
|
||||
placeholder="请输入审批意见"
|
||||
required
|
||||
maxlength="100"
|
||||
show-word-limit
|
||||
:rules="[{ required: true, message: '请填写审批意见' }]"
|
||||
></van-field>
|
||||
</van-form>
|
||||
<div class="case-check-actions">
|
||||
<van-button plain @click="historyBack">取消</van-button>
|
||||
<van-button type="primary" :loading="formLoading" @click="handleTaskAction">同意</van-button>
|
||||
</div>
|
||||
</div>
|
||||
</proposal-info>
|
||||
|
||||
<van-popup v-model="showReplyUnitPicker" position="bottom" round :style="{ height: '70%' }">
|
||||
<div class="reply-unit-popup">
|
||||
<div class="reply-unit-toolbar">
|
||||
<button type="button" @click="cancelReplyUnitPicker">取消</button>
|
||||
<div class="reply-unit-toolbar-title">选择答复单位</div>
|
||||
<button type="button" @click="confirmReplyUnitPicker">确定</button>
|
||||
</div>
|
||||
<div class="reply-unit-list" v-if="replyUnitOptions.length">
|
||||
<van-checkbox-group v-model="pendingReplyUnitIds">
|
||||
<van-cell
|
||||
v-for="item in replyUnitOptions"
|
||||
:key="item.unitId"
|
||||
clickable
|
||||
:title="item.unitName"
|
||||
:label="item.isMaster ? '主办单位' : '协办单位'"
|
||||
@click="toggleReplyUnit(item)"
|
||||
>
|
||||
<template #right-icon>
|
||||
<van-checkbox :name="item.unitId" @click.stop></van-checkbox>
|
||||
</template>
|
||||
</van-cell>
|
||||
</van-checkbox-group>
|
||||
</div>
|
||||
<div class="reply-unit-empty" v-else>暂无可选办理单位</div>
|
||||
</div>
|
||||
</van-popup>
|
||||
</div>
|
||||
<script nonce="${cspNonce!}">
|
||||
<!--#include("../../common/info.js"){}#-->
|
||||
|
||||
new Vue({
|
||||
el: "#app",
|
||||
store,
|
||||
components: {
|
||||
"proposal-info": PROPOSAL_INFO
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
bizId: "",
|
||||
action: "view",
|
||||
formData: {},
|
||||
formLoading: false,
|
||||
replyUnitOptions: [],
|
||||
pendingReplyUnitIds: [],
|
||||
showReplyUnitPicker: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isApproval() {
|
||||
return this.action === "approval"
|
||||
},
|
||||
pageTitle() {
|
||||
return this.isApproval ? "提案委员会审查" : "提案详情"
|
||||
},
|
||||
selectedReplyUnitNames() {
|
||||
const selectedIds = this.formData.tf_secondReplyUnitIds || []
|
||||
return this.replyUnitOptions
|
||||
.filter((item) => selectedIds.indexOf(item.unitId) > -1)
|
||||
.map((item) => item.unitName + "(" + (item.isMaster ? "主办" : "协办") + ")")
|
||||
.join("、")
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 二次答复使用数字 0/1,与 PC 端和流程拦截器读取的字段保持一致。
|
||||
validateSecondReply(value) {
|
||||
return value === 0 || value === 1
|
||||
},
|
||||
|
||||
// 选择需要二次答复时,至少需要选择一个当前提案的办理单位。
|
||||
validateSecondReplyUnits() {
|
||||
return this.formData.tf_caseCheckNeedSecondReply !== 1
|
||||
|| (this.formData.tf_secondReplyUnitIds || []).length > 0
|
||||
},
|
||||
|
||||
onSecondReplyChange(value) {
|
||||
if (value !== 1) {
|
||||
this.$set(this.formData, "tf_secondReplyUnitIds", [])
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 查询当前提案的承办单位。
|
||||
* proposalId 为提案主键;接口返回 ProposalReplyUnit 数组,包含 unitId、unitName、isMaster。
|
||||
*/
|
||||
loadReplyUnits(proposalId) {
|
||||
this.$axios.post("/platform/proposal/case/check/listReplyUnits", {proposalId: proposalId})
|
||||
.then((res) => {
|
||||
if (res && res.code === 0) {
|
||||
this.$set(this, "replyUnitOptions", res.data || [])
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
openReplyUnitPicker() {
|
||||
this.$set(this, "pendingReplyUnitIds", [...(this.formData.tf_secondReplyUnitIds || [])])
|
||||
this.$set(this, "showReplyUnitPicker", true)
|
||||
},
|
||||
|
||||
toggleReplyUnit(item) {
|
||||
const ids = [...this.pendingReplyUnitIds]
|
||||
const index = ids.indexOf(item.unitId)
|
||||
if (index > -1) {
|
||||
ids.splice(index, 1)
|
||||
} else {
|
||||
ids.push(item.unitId)
|
||||
}
|
||||
this.$set(this, "pendingReplyUnitIds", ids)
|
||||
},
|
||||
|
||||
cancelReplyUnitPicker() {
|
||||
this.$set(this, "showReplyUnitPicker", false)
|
||||
},
|
||||
|
||||
confirmReplyUnitPicker() {
|
||||
this.$set(this.formData, "tf_secondReplyUnitIds", [...this.pendingReplyUnitIds])
|
||||
this.$set(this, "showReplyUnitPicker", false)
|
||||
},
|
||||
|
||||
/**
|
||||
* 组装流程提交参数。
|
||||
* 根据选中的 ProposalReplyUnit 拆分主办和协办单位,返回 flow/common/executeTask 所需对象。
|
||||
*/
|
||||
buildSubmitData() {
|
||||
const submitData = {...this.formData}
|
||||
if (submitData.tf_caseCheckNeedSecondReply === 1) {
|
||||
const secondReplyUnits = this.replyUnitOptions.filter((item) => {
|
||||
return submitData.tf_secondReplyUnitIds.indexOf(item.unitId) > -1
|
||||
})
|
||||
const masterUnits = secondReplyUnits.filter((item) => item.isMaster)
|
||||
const slaveUnits = secondReplyUnits.filter((item) => !item.isMaster)
|
||||
const masterUnitIds = masterUnits.map((item) => item.unitId)
|
||||
const masterUnitNames = masterUnits.map((item) => item.unitName)
|
||||
const slaveUnitIds = slaveUnits.map((item) => item.unitId)
|
||||
const slaveUnitNames = slaveUnits.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 = ""
|
||||
}
|
||||
return submitData
|
||||
},
|
||||
|
||||
// 完成审批后记录任务 ID,列表返回缓存只移除该条记录,不影响其他查看位置。
|
||||
markListCacheCompleted() {
|
||||
const cacheKey = "proposal:case-check:h5:list-state"
|
||||
const cacheText = sessionStorage.getItem(cacheKey)
|
||||
if (!cacheText) return
|
||||
try {
|
||||
const cache = JSON.parse(cacheText)
|
||||
cache.completedTaskId = this.formData.processTaskId || ""
|
||||
sessionStorage.setItem(cacheKey, JSON.stringify(cache))
|
||||
} catch (e) {
|
||||
sessionStorage.removeItem(cacheKey)
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 提交提案委员会审查结果。
|
||||
* 参数包含 taskId 对应的 processTaskId、proposalId、审批意见和二次答复单位;Result.code 为 0 表示成功。
|
||||
*/
|
||||
handleTaskAction() {
|
||||
this.$refs.formRef.validate()
|
||||
.then(() => this.$dialog.confirm({title: "提示", message: "您确定要提交吗?"}))
|
||||
.then(() => {
|
||||
this.$set(this, "formLoading", true)
|
||||
const submitData = this.buildSubmitData()
|
||||
return this.$axios.post("/flow/common/executeTask", {
|
||||
data: JSON.stringify({
|
||||
...submitData,
|
||||
submitType: 1
|
||||
})
|
||||
})
|
||||
})
|
||||
.then((res) => {
|
||||
if (res && res.code === 0) {
|
||||
this.markListCacheCompleted()
|
||||
this.$toast.success(res.msg)
|
||||
this.historyBack()
|
||||
}
|
||||
})
|
||||
.catch(() => {})
|
||||
.finally(() => {
|
||||
this.$set(this, "formLoading", false)
|
||||
})
|
||||
}
|
||||
},
|
||||
created() {
|
||||
const params = new URLSearchParams(window.location.search)
|
||||
// bizId 为提案主键;taskId 和 taskName 用于执行当前 wf 流程任务。
|
||||
this.$set(this, "bizId", params.get("bizId") || "")
|
||||
this.$set(this, "action", params.get("action") || "view")
|
||||
if (this.isApproval) {
|
||||
this.$set(this.formData, "processTaskId", params.get("taskId") || "")
|
||||
this.$set(this.formData, "taskName", params.get("taskName") || "提案委员会审查")
|
||||
this.$set(this.formData, "proposalId", this.bizId)
|
||||
this.$set(this.formData, "tf_auditTime", moment().format("YYYY-MM-DD"))
|
||||
this.$set(this.formData, "tf_username", (this.$store.state.user && this.$store.state.user.username) || "")
|
||||
this.$set(this.formData, "tf_caseCheckNeedSecondReply", 0)
|
||||
this.$set(this.formData, "tf_secondReplyUnitIds", [])
|
||||
this.loadReplyUnits(this.bizId)
|
||||
}
|
||||
if (!this.bizId) {
|
||||
this.$toast.fail("缺少提案参数")
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
+161
-6
@@ -1,8 +1,11 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_h5.html"){
|
||||
#-->
|
||||
<style>
|
||||
<!--#include("../../common/info.css"){}#-->
|
||||
</style>
|
||||
<div id="app" v-cloak>
|
||||
<van-nav-bar @click-left="historyBack" left-arrow left-text="返回" title="委员会成员意见" placeholder
|
||||
<van-nav-bar @click-left="handlePageBack" left-arrow left-text="返回" title="委员会成员意见" placeholder
|
||||
fixed></van-nav-bar>
|
||||
<van-sticky offset-top="46px">
|
||||
<van-search
|
||||
@@ -41,21 +44,81 @@ layout("/layouts/platform_h5.html"){
|
||||
</template>
|
||||
<template #actions="{index,row}">
|
||||
<div class="action-btn" @click="onView(row)">
|
||||
<i class="fa fa-eye"></i>
|
||||
<van-icon class="proposal-action-icon" name="eye-o"></van-icon>
|
||||
<span>查看</span>
|
||||
</div>
|
||||
<div class="action-btn" v-if="!row.pcoId" @click="onApproval(row)">
|
||||
<i class="fa fa-edit"></i>
|
||||
<van-icon class="proposal-action-icon" name="edit"></van-icon>
|
||||
<span>审核</span>
|
||||
</div>
|
||||
</template>
|
||||
</table-list>
|
||||
|
||||
<van-popup v-model="detailVisible" class="proposal-full-popup" position="right"
|
||||
:close-on-click-overlay="false" safe-area-inset-bottom>
|
||||
<div class="proposal-full-popup__page">
|
||||
<van-nav-bar :title="popupTitle" left-arrow left-text="返回" fixed
|
||||
@click-left="closeHistoryLayer('detail')"></van-nav-bar>
|
||||
<div class="proposal-full-popup__scroll">
|
||||
<proposal-info v-if="detailVisible && detailBizId" :biz-id="detailBizId" :visible="detailVisible">
|
||||
<div v-if="isApproval">
|
||||
<van-form ref="formRef">
|
||||
<van-field v-model="formData.caseFilingResultName" name="caseFilingResultName"
|
||||
label="立案结果" placeholder="请选择立案结果" readonly required is-link
|
||||
:rules="[{ required: true, message: '请选择立案结果' }]"
|
||||
@click="openHistoryLayer('result-picker')"></van-field>
|
||||
<template v-if="formData.caseFilingResult === 'CONFIRM_FILING'">
|
||||
<van-field v-model="formData.caseFilingTypeName" name="caseFilingTypeName"
|
||||
label="立案类型" placeholder="请选择立案类型" readonly required is-link
|
||||
:rules="[{ required: true, message: '请选择立案类型' }]"
|
||||
@click="openHistoryLayer('type-picker')"></van-field>
|
||||
</template>
|
||||
<section class="proposal-view-card">
|
||||
<h2 class="proposal-view-card__title">
|
||||
审批意见
|
||||
<span class="proposal-audit-card__required">*</span>
|
||||
</h2>
|
||||
<van-field v-model="formData.opinion" class="proposal-audit-field" name="opinion"
|
||||
type="textarea" rows="6" label="" placeholder="请输入审批意见"
|
||||
required maxlength="100" show-word-limit
|
||||
:rules="[{ required: true, message: '请填写审批意见' }]"></van-field>
|
||||
</section>
|
||||
</van-form>
|
||||
<div class="proposal-popup-form-actions">
|
||||
<van-button block :disabled="formLoading" @click="closeHistoryLayer('detail')">取消</van-button>
|
||||
<van-button type="primary" block :loading="formLoading" @click="submitApproval">提交</van-button>
|
||||
</div>
|
||||
</div>
|
||||
</proposal-info>
|
||||
</div>
|
||||
</div>
|
||||
</van-popup>
|
||||
|
||||
<van-popup v-model="showCaseFilingResultPicker" position="bottom" :close-on-click-overlay="false">
|
||||
<van-picker show-toolbar
|
||||
:columns="dict.type.PROPOSAL_CASE_FILING_RESULT.map(item => ({text: item.label, value: item.code}))"
|
||||
@confirm="onCaseFilingResultConfirm"
|
||||
@cancel="closeHistoryLayer('result-picker')"></van-picker>
|
||||
</van-popup>
|
||||
<van-popup v-model="showCaseFilingTypePicker" position="bottom" :close-on-click-overlay="false">
|
||||
<van-picker show-toolbar
|
||||
:columns="dict.type.PROPOSAL_CASE_FILING_TYPE.map(item => ({text: item.label, value: item.code}))"
|
||||
@confirm="onCaseFilingTypeConfirm"
|
||||
@cancel="closeHistoryLayer('type-picker')"></van-picker>
|
||||
</van-popup>
|
||||
<van-dialog :value="submitConfirmVisible" title="提示" message="您确定要提交吗?" show-cancel-button
|
||||
@confirm="confirmApproval" @cancel="closeHistoryLayer('submit-confirm')"></van-dialog>
|
||||
|
||||
</div>
|
||||
<script nonce="${cspNonce!}">
|
||||
<!--#include("../../common/info.js"){}#-->
|
||||
const vue = new Vue({
|
||||
el: "#app",
|
||||
store,
|
||||
dicts: ["PROPOSAL_CASE_FILING_RESULT", "PROPOSAL_CASE_FILING_TYPE"],
|
||||
components: {
|
||||
"proposal-info": PROPOSAL_INFO
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
pageForm: {
|
||||
@@ -68,10 +131,58 @@ layout("/layouts/platform_h5.html"){
|
||||
approval: false
|
||||
},
|
||||
|
||||
sessionOptions: []
|
||||
sessionOptions: [],
|
||||
detailVisible: false,
|
||||
detailBizId: "",
|
||||
popupAction: "view",
|
||||
formData: {},
|
||||
formLoading: false,
|
||||
showCaseFilingResultPicker: false,
|
||||
showCaseFilingTypePicker: false,
|
||||
submitConfirmVisible: false,
|
||||
historyLayerPageKey: "proposal-commissioner-h5"
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isApproval() {
|
||||
return this.popupAction === "approval"
|
||||
},
|
||||
popupTitle() {
|
||||
return this.isApproval ? "委员会成员意见" : "提案详情"
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
registerHistoryLayers() {
|
||||
if (!window.h5HistoryLayerManager) return
|
||||
window.h5HistoryLayerManager.register(this.historyLayerPageKey, (stack) => {
|
||||
this.$set(this, "detailVisible", stack.includes("detail"))
|
||||
this.$set(this, "showCaseFilingResultPicker", stack.includes("result-picker"))
|
||||
this.$set(this, "showCaseFilingTypePicker", stack.includes("type-picker"))
|
||||
this.$set(this, "submitConfirmVisible", stack.includes("submit-confirm"))
|
||||
})
|
||||
},
|
||||
openHistoryLayer(layerName) {
|
||||
if (window.h5HistoryLayerManager && window.h5HistoryLayerManager.open(layerName)) return
|
||||
this.setHistoryLayerVisible(layerName, true)
|
||||
},
|
||||
closeHistoryLayer(layerName, afterClose = null) {
|
||||
if (window.h5HistoryLayerManager && window.h5HistoryLayerManager.close(layerName, afterClose)) return
|
||||
this.setHistoryLayerVisible(layerName, false)
|
||||
if (typeof afterClose === "function") afterClose()
|
||||
},
|
||||
setHistoryLayerVisible(layerName, visible) {
|
||||
if (layerName === "detail") this.$set(this, "detailVisible", visible)
|
||||
if (layerName === "result-picker") this.$set(this, "showCaseFilingResultPicker", visible)
|
||||
if (layerName === "type-picker") this.$set(this, "showCaseFilingTypePicker", visible)
|
||||
if (layerName === "submit-confirm") this.$set(this, "submitConfirmVisible", visible)
|
||||
},
|
||||
handlePageBack() {
|
||||
if (window.h5HistoryLayerManager && window.h5HistoryLayerManager.stack.length) {
|
||||
window.h5HistoryLayerManager.close()
|
||||
return
|
||||
}
|
||||
this.historyBack()
|
||||
},
|
||||
onReady() {
|
||||
this.listSession()
|
||||
},
|
||||
@@ -93,11 +204,49 @@ layout("/layouts/platform_h5.html"){
|
||||
},
|
||||
|
||||
onView(row) {
|
||||
this.$pjaxReplace("/platform/proposal/commissioner/info/h5?bizId=" + encodeURIComponent(row.id) + "&action=view")
|
||||
this.$set(this, "detailBizId", row.id)
|
||||
this.$set(this, "popupAction", "view")
|
||||
this.$set(this, "formData", {})
|
||||
this.openHistoryLayer("detail")
|
||||
},
|
||||
|
||||
onApproval(row) {
|
||||
this.$pjaxReplace("/platform/proposal/commissioner/info/h5?bizId=" + encodeURIComponent(row.id) + "&action=approval")
|
||||
this.$set(this, "detailBizId", row.id)
|
||||
this.$set(this, "popupAction", "approval")
|
||||
this.$set(this, "formData", {
|
||||
proposalId: row.id,
|
||||
caseFilingResult: null,
|
||||
caseFilingType: null,
|
||||
opinion: null
|
||||
})
|
||||
this.openHistoryLayer("detail")
|
||||
},
|
||||
onCaseFilingResultConfirm(value) {
|
||||
this.$set(this.formData, "caseFilingResultName", value.text)
|
||||
this.$set(this.formData, "caseFilingResult", value.value)
|
||||
this.closeHistoryLayer("result-picker")
|
||||
},
|
||||
onCaseFilingTypeConfirm(value) {
|
||||
this.$set(this.formData, "caseFilingTypeName", value.text)
|
||||
this.$set(this.formData, "caseFilingType", value.value)
|
||||
this.closeHistoryLayer("type-picker")
|
||||
},
|
||||
submitApproval() {
|
||||
this.$refs.formRef.validate().then(() => this.openHistoryLayer("submit-confirm")).catch(() => {})
|
||||
},
|
||||
confirmApproval() {
|
||||
this.closeHistoryLayer("submit-confirm", () => this.doSubmitApproval())
|
||||
},
|
||||
doSubmitApproval() {
|
||||
this.$set(this, "formLoading", true)
|
||||
this.$axios.post("/platform/proposal/commissioner/doApproval", this.formData)
|
||||
.then((res) => {
|
||||
if (res && res.code === 0) {
|
||||
this.$toast.success(res.msg)
|
||||
this.closeHistoryLayer("detail", () => this.doSearch())
|
||||
}
|
||||
})
|
||||
.finally(() => this.$set(this, "formLoading", false))
|
||||
},
|
||||
|
||||
doSearch() {
|
||||
@@ -107,6 +256,12 @@ layout("/layouts/platform_h5.html"){
|
||||
this.$refs.tableListRef.doSearch()
|
||||
})
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.registerHistoryLayers()
|
||||
},
|
||||
beforeDestroy() {
|
||||
if (window.h5HistoryLayerManager) window.h5HistoryLayerManager.unregister(this.historyLayerPageKey)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
-152
@@ -1,152 +0,0 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_h5.html"){
|
||||
#-->
|
||||
<style id="style-proposal-info-h5">
|
||||
<!--#include("../../common/info.css"){}#-->
|
||||
</style>
|
||||
<div id="app" v-cloak>
|
||||
<van-nav-bar @click-left="historyBack" left-arrow left-text="返回" :title="pageTitle" placeholder fixed></van-nav-bar>
|
||||
<proposal-info v-if="bizId" :biz-id="bizId">
|
||||
<div v-if="isApproval">
|
||||
<div class="process-title">提案委员会成员意见</div>
|
||||
<van-form ref="formRef">
|
||||
<van-field
|
||||
v-model="formData.caseFilingResultName"
|
||||
name="caseFilingResultName"
|
||||
label="立案结果"
|
||||
placeholder="请选择立案结果"
|
||||
:rules="[{ required: true, message: '请选择立案结果' }]"
|
||||
required
|
||||
is-link
|
||||
@click="showCaseFilingResultPicker = true"
|
||||
></van-field>
|
||||
<van-popup v-model="showCaseFilingResultPicker" position="bottom">
|
||||
<van-picker
|
||||
show-toolbar
|
||||
:columns="dict.type.PROPOSAL_CASE_FILING_RESULT.map(item => ({text: item.label, value: item.code}))"
|
||||
@confirm="onCaseFilingResultConfirm"
|
||||
@cancel="showCaseFilingResultPicker = false"
|
||||
></van-picker>
|
||||
</van-popup>
|
||||
|
||||
<template v-if="formData.caseFilingResult === 'CONFIRM_FILING'">
|
||||
<van-field
|
||||
v-model="formData.caseFilingTypeName"
|
||||
name="caseFilingTypeName"
|
||||
label="立案类型"
|
||||
placeholder="请选择立案类型"
|
||||
:rules="[{ required: true, message: '请选择立案类型' }]"
|
||||
required
|
||||
is-link
|
||||
@click="showCaseFilingTypePicker = true"
|
||||
></van-field>
|
||||
<van-popup v-model="showCaseFilingTypePicker" position="bottom">
|
||||
<van-picker
|
||||
show-toolbar
|
||||
:columns="dict.type.PROPOSAL_CASE_FILING_TYPE.map(item => ({text: item.label, value: item.code}))"
|
||||
@confirm="onCaseFilingTypeConfirm"
|
||||
@cancel="showCaseFilingTypePicker = false"
|
||||
></van-picker>
|
||||
</van-popup>
|
||||
</template>
|
||||
|
||||
<van-field
|
||||
v-model="formData.opinion"
|
||||
name="opinion"
|
||||
label="审批意见"
|
||||
placeholder="请输入审批意见"
|
||||
:rules="[{ required: true, message: '请填写审批意见' }]"
|
||||
required
|
||||
maxlength="100"
|
||||
show-word-limit
|
||||
></van-field>
|
||||
</van-form>
|
||||
<div style="display: flex; justify-content: space-between; column-gap: 10px; padding: 10px">
|
||||
<van-button block :disabled="formLoading" @click="historyBack">取消</van-button>
|
||||
<van-button type="primary" block :loading="formLoading" @click="doSubmit">提交</van-button>
|
||||
</div>
|
||||
</div>
|
||||
</proposal-info>
|
||||
</div>
|
||||
<script nonce="${cspNonce!}">
|
||||
<!--#include("../../common/info.js"){}#-->
|
||||
|
||||
new Vue({
|
||||
el: "#app",
|
||||
store,
|
||||
dicts: ["PROPOSAL_CASE_FILING_RESULT", "PROPOSAL_CASE_FILING_TYPE"],
|
||||
components: {
|
||||
"proposal-info": PROPOSAL_INFO
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
bizId: "",
|
||||
action: "view",
|
||||
formData: {},
|
||||
formLoading: false,
|
||||
showCaseFilingResultPicker: false,
|
||||
showCaseFilingTypePicker: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isApproval() {
|
||||
return this.action === "approval"
|
||||
},
|
||||
pageTitle() {
|
||||
return this.isApproval ? "委员会成员意见" : "提案详情"
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onCaseFilingResultConfirm(value) {
|
||||
this.$set(this.formData, "caseFilingResultName", value.text)
|
||||
this.$set(this.formData, "caseFilingResult", value.value)
|
||||
this.showCaseFilingResultPicker = false
|
||||
},
|
||||
onCaseFilingTypeConfirm(value) {
|
||||
this.$set(this.formData, "caseFilingTypeName", value.text)
|
||||
this.$set(this.formData, "caseFilingType", value.value)
|
||||
this.showCaseFilingTypePicker = false
|
||||
},
|
||||
/**
|
||||
* 提交委员会成员意见。
|
||||
* 参数包含 proposalId、立案结果、立案类型和意见;接口返回 Result。
|
||||
*/
|
||||
doSubmit() {
|
||||
this.$refs.formRef.validate()
|
||||
.then(() => this.$dialog.confirm({title: "提示", message: "您确定要提交吗?"}))
|
||||
.then(() => {
|
||||
this.formLoading = true
|
||||
return this.$axios.post("/platform/proposal/commissioner/doApproval", this.formData)
|
||||
})
|
||||
.then((res) => {
|
||||
if (res && res.code === 0) {
|
||||
this.$toast.success(res.msg)
|
||||
this.historyBack()
|
||||
}
|
||||
})
|
||||
.catch(() => {})
|
||||
.finally(() => {
|
||||
this.formLoading = false
|
||||
})
|
||||
}
|
||||
},
|
||||
created() {
|
||||
const params = new URLSearchParams(window.location.search)
|
||||
// bizId 为详情查询和委员会意见提交共同使用的提案主键。
|
||||
this.bizId = params.get("bizId") || ""
|
||||
this.action = params.get("action") || "view"
|
||||
if (this.isApproval) {
|
||||
this.$set(this.formData, "proposalId", this.bizId)
|
||||
this.$set(this.formData, "caseFilingResult", null)
|
||||
this.$set(this.formData, "caseFilingType", null)
|
||||
this.$set(this.formData, "opinion", null)
|
||||
}
|
||||
if (!this.bizId) {
|
||||
this.$toast.fail("缺少提案参数")
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
+14
-255
@@ -229,6 +229,9 @@ layout("/layouts/platform_h5.html"){
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style id="style-proposal-task-popup-h5">
|
||||
<!--#include("../../common/info.css"){}#-->
|
||||
</style>
|
||||
<div id="app" v-cloak>
|
||||
<div class="proposal-delegation-page">
|
||||
<van-nav-bar @click-left="historyBack" left-arrow left-text="返回" title="团长审核" placeholder fixed></van-nav-bar>
|
||||
@@ -303,15 +306,15 @@ layout("/layouts/platform_h5.html"){
|
||||
</template>
|
||||
<template #actions="{index,row}">
|
||||
<div class="action-btn" @click="onView(row,index)">
|
||||
<i class="fa fa-eye"></i>
|
||||
<van-icon class="proposal-action-icon" name="eye-o"></van-icon>
|
||||
<span>查看</span>
|
||||
</div>
|
||||
<div class="action-btn" v-if="row.taskState === 10" @click="onApproval(row,index)">
|
||||
<i class="fa fa-edit"></i>
|
||||
<van-icon class="proposal-action-icon" name="edit"></van-icon>
|
||||
<span>审核</span>
|
||||
</div>
|
||||
<div class="action-btn delete" v-if="row.canRevoke" @click="onRevoke(row)">
|
||||
<i class="fa fa-reply"></i>
|
||||
<van-icon class="proposal-action-icon" name="revoke"></van-icon>
|
||||
<span>撤回</span>
|
||||
</div>
|
||||
</template>
|
||||
@@ -319,12 +322,15 @@ layout("/layouts/platform_h5.html"){
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<proposal-task-popup ref="taskPopup" kind="delegation" page-key="proposal-delegation-task" @success="doSearch"></proposal-task-popup>
|
||||
</div>
|
||||
<script nonce="${cspNonce!}">
|
||||
<!--#include("../../common/info.js"){}#-->
|
||||
<!--#include("../../common/task-popup.js"){}#-->
|
||||
new Vue({
|
||||
el: "#app",
|
||||
store,
|
||||
components: {"proposal-task-popup": PROPOSAL_TASK_POPUP},
|
||||
data() {
|
||||
return {
|
||||
pageForm: {
|
||||
@@ -345,16 +351,10 @@ layout("/layouts/platform_h5.html"){
|
||||
{text: "未审核", value: "0"},
|
||||
{text: "已审核", value: "1"}
|
||||
],
|
||||
pendingListCache: null
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onReady() {
|
||||
if (this.pendingListCache) {
|
||||
this.restoreListCache()
|
||||
this.listSession(true)
|
||||
return
|
||||
}
|
||||
this.listSession(false)
|
||||
},
|
||||
// 审核状态下拉框使用字符串值展示,查询接口使用布尔值区分已审核和未审核。
|
||||
@@ -375,249 +375,11 @@ layout("/layouts/platform_h5.html"){
|
||||
},
|
||||
|
||||
onView(row, index) {
|
||||
this.saveListCache(row, index)
|
||||
this.$pjaxReplace("/platform/proposal/delegation/info/h5?bizId=" + encodeURIComponent(row.id) + "&action=view")
|
||||
this.$refs.taskPopup.open(row, "view")
|
||||
},
|
||||
|
||||
onApproval(row, index) {
|
||||
this.saveListCache(row, index)
|
||||
const params = new URLSearchParams()
|
||||
params.set("bizId", row.id)
|
||||
params.set("action", "approval")
|
||||
params.set("taskId", row.taskId)
|
||||
params.set("taskName", row.curTaskName || row.taskName || "团长审核")
|
||||
this.$pjaxReplace("/platform/proposal/delegation/info/h5?" + params.toString())
|
||||
},
|
||||
|
||||
getListCacheKey() {
|
||||
return "proposal:delegation:h5:list-state"
|
||||
},
|
||||
|
||||
getListCacheTokenParam() {
|
||||
return "delegationListCacheToken"
|
||||
},
|
||||
|
||||
getCurrentListCacheToken() {
|
||||
return new URLSearchParams(window.location.search).get(this.getListCacheTokenParam()) || ""
|
||||
},
|
||||
|
||||
/**
|
||||
* 将团长审核列表缓存标识绑定到当前历史记录。
|
||||
* PJAX 重复初始化时,每个列表实例都通过该标识恢复同一份筛选、分页和滚动快照。
|
||||
*/
|
||||
bindListCacheToken(token) {
|
||||
const currentUrl = new URL(window.location.href)
|
||||
currentUrl.searchParams.set(this.getListCacheTokenParam(), token)
|
||||
const currentState = window.history.state ? {...window.history.state} : null
|
||||
if (currentState && currentState.url) {
|
||||
currentState.url = currentUrl.toString()
|
||||
}
|
||||
window.history.replaceState(currentState, document.title, currentUrl.toString())
|
||||
if ($.pjax && $.pjax.state) {
|
||||
$.pjax.state.url = currentUrl.toString()
|
||||
}
|
||||
},
|
||||
|
||||
// 用户主动查询时清除详情返回标识,避免重新进入页面后误用旧列表现场。
|
||||
clearListCache() {
|
||||
const token = this.getCurrentListCacheToken()
|
||||
if (!token) return
|
||||
const currentUrl = new URL(window.location.href)
|
||||
currentUrl.searchParams.delete(this.getListCacheTokenParam())
|
||||
const currentState = window.history.state ? {...window.history.state} : null
|
||||
if (currentState && currentState.url) {
|
||||
currentState.url = currentUrl.toString()
|
||||
}
|
||||
window.history.replaceState(currentState, document.title, currentUrl.toString())
|
||||
if ($.pjax && $.pjax.state) {
|
||||
$.pjax.state.url = currentUrl.toString()
|
||||
}
|
||||
sessionStorage.removeItem(this.getListCacheKey())
|
||||
},
|
||||
|
||||
// platform_h5 的实际滚动区域是 page-wrapper,列表返回位置必须基于该容器保存和恢复。
|
||||
getListScrollContainer() {
|
||||
return document.querySelector(".page-wrapper") || document.scrollingElement || document.documentElement
|
||||
},
|
||||
|
||||
/**
|
||||
* 进入查看或审核详情前保存列表现场。
|
||||
* row 为当前提案,index 为已加载列表索引;缓存包含查询条件、分页数据和相邻记录锚点。
|
||||
*/
|
||||
saveListCache(row, index) {
|
||||
const tableList = this.$refs.tableListRef
|
||||
if (!tableList) return
|
||||
const cacheToken = Date.now() + "-" + Math.random().toString(36).slice(2)
|
||||
const tableState = typeof tableList.getListState === "function"
|
||||
? tableList.getListState()
|
||||
: {
|
||||
tableData: JSON.parse(JSON.stringify(tableList.tableData || [])),
|
||||
localPageForm: JSON.parse(JSON.stringify(tableList.localPageForm || this.pageForm)),
|
||||
tableFinished: !!tableList.tableFinished
|
||||
}
|
||||
const cards = document.querySelectorAll(".proposal-delegation-list .table-list-item")
|
||||
const currentCard = cards[index]
|
||||
const scrollContainer = this.getListScrollContainer()
|
||||
const cache = {
|
||||
time: Date.now(),
|
||||
token: cacheToken,
|
||||
pageForm: JSON.parse(JSON.stringify(this.pageForm)),
|
||||
tableState: tableState,
|
||||
completedBizId: "",
|
||||
anchor: {
|
||||
rowId: row.id,
|
||||
previousRowId: index > 0 && tableState.tableData[index - 1] ? tableState.tableData[index - 1].id : "",
|
||||
nextRowId: tableState.tableData[index + 1] ? tableState.tableData[index + 1].id : "",
|
||||
viewportTop: currentCard ? currentCard.getBoundingClientRect().top : 0,
|
||||
scrollTop: scrollContainer ? scrollContainer.scrollTop : 0
|
||||
}
|
||||
}
|
||||
try {
|
||||
sessionStorage.setItem(this.getListCacheKey(), JSON.stringify(cache))
|
||||
this.bindListCacheToken(cacheToken)
|
||||
} catch (error) {
|
||||
sessionStorage.removeItem(this.getListCacheKey())
|
||||
}
|
||||
},
|
||||
|
||||
// 仅恢复当前历史记录对应且十分钟内有效的团长审核列表缓存。
|
||||
prepareListCache() {
|
||||
try {
|
||||
const cacheToken = this.getCurrentListCacheToken()
|
||||
if (!cacheToken) return
|
||||
const cacheText = sessionStorage.getItem(this.getListCacheKey())
|
||||
if (!cacheText) return
|
||||
const cache = JSON.parse(cacheText)
|
||||
if (!cache || cache.token !== cacheToken || !cache.tableState) return
|
||||
if (Date.now() - cache.time > 10 * 60 * 1000) {
|
||||
this.clearListCache()
|
||||
return
|
||||
}
|
||||
Object.keys(cache.pageForm || {}).forEach((key) => {
|
||||
this.$set(this.pageForm, key, cache.pageForm[key])
|
||||
})
|
||||
this.$set(this, "pendingListCache", cache)
|
||||
} catch (error) {
|
||||
sessionStorage.removeItem(this.getListCacheKey())
|
||||
}
|
||||
},
|
||||
|
||||
// 普通查看返回恢复旧快照;审核完成返回重新查询,避免未审核列表继续显示已处理记录。
|
||||
restoreListCache() {
|
||||
const cache = this.pendingListCache
|
||||
const tableList = this.$refs.tableListRef
|
||||
if (!cache || !tableList) return
|
||||
const anchor = cache.anchor || {}
|
||||
if (cache.completedBizId) {
|
||||
this.refreshCompletedListCache(cache)
|
||||
return
|
||||
}
|
||||
this.applyListCache(cache.tableState, anchor.rowId, anchor)
|
||||
},
|
||||
|
||||
/**
|
||||
* 按离开前已加载页数重新获取审核后的列表。
|
||||
* 返回值仍转换为 TableList 状态,并定位下一条;没有下一条时定位上一条。
|
||||
*/
|
||||
refreshCompletedListCache(cache) {
|
||||
const originalPageSize = Number(cache.pageForm.pageSize || 10)
|
||||
const loadedCount = Math.max(cache.tableState.tableData.length, originalPageSize)
|
||||
const loadedPageCount = Math.max(1, Math.ceil(loadedCount / originalPageSize))
|
||||
const requestForm = {
|
||||
...cache.pageForm,
|
||||
pageNumber: 1,
|
||||
pageSize: loadedPageCount * originalPageSize
|
||||
}
|
||||
const loading = createListLoading()
|
||||
this.$axios.post("/platform/proposal/delegation/pageData", requestForm, {h5SkeletonLoading: true})
|
||||
.then((res) => {
|
||||
if (res.code !== 0) {
|
||||
this.applyCompletedCacheFallback(cache)
|
||||
return
|
||||
}
|
||||
const freshState = {
|
||||
tableData: res.data.list || [],
|
||||
localPageForm: {
|
||||
...cache.pageForm,
|
||||
pageNumber: loadedPageCount,
|
||||
pageSize: originalPageSize,
|
||||
totalCount: res.data.totalCount
|
||||
},
|
||||
tableFinished: (res.data.list || []).length >= res.data.totalCount
|
||||
}
|
||||
const anchor = cache.anchor || {}
|
||||
this.applyListCache(freshState, anchor.nextRowId || anchor.previousRowId, anchor)
|
||||
})
|
||||
.catch(() => {
|
||||
this.applyCompletedCacheFallback(cache)
|
||||
})
|
||||
.finally(() => {
|
||||
loading.close()
|
||||
})
|
||||
},
|
||||
|
||||
// 审核后刷新失败时从旧快照移除已处理记录,保证未审核列表不会保留脏数据。
|
||||
applyCompletedCacheFallback(cache) {
|
||||
const tableState = cache.tableState
|
||||
const completedIndex = tableState.tableData.findIndex((item) => String(item.id) === String(cache.completedBizId))
|
||||
if (completedIndex >= 0 && cache.pageForm.approval === false) {
|
||||
tableState.tableData.splice(completedIndex, 1)
|
||||
if (tableState.localPageForm && tableState.localPageForm.totalCount > 0) {
|
||||
tableState.localPageForm.totalCount--
|
||||
}
|
||||
} else if (completedIndex >= 0) {
|
||||
this.$set(tableState.tableData[completedIndex], "taskState", 20)
|
||||
}
|
||||
const anchor = cache.anchor || {}
|
||||
this.applyListCache(tableState, anchor.nextRowId || anchor.previousRowId, anchor)
|
||||
},
|
||||
|
||||
/**
|
||||
* 恢复 TableList 数据并将目标卡片放回离开页面前的视口位置。
|
||||
* sticky 吸顶会改变一次布局,因此首次滚动后再执行一次位置校正。
|
||||
*/
|
||||
applyListCache(tableState, targetRowId, anchor) {
|
||||
const tableList = this.$refs.tableListRef
|
||||
if (!tableList) return
|
||||
if (typeof tableList.restoreListState === "function") {
|
||||
if (!tableList.restoreListState(tableState)) return
|
||||
} else {
|
||||
this.$set(tableList, "tableData", tableState.tableData || [])
|
||||
this.$set(tableList, "localPageForm", {...tableList.localPageForm, ...(tableState.localPageForm || {})})
|
||||
this.$set(tableList, "tableFinished", !!tableState.tableFinished)
|
||||
this.$set(tableList, "tableLoading", false)
|
||||
this.$set(tableList, "tableRefreshing", false)
|
||||
tableList.$emit("update:page_form", {...tableList.localPageForm})
|
||||
}
|
||||
this.$set(this, "pendingListCache", null)
|
||||
this.$nextTick(() => {
|
||||
setTimeout(() => {
|
||||
const cards = Array.from(document.querySelectorAll(".proposal-delegation-list .table-list-item"))
|
||||
const scrollContainer = this.getListScrollContainer()
|
||||
if (!scrollContainer) return
|
||||
const candidateIds = [targetRowId, anchor.nextRowId, anchor.previousRowId]
|
||||
.filter((id) => id)
|
||||
.map((id) => String(id))
|
||||
.filter((id, index, values) => values.indexOf(id) === index)
|
||||
let targetIndex = -1
|
||||
candidateIds.some((candidateId) => {
|
||||
targetIndex = (tableState.tableData || []).findIndex((item) => String(item.id) === candidateId)
|
||||
return targetIndex >= 0
|
||||
})
|
||||
const targetCard = targetIndex >= 0 ? cards[targetIndex] : null
|
||||
if (targetCard) {
|
||||
const restoreTargetCard = () => {
|
||||
if (!targetCard.isConnected) return
|
||||
const targetTop = scrollContainer.scrollTop + targetCard.getBoundingClientRect().top - Number(anchor.viewportTop || 0)
|
||||
scrollContainer.scrollTo(0, Math.max(0, targetTop))
|
||||
}
|
||||
restoreTargetCard()
|
||||
setTimeout(restoreTargetCard, 100)
|
||||
return
|
||||
}
|
||||
scrollContainer.scrollTo(0, Number(anchor.scrollTop || 0))
|
||||
}, 0)
|
||||
})
|
||||
this.$refs.taskPopup.open(row, "approval")
|
||||
},
|
||||
|
||||
onRevoke(row){
|
||||
@@ -635,17 +397,14 @@ layout("/layouts/platform_h5.html"){
|
||||
},
|
||||
|
||||
doSearch() {
|
||||
this.clearListCache()
|
||||
this.$nextTick(() => {
|
||||
this.pageForm.pageNumber = 1
|
||||
this.pageForm.totalCount = 0
|
||||
this.$set(this.pageForm, "pageNumber", 1)
|
||||
this.$set(this.pageForm, "totalCount", 0)
|
||||
this.$refs.tableListRef.doSearch()
|
||||
})
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.prepareListCache()
|
||||
if (this.pendingListCache) return
|
||||
const tab = new URLSearchParams(window.location.search).get("tab")
|
||||
if (tab === "done") {
|
||||
this.$set(this.pageForm, "approval", true)
|
||||
|
||||
-122
@@ -1,122 +0,0 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_h5.html"){
|
||||
#-->
|
||||
<style id="style-proposal-info-h5">
|
||||
<!--#include("../../common/info.css"){}#-->
|
||||
</style>
|
||||
<div id="app" v-cloak>
|
||||
<van-nav-bar @click-left="historyBack" left-arrow left-text="返回" :title="pageTitle" placeholder fixed></van-nav-bar>
|
||||
<proposal-info v-if="bizId" :biz-id="bizId">
|
||||
<div v-if="isApproval">
|
||||
<div class="process-title">{{formData.taskName}}</div>
|
||||
<van-form ref="formRef">
|
||||
<van-field
|
||||
v-model="formData.tf_opinion"
|
||||
name="tf_opinion"
|
||||
label="审批意见"
|
||||
placeholder="请输入审批意见"
|
||||
:rules="[{ required: true, message: '请填写审批意见' }]"
|
||||
required
|
||||
maxlength="100"
|
||||
show-word-limit
|
||||
></van-field>
|
||||
</van-form>
|
||||
<div style="display: flex; justify-content: space-between; column-gap: 10px; padding: 10px">
|
||||
<van-button type="danger" block :loading="formLoading" @click="handleTaskAction(6)">退回</van-button>
|
||||
<van-button type="danger" block :loading="formLoading" @click="handleTaskAction(2)">不同意</van-button>
|
||||
<van-button type="primary" block :loading="formLoading" @click="handleTaskAction(1)">同意</van-button>
|
||||
</div>
|
||||
</div>
|
||||
</proposal-info>
|
||||
</div>
|
||||
<script nonce="${cspNonce!}">
|
||||
<!--#include("../../common/info.js"){}#-->
|
||||
|
||||
new Vue({
|
||||
el: "#app",
|
||||
store,
|
||||
components: {
|
||||
"proposal-info": PROPOSAL_INFO
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
bizId: "",
|
||||
action: "view",
|
||||
formData: {},
|
||||
formLoading: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isApproval() {
|
||||
return this.action === "approval"
|
||||
},
|
||||
pageTitle() {
|
||||
return this.isApproval ? "团长审核" : "提案详情"
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* 提交团长审核结果。
|
||||
* val 为 WF 提交类型:1 同意、2 不同意、6 退回;接口返回 Result。
|
||||
*/
|
||||
handleTaskAction(val) {
|
||||
this.$refs.formRef.validate()
|
||||
.then(() => this.$dialog.confirm({title: "提示", message: "您确定要提交吗?"}))
|
||||
.then(() => {
|
||||
this.formLoading = true
|
||||
return this.$axios.post("/flow/common/executeTask", {
|
||||
data: JSON.stringify({
|
||||
...this.formData,
|
||||
submitType: val
|
||||
})
|
||||
})
|
||||
})
|
||||
.then((res) => {
|
||||
if (res && res.code === 0) {
|
||||
this.markListCacheCompleted()
|
||||
this.$toast.success(res.msg)
|
||||
this.historyBack()
|
||||
}
|
||||
})
|
||||
.catch(() => {})
|
||||
.finally(() => {
|
||||
this.formLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 团长审核成功后标记已处理提案主键。
|
||||
* 返回未审核列表时根据该标记重新查询原浏览范围,并定位到相邻记录。
|
||||
*/
|
||||
markListCacheCompleted() {
|
||||
const cacheKey = "proposal:delegation:h5:list-state"
|
||||
try {
|
||||
const cacheText = sessionStorage.getItem(cacheKey)
|
||||
if (!cacheText) return
|
||||
const cache = JSON.parse(cacheText)
|
||||
cache.completedBizId = this.bizId
|
||||
cache.time = Date.now()
|
||||
sessionStorage.setItem(cacheKey, JSON.stringify(cache))
|
||||
} catch (error) {
|
||||
sessionStorage.removeItem(cacheKey)
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
const params = new URLSearchParams(window.location.search)
|
||||
// bizId 用于查询详情,taskId 和 taskName 用于构造 WF 审核提交数据。
|
||||
this.bizId = params.get("bizId") || ""
|
||||
this.action = params.get("action") || "view"
|
||||
if (this.isApproval) {
|
||||
this.$set(this.formData, "processTaskId", params.get("taskId") || "")
|
||||
this.$set(this.formData, "taskName", params.get("taskName") || "团长审核")
|
||||
}
|
||||
if (!this.bizId) {
|
||||
this.$toast.fail("缺少提案参数")
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
+14
-260
@@ -229,6 +229,9 @@ layout("/layouts/platform_h5.html"){
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style id="style-proposal-task-popup-h5">
|
||||
<!--#include("../../common/info.css"){}#-->
|
||||
</style>
|
||||
<div id="app" v-cloak>
|
||||
<div class="proposal-feedback-evaluation-page">
|
||||
<van-nav-bar @click-left="historyBack" left-arrow left-text="返回" title="反馈评价" placeholder fixed></van-nav-bar>
|
||||
@@ -303,15 +306,15 @@ layout("/layouts/platform_h5.html"){
|
||||
</template>
|
||||
<template #actions="{index,row}">
|
||||
<div class="action-btn" @click="onView(row,index)">
|
||||
<i class="fa fa-eye"></i>
|
||||
<van-icon class="proposal-action-icon" name="eye-o"></van-icon>
|
||||
<span>查看</span>
|
||||
</div>
|
||||
<div class="action-btn" v-if="row.taskState === 10" @click="onApproval(row,index)">
|
||||
<i class="fa fa-edit"></i>
|
||||
<van-icon class="proposal-action-icon" name="edit"></van-icon>
|
||||
<span>评价</span>
|
||||
</div>
|
||||
<div class="action-btn delete" v-if="row.canRevoke" @click="onRevoke(row)">
|
||||
<i class="fa fa-reply"></i>
|
||||
<van-icon class="proposal-action-icon" name="revoke"></van-icon>
|
||||
<span>撤回</span>
|
||||
</div>
|
||||
</template>
|
||||
@@ -320,11 +323,15 @@ layout("/layouts/platform_h5.html"){
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<proposal-task-popup ref="taskPopup" kind="feedbackEvaluation" page-key="proposal-feedback-task" @success="doSearch"></proposal-task-popup>
|
||||
</div>
|
||||
<script nonce="${cspNonce!}">
|
||||
<!--#include("../../common/info.js"){}#-->
|
||||
<!--#include("../../common/task-popup.js"){}#-->
|
||||
const vue = new Vue({
|
||||
el: "#app",
|
||||
store,
|
||||
components: {"proposal-task-popup": PROPOSAL_TASK_POPUP},
|
||||
data() {
|
||||
return {
|
||||
pageForm: {
|
||||
@@ -344,16 +351,10 @@ layout("/layouts/platform_h5.html"){
|
||||
{text: "未评价", value: "0"},
|
||||
{text: "已评价", value: "1"}
|
||||
],
|
||||
pendingListCache: null
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onReady() {
|
||||
if (this.pendingListCache) {
|
||||
this.restoreListCache()
|
||||
this.listSession(true)
|
||||
return
|
||||
}
|
||||
this.listSession(false)
|
||||
},
|
||||
|
||||
@@ -378,255 +379,11 @@ layout("/layouts/platform_h5.html"){
|
||||
},
|
||||
|
||||
onView(row, index) {
|
||||
this.saveListCache(row, index)
|
||||
this.$pjaxReplace("/platform/proposal/feedbackEvaluation/info/h5?bizId=" + encodeURIComponent(row.id) + "&action=view")
|
||||
this.$refs.taskPopup.open(row, "view")
|
||||
},
|
||||
|
||||
onApproval(row, index) {
|
||||
this.saveListCache(row, index)
|
||||
const params = new URLSearchParams()
|
||||
params.set("bizId", row.id)
|
||||
params.set("action", "approval")
|
||||
params.set("taskId", row.taskId)
|
||||
params.set("taskName", row.curTaskName || "反馈评价")
|
||||
params.set("instanceId", row.instanceId)
|
||||
this.$pjaxReplace("/platform/proposal/feedbackEvaluation/info/h5?" + params.toString())
|
||||
},
|
||||
|
||||
getListCacheKey() {
|
||||
return "proposal:feedback-evaluation:h5:list-state"
|
||||
},
|
||||
|
||||
getListCacheTokenParam() {
|
||||
return "feedbackEvaluationListCacheToken"
|
||||
},
|
||||
|
||||
getCurrentListCacheToken() {
|
||||
return new URLSearchParams(window.location.search).get(this.getListCacheTokenParam()) || ""
|
||||
},
|
||||
|
||||
/**
|
||||
* 将反馈评价列表缓存标识绑定到当前历史记录。
|
||||
* PJAX 返回时仅恢复当前历史记录对应的筛选条件、分页数据和滚动快照。
|
||||
*/
|
||||
bindListCacheToken(token) {
|
||||
const currentUrl = new URL(window.location.href)
|
||||
currentUrl.searchParams.set(this.getListCacheTokenParam(), token)
|
||||
const currentState = window.history.state ? {...window.history.state} : null
|
||||
if (currentState && currentState.url) {
|
||||
currentState.url = currentUrl.toString()
|
||||
}
|
||||
window.history.replaceState(currentState, document.title, currentUrl.toString())
|
||||
if ($.pjax && $.pjax.state) {
|
||||
$.pjax.state.url = currentUrl.toString()
|
||||
}
|
||||
},
|
||||
|
||||
// 用户主动搜索、切换届次或评价状态时使旧返回缓存失效。
|
||||
clearListCache() {
|
||||
const token = this.getCurrentListCacheToken()
|
||||
if (!token) return
|
||||
const currentUrl = new URL(window.location.href)
|
||||
currentUrl.searchParams.delete(this.getListCacheTokenParam())
|
||||
const currentState = window.history.state ? {...window.history.state} : null
|
||||
if (currentState && currentState.url) {
|
||||
currentState.url = currentUrl.toString()
|
||||
}
|
||||
window.history.replaceState(currentState, document.title, currentUrl.toString())
|
||||
if ($.pjax && $.pjax.state) {
|
||||
$.pjax.state.url = currentUrl.toString()
|
||||
}
|
||||
sessionStorage.removeItem(this.getListCacheKey())
|
||||
},
|
||||
|
||||
// platform_h5 的实际滚动区域是 page-wrapper,列表位置必须基于该容器保存和恢复。
|
||||
getListScrollContainer() {
|
||||
return document.querySelector(".page-wrapper") || document.scrollingElement || document.documentElement
|
||||
},
|
||||
|
||||
/**
|
||||
* 进入查看或评价详情前保存列表现场。
|
||||
* row 为当前反馈任务,index 为已加载列表索引;任务和相邻锚点统一使用唯一 taskId。
|
||||
*/
|
||||
saveListCache(row, index) {
|
||||
const tableList = this.$refs.tableListRef
|
||||
if (!tableList) return
|
||||
const cacheToken = Date.now() + "-" + Math.random().toString(36).slice(2)
|
||||
const tableState = typeof tableList.getListState === "function"
|
||||
? tableList.getListState()
|
||||
: {
|
||||
tableData: JSON.parse(JSON.stringify(tableList.tableData || [])),
|
||||
localPageForm: JSON.parse(JSON.stringify(tableList.localPageForm || this.pageForm)),
|
||||
tableFinished: !!tableList.tableFinished
|
||||
}
|
||||
const cards = document.querySelectorAll(".proposal-feedback-evaluation-list .table-list-item")
|
||||
const currentCard = cards[index]
|
||||
const scrollContainer = this.getListScrollContainer()
|
||||
const cache = {
|
||||
time: Date.now(),
|
||||
token: cacheToken,
|
||||
pageForm: JSON.parse(JSON.stringify(this.pageForm)),
|
||||
tableState: tableState,
|
||||
completedTaskId: "",
|
||||
anchor: {
|
||||
taskId: row.taskId,
|
||||
previousTaskId: index > 0 && tableState.tableData[index - 1]
|
||||
? tableState.tableData[index - 1].taskId
|
||||
: "",
|
||||
nextTaskId: tableState.tableData[index + 1] ? tableState.tableData[index + 1].taskId : "",
|
||||
viewportTop: currentCard ? currentCard.getBoundingClientRect().top : 0,
|
||||
scrollTop: scrollContainer ? scrollContainer.scrollTop : 0
|
||||
}
|
||||
}
|
||||
try {
|
||||
sessionStorage.setItem(this.getListCacheKey(), JSON.stringify(cache))
|
||||
this.bindListCacheToken(cacheToken)
|
||||
} catch (error) {
|
||||
sessionStorage.removeItem(this.getListCacheKey())
|
||||
}
|
||||
},
|
||||
|
||||
// 仅恢复当前历史记录对应且十分钟内有效的反馈评价列表缓存。
|
||||
prepareListCache() {
|
||||
try {
|
||||
const cacheToken = this.getCurrentListCacheToken()
|
||||
if (!cacheToken) return
|
||||
const cacheText = sessionStorage.getItem(this.getListCacheKey())
|
||||
if (!cacheText) return
|
||||
const cache = JSON.parse(cacheText)
|
||||
if (!cache || cache.token !== cacheToken || !cache.tableState) return
|
||||
if (Date.now() - cache.time > 10 * 60 * 1000) {
|
||||
this.clearListCache()
|
||||
return
|
||||
}
|
||||
Object.keys(cache.pageForm || {}).forEach((key) => {
|
||||
this.$set(this.pageForm, key, cache.pageForm[key])
|
||||
})
|
||||
this.$set(this, "pendingListCache", cache)
|
||||
} catch (error) {
|
||||
sessionStorage.removeItem(this.getListCacheKey())
|
||||
}
|
||||
},
|
||||
|
||||
// 普通查看返回恢复旧快照;评价完成返回重新查询,避免未评价列表继续显示已处理任务。
|
||||
restoreListCache() {
|
||||
const cache = this.pendingListCache
|
||||
const tableList = this.$refs.tableListRef
|
||||
if (!cache || !tableList) return
|
||||
const anchor = cache.anchor || {}
|
||||
if (cache.completedTaskId) {
|
||||
this.refreshCompletedListCache(cache)
|
||||
return
|
||||
}
|
||||
this.applyListCache(cache.tableState, anchor.taskId, anchor)
|
||||
},
|
||||
|
||||
/**
|
||||
* 按离开前已加载页数重新获取评价后的列表。
|
||||
* 返回值转换为 TableList 状态,并优先定位下一任务,没有下一任务时定位上一任务。
|
||||
*/
|
||||
refreshCompletedListCache(cache) {
|
||||
const originalPageSize = Number(cache.pageForm.pageSize || 10)
|
||||
const loadedCount = Math.max(cache.tableState.tableData.length, originalPageSize)
|
||||
const loadedPageCount = Math.max(1, Math.ceil(loadedCount / originalPageSize))
|
||||
const requestForm = {
|
||||
...cache.pageForm,
|
||||
pageNumber: 1,
|
||||
pageSize: loadedPageCount * originalPageSize
|
||||
}
|
||||
const loading = createListLoading()
|
||||
this.$axios.post("/platform/proposal/feedbackEvaluation/pageData", requestForm, {h5SkeletonLoading: true})
|
||||
.then((res) => {
|
||||
if (res.code !== 0) {
|
||||
this.applyCompletedCacheFallback(cache)
|
||||
return
|
||||
}
|
||||
const freshState = {
|
||||
tableData: res.data.list || [],
|
||||
localPageForm: {
|
||||
...cache.pageForm,
|
||||
pageNumber: loadedPageCount,
|
||||
pageSize: originalPageSize,
|
||||
totalCount: res.data.totalCount
|
||||
},
|
||||
tableFinished: (res.data.list || []).length >= res.data.totalCount
|
||||
}
|
||||
const anchor = cache.anchor || {}
|
||||
this.applyListCache(freshState, anchor.nextTaskId || anchor.previousTaskId, anchor)
|
||||
})
|
||||
.catch(() => {
|
||||
this.applyCompletedCacheFallback(cache)
|
||||
})
|
||||
.finally(() => {
|
||||
loading.close()
|
||||
})
|
||||
},
|
||||
|
||||
// 评价后刷新失败时只处理已完成 taskId,避免误改同一提案的其他流程记录。
|
||||
applyCompletedCacheFallback(cache) {
|
||||
const tableState = cache.tableState
|
||||
const completedIndex = tableState.tableData.findIndex((item) => String(item.taskId) === String(cache.completedTaskId))
|
||||
if (completedIndex >= 0 && cache.pageForm.approval === false) {
|
||||
tableState.tableData.splice(completedIndex, 1)
|
||||
if (tableState.localPageForm && tableState.localPageForm.totalCount > 0) {
|
||||
tableState.localPageForm.totalCount--
|
||||
}
|
||||
} else if (completedIndex >= 0) {
|
||||
this.$set(tableState.tableData[completedIndex], "taskState", 20)
|
||||
}
|
||||
const anchor = cache.anchor || {}
|
||||
this.applyListCache(tableState, anchor.nextTaskId || anchor.previousTaskId, anchor)
|
||||
},
|
||||
|
||||
/**
|
||||
* 恢复 TableList 数据并将目标任务卡片放回离开页面前的视口位置。
|
||||
* sticky 吸顶会改变一次布局,因此首次滚动后再执行一次位置校正。
|
||||
*/
|
||||
applyListCache(tableState, targetTaskId, anchor) {
|
||||
const tableList = this.$refs.tableListRef
|
||||
if (!tableList) return
|
||||
if (typeof tableList.restoreListState === "function") {
|
||||
if (!tableList.restoreListState(tableState)) return
|
||||
} else {
|
||||
this.$set(tableList, "tableData", tableState.tableData || [])
|
||||
this.$set(tableList, "localPageForm", {...tableList.localPageForm, ...(tableState.localPageForm || {})})
|
||||
this.$set(tableList, "tableFinished", !!tableState.tableFinished)
|
||||
this.$set(tableList, "tableLoading", false)
|
||||
this.$set(tableList, "tableRefreshing", false)
|
||||
tableList.$emit("update:page_form", {...tableList.localPageForm})
|
||||
}
|
||||
this.$set(this, "pendingListCache", null)
|
||||
this.$nextTick(() => {
|
||||
setTimeout(() => {
|
||||
const cards = Array.from(document.querySelectorAll(".proposal-feedback-evaluation-list .table-list-item"))
|
||||
const scrollContainer = this.getListScrollContainer()
|
||||
if (!scrollContainer) return
|
||||
const candidateTaskIds = [targetTaskId, anchor.nextTaskId, anchor.previousTaskId]
|
||||
.filter((taskId) => taskId)
|
||||
.map((taskId) => String(taskId))
|
||||
.filter((taskId, index, values) => values.indexOf(taskId) === index)
|
||||
let targetIndex = -1
|
||||
candidateTaskIds.some((candidateTaskId) => {
|
||||
targetIndex = (tableState.tableData || [])
|
||||
.findIndex((item) => String(item.taskId) === candidateTaskId)
|
||||
return targetIndex >= 0
|
||||
})
|
||||
const targetCard = targetIndex >= 0 ? cards[targetIndex] : null
|
||||
if (targetCard) {
|
||||
const restoreTargetCard = () => {
|
||||
if (!targetCard.isConnected) return
|
||||
const targetTop = scrollContainer.scrollTop
|
||||
+ targetCard.getBoundingClientRect().top
|
||||
- Number(anchor.viewportTop || 0)
|
||||
scrollContainer.scrollTo(0, Math.max(0, targetTop))
|
||||
}
|
||||
restoreTargetCard()
|
||||
setTimeout(restoreTargetCard, 100)
|
||||
return
|
||||
}
|
||||
scrollContainer.scrollTo(0, Number(anchor.scrollTop || 0))
|
||||
}, 0)
|
||||
})
|
||||
this.$refs.taskPopup.open(row, "approval")
|
||||
},
|
||||
|
||||
onRevoke(row) {
|
||||
@@ -644,17 +401,14 @@ layout("/layouts/platform_h5.html"){
|
||||
},
|
||||
|
||||
doSearch() {
|
||||
this.clearListCache()
|
||||
this.$nextTick(() => {
|
||||
this.pageForm.pageNumber = 1
|
||||
this.pageForm.totalCount = 0
|
||||
this.$set(this.pageForm, "pageNumber", 1)
|
||||
this.$set(this.pageForm, "totalCount", 0)
|
||||
this.$refs.tableListRef.doSearch()
|
||||
})
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.prepareListCache()
|
||||
if (this.pendingListCache) return
|
||||
const tab = new URLSearchParams(window.location.search).get("tab")
|
||||
if (tab === "done") {
|
||||
this.$set(this.pageForm, "approval", true)
|
||||
|
||||
-187
@@ -1,187 +0,0 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_h5.html"){
|
||||
#-->
|
||||
<style id="style-proposal-info-h5">
|
||||
<!--#include("../../common/info.css"){}#-->
|
||||
</style>
|
||||
<div id="app" v-cloak>
|
||||
<van-nav-bar @click-left="historyBack" left-arrow left-text="返回" :title="pageTitle" placeholder fixed></van-nav-bar>
|
||||
<proposal-info v-if="bizId" :biz-id="bizId">
|
||||
<div v-if="isApproval">
|
||||
<div class="process-title">{{formData.taskName}}</div>
|
||||
<van-form ref="formRef">
|
||||
<van-field
|
||||
v-model="formData.tf_feedback_name"
|
||||
name="tf_feedback_name"
|
||||
label="满意度"
|
||||
placeholder="请选择满意度"
|
||||
:rules="[{ required: true, message: '请选择满意度' }]"
|
||||
required
|
||||
is-link
|
||||
@click="showFeedBackPicker = true"
|
||||
></van-field>
|
||||
<van-popup v-model="showFeedBackPicker" position="bottom">
|
||||
<van-picker
|
||||
show-toolbar
|
||||
:columns="dict.type.PROPOSAL_FEEDBACK.map(item => ({text: item.label, value: item.code}))"
|
||||
@confirm="onFeedBackConfirm"
|
||||
@cancel="showFeedBackPicker = false"
|
||||
></van-picker>
|
||||
</van-popup>
|
||||
<van-field
|
||||
v-model="formData.tf_opinion"
|
||||
name="tf_opinion"
|
||||
label="审批意见"
|
||||
placeholder="请输入审批意见"
|
||||
:rules="[{ required: true, message: '请填写审批意见' }]"
|
||||
required
|
||||
maxlength="100"
|
||||
show-word-limit
|
||||
></van-field>
|
||||
<!-- <template v-if="['SATISFIED','FAIRLY_SATISFIED'].includes(formData.tf_feedback)">
|
||||
<van-field
|
||||
v-model="formData.tf_address"
|
||||
name="tf_address"
|
||||
label="通讯地址"
|
||||
placeholder="请输入通讯地址"
|
||||
:rules="[{ required: true, message: '请输入通讯地址' }]"
|
||||
required
|
||||
></van-field>
|
||||
<van-field
|
||||
v-model="formData.tf_phone"
|
||||
name="tf_phone"
|
||||
label="联系电话"
|
||||
placeholder="请输入联系电话"
|
||||
:rules="[{ required: true, message: '请输入联系电话' }]"
|
||||
required
|
||||
></van-field>
|
||||
<van-field
|
||||
v-model="formData.tf_postcode"
|
||||
name="tf_postcode"
|
||||
label="邮政编码"
|
||||
placeholder="请输入邮政编码"
|
||||
:rules="[{ required: true, message: '请输入邮政编码' }]"
|
||||
required
|
||||
></van-field>
|
||||
</template>-->
|
||||
</van-form>
|
||||
<div style="display: flex; justify-content: space-between; column-gap: 10px; padding: 10px">
|
||||
<van-button type="danger" block :disabled="formLoading" @click="historyBack">取消</van-button>
|
||||
<van-button type="primary" block :loading="formLoading" @click="handleTaskAction">提交</van-button>
|
||||
</div>
|
||||
</div>
|
||||
</proposal-info>
|
||||
</div>
|
||||
<script nonce="${cspNonce!}">
|
||||
<!--#include("../../common/info.js"){}#-->
|
||||
|
||||
new Vue({
|
||||
el: "#app",
|
||||
store,
|
||||
dicts: ["PROPOSAL_FEEDBACK"],
|
||||
components: {
|
||||
"proposal-info": PROPOSAL_INFO
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
bizId: "",
|
||||
action: "view",
|
||||
formData: {},
|
||||
formLoading: false,
|
||||
showFeedBackPicker: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isApproval() {
|
||||
return this.action === "approval"
|
||||
},
|
||||
pageTitle() {
|
||||
return this.isApproval ? "反馈评价" : "提案详情"
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onFeedBackConfirm(value) {
|
||||
this.$set(this.formData, "tf_feedback_name", value.text)
|
||||
this.$set(this.formData, "tf_feedback", value.value)
|
||||
this.showFeedBackPicker = false
|
||||
},
|
||||
/**
|
||||
* 提交反馈评价;不满意时先用 instanceId 查询立案主办单位,再提交完整 WF 表单数据。
|
||||
* 两个接口均返回 Result,code 为 0 表示成功。
|
||||
*/
|
||||
handleTaskAction() {
|
||||
this.$refs.formRef.validate()
|
||||
.then(() => this.$dialog.confirm({title: "提示", message: "您确定要提交吗?"}))
|
||||
.then(() => {
|
||||
this.formLoading = true
|
||||
const submitData = {...this.formData, submitType: 1}
|
||||
if (this.formData.tf_feedback !== "DISSATISFIED") {
|
||||
return submitData
|
||||
}
|
||||
return this.$axios.post("/platform/proposal/feedbackEvaluation/caseInfo", {
|
||||
instId: this.formData.instanceId
|
||||
}).then((res) => {
|
||||
if (res.code !== 0) {
|
||||
return Promise.reject(new Error(res.msg || "查询立案信息失败"))
|
||||
}
|
||||
submitData.tf_masterUnitId = res.data.tf_masterUnitId
|
||||
return submitData
|
||||
})
|
||||
})
|
||||
.then((submitData) => this.$axios.post("/flow/common/executeTask", {
|
||||
data: JSON.stringify(submitData)
|
||||
}))
|
||||
.then((res) => {
|
||||
if (res && res.code === 0) {
|
||||
this.markListCacheCompleted()
|
||||
this.$toast.success(res.msg)
|
||||
this.historyBack()
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
if (error && error.message && error.message !== "cancel") {
|
||||
this.$toast.fail(error.message)
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
this.formLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 评价成功后记录已处理 WF 任务主键。
|
||||
* 返回列表时按原筛选和已加载范围刷新数据,并定位到相邻评价任务。
|
||||
*/
|
||||
markListCacheCompleted() {
|
||||
const cacheKey = "proposal:feedback-evaluation:h5:list-state"
|
||||
try {
|
||||
const cacheText = sessionStorage.getItem(cacheKey)
|
||||
if (!cacheText) return
|
||||
const cache = JSON.parse(cacheText)
|
||||
cache.completedTaskId = this.formData.processTaskId || ""
|
||||
cache.time = Date.now()
|
||||
sessionStorage.setItem(cacheKey, JSON.stringify(cache))
|
||||
} catch (error) {
|
||||
sessionStorage.removeItem(cacheKey)
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
const params = new URLSearchParams(window.location.search)
|
||||
// bizId 用于详情查询,taskId、taskName、instanceId 用于反馈评价的 WF 提交与立案信息查询。
|
||||
this.bizId = params.get("bizId") || ""
|
||||
this.action = params.get("action") || "view"
|
||||
if (this.isApproval) {
|
||||
this.$set(this.formData, "processTaskId", params.get("taskId") || "")
|
||||
this.$set(this.formData, "taskName", params.get("taskName") || "反馈评价")
|
||||
this.$set(this.formData, "instanceId", params.get("instanceId") || "")
|
||||
}
|
||||
if (!this.bizId) {
|
||||
this.$toast.fail("缺少提案参数")
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
+161
-10
@@ -2,6 +2,8 @@
|
||||
layout("/layouts/platform_h5.html"){
|
||||
#-->
|
||||
<style>
|
||||
<!--#include("../../common/info.css"){}#-->
|
||||
|
||||
body {
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
@@ -28,6 +30,51 @@ layout("/layouts/platform_h5.html"){
|
||||
color: #1989fa;
|
||||
}
|
||||
|
||||
.proposal-mine-popup {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
|
||||
.proposal-mine-popup .van-nav-bar {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.proposal-mine-popup .van-nav-bar .van-icon,
|
||||
.proposal-mine-popup .van-nav-bar__text {
|
||||
color: #1989fa;
|
||||
}
|
||||
|
||||
/* 详情弹框复用项目全屏 Popup 的固定导航结构,内容区域单独滚动。 */
|
||||
.proposal-detail-popup {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.proposal-detail-popup-page {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
padding-top: 46px;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.proposal-detail-popup-page .van-nav-bar {
|
||||
z-index: 20;
|
||||
}
|
||||
|
||||
.proposal-detail-scroll {
|
||||
min-height: 0;
|
||||
overflow-y: auto;
|
||||
flex: 1;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
.proposal-detail-scroll .proposal-view-main {
|
||||
padding-top: 18px;
|
||||
}
|
||||
|
||||
.proposal-mine-content {
|
||||
padding: 0 12px;
|
||||
}
|
||||
@@ -257,6 +304,11 @@ layout("/layouts/platform_h5.html"){
|
||||
background-color: #eaf4ff;
|
||||
}
|
||||
|
||||
.proposal-mine-page .table-list-container .table-list-item .action-btn .van-icon {
|
||||
margin-right: 6px;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
@media (max-width: 350px) {
|
||||
.proposal-mine-content {
|
||||
padding-right: 10px;
|
||||
@@ -271,7 +323,7 @@ layout("/layouts/platform_h5.html"){
|
||||
</style>
|
||||
<div id="app" v-cloak>
|
||||
<div class="proposal-mine-page">
|
||||
<van-nav-bar @click-left="historyBack" left-arrow left-text="返回" title="我的提案" placeholder fixed></van-nav-bar>
|
||||
<van-nav-bar @click-left="handlePageBack" left-arrow left-text="返回" title="我的提案" placeholder fixed></van-nav-bar>
|
||||
|
||||
<van-sticky :offset-top="46">
|
||||
<div class="proposal-mine-sticky">
|
||||
@@ -338,27 +390,27 @@ layout("/layouts/platform_h5.html"){
|
||||
</template>
|
||||
<template #actions="{index,row}">
|
||||
<div class="action-btn" @click="onView(row)">
|
||||
<i class="fa fa-eye"></i>
|
||||
<van-icon name="eye-o"></van-icon>
|
||||
<span>查看</span>
|
||||
</div>
|
||||
<div class="action-btn" v-if="row.taskKey === 'startTask' || !row.instanceId"
|
||||
@click="onEdit(row)">
|
||||
<i class="fa fa-edit"></i>
|
||||
<van-icon class="proposal-action-icon" name="edit"></van-icon>
|
||||
<span>编辑</span>
|
||||
</div>
|
||||
<div class="action-btn"
|
||||
v-if="row.taskKey === 'invite' || row.taskKey === 'second'"
|
||||
@click="onInvite(row)">
|
||||
<i class="fa fa-user-plus"></i>
|
||||
<van-icon class="proposal-action-icon" name="friends-o"></van-icon>
|
||||
<span>邀请附议人</span>
|
||||
</div>
|
||||
<div class="action-btn delete" v-if="row.canRevoke" @click="onRevoke(row)">
|
||||
<i class="fa fa-undo"></i>
|
||||
<van-icon class="proposal-action-icon" name="revoke"></van-icon>
|
||||
<span>撤回</span>
|
||||
</div>
|
||||
<div class="action-btn delete" v-if="row.taskKey === 'startTask' || !row.instanceId"
|
||||
@click="onDelete(row)">
|
||||
<i class="fa fa-trash"></i>
|
||||
<van-icon class="proposal-action-icon" name="delete-o"></van-icon>
|
||||
<span>删除</span>
|
||||
</div>
|
||||
</template>
|
||||
@@ -366,18 +418,49 @@ layout("/layouts/platform_h5.html"){
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<invite-seconder @refresh="doSearch" ref="inviteSeconderRef"></invite-seconder>
|
||||
<van-popup
|
||||
v-model="detailVisible"
|
||||
class="proposal-mine-popup proposal-detail-popup"
|
||||
position="right"
|
||||
:close-on-click-overlay="false"
|
||||
safe-area-inset-bottom>
|
||||
<div class="proposal-detail-popup-page">
|
||||
<van-nav-bar
|
||||
title="提案详情"
|
||||
left-arrow
|
||||
left-text="返回"
|
||||
fixed
|
||||
@click-left="closeHistoryLayer('detail')">
|
||||
</van-nav-bar>
|
||||
<div class="proposal-detail-scroll">
|
||||
<proposal-info v-if="detailVisible && detailBizId" :biz-id="detailBizId" :visible="detailVisible"></proposal-info>
|
||||
</div>
|
||||
</div>
|
||||
</van-popup>
|
||||
|
||||
<invite-seconder
|
||||
:visible="inviteVisible"
|
||||
:confirm-visible="inviteConfirmVisible"
|
||||
@close="closeHistoryLayer('invite')"
|
||||
@open-confirm="openHistoryLayer('invite-confirm')"
|
||||
@close-confirm="closeHistoryLayer('invite-confirm')"
|
||||
@confirm-invite="confirmInvite"
|
||||
@refresh="doSearch"
|
||||
ref="inviteSeconderRef">
|
||||
</invite-seconder>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<script nonce="${cspNonce!}">
|
||||
<!--#include("../../common/info.js"){}#-->
|
||||
<!--#include("inviteSeconder.js"){}#-->
|
||||
|
||||
const vue = new Vue({
|
||||
el: "#app",
|
||||
store,
|
||||
components: {
|
||||
"proposal-info": PROPOSAL_INFO,
|
||||
"invite-seconder": PROPOSAL_INVITE_SECONDER_COMPONENT
|
||||
},
|
||||
data() {
|
||||
@@ -393,10 +476,61 @@ layout("/layouts/platform_h5.html"){
|
||||
},
|
||||
|
||||
sessionOptions: [],
|
||||
filterOpened: false
|
||||
filterOpened: false,
|
||||
detailVisible: false,
|
||||
detailBizId: "",
|
||||
inviteVisible: false,
|
||||
inviteConfirmVisible: false,
|
||||
historyLayerPageKey: "proposal-mine-h5"
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* 注册“我的提案”页面弹层历史。
|
||||
* pageKey 使用固定页面标识;回调参数 stack 为当前弹层名称数组,无返回值。
|
||||
*/
|
||||
registerHistoryLayers() {
|
||||
if (!window.h5HistoryLayerManager) return
|
||||
window.h5HistoryLayerManager.register(this.historyLayerPageKey, (stack) => {
|
||||
this.syncHistoryLayerStack(stack)
|
||||
})
|
||||
},
|
||||
|
||||
// 根据浏览器历史栈同步详情、邀请附议和邀请确认弹层的显示状态。
|
||||
syncHistoryLayerStack(stack) {
|
||||
this.$set(this, "detailVisible", stack.includes("detail"))
|
||||
this.$set(this, "inviteVisible", stack.includes("invite"))
|
||||
this.$set(this, "inviteConfirmVisible", stack.includes("invite-confirm"))
|
||||
},
|
||||
|
||||
// 打开弹层时同步增加当前地址的浏览器历史记录。
|
||||
openHistoryLayer(layerName) {
|
||||
if (window.h5HistoryLayerManager && window.h5HistoryLayerManager.open(layerName)) return
|
||||
this.setHistoryLayerVisible(layerName, true)
|
||||
},
|
||||
|
||||
// 主动关闭弹层时回退对应历史记录,afterClose 在历史状态同步后执行。
|
||||
closeHistoryLayer(layerName, afterClose = null) {
|
||||
if (window.h5HistoryLayerManager && window.h5HistoryLayerManager.close(layerName, afterClose)) return
|
||||
this.setHistoryLayerVisible(layerName, false)
|
||||
if (typeof afterClose === "function") afterClose()
|
||||
},
|
||||
|
||||
setHistoryLayerVisible(layerName, visible) {
|
||||
if (layerName === "detail") this.$set(this, "detailVisible", visible)
|
||||
if (layerName === "invite") this.$set(this, "inviteVisible", visible)
|
||||
if (layerName === "invite-confirm") this.$set(this, "inviteConfirmVisible", visible)
|
||||
},
|
||||
|
||||
// 页面返回时优先关闭最上层弹框,没有弹框时再返回上一业务页面。
|
||||
handlePageBack() {
|
||||
if (window.h5HistoryLayerManager && window.h5HistoryLayerManager.stack.length) {
|
||||
window.h5HistoryLayerManager.close()
|
||||
return
|
||||
}
|
||||
this.historyBack()
|
||||
},
|
||||
|
||||
listSession() {
|
||||
this.$axios.post("/platform/proposal/common/listSession").then((res) => {
|
||||
if (res.code === 0) {
|
||||
@@ -413,7 +547,8 @@ layout("/layouts/platform_h5.html"){
|
||||
},
|
||||
|
||||
onView(row) {
|
||||
this.$pjaxReplace("/platform/proposal/mine/info/h5?bizId=" + encodeURIComponent(row.id))
|
||||
this.$set(this, "detailBizId", row.id)
|
||||
this.openHistoryLayer("detail")
|
||||
},
|
||||
|
||||
onEdit(row) {
|
||||
@@ -463,14 +598,30 @@ layout("/layouts/platform_h5.html"){
|
||||
onInvite(row) {
|
||||
this.$axios.post("/platform/proposal/mine/inviteCheck", {id: row.id}).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.$refs.inviteSeconderRef.onOpen(row)
|
||||
this.$refs.inviteSeconderRef.prepare(row)
|
||||
this.openHistoryLayer("invite")
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 邀请确认后先关闭确认层,再提交邀请,避免浏览器历史中残留已关闭的 Dialog。
|
||||
confirmInvite() {
|
||||
this.closeHistoryLayer("invite-confirm", () => {
|
||||
this.$refs.inviteSeconderRef.submitInvite()
|
||||
})
|
||||
},
|
||||
|
||||
onReady() {
|
||||
this.listSession()
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.registerHistoryLayers()
|
||||
},
|
||||
beforeDestroy() {
|
||||
if (window.h5HistoryLayerManager) {
|
||||
window.h5HistoryLayerManager.unregister(this.historyLayerPageKey)
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_h5.html"){
|
||||
#-->
|
||||
<style id="style-proposal-info-h5">
|
||||
<!--#include("../../common/info.css"){}#-->
|
||||
</style>
|
||||
<div id="app" v-cloak>
|
||||
<van-nav-bar @click-left="historyBack" left-arrow left-text="返回" title="提案详情" placeholder fixed></van-nav-bar>
|
||||
<proposal-info v-if="bizId" :biz-id="bizId"></proposal-info>
|
||||
</div>
|
||||
<script nonce="${cspNonce!}">
|
||||
<!--#include("../../common/info.js"){}#-->
|
||||
|
||||
new Vue({
|
||||
el: "#app",
|
||||
store,
|
||||
components: {
|
||||
"proposal-info": PROPOSAL_INFO
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
bizId: ""
|
||||
}
|
||||
},
|
||||
created() {
|
||||
// bizId 为提案主键,公共详情组件根据该参数返回提案详情对象和流程记录数组。
|
||||
this.bizId = new URLSearchParams(window.location.search).get("bizId") || ""
|
||||
if (!this.bizId) {
|
||||
this.$toast.fail("缺少提案参数")
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
+166
-108
@@ -1,62 +1,101 @@
|
||||
const PROPOSAL_INVITE_SECONDER_COMPONENT = {
|
||||
template: `
|
||||
<van-action-sheet v-model="visible" title="邀请附议人" class="height100">
|
||||
<van-search
|
||||
v-model="pageForm.searchKeyword"
|
||||
:show-action="false"
|
||||
placeholder="请输入工号或者姓名查询"
|
||||
@search="doSearch"
|
||||
></van-search>
|
||||
<van-tabs v-model="isInvite" @click="isInviteClick">
|
||||
<van-tab title="已邀请" name="1"></van-tab>
|
||||
<van-tab title="可邀请" name="0"></van-tab>
|
||||
</van-tabs>
|
||||
|
||||
<van-checkbox-group v-model="tableSelection" v-if="tableData && tableData.length>0">
|
||||
<van-cell-group >
|
||||
<van-cell
|
||||
v-for="(item, index) in tableData"
|
||||
clickable
|
||||
:key="item.loginName"
|
||||
@click="tableRowToggle(index)"
|
||||
>
|
||||
<span slot="title">
|
||||
{{item.userName}}
|
||||
({{item.loginName}})
|
||||
</span>
|
||||
<span slot="label" class="font-size0 van-color-text-assist">
|
||||
{{item.unitName}}
|
||||
</span>
|
||||
<van-checkbox
|
||||
:name="item"
|
||||
:ref="'checkboxes'+item.loginName"
|
||||
slot="right-icon"
|
||||
v-if="!pageForm.isInvite"></van-checkbox>
|
||||
</van-cell>
|
||||
</van-cell-group>
|
||||
<div class="p10">
|
||||
<van-pagination
|
||||
v-model="pageForm.pageNumber"
|
||||
:total-items="pageForm.totalCount"
|
||||
:items-per-page="pageForm.pageSize"
|
||||
@change="pageData"
|
||||
></van-pagination>
|
||||
<van-button @click="invite" type="primary" block :disabled="pageForm.isInvite" class="mt10">邀请</van-button>
|
||||
</div>
|
||||
</van-checkbox-group>
|
||||
<!-- 空状态提示随“已邀请 / 可邀请”标签切换,便于用户判断当前无数据的具体范围。 -->
|
||||
<div v-else class="proposal-invite-empty">
|
||||
<img src="/assets/mobile/img/proposal/proposal-empty.png" alt="暂无附议人插画">
|
||||
<div class="proposal-invite-empty__title">暂无附议人</div>
|
||||
<div class="proposal-invite-empty__hint">
|
||||
{{ isInvite === "1" ? "当前暂无已邀请的附议人" : "当前暂无可邀请的附议人" }}
|
||||
</div>
|
||||
template: /*language=HTML*/ `
|
||||
<van-popup
|
||||
:value="visible"
|
||||
class="proposal-mine-popup proposal-invite-popup"
|
||||
position="right"
|
||||
:close-on-click-overlay="false"
|
||||
safe-area-inset-bottom>
|
||||
<van-nav-bar
|
||||
title="邀请附议人"
|
||||
left-arrow
|
||||
left-text="返回"
|
||||
fixed
|
||||
placeholder
|
||||
@click-left="$emit('close')">
|
||||
</van-nav-bar>
|
||||
|
||||
<van-search
|
||||
v-model="pageForm.searchKeyword"
|
||||
:show-action="false"
|
||||
placeholder="请输入工号或者姓名查询"
|
||||
@search="doSearch">
|
||||
</van-search>
|
||||
<van-tabs v-model="isInvite" @click="isInviteClick">
|
||||
<van-tab title="已邀请" name="1"></van-tab>
|
||||
<van-tab title="可邀请" name="0"></van-tab>
|
||||
</van-tabs>
|
||||
|
||||
<van-checkbox-group v-model="tableSelection" v-if="tableData && tableData.length > 0">
|
||||
<van-cell-group>
|
||||
<van-cell
|
||||
v-for="(item, index) in tableData"
|
||||
clickable
|
||||
:key="item.loginName"
|
||||
@click="tableRowToggle(index)">
|
||||
<span slot="title">
|
||||
{{item.userName}}({{item.loginName}})
|
||||
</span>
|
||||
<span slot="label" class="font-size0 van-color-text-assist">
|
||||
{{item.unitName}}
|
||||
</span>
|
||||
<van-checkbox
|
||||
:name="item"
|
||||
:ref="'checkboxes' + item.loginName"
|
||||
slot="right-icon"
|
||||
v-if="!pageForm.isInvite">
|
||||
</van-checkbox>
|
||||
</van-cell>
|
||||
</van-cell-group>
|
||||
<div class="p10">
|
||||
<van-pagination
|
||||
v-model="pageForm.pageNumber"
|
||||
:total-items="pageForm.totalCount"
|
||||
:items-per-page="pageForm.pageSize"
|
||||
@change="pageData">
|
||||
</van-pagination>
|
||||
<van-button
|
||||
@click="invite"
|
||||
type="primary"
|
||||
block
|
||||
:disabled="pageForm.isInvite"
|
||||
class="mt10">
|
||||
邀请
|
||||
</van-button>
|
||||
</div>
|
||||
</van-action-sheet>
|
||||
`,
|
||||
</van-checkbox-group>
|
||||
|
||||
<!-- 空状态提示随“已邀请 / 可邀请”标签切换,便于用户判断当前无数据的具体范围。 -->
|
||||
<div v-else class="proposal-invite-empty">
|
||||
<img src="/assets/mobile/img/proposal/proposal-empty.png" alt="暂无附议人插画">
|
||||
<div class="proposal-invite-empty__title">暂无附议人</div>
|
||||
<div class="proposal-invite-empty__hint">
|
||||
{{ isInvite === "1" ? "当前暂无已邀请的附议人" : "当前暂无可邀请的附议人" }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<van-dialog
|
||||
:value="confirmVisible"
|
||||
title="提示"
|
||||
:message="confirmMessage"
|
||||
show-cancel-button
|
||||
@confirm="$emit('confirm-invite')"
|
||||
@cancel="$emit('close-confirm')">
|
||||
</van-dialog>
|
||||
</van-popup>
|
||||
`,
|
||||
props: {
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
confirmVisible: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
visible: false,
|
||||
secondedNum: 0,
|
||||
record: {},
|
||||
tableData: [],
|
||||
@@ -71,72 +110,86 @@ const PROPOSAL_INVITE_SECONDER_COMPONENT = {
|
||||
},
|
||||
config: {},
|
||||
isInvite: "0",
|
||||
tableSelection: []
|
||||
tableSelection: [],
|
||||
confirmMessage: ""
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
visible(value) {
|
||||
if (!value || !this.record.id) return
|
||||
this.getConfig().then(() => {
|
||||
this.pageData()
|
||||
})
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async onOpen(record) {
|
||||
this.visible = true
|
||||
this.record = record
|
||||
await this.getConfig()
|
||||
this.pageData()
|
||||
|
||||
|
||||
},
|
||||
detail(id) {
|
||||
/**
|
||||
* 准备邀请附议弹框数据。
|
||||
* record 为列表当前提案对象,至少包含 id 和 sessionId;该方法只缓存提案并重置查询条件,无返回值。
|
||||
*/
|
||||
prepare(record) {
|
||||
this.$set(this, "record", record || {})
|
||||
this.$set(this, "isInvite", "0")
|
||||
this.$set(this, "tableSelection", [])
|
||||
this.$set(this.pageForm, "pageNumber", 1)
|
||||
this.$set(this.pageForm, "isInvite", false)
|
||||
this.$set(this.pageForm, "searchKeyword", null)
|
||||
},
|
||||
|
||||
// 校验勾选结果后打开确认 Dialog,实际提交在确认并回退 Dialog 历史层后执行。
|
||||
invite() {
|
||||
if (this.tableSelection.length === 0) {
|
||||
this.$toast("请先选择附议人后在点击邀请")
|
||||
this.$toast("请先选择附议人后再点击邀请")
|
||||
return
|
||||
}
|
||||
const userNames = [...new Set(this.tableSelection.map((item) => item.userName))]
|
||||
this.$set(this, "confirmMessage", "您确定要邀请" + userNames.join("、") + "代表附议吗?")
|
||||
this.$emit("open-confirm")
|
||||
},
|
||||
|
||||
const loginNames = [...new Set(this.tableSelection.map((s) => s.loginName))]
|
||||
const userName = [...new Set(this.tableSelection.map((s) => s.userName))]
|
||||
|
||||
console.log(this.tableSelection)
|
||||
|
||||
this.$dialog.confirm({
|
||||
title: '提示',
|
||||
message: "您确定要邀请" + userName.join("、") + "代表附议吗?",
|
||||
}).then(() => {
|
||||
this.$axios.post("/platform/proposal/mine/inviteSeconder", {
|
||||
proposalId: this.record.id,
|
||||
seconders: JSON.stringify(loginNames)
|
||||
}).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.pageData()
|
||||
this.$toast.success(res.msg)
|
||||
this.tableSelection = []
|
||||
// this.visible = false
|
||||
this.$emit("refresh", null)
|
||||
}
|
||||
})
|
||||
}).catch(() => {
|
||||
|
||||
/**
|
||||
* 提交邀请附议人。
|
||||
* 参数 proposalId 为当前提案主键,seconders 为已勾选人员工号数组;接口返回 Result,code 为 0 表示邀请成功。
|
||||
*/
|
||||
submitInvite() {
|
||||
const loginNames = [...new Set(this.tableSelection.map((item) => item.loginName))]
|
||||
this.$axios.post("/platform/proposal/mine/inviteSeconder", {
|
||||
proposalId: this.record.id,
|
||||
seconders: JSON.stringify(loginNames)
|
||||
}).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.pageData()
|
||||
this.$toast.success(res.msg)
|
||||
this.$set(this, "tableSelection", [])
|
||||
this.$emit("refresh")
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 查询邀请附议人列表。
|
||||
* 参数包含当前提案 ID、届次 ID、邀请状态、关键词及分页条件;返回分页对象并更新列表和总数。
|
||||
*/
|
||||
pageData() {
|
||||
this.$axios.post("/platform/proposal/mine/listSeconder", {
|
||||
...this.pageForm,
|
||||
sessionId: this.record.sessionId,
|
||||
proposalId: this.record.id
|
||||
}).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.$set(this, "tableData", res.data.list || [])
|
||||
this.$set(this.pageForm, "totalCount", res.data.totalCount || 0)
|
||||
this.echoCheckBox()
|
||||
}
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.tableData = res.data.list
|
||||
this.pageForm.totalCount = res.data.totalCount
|
||||
this.echoCheckBox()
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 翻页回显勾选
|
||||
// 翻页后回显当前已勾选的附议人。
|
||||
echoCheckBox() {
|
||||
this.$nextTick(() => {
|
||||
this.tableData.forEach((item) => {
|
||||
const checkboxRef = this.$refs['checkboxes' + item.loginName]
|
||||
if (checkboxRef && this.tableSelection.map((s) => s.loginName).includes(item.loginName)) {
|
||||
const checkboxRef = this.$refs["checkboxes" + item.loginName]
|
||||
if (checkboxRef && this.tableSelection.map((selected) => selected.loginName).includes(item.loginName)) {
|
||||
checkboxRef[0].toggle()
|
||||
}
|
||||
})
|
||||
@@ -144,24 +197,29 @@ const PROPOSAL_INVITE_SECONDER_COMPONENT = {
|
||||
},
|
||||
|
||||
doSearch() {
|
||||
this.pageForm.pageNumber = 1
|
||||
this.$set(this.pageForm, "pageNumber", 1)
|
||||
this.pageData()
|
||||
},
|
||||
|
||||
isInviteClick(index, title) {
|
||||
this.pageForm.isInvite = index === "1"
|
||||
isInviteClick(name) {
|
||||
this.$set(this.pageForm, "isInvite", name === "1")
|
||||
this.doSearch()
|
||||
},
|
||||
|
||||
tableRowToggle(index) {
|
||||
console.log(index)
|
||||
if (this.pageForm.isInvite || index < 0) return
|
||||
},
|
||||
|
||||
async getConfig() {
|
||||
const {code, data} = await this.$axios.post("/platform/proposal/common/config")
|
||||
if (code === 0) {
|
||||
this.config = data
|
||||
}
|
||||
/**
|
||||
* 查询提案附议配置。
|
||||
* 接口无业务参数,返回 ProposalConfig 配置对象;Promise 用于确保配置完成后再查询人员列表。
|
||||
*/
|
||||
getConfig() {
|
||||
return this.$axios.post("/platform/proposal/common/config").then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.$set(this, "config", res.data || {})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+14
-255
@@ -212,6 +212,9 @@ layout("/layouts/platform_h5.html"){
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style id="style-proposal-task-popup-h5">
|
||||
<!--#include("../../common/info.css"){}#-->
|
||||
</style>
|
||||
<div id="app" v-cloak>
|
||||
<div class="proposal-pre-audit-page">
|
||||
<van-nav-bar @click-left="historyBack" left-arrow left-text="返回" title="校工会预审核" placeholder fixed></van-nav-bar>
|
||||
@@ -287,15 +290,15 @@ layout("/layouts/platform_h5.html"){
|
||||
</template>
|
||||
<template #actions="{index,row}">
|
||||
<div class="action-btn" @click="onView(row,index)">
|
||||
<i class="fa fa-eye"></i>
|
||||
<van-icon class="proposal-action-icon" name="eye-o"></van-icon>
|
||||
<span>查看</span>
|
||||
</div>
|
||||
<div class="action-btn" v-if="row.taskState === 10" @click="onApproval(row,index)">
|
||||
<i class="fa fa-edit"></i>
|
||||
<van-icon class="proposal-action-icon" name="edit"></van-icon>
|
||||
<span>审核</span>
|
||||
</div>
|
||||
<div class="action-btn delete" v-if="row.canRevoke" @click="onRevoke(row)">
|
||||
<i class="fa fa-reply"></i>
|
||||
<van-icon class="proposal-action-icon" name="revoke"></van-icon>
|
||||
<span>撤回</span>
|
||||
</div>
|
||||
</template>
|
||||
@@ -303,11 +306,15 @@ layout("/layouts/platform_h5.html"){
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
<proposal-task-popup ref="taskPopup" kind="preAudit" page-key="proposal-pre-audit-task" @success="doSearch"></proposal-task-popup>
|
||||
</div>
|
||||
<script nonce="${cspNonce!}">
|
||||
<!--#include("../../common/info.js"){}#-->
|
||||
<!--#include("../../common/task-popup.js"){}#-->
|
||||
new Vue({
|
||||
el: "#app",
|
||||
store,
|
||||
components: {"proposal-task-popup": PROPOSAL_TASK_POPUP},
|
||||
data() {
|
||||
return {
|
||||
pageForm: {
|
||||
@@ -327,16 +334,10 @@ layout("/layouts/platform_h5.html"){
|
||||
{text: "未审核", value: "0"},
|
||||
{text: "已审核", value: "1"}
|
||||
],
|
||||
pendingListCache: null
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onReady() {
|
||||
if (this.pendingListCache) {
|
||||
this.restoreListCache()
|
||||
this.listSession(true)
|
||||
return
|
||||
}
|
||||
this.listSession(false)
|
||||
},
|
||||
|
||||
@@ -368,250 +369,11 @@ layout("/layouts/platform_h5.html"){
|
||||
},
|
||||
|
||||
onView(row, index) {
|
||||
this.saveListCache(row, index)
|
||||
this.$pjaxReplace("/platform/proposal/pre/audit/info/h5?bizId=" + encodeURIComponent(row.id) + "&action=view")
|
||||
this.$refs.taskPopup.open(row, "view")
|
||||
},
|
||||
|
||||
onApproval(row, index) {
|
||||
this.saveListCache(row, index)
|
||||
const params = new URLSearchParams()
|
||||
params.set("bizId", row.id)
|
||||
params.set("action", "approval")
|
||||
params.set("taskId", row.taskId)
|
||||
params.set("taskKey", row.taskKey || "preAudit")
|
||||
params.set("taskName", row.curTaskName || row.taskName || "校工会预审核")
|
||||
this.$pjaxReplace("/platform/proposal/pre/audit/info/h5?" + params.toString())
|
||||
},
|
||||
|
||||
getListCacheKey() {
|
||||
return "proposal:pre-audit:h5:list-state"
|
||||
},
|
||||
|
||||
getListCacheTokenParam() {
|
||||
return "preAuditListCacheToken"
|
||||
},
|
||||
|
||||
getCurrentListCacheToken() {
|
||||
return new URLSearchParams(window.location.search).get(this.getListCacheTokenParam()) || ""
|
||||
},
|
||||
|
||||
/**
|
||||
* 将预审核列表缓存标识绑定到当前历史记录。
|
||||
* PJAX 返回时仅恢复当前历史记录对应的筛选、分页数据和滚动快照。
|
||||
*/
|
||||
bindListCacheToken(token) {
|
||||
const currentUrl = new URL(window.location.href)
|
||||
currentUrl.searchParams.set(this.getListCacheTokenParam(), token)
|
||||
const currentState = window.history.state ? {...window.history.state} : null
|
||||
if (currentState && currentState.url) {
|
||||
currentState.url = currentUrl.toString()
|
||||
}
|
||||
window.history.replaceState(currentState, document.title, currentUrl.toString())
|
||||
if ($.pjax && $.pjax.state) {
|
||||
$.pjax.state.url = currentUrl.toString()
|
||||
}
|
||||
},
|
||||
|
||||
// 用户主动搜索或切换筛选时使旧返回缓存失效。
|
||||
clearListCache() {
|
||||
const token = this.getCurrentListCacheToken()
|
||||
if (!token) return
|
||||
const currentUrl = new URL(window.location.href)
|
||||
currentUrl.searchParams.delete(this.getListCacheTokenParam())
|
||||
const currentState = window.history.state ? {...window.history.state} : null
|
||||
if (currentState && currentState.url) {
|
||||
currentState.url = currentUrl.toString()
|
||||
}
|
||||
window.history.replaceState(currentState, document.title, currentUrl.toString())
|
||||
if ($.pjax && $.pjax.state) {
|
||||
$.pjax.state.url = currentUrl.toString()
|
||||
}
|
||||
sessionStorage.removeItem(this.getListCacheKey())
|
||||
},
|
||||
|
||||
// platform_h5 的实际滚动区域是 page-wrapper,列表位置必须基于该容器保存和恢复。
|
||||
getListScrollContainer() {
|
||||
return document.querySelector(".page-wrapper") || document.scrollingElement || document.documentElement
|
||||
},
|
||||
|
||||
/**
|
||||
* 进入查看或审核详情前保存列表现场。
|
||||
* row 为当前提案,index 为已加载列表索引;缓存同时保存相邻记录作为审核后的定位候选。
|
||||
*/
|
||||
saveListCache(row, index) {
|
||||
const tableList = this.$refs.tableListRef
|
||||
if (!tableList) return
|
||||
const cacheToken = Date.now() + "-" + Math.random().toString(36).slice(2)
|
||||
const tableState = typeof tableList.getListState === "function"
|
||||
? tableList.getListState()
|
||||
: {
|
||||
tableData: JSON.parse(JSON.stringify(tableList.tableData || [])),
|
||||
localPageForm: JSON.parse(JSON.stringify(tableList.localPageForm || this.pageForm)),
|
||||
tableFinished: !!tableList.tableFinished
|
||||
}
|
||||
const cards = document.querySelectorAll(".proposal-pre-audit-list .table-list-item")
|
||||
const currentCard = cards[index]
|
||||
const scrollContainer = this.getListScrollContainer()
|
||||
const cache = {
|
||||
time: Date.now(),
|
||||
token: cacheToken,
|
||||
pageForm: JSON.parse(JSON.stringify(this.pageForm)),
|
||||
tableState: tableState,
|
||||
completedBizId: "",
|
||||
anchor: {
|
||||
rowId: row.id,
|
||||
previousRowId: index > 0 && tableState.tableData[index - 1] ? tableState.tableData[index - 1].id : "",
|
||||
nextRowId: tableState.tableData[index + 1] ? tableState.tableData[index + 1].id : "",
|
||||
viewportTop: currentCard ? currentCard.getBoundingClientRect().top : 0,
|
||||
scrollTop: scrollContainer ? scrollContainer.scrollTop : 0
|
||||
}
|
||||
}
|
||||
try {
|
||||
sessionStorage.setItem(this.getListCacheKey(), JSON.stringify(cache))
|
||||
this.bindListCacheToken(cacheToken)
|
||||
} catch (error) {
|
||||
sessionStorage.removeItem(this.getListCacheKey())
|
||||
}
|
||||
},
|
||||
|
||||
// 仅恢复当前历史记录对应且十分钟内有效的校工会预审核列表缓存。
|
||||
prepareListCache() {
|
||||
try {
|
||||
const cacheToken = this.getCurrentListCacheToken()
|
||||
if (!cacheToken) return
|
||||
const cacheText = sessionStorage.getItem(this.getListCacheKey())
|
||||
if (!cacheText) return
|
||||
const cache = JSON.parse(cacheText)
|
||||
if (!cache || cache.token !== cacheToken || !cache.tableState) return
|
||||
if (Date.now() - cache.time > 10 * 60 * 1000) {
|
||||
this.clearListCache()
|
||||
return
|
||||
}
|
||||
Object.keys(cache.pageForm || {}).forEach((key) => {
|
||||
this.$set(this.pageForm, key, cache.pageForm[key])
|
||||
})
|
||||
this.$set(this, "pendingListCache", cache)
|
||||
} catch (error) {
|
||||
sessionStorage.removeItem(this.getListCacheKey())
|
||||
}
|
||||
},
|
||||
|
||||
// 普通查看返回恢复原快照;审核完成返回重新查询,避免未审核列表保留已处理记录。
|
||||
restoreListCache() {
|
||||
const cache = this.pendingListCache
|
||||
const tableList = this.$refs.tableListRef
|
||||
if (!cache || !tableList) return
|
||||
const anchor = cache.anchor || {}
|
||||
if (cache.completedBizId) {
|
||||
this.refreshCompletedListCache(cache)
|
||||
return
|
||||
}
|
||||
this.applyListCache(cache.tableState, anchor.rowId, anchor)
|
||||
},
|
||||
|
||||
/**
|
||||
* 按离开前已加载页数重新查询审核后的列表。
|
||||
* 查询结果转换为 TableList 状态,并优先定位原记录的下一条、其次定位上一条。
|
||||
*/
|
||||
refreshCompletedListCache(cache) {
|
||||
const originalPageSize = Number(cache.pageForm.pageSize || 10)
|
||||
const loadedCount = Math.max(cache.tableState.tableData.length, originalPageSize)
|
||||
const loadedPageCount = Math.max(1, Math.ceil(loadedCount / originalPageSize))
|
||||
const requestForm = {
|
||||
...cache.pageForm,
|
||||
pageNumber: 1,
|
||||
pageSize: loadedPageCount * originalPageSize
|
||||
}
|
||||
const loading = createListLoading()
|
||||
this.$axios.post("/platform/proposal/pre/audit/pageData", requestForm, {h5SkeletonLoading: true})
|
||||
.then((res) => {
|
||||
if (res.code !== 0) {
|
||||
this.applyCompletedCacheFallback(cache)
|
||||
return
|
||||
}
|
||||
const freshState = {
|
||||
tableData: res.data.list || [],
|
||||
localPageForm: {
|
||||
...cache.pageForm,
|
||||
pageNumber: loadedPageCount,
|
||||
pageSize: originalPageSize,
|
||||
totalCount: res.data.totalCount
|
||||
},
|
||||
tableFinished: (res.data.list || []).length >= res.data.totalCount
|
||||
}
|
||||
const anchor = cache.anchor || {}
|
||||
this.applyListCache(freshState, anchor.nextRowId || anchor.previousRowId, anchor)
|
||||
})
|
||||
.catch(() => {
|
||||
this.applyCompletedCacheFallback(cache)
|
||||
})
|
||||
.finally(() => {
|
||||
loading.close()
|
||||
})
|
||||
},
|
||||
|
||||
// 审核后刷新失败时从旧快照移除已处理记录,避免未审核列表保留脏数据。
|
||||
applyCompletedCacheFallback(cache) {
|
||||
const tableState = cache.tableState
|
||||
const completedIndex = tableState.tableData.findIndex((item) => String(item.id) === String(cache.completedBizId))
|
||||
if (completedIndex >= 0 && cache.pageForm.approval === false) {
|
||||
tableState.tableData.splice(completedIndex, 1)
|
||||
if (tableState.localPageForm && tableState.localPageForm.totalCount > 0) {
|
||||
tableState.localPageForm.totalCount--
|
||||
}
|
||||
} else if (completedIndex >= 0) {
|
||||
this.$set(tableState.tableData[completedIndex], "taskState", 20)
|
||||
}
|
||||
const anchor = cache.anchor || {}
|
||||
this.applyListCache(tableState, anchor.nextRowId || anchor.previousRowId, anchor)
|
||||
},
|
||||
|
||||
/**
|
||||
* 恢复 TableList 数据并将目标卡片放回离开页面前的视口位置。
|
||||
* sticky 吸顶会改变一次布局,因此首次滚动后再执行一次位置校正。
|
||||
*/
|
||||
applyListCache(tableState, targetRowId, anchor) {
|
||||
const tableList = this.$refs.tableListRef
|
||||
if (!tableList) return
|
||||
if (typeof tableList.restoreListState === "function") {
|
||||
if (!tableList.restoreListState(tableState)) return
|
||||
} else {
|
||||
this.$set(tableList, "tableData", tableState.tableData || [])
|
||||
this.$set(tableList, "localPageForm", {...tableList.localPageForm, ...(tableState.localPageForm || {})})
|
||||
this.$set(tableList, "tableFinished", !!tableState.tableFinished)
|
||||
this.$set(tableList, "tableLoading", false)
|
||||
this.$set(tableList, "tableRefreshing", false)
|
||||
tableList.$emit("update:page_form", {...tableList.localPageForm})
|
||||
}
|
||||
this.$set(this, "pendingListCache", null)
|
||||
this.$nextTick(() => {
|
||||
setTimeout(() => {
|
||||
const cards = Array.from(document.querySelectorAll(".proposal-pre-audit-list .table-list-item"))
|
||||
const scrollContainer = this.getListScrollContainer()
|
||||
if (!scrollContainer) return
|
||||
const candidateIds = [targetRowId, anchor.nextRowId, anchor.previousRowId]
|
||||
.filter((id) => id)
|
||||
.map((id) => String(id))
|
||||
.filter((id, index, values) => values.indexOf(id) === index)
|
||||
let targetIndex = -1
|
||||
candidateIds.some((candidateId) => {
|
||||
targetIndex = (tableState.tableData || []).findIndex((item) => String(item.id) === candidateId)
|
||||
return targetIndex >= 0
|
||||
})
|
||||
const targetCard = targetIndex >= 0 ? cards[targetIndex] : null
|
||||
if (targetCard) {
|
||||
const restoreTargetCard = () => {
|
||||
if (!targetCard.isConnected) return
|
||||
const targetTop = scrollContainer.scrollTop + targetCard.getBoundingClientRect().top - Number(anchor.viewportTop || 0)
|
||||
scrollContainer.scrollTo(0, Math.max(0, targetTop))
|
||||
}
|
||||
restoreTargetCard()
|
||||
setTimeout(restoreTargetCard, 100)
|
||||
return
|
||||
}
|
||||
scrollContainer.scrollTo(0, Number(anchor.scrollTop || 0))
|
||||
}, 0)
|
||||
})
|
||||
this.$refs.taskPopup.open(row, "approval")
|
||||
},
|
||||
|
||||
onRevoke(row) {
|
||||
@@ -629,17 +391,14 @@ layout("/layouts/platform_h5.html"){
|
||||
},
|
||||
|
||||
doSearch() {
|
||||
this.clearListCache()
|
||||
this.$nextTick(() => {
|
||||
this.pageForm.pageNumber = 1
|
||||
this.pageForm.totalCount = 0
|
||||
this.$set(this.pageForm, "pageNumber", 1)
|
||||
this.$set(this.pageForm, "totalCount", 0)
|
||||
this.$refs.tableListRef.doSearch()
|
||||
})
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.prepareListCache()
|
||||
if (this.pendingListCache) return
|
||||
const tab = new URLSearchParams(window.location.search).get("tab")
|
||||
if (tab === "done") {
|
||||
this.$set(this.pageForm, "approval", true)
|
||||
|
||||
-143
@@ -1,143 +0,0 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_h5.html"){
|
||||
#-->
|
||||
<style id="style-proposal-info-h5">
|
||||
<!--#include("../../common/info.css"){}#-->
|
||||
</style>
|
||||
<style>
|
||||
.proposal-pre-audit-actions {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 10px;
|
||||
padding: 10px 12px calc(12px + env(safe-area-inset-bottom));
|
||||
}
|
||||
|
||||
.proposal-pre-audit-actions .van-button {
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
<div id="app" v-cloak>
|
||||
<van-nav-bar @click-left="historyBack" left-arrow left-text="返回" :title="pageTitle" placeholder fixed></van-nav-bar>
|
||||
<proposal-info v-if="bizId" :biz-id="bizId">
|
||||
<div v-if="isApproval">
|
||||
<div class="process-title">{{formData.taskDisplayName}}</div>
|
||||
<van-form ref="formRef">
|
||||
<van-field
|
||||
v-model="formData.tf_opinion"
|
||||
name="tf_opinion"
|
||||
label="审批意见"
|
||||
placeholder="请输入审批意见"
|
||||
:rules="[{ required: true, message: '请填写审批意见' }]"
|
||||
required
|
||||
maxlength="100"
|
||||
show-word-limit
|
||||
></van-field>
|
||||
</van-form>
|
||||
<div class="proposal-pre-audit-actions">
|
||||
<van-button type="warning" :loading="formLoading" @click="handleTaskAction(4)">退回(不审核)</van-button>
|
||||
<van-button type="warning" :loading="formLoading" @click="handleTaskAction(6)">退回(审核)</van-button>
|
||||
<van-button type="danger" :loading="formLoading" @click="handleTaskAction(2)">不同意</van-button>
|
||||
<van-button type="primary" :loading="formLoading" @click="handleTaskAction(1)">同意</van-button>
|
||||
</div>
|
||||
</div>
|
||||
</proposal-info>
|
||||
</div>
|
||||
<script nonce="${cspNonce!}">
|
||||
<!--#include("../../common/info.js"){}#-->
|
||||
|
||||
new Vue({
|
||||
el: "#app",
|
||||
store,
|
||||
components: {
|
||||
"proposal-info": PROPOSAL_INFO
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
bizId: "",
|
||||
action: "view",
|
||||
formData: {},
|
||||
formLoading: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isApproval() {
|
||||
return this.action === "approval"
|
||||
},
|
||||
pageTitle() {
|
||||
return this.isApproval ? "校工会预审核" : "提案详情"
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* 提交校工会预审核结果。
|
||||
* val 为 WF 提交类型:1 同意、2 不同意、4 退回且不重复审核、6 退回并重新审核;接口返回 Result。
|
||||
*/
|
||||
handleTaskAction(val) {
|
||||
this.$refs.formRef.validate()
|
||||
.then(() => this.$dialog.confirm({title: "提示", message: "您确定要提交吗?"}))
|
||||
.then(() => {
|
||||
const params = {
|
||||
...this.formData,
|
||||
submitType: val,
|
||||
taskName: "startTask"
|
||||
}
|
||||
if (val === 4) {
|
||||
params.tf_sourceTaskKey = this.formData.taskKey
|
||||
params.tf_audit = false
|
||||
}
|
||||
this.formLoading = true
|
||||
return this.$axios.post("/flow/common/executeTask", {
|
||||
data: JSON.stringify(params)
|
||||
})
|
||||
})
|
||||
.then((res) => {
|
||||
if (res && res.code === 0) {
|
||||
this.markListCacheCompleted()
|
||||
this.$toast.success(res.msg)
|
||||
this.historyBack()
|
||||
}
|
||||
})
|
||||
.catch(() => {})
|
||||
.finally(() => {
|
||||
this.formLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 审核成功后记录已处理提案主键。
|
||||
* 返回列表时按原筛选和已加载范围刷新数据,并定位到相邻记录。
|
||||
*/
|
||||
markListCacheCompleted() {
|
||||
const cacheKey = "proposal:pre-audit:h5:list-state"
|
||||
try {
|
||||
const cacheText = sessionStorage.getItem(cacheKey)
|
||||
if (!cacheText) return
|
||||
const cache = JSON.parse(cacheText)
|
||||
cache.completedBizId = this.bizId
|
||||
cache.time = Date.now()
|
||||
sessionStorage.setItem(cacheKey, JSON.stringify(cache))
|
||||
} catch (error) {
|
||||
sessionStorage.removeItem(cacheKey)
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
const params = new URLSearchParams(window.location.search)
|
||||
// bizId 查询提案详情;taskId、taskKey 和 taskName 构造 WF 预审核提交参数。
|
||||
this.bizId = params.get("bizId") || ""
|
||||
this.action = params.get("action") || "view"
|
||||
if (this.isApproval) {
|
||||
this.$set(this.formData, "processTaskId", params.get("taskId") || "")
|
||||
this.$set(this.formData, "taskKey", params.get("taskKey") || "preAudit")
|
||||
this.$set(this.formData, "taskDisplayName", params.get("taskName") || "校工会预审核")
|
||||
}
|
||||
if (!this.bizId) {
|
||||
this.$toast.fail("缺少提案参数")
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
+44
-117
@@ -1,131 +1,58 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_h5.html"){
|
||||
#-->
|
||||
<style id="style-proposal-school-leader-h5">
|
||||
<!--#include("../../common/info.css"){}#-->
|
||||
</style>
|
||||
<div id="app" v-cloak>
|
||||
<van-nav-bar @click-left="historyBack" left-arrow left-text="返回" title="分管校领导审批" placeholder fixed></van-nav-bar>
|
||||
<van-nav-bar @click-left="handlePageBack" left-arrow left-text="返回" title="分管校领导审批" placeholder fixed></van-nav-bar>
|
||||
<van-sticky offset-top="46px">
|
||||
<van-search
|
||||
v-model="pageForm.name"
|
||||
:show-action="false"
|
||||
:reverse-color="false"
|
||||
input-align="left"
|
||||
placeholder="请输入提案名称搜索"
|
||||
@search="doSearch"
|
||||
></van-search>
|
||||
<van-dropdown-menu :close-on-click-outside="false" :close-on-click-overlay="false">
|
||||
<van-dropdown-item v-model="pageForm.sessionId" :options="sessionOptions" :multiple="false"
|
||||
@change="doSearch"></van-dropdown-item>
|
||||
</van-dropdown-menu>
|
||||
<van-tabs v-model="pageForm.approvalText"
|
||||
@change="(val)=>{this.pageForm.approval = val==='1';this.doSearch();}">
|
||||
<van-tab title="已审核" name="1"></van-tab>
|
||||
<van-tab title="未审核" name="0"></van-tab>
|
||||
</van-tabs>
|
||||
<van-search v-model="pageForm.name" placeholder="请输入提案名称搜索" @search="doSearch"></van-search>
|
||||
<van-dropdown-menu :close-on-click-outside="false" :close-on-click-overlay="false"><van-dropdown-item v-model="pageForm.sessionId" :options="sessionOptions" @change="doSearch"></van-dropdown-item></van-dropdown-menu>
|
||||
<van-tabs v-model="pageForm.approvalText" @change="approvalChange"><van-tab title="已审核" name="1"></van-tab><van-tab title="未审核" name="0"></van-tab></van-tabs>
|
||||
</van-sticky>
|
||||
|
||||
<table-list api="/platform/proposal/schoolLeaderApproval/pageData" :page_form.sync="pageForm" @ready="onReady"
|
||||
ref="tableListRef"
|
||||
title="name">
|
||||
<template v-slot="{index,row}">
|
||||
<table-column label="提案编号">{{row.code}}</table-column>
|
||||
<table-column label="提案类别">{{row.typeName}}</table-column>
|
||||
<table-column label="提案人">{{row.createUserName}}</table-column>
|
||||
<table-column label="代表团">{{row.delegationName}}</table-column>
|
||||
<table-column label="当前节点">{{row.curTaskName}}</table-column>
|
||||
</template>
|
||||
<template #actions="{index,row}">
|
||||
<div class="action-btn" @click="onView(row)">
|
||||
<i class="fa fa-eye"></i>
|
||||
<span>查看</span>
|
||||
</div>
|
||||
<div class="action-btn" v-if="row.taskState === 10" @click="onApproval(row)">
|
||||
<i class="fa fa-edit"></i>
|
||||
<span>审核</span>
|
||||
</div>
|
||||
<div class="action-btn delete" v-if="row.canRevoke" @click="onRevoke(row)">
|
||||
<i class="fa fa-reply"></i>
|
||||
<span>撤回</span>
|
||||
</div>
|
||||
<table-list api="/platform/proposal/schoolLeaderApproval/pageData" :page_form.sync="pageForm" @ready="onReady" ref="tableListRef" title="name">
|
||||
<template v-slot="{row}"><table-column label="提案编号">{{row.code}}</table-column><table-column label="提案类别">{{row.typeName}}</table-column><table-column label="提案人">{{row.createUserName}}</table-column><table-column label="代表团">{{row.delegationName}}</table-column><table-column label="当前节点">{{row.curTaskName}}</table-column></template>
|
||||
<template #actions="{row}">
|
||||
<div class="action-btn" @click="onView(row)"><van-icon class="proposal-action-icon" name="eye-o"></van-icon><span>查看</span></div>
|
||||
<div class="action-btn" v-if="row.taskState === 10" @click="onApproval(row)"><van-icon class="proposal-action-icon" name="edit"></van-icon><span>审核</span></div>
|
||||
<div class="action-btn delete" v-if="row.canRevoke" @click="onRevoke(row)"><van-icon class="proposal-action-icon" name="revoke"></van-icon><span>撤回</span></div>
|
||||
</template>
|
||||
</table-list>
|
||||
|
||||
<van-popup v-model="detailVisible" position="right" class="proposal-full-popup" :close-on-click-overlay="false" get-container="#app">
|
||||
<div class="proposal-full-popup__page"><van-nav-bar @click-left="closeDetail" left-arrow left-text="返回" :title="popupTitle" placeholder fixed></van-nav-bar>
|
||||
<div class="proposal-full-popup__scroll"><proposal-info v-if="detailBizId" :biz-id="detailBizId" :visible="detailVisible">
|
||||
<div v-if="isApproval"><van-form ref="formRef"><section class="proposal-view-card"><h2 class="proposal-view-card__title">审批意见<span class="proposal-audit-card__required">*</span></h2><van-field v-model="formData.tf_opinion" class="proposal-audit-field" name="tf_opinion" type="textarea" rows="6" label="" placeholder="请输入审批意见" :rules="[{required:true,message:'请填写审批意见'}]" required maxlength="100" show-word-limit></van-field></section></van-form>
|
||||
<div class="proposal-popup-form-actions"><van-button type="danger" block :loading="formLoading" @click="handleTaskAction('back')">退回答复</van-button><van-button type="primary" block :loading="formLoading" @click="handleTaskAction('agree')">同意答复</van-button></div>
|
||||
</div>
|
||||
</proposal-info></div>
|
||||
</div>
|
||||
</van-popup>
|
||||
<van-dialog :value="submitConfirmVisible" title="提示" message="您确定要提交吗?" show-cancel-button @confirm="confirmTaskAction" @cancel="closeSubmitConfirm"></van-dialog>
|
||||
</div>
|
||||
<script nonce="${cspNonce!}">
|
||||
const vue = new Vue({
|
||||
el: "#app",
|
||||
store,
|
||||
data() {
|
||||
return {
|
||||
pageForm: {
|
||||
pageNumber: 1,
|
||||
pageSize: 10,
|
||||
totalCount: 0,
|
||||
name: null,
|
||||
sessionId: null,
|
||||
approvalText: "0",
|
||||
approval: false
|
||||
},
|
||||
|
||||
sessionOptions: []
|
||||
}
|
||||
},
|
||||
<!--#include("../../common/info.js"){}#-->
|
||||
new Vue({
|
||||
el: "#app", store, components: {"proposal-info": PROPOSAL_INFO},
|
||||
data() { return {pageForm:{pageNumber:1,pageSize:10,totalCount:0,name:null,sessionId:null,approvalText:"0",approval:false},sessionOptions:[],detailVisible:false,detailBizId:"",action:"view",formData:{},formLoading:false,submitConfirmVisible:false,pendingSubmitType:"",historyLayerPageKey:"proposal-school-leader-approval"} },
|
||||
computed: {isApproval() { return this.action === "approval" }, popupTitle() { return this.isApproval ? "分管校领导审批" : "提案详情" }},
|
||||
methods: {
|
||||
onReady() {
|
||||
this.listSession()
|
||||
},
|
||||
listSession() {
|
||||
this.$axios.post("/platform/proposal/common/listSession").then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.sessionOptions = [
|
||||
{
|
||||
text: "全部届次",
|
||||
value: null
|
||||
}
|
||||
].concat(res.data.map((v) => ({text: v.fullName, value: v.id})))
|
||||
if (this.sessionOptions.length > 0) {
|
||||
this.pageForm.sessionId = this.sessionOptions[0].value
|
||||
this.doSearch()
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
onView(row) {
|
||||
this.$pjaxReplace("/platform/proposal/schoolLeaderApproval/info/h5?bizId=" + encodeURIComponent(row.id) + "&action=view")
|
||||
},
|
||||
|
||||
onApproval(row) {
|
||||
const params = new URLSearchParams()
|
||||
params.set("bizId", row.id)
|
||||
params.set("action", "approval")
|
||||
params.set("taskId", row.taskId)
|
||||
params.set("taskKey", row.taskKey || "")
|
||||
params.set("taskName", row.taskName || "分管校领导审批")
|
||||
this.$pjaxReplace("/platform/proposal/schoolLeaderApproval/info/h5?" + params.toString())
|
||||
},
|
||||
|
||||
onRevoke(row){
|
||||
this.$dialog.confirm({
|
||||
title: "提示",
|
||||
message: "您确定要撤回吗?"
|
||||
}).then(() => {
|
||||
this.$axios.post("/flow/common/revokeTask", {taskId: row.taskId}).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.$toast.success(res.msg)
|
||||
this.doSearch()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
doSearch() {
|
||||
this.$nextTick(() => {
|
||||
this.pageForm.pageNumber = 1
|
||||
this.pageForm.totalCount = 0
|
||||
this.$refs.tableListRef.doSearch()
|
||||
})
|
||||
},
|
||||
}
|
||||
registerHistoryLayers() { window.h5HistoryLayerManager.register(this.historyLayerPageKey, (stack) => { this.$set(this,"detailVisible",stack.includes("detail")); this.$set(this,"submitConfirmVisible",stack.includes("submit-confirm")) }) },
|
||||
openHistoryLayer(name) { window.h5HistoryLayerManager.open(name) },
|
||||
closeHistoryLayer(name,callback) { window.h5HistoryLayerManager.close(name,callback) },
|
||||
handlePageBack() { if (window.h5HistoryLayerManager.stack.length) { window.h5HistoryLayerManager.close(); return } historyBack() },
|
||||
closeDetail() { this.closeHistoryLayer("detail") }, closeSubmitConfirm() { this.closeHistoryLayer("submit-confirm") },
|
||||
approvalChange(value) { this.$set(this.pageForm,"approval",value === "1"); this.doSearch() }, onReady() { this.listSession() },
|
||||
listSession() { this.$axios.post("/platform/proposal/common/listSession").then((res) => { if (res.code !== 0) return; this.$set(this,"sessionOptions",[{text:"全部届次",value:null}].concat(res.data.map((v) => ({text:v.fullName,value:v.id})))); this.$set(this.pageForm,"sessionId",this.sessionOptions[0].value); this.doSearch() }) },
|
||||
onView(row) { this.$set(this,"detailBizId",row.id); this.$set(this,"action","view"); this.$set(this,"formData",{}); this.openHistoryLayer("detail") },
|
||||
onApproval(row) { this.$set(this,"detailBizId",row.id); this.$set(this,"action","approval"); this.$set(this,"formData",{processTaskId:row.taskId,taskKey:row.taskKey || "",taskName:row.taskName || "分管校领导审批",proposalId:row.id,tf_opinion:""}); this.openHistoryLayer("detail") },
|
||||
/** val 为 back 或 agree,确认后提交分管校领导审批接口。 */
|
||||
handleTaskAction(val) { this.$refs.formRef.validate().then(() => { this.$set(this,"pendingSubmitType",val); this.openHistoryLayer("submit-confirm") }).catch(() => {}) },
|
||||
confirmTaskAction() { const submitData={...this.formData,tf_approval:this.pendingSubmitType}; delete submitData.taskKey; delete submitData.taskName; this.$set(this,"formLoading",true); this.$axios.post("/platform/proposal/schoolLeaderApproval/executeTask",{data:JSON.stringify(submitData)}).then((res) => { if (res && res.code === 0) { this.$toast.success(res.msg); window.h5HistoryLayerManager.closeAll(() => this.doSearch()) } }).finally(() => { this.$set(this,"formLoading",false) }) },
|
||||
onRevoke(row) { this.$dialog.confirm({title:"提示",message:"您确定要撤回吗?"}).then(() => this.$axios.post("/flow/common/revokeTask",{taskId:row.taskId})).then((res) => { if (res && res.code === 0) { this.$toast.success(res.msg); this.doSearch() } }).catch(() => {}) },
|
||||
doSearch() { this.$nextTick(() => { this.$set(this.pageForm,"pageNumber",1); this.$set(this.pageForm,"totalCount",0); this.$refs.tableListRef.doSearch() }) }
|
||||
},
|
||||
created() { this.registerHistoryLayers() }, beforeDestroy() { window.h5HistoryLayerManager.unregister(this.historyLayerPageKey) }
|
||||
})
|
||||
</script>
|
||||
<!--#
|
||||
|
||||
-107
@@ -1,107 +0,0 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_h5.html"){
|
||||
#-->
|
||||
<style id="style-proposal-info-h5">
|
||||
<!--#include("../../common/info.css"){}#-->
|
||||
</style>
|
||||
<div id="app" v-cloak>
|
||||
<van-nav-bar @click-left="historyBack" left-arrow left-text="返回" :title="pageTitle" placeholder fixed></van-nav-bar>
|
||||
<proposal-info v-if="bizId" :biz-id="bizId">
|
||||
<div v-if="isApproval">
|
||||
<div class="process-title">{{formData.taskName}}</div>
|
||||
<van-form ref="formRef">
|
||||
<van-field
|
||||
v-model="formData.tf_opinion"
|
||||
name="tf_opinion"
|
||||
label="审批意见"
|
||||
placeholder="请输入审批意见"
|
||||
:rules="[{ required: true, message: '请填写审批意见' }]"
|
||||
required
|
||||
maxlength="100"
|
||||
show-word-limit
|
||||
></van-field>
|
||||
</van-form>
|
||||
<div style="display: flex; justify-content: space-between; column-gap: 10px; padding: 10px">
|
||||
<van-button type="danger" block :loading="formLoading" @click="handleTaskAction('back')">退回答复</van-button>
|
||||
<van-button type="primary" block :loading="formLoading" @click="handleTaskAction('agree')">同意答复</van-button>
|
||||
</div>
|
||||
</div>
|
||||
</proposal-info>
|
||||
</div>
|
||||
<script nonce="${cspNonce!}">
|
||||
<!--#include("../../common/info.js"){}#-->
|
||||
|
||||
new Vue({
|
||||
el: "#app",
|
||||
store,
|
||||
components: {
|
||||
"proposal-info": PROPOSAL_INFO
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
bizId: "",
|
||||
action: "view",
|
||||
formData: {},
|
||||
formLoading: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isApproval() {
|
||||
return this.action === "approval"
|
||||
},
|
||||
pageTitle() {
|
||||
return this.isApproval ? "分管校领导审批" : "提案详情"
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* 提交分管校领导审批结果。
|
||||
* val 为 back 或 agree;接口返回 Result,code 为 0 表示处理成功。
|
||||
*/
|
||||
handleTaskAction(val) {
|
||||
this.$refs.formRef.validate()
|
||||
.then(() => this.$dialog.confirm({title: "提示", message: "您确定要提交吗?"}))
|
||||
.then(() => {
|
||||
const submitData = {
|
||||
...this.formData,
|
||||
tf_approval: val
|
||||
}
|
||||
delete submitData.taskKey
|
||||
delete submitData.taskName
|
||||
this.formLoading = true
|
||||
return this.$axios.post("/platform/proposal/schoolLeaderApproval/executeTask", {
|
||||
data: JSON.stringify(submitData)
|
||||
})
|
||||
})
|
||||
.then((res) => {
|
||||
if (res && res.code === 0) {
|
||||
this.$toast.success(res.msg)
|
||||
this.historyBack()
|
||||
}
|
||||
})
|
||||
.catch(() => {})
|
||||
.finally(() => {
|
||||
this.formLoading = false
|
||||
})
|
||||
}
|
||||
},
|
||||
created() {
|
||||
const params = new URLSearchParams(window.location.search)
|
||||
// bizId 用于详情查询;taskId、taskKey、taskName 和 proposalId 构成校领导审批接口参数。
|
||||
this.bizId = params.get("bizId") || ""
|
||||
this.action = params.get("action") || "view"
|
||||
if (this.isApproval) {
|
||||
this.$set(this.formData, "processTaskId", params.get("taskId") || "")
|
||||
this.$set(this.formData, "taskKey", params.get("taskKey") || "")
|
||||
this.$set(this.formData, "taskName", params.get("taskName") || "分管校领导审批")
|
||||
this.$set(this.formData, "proposalId", this.bizId)
|
||||
}
|
||||
if (!this.bizId) {
|
||||
this.$toast.fail("缺少提案参数")
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
+244
-257
@@ -2,6 +2,8 @@
|
||||
layout("/layouts/platform_h5.html"){
|
||||
#-->
|
||||
<style>
|
||||
<!--#include("../../common/info.css"){}#-->
|
||||
|
||||
body {
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
@@ -28,6 +30,45 @@ layout("/layouts/platform_h5.html"){
|
||||
color: #1989fa;
|
||||
}
|
||||
|
||||
.proposal-seconded-popup {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
|
||||
.proposal-seconded-popup-page {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
padding-top: 46px;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.proposal-seconded-popup-page .van-nav-bar {
|
||||
z-index: 20;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.proposal-seconded-popup-scroll {
|
||||
min-height: 0;
|
||||
overflow-y: auto;
|
||||
flex: 1;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
.proposal-seconded-popup-scroll .proposal-view-main {
|
||||
padding-top: 18px;
|
||||
}
|
||||
|
||||
.proposal-seconded-form-actions {
|
||||
display: flex;
|
||||
padding: 10px;
|
||||
justify-content: space-between;
|
||||
column-gap: 10px;
|
||||
}
|
||||
|
||||
.proposal-seconded-content {
|
||||
padding: 0 12px;
|
||||
}
|
||||
@@ -222,6 +263,11 @@ layout("/layouts/platform_h5.html"){
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.proposal-seconded-page .table-list-container .table-list-item .action-btn .van-icon {
|
||||
margin-right: 6px;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
@media (max-width: 350px) {
|
||||
.proposal-seconded-content {
|
||||
padding-right: 10px;
|
||||
@@ -236,7 +282,7 @@ layout("/layouts/platform_h5.html"){
|
||||
</style>
|
||||
<div id="app" v-cloak>
|
||||
<div class="proposal-seconded-page">
|
||||
<van-nav-bar @click-left="historyBack" left-arrow left-text="返回" title="附议提案" placeholder fixed></van-nav-bar>
|
||||
<van-nav-bar @click-left="handlePageBack" left-arrow left-text="返回" title="附议提案" placeholder fixed></van-nav-bar>
|
||||
|
||||
<van-sticky :offset-top="46">
|
||||
<div class="proposal-seconded-sticky">
|
||||
@@ -309,16 +355,15 @@ layout("/layouts/platform_h5.html"){
|
||||
<table-column label="当前节点">{{row.curTaskName || '--'}}</table-column>
|
||||
</template>
|
||||
<template #actions="{index,row}">
|
||||
<div class="action-btn" @click="onView(row,index)">
|
||||
<i class="fa fa-eye"></i>
|
||||
<div class="action-btn" @click="onView(row)">
|
||||
<van-icon name="eye-o"></van-icon>
|
||||
<span>查看</span>
|
||||
</div>
|
||||
<div class="action-btn" v-if="showSecondAction(row)" @click="onApproval(row,index)">
|
||||
<i class="fa fa-edit"></i>
|
||||
<div class="action-btn" v-if="showSecondAction(row)" @click="onApproval(row)">
|
||||
<van-icon name="edit"></van-icon>
|
||||
<span>附议</span>
|
||||
</div>
|
||||
<!-- <div class="action-btn delete" v-if="row.canRevoke" @click="onRevoke(row)">-->
|
||||
<!-- <i class="fa fa-reply"></i>-->
|
||||
<!-- <span>撤回</span>-->
|
||||
<!-- </div>-->
|
||||
</template>
|
||||
@@ -326,13 +371,75 @@ layout("/layouts/platform_h5.html"){
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<van-popup
|
||||
v-model="detailVisible"
|
||||
class="proposal-seconded-popup"
|
||||
position="right"
|
||||
:close-on-click-overlay="false"
|
||||
safe-area-inset-bottom>
|
||||
<div class="proposal-seconded-popup-page">
|
||||
<van-nav-bar
|
||||
:title="popupTitle"
|
||||
left-arrow
|
||||
left-text="返回"
|
||||
fixed
|
||||
@click-left="closeHistoryLayer('detail')">
|
||||
</van-nav-bar>
|
||||
<div class="proposal-seconded-popup-scroll">
|
||||
<proposal-info v-if="detailVisible && detailBizId" :biz-id="detailBizId" :visible="detailVisible">
|
||||
<div v-if="isApproval">
|
||||
<section class="proposal-view-card proposal-seconded-opinion-card">
|
||||
<h2 class="proposal-view-card__title">
|
||||
提案附议
|
||||
<span class="proposal-audit-card__required">*</span>
|
||||
</h2>
|
||||
<van-form ref="formRef">
|
||||
<van-field
|
||||
v-model="formData.tf_opinion"
|
||||
class="proposal-audit-field"
|
||||
name="tf_opinion"
|
||||
type="textarea"
|
||||
rows="6"
|
||||
label=""
|
||||
placeholder="请输入附议意见"
|
||||
:rules="[{ required: true, message: '请填写附议意见' }]"
|
||||
required
|
||||
maxlength="200"
|
||||
show-word-limit>
|
||||
</van-field>
|
||||
</van-form>
|
||||
</section>
|
||||
<div class="proposal-seconded-form-actions">
|
||||
<van-button type="danger" block :loading="formLoading" @click="submitSeconded(false)">不同意</van-button>
|
||||
<van-button type="primary" block :loading="formLoading" @click="submitSeconded(true)">同意</van-button>
|
||||
</div>
|
||||
</div>
|
||||
</proposal-info>
|
||||
</div>
|
||||
</div>
|
||||
</van-popup>
|
||||
|
||||
<van-dialog
|
||||
:value="submitConfirmVisible"
|
||||
title="提示"
|
||||
message="您确定要提交吗?"
|
||||
show-cancel-button
|
||||
@confirm="confirmSubmitSeconded"
|
||||
@cancel="closeHistoryLayer('submit-confirm')">
|
||||
</van-dialog>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<script nonce="${cspNonce!}">
|
||||
<!--#include("../../common/info.js"){}#-->
|
||||
|
||||
new Vue({
|
||||
el: "#app",
|
||||
store,
|
||||
components: {
|
||||
"proposal-info": PROPOSAL_INFO
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
pageForm: {
|
||||
@@ -355,10 +462,70 @@ layout("/layouts/platform_h5.html"){
|
||||
{text: "未附议", value: "0"},
|
||||
{text: "已附议", value: "1"}
|
||||
],
|
||||
pendingListCache: null
|
||||
detailVisible: false,
|
||||
detailBizId: "",
|
||||
popupAction: "view",
|
||||
curTaskCode: "",
|
||||
formData: {},
|
||||
formLoading: false,
|
||||
submitConfirmVisible: false,
|
||||
pendingSubmitAgree: true,
|
||||
historyLayerPageKey: "proposal-seconded-h5"
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isApproval() {
|
||||
return this.popupAction === "approval"
|
||||
},
|
||||
popupTitle() {
|
||||
return this.isApproval ? "提案附议" : "提案详情"
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* 注册附议提案页面弹层历史。
|
||||
* pageKey 使用固定页面标识;回调参数 stack 为当前弹层名称数组,无返回值。
|
||||
*/
|
||||
registerHistoryLayers() {
|
||||
if (!window.h5HistoryLayerManager) return
|
||||
window.h5HistoryLayerManager.register(this.historyLayerPageKey, (stack) => {
|
||||
this.syncHistoryLayerStack(stack)
|
||||
})
|
||||
},
|
||||
|
||||
// 根据浏览器历史栈同步详情 Popup 和提交确认 Dialog 的显示状态。
|
||||
syncHistoryLayerStack(stack) {
|
||||
this.$set(this, "detailVisible", stack.includes("detail"))
|
||||
this.$set(this, "submitConfirmVisible", stack.includes("submit-confirm"))
|
||||
},
|
||||
|
||||
// 打开弹层时同步增加当前地址的浏览器历史记录。
|
||||
openHistoryLayer(layerName) {
|
||||
if (window.h5HistoryLayerManager && window.h5HistoryLayerManager.open(layerName)) return
|
||||
this.setHistoryLayerVisible(layerName, true)
|
||||
},
|
||||
|
||||
// 主动关闭弹层时回退对应历史记录,afterClose 在历史状态同步后执行。
|
||||
closeHistoryLayer(layerName, afterClose = null) {
|
||||
if (window.h5HistoryLayerManager && window.h5HistoryLayerManager.close(layerName, afterClose)) return
|
||||
this.setHistoryLayerVisible(layerName, false)
|
||||
if (typeof afterClose === "function") afterClose()
|
||||
},
|
||||
|
||||
setHistoryLayerVisible(layerName, visible) {
|
||||
if (layerName === "detail") this.$set(this, "detailVisible", visible)
|
||||
if (layerName === "submit-confirm") this.$set(this, "submitConfirmVisible", visible)
|
||||
},
|
||||
|
||||
// 页面返回时优先关闭最上层弹框,没有弹框时再返回上一业务页面。
|
||||
handlePageBack() {
|
||||
if (window.h5HistoryLayerManager && window.h5HistoryLayerManager.stack.length) {
|
||||
window.h5HistoryLayerManager.close()
|
||||
return
|
||||
}
|
||||
this.historyBack()
|
||||
},
|
||||
|
||||
// 附议按钮显示规则:
|
||||
// 1. 当前任务进行中(taskState=10)时显示
|
||||
// 2. 当前任务已废弃(taskState=99)时,仅 invite、second、delegation、committee 节点显示
|
||||
@@ -366,11 +533,6 @@ layout("/layouts/platform_h5.html"){
|
||||
return row.taskState === 10 || (row.taskState === 99 && ["invite", "second", "preAudit", "delegation", "committee"].includes(row.taskKey))
|
||||
},
|
||||
onReady() {
|
||||
if (this.pendingListCache) {
|
||||
this.restoreListCache()
|
||||
this.listSession(true)
|
||||
return
|
||||
}
|
||||
this.listSession(false)
|
||||
},
|
||||
// 附议状态下拉框使用字符串值展示,查询接口使用布尔值区分已附议和未附议。
|
||||
@@ -391,273 +553,98 @@ layout("/layouts/platform_h5.html"){
|
||||
})
|
||||
},
|
||||
|
||||
onView(row, index) {
|
||||
this.saveListCache(row, index)
|
||||
this.$pjaxReplace("/platform/proposal/seconded/info/h5?bizId=" + encodeURIComponent(row.id) + "&action=view")
|
||||
},
|
||||
|
||||
onApproval(row, index) {
|
||||
this.saveListCache(row, index)
|
||||
const params = new URLSearchParams()
|
||||
params.set("bizId", row.id)
|
||||
params.set("action", "approval")
|
||||
params.set("taskId", row.taskId)
|
||||
params.set("taskActorUserId", row.taskActorUserId)
|
||||
params.set("curTaskCode", row.curTaskCode || "")
|
||||
params.set("taskName", row.curTaskName || "提案附议")
|
||||
this.$pjaxReplace("/platform/proposal/seconded/info/h5?" + params.toString())
|
||||
},
|
||||
|
||||
getListCacheKey() {
|
||||
return "proposal:seconded:h5:list-state"
|
||||
},
|
||||
|
||||
getListCacheTokenParam() {
|
||||
return "secondedListCacheToken"
|
||||
},
|
||||
|
||||
getCurrentListCacheToken() {
|
||||
return new URLSearchParams(window.location.search).get(this.getListCacheTokenParam()) || ""
|
||||
onView(row) {
|
||||
this.$set(this, "detailBizId", row.id)
|
||||
this.$set(this, "popupAction", "view")
|
||||
this.$set(this, "curTaskCode", "")
|
||||
this.$set(this, "formData", {})
|
||||
this.openHistoryLayer("detail")
|
||||
},
|
||||
|
||||
/**
|
||||
* 将本次列表缓存标识绑定到当前历史记录。
|
||||
* PJAX 返回时可能重复初始化列表,两个实例通过同一标识读取同一份快照,避免后一次初始化覆盖恢复结果。
|
||||
* 打开提案附议 Popup。
|
||||
* row 包含提案、任务和附议人信息;这些字段用于详情查询、任务定位、附议人校验和提交链路选择。
|
||||
*/
|
||||
bindListCacheToken(token) {
|
||||
const currentUrl = new URL(window.location.href)
|
||||
currentUrl.searchParams.set(this.getListCacheTokenParam(), token)
|
||||
const currentState = window.history.state ? {...window.history.state} : null
|
||||
if (currentState && currentState.url) {
|
||||
currentState.url = currentUrl.toString()
|
||||
}
|
||||
window.history.replaceState(currentState, document.title, currentUrl.toString())
|
||||
if ($.pjax && $.pjax.state) {
|
||||
$.pjax.state.url = currentUrl.toString()
|
||||
}
|
||||
onApproval(row) {
|
||||
this.$set(this, "detailBizId", row.id)
|
||||
this.$set(this, "popupAction", "approval")
|
||||
this.$set(this, "curTaskCode", row.curTaskCode || "")
|
||||
this.$set(this, "formData", {
|
||||
processTaskId: row.taskId,
|
||||
taskId: row.taskId,
|
||||
proposalId: row.id,
|
||||
taskActorUserId: row.taskActorUserId,
|
||||
taskName: row.curTaskName || "提案附议",
|
||||
tf_opinion: "同意该提案"
|
||||
})
|
||||
this.openHistoryLayer("detail")
|
||||
},
|
||||
|
||||
/**
|
||||
* 用户主动重新查询时清除详情返回标识,防止后续重新进入列表时误用旧筛选和旧锚点。
|
||||
*/
|
||||
clearListCache() {
|
||||
const token = this.getCurrentListCacheToken()
|
||||
if (!token) return
|
||||
const currentUrl = new URL(window.location.href)
|
||||
currentUrl.searchParams.delete(this.getListCacheTokenParam())
|
||||
const currentState = window.history.state ? {...window.history.state} : null
|
||||
if (currentState && currentState.url) {
|
||||
currentState.url = currentUrl.toString()
|
||||
}
|
||||
window.history.replaceState(currentState, document.title, currentUrl.toString())
|
||||
if ($.pjax && $.pjax.state) {
|
||||
$.pjax.state.url = currentUrl.toString()
|
||||
}
|
||||
sessionStorage.removeItem(this.getListCacheKey())
|
||||
},
|
||||
|
||||
// H5 页面由 page-wrapper 承担滚动,缓存和恢复位置时不能使用 window 的滚动值。
|
||||
getListScrollContainer() {
|
||||
return document.querySelector(".page-wrapper") || document.scrollingElement || document.documentElement
|
||||
},
|
||||
|
||||
/**
|
||||
* 进入详情前保存查询条件、已加载分页和点击卡片锚点。
|
||||
* row/index 分别为当前记录和它在已加载列表中的位置;缓存仅在当前标签页保留。
|
||||
*/
|
||||
saveListCache(row, index) {
|
||||
const tableList = this.$refs.tableListRef
|
||||
if (!tableList) return
|
||||
const cacheToken = Date.now() + "-" + Math.random().toString(36).slice(2)
|
||||
const tableState = typeof tableList.getListState === "function"
|
||||
? tableList.getListState()
|
||||
: {
|
||||
tableData: JSON.parse(JSON.stringify(tableList.tableData || [])),
|
||||
localPageForm: JSON.parse(JSON.stringify(tableList.localPageForm || this.pageForm)),
|
||||
tableFinished: !!tableList.tableFinished
|
||||
}
|
||||
const cards = document.querySelectorAll(".proposal-seconded-list .table-list-item")
|
||||
const currentCard = cards[index]
|
||||
const scrollContainer = this.getListScrollContainer()
|
||||
const cache = {
|
||||
time: Date.now(),
|
||||
token: cacheToken,
|
||||
pageForm: JSON.parse(JSON.stringify(this.pageForm)),
|
||||
tableState: tableState,
|
||||
completedBizId: "",
|
||||
anchor: {
|
||||
rowId: row.id,
|
||||
previousRowId: index > 0 && tableState.tableData[index - 1] ? tableState.tableData[index - 1].id : "",
|
||||
nextRowId: tableState.tableData[index + 1] ? tableState.tableData[index + 1].id : "",
|
||||
viewportTop: currentCard ? currentCard.getBoundingClientRect().top : 0,
|
||||
scrollTop: scrollContainer ? scrollContainer.scrollTop : 0
|
||||
}
|
||||
}
|
||||
try {
|
||||
sessionStorage.setItem(this.getListCacheKey(), JSON.stringify(cache))
|
||||
this.bindListCacheToken(cacheToken)
|
||||
} catch (error) {
|
||||
sessionStorage.removeItem(this.getListCacheKey())
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 读取十分钟内的列表缓存,并先恢复查询参数,保证 TableList 创建时使用原查询条件。
|
||||
*/
|
||||
prepareListCache() {
|
||||
try {
|
||||
const cacheToken = this.getCurrentListCacheToken()
|
||||
if (!cacheToken) return
|
||||
const cacheText = sessionStorage.getItem(this.getListCacheKey())
|
||||
if (!cacheText) return
|
||||
const cache = JSON.parse(cacheText)
|
||||
if (!cache || cache.token !== cacheToken || !cache.tableState) return
|
||||
if (Date.now() - cache.time > 10 * 60 * 1000) {
|
||||
this.clearListCache()
|
||||
return
|
||||
}
|
||||
Object.keys(cache.pageForm || {}).forEach((key) => {
|
||||
this.$set(this.pageForm, key, cache.pageForm[key])
|
||||
// 表单校验通过后打开提交确认 Dialog,并记录本次附议结果。
|
||||
submitSeconded(isAgree) {
|
||||
this.$refs.formRef.validate()
|
||||
.then(() => {
|
||||
this.$set(this, "pendingSubmitAgree", isAgree)
|
||||
this.openHistoryLayer("submit-confirm")
|
||||
})
|
||||
this.$set(this, "pendingListCache", cache)
|
||||
} catch (error) {
|
||||
sessionStorage.removeItem(this.getListCacheKey())
|
||||
}
|
||||
.catch(() => {})
|
||||
},
|
||||
|
||||
// 确认提交时先关闭 Dialog 历史层,再调用附议接口。
|
||||
confirmSubmitSeconded() {
|
||||
this.closeHistoryLayer("submit-confirm", () => {
|
||||
this.doSubmitSeconded()
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 恢复列表并按业务结果选择定位锚点。
|
||||
* 未提交时定位原记录;附议成功且原筛选为未附议时移除原记录并定位下一条,下一条不存在则定位上一条。
|
||||
* 提交附议结果。
|
||||
* second 节点向 executeTask 提交完整 WF 数据,其他关联节点向 updateInfo 提交提案、任务、附议人和意见;接口返回 Result。
|
||||
*/
|
||||
restoreListCache() {
|
||||
const cache = this.pendingListCache
|
||||
const tableList = this.$refs.tableListRef
|
||||
if (!cache || !tableList) return
|
||||
const anchor = cache.anchor || {}
|
||||
if (cache.completedBizId) {
|
||||
this.refreshCompletedListCache(cache)
|
||||
return
|
||||
}
|
||||
this.applyListCache(cache.tableState, anchor.rowId, anchor)
|
||||
},
|
||||
|
||||
/**
|
||||
* 附议成功后按原来已加载的页数重新查询最新数据。
|
||||
* 请求参数沿用原筛选条件,并临时扩大 pageSize,一次取回原浏览范围,避免删除记录造成后续分页漏数。
|
||||
*/
|
||||
refreshCompletedListCache(cache) {
|
||||
const originalPageSize = Number(cache.pageForm.pageSize || 10)
|
||||
const loadedCount = Math.max(cache.tableState.tableData.length, originalPageSize)
|
||||
const loadedPageCount = Math.max(1, Math.ceil(loadedCount / originalPageSize))
|
||||
const requestForm = {
|
||||
...cache.pageForm,
|
||||
pageNumber: 1,
|
||||
pageSize: loadedPageCount * originalPageSize
|
||||
}
|
||||
const loading = createListLoading()
|
||||
this.$axios.post("/platform/proposal/seconded/pageData", requestForm, {h5SkeletonLoading: true})
|
||||
.then((res) => {
|
||||
if (res.code !== 0) {
|
||||
this.applyCompletedCacheFallback(cache)
|
||||
return
|
||||
}
|
||||
const freshState = {
|
||||
tableData: res.data.list || [],
|
||||
localPageForm: {
|
||||
...cache.pageForm,
|
||||
pageNumber: loadedPageCount,
|
||||
pageSize: originalPageSize,
|
||||
totalCount: res.data.totalCount
|
||||
},
|
||||
tableFinished: (res.data.list || []).length >= res.data.totalCount
|
||||
}
|
||||
const anchor = cache.anchor || {}
|
||||
this.applyListCache(freshState, anchor.nextRowId || anchor.previousRowId, anchor)
|
||||
})
|
||||
.catch(() => {
|
||||
this.applyCompletedCacheFallback(cache)
|
||||
})
|
||||
.finally(() => {
|
||||
loading.close()
|
||||
})
|
||||
},
|
||||
|
||||
// 最新列表查询失败时,仅从旧快照移除已处理记录,仍保证用户能够回到原浏览区域。
|
||||
applyCompletedCacheFallback(cache) {
|
||||
const tableState = cache.tableState
|
||||
const completedIndex = tableState.tableData.findIndex((item) => String(item.id) === String(cache.completedBizId))
|
||||
if (completedIndex >= 0 && cache.pageForm.approval === false) {
|
||||
tableState.tableData.splice(completedIndex, 1)
|
||||
if (tableState.localPageForm && tableState.localPageForm.totalCount > 0) {
|
||||
tableState.localPageForm.totalCount--
|
||||
}
|
||||
} else if (completedIndex >= 0) {
|
||||
this.$set(tableState.tableData[completedIndex], "taskState", 20)
|
||||
}
|
||||
const anchor = cache.anchor || {}
|
||||
this.applyListCache(tableState, anchor.nextRowId || anchor.previousRowId, anchor)
|
||||
},
|
||||
|
||||
/**
|
||||
* 将列表状态写回 TableList,并把目标卡片恢复到离开页面前的屏幕位置。
|
||||
*/
|
||||
applyListCache(tableState, targetRowId, anchor) {
|
||||
const tableList = this.$refs.tableListRef
|
||||
if (!tableList) return
|
||||
if (typeof tableList.restoreListState === "function") {
|
||||
if (!tableList.restoreListState(tableState)) return
|
||||
} else {
|
||||
this.$set(tableList, "tableData", tableState.tableData || [])
|
||||
this.$set(tableList, "localPageForm", {...tableList.localPageForm, ...(tableState.localPageForm || {})})
|
||||
this.$set(tableList, "tableFinished", !!tableState.tableFinished)
|
||||
this.$set(tableList, "tableLoading", false)
|
||||
this.$set(tableList, "tableRefreshing", false)
|
||||
tableList.$emit("update:page_form", {...tableList.localPageForm})
|
||||
}
|
||||
this.$set(this, "pendingListCache", null)
|
||||
this.$nextTick(() => {
|
||||
setTimeout(() => {
|
||||
const cards = Array.from(document.querySelectorAll(".proposal-seconded-list .table-list-item"))
|
||||
const scrollContainer = this.getListScrollContainer()
|
||||
if (!scrollContainer) return
|
||||
const candidateIds = [targetRowId, anchor.nextRowId, anchor.previousRowId]
|
||||
.filter((id) => id)
|
||||
.map((id) => String(id))
|
||||
.filter((id, index, values) => values.indexOf(id) === index)
|
||||
// 严格按当前记录、下一条、上一条的顺序选择锚点,避免列表中靠前的上一条被提前命中。
|
||||
let targetIndex = -1
|
||||
candidateIds.some((candidateId) => {
|
||||
targetIndex = (tableState.tableData || []).findIndex((item) => String(item.id) === candidateId)
|
||||
return targetIndex >= 0
|
||||
doSubmitSeconded() {
|
||||
const isAgree = this.pendingSubmitAgree
|
||||
this.$set(this, "formLoading", true)
|
||||
const request = this.curTaskCode === "second"
|
||||
? this.$axios.post("/platform/proposal/seconded/executeTask", {
|
||||
data: JSON.stringify({
|
||||
...this.formData,
|
||||
submitType: isAgree ? 1 : 20
|
||||
})
|
||||
const targetCard = targetIndex >= 0 ? cards[targetIndex] : null
|
||||
if (targetCard) {
|
||||
// 首次滚动会触发筛选栏吸顶,再次校正可消除 sticky 布局切换造成的位置偏差。
|
||||
const restoreTargetCard = () => {
|
||||
if (!targetCard.isConnected) return
|
||||
const targetTop = scrollContainer.scrollTop + targetCard.getBoundingClientRect().top - Number(anchor.viewportTop || 0)
|
||||
scrollContainer.scrollTo(0, Math.max(0, targetTop))
|
||||
}
|
||||
restoreTargetCard()
|
||||
setTimeout(restoreTargetCard, 100)
|
||||
return
|
||||
}
|
||||
scrollContainer.scrollTo(0, Number(anchor.scrollTop || 0))
|
||||
}, 0)
|
||||
})
|
||||
: this.$axios.post("/platform/proposal/seconded/updateInfo", {
|
||||
proposalId: this.formData.proposalId,
|
||||
taskId: this.formData.taskId,
|
||||
taskActorUserId: this.formData.taskActorUserId,
|
||||
opinion: this.formData.tf_opinion,
|
||||
submitType: isAgree ? 1 : 2
|
||||
})
|
||||
request.then((res) => {
|
||||
if (res && res.code === 0) {
|
||||
this.$toast.success(res.msg)
|
||||
this.closeHistoryLayer("detail", () => {
|
||||
this.doSearch()
|
||||
})
|
||||
}
|
||||
}).finally(() => {
|
||||
this.$set(this, "formLoading", false)
|
||||
})
|
||||
},
|
||||
|
||||
doSearch() {
|
||||
this.clearListCache()
|
||||
this.$nextTick(() => {
|
||||
this.pageForm.pageNumber = 1
|
||||
this.pageForm.totalCount = 0
|
||||
this.$set(this.pageForm, "pageNumber", 1)
|
||||
this.$set(this.pageForm, "totalCount", 0)
|
||||
this.$refs.tableListRef.doSearch()
|
||||
})
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.prepareListCache()
|
||||
this.registerHistoryLayers()
|
||||
},
|
||||
beforeDestroy() {
|
||||
if (window.h5HistoryLayerManager) {
|
||||
window.h5HistoryLayerManager.unregister(this.historyLayerPageKey)
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
-136
@@ -1,136 +0,0 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_h5.html"){
|
||||
#-->
|
||||
<style id="style-proposal-info-h5">
|
||||
<!--#include("../../common/info.css"){}#-->
|
||||
</style>
|
||||
<div id="app" v-cloak>
|
||||
<van-nav-bar @click-left="historyBack" left-arrow left-text="返回" :title="pageTitle" placeholder fixed></van-nav-bar>
|
||||
<proposal-info v-if="bizId" :biz-id="bizId">
|
||||
<div v-if="isApproval">
|
||||
<div class="process-title">提案附议</div>
|
||||
<van-form ref="formRef">
|
||||
<van-field
|
||||
v-model="formData.tf_opinion"
|
||||
name="tf_opinion"
|
||||
label="审批意见"
|
||||
placeholder="请输入审批意见"
|
||||
:rules="[{ required: true, message: '请填写审批意见' }]"
|
||||
required
|
||||
maxlength="100"
|
||||
show-word-limit
|
||||
></van-field>
|
||||
</van-form>
|
||||
<div style="display: flex; justify-content: space-between; column-gap: 10px; padding: 10px">
|
||||
<van-button type="danger" block :loading="formLoading" @click="submitSeconded(false)">不同意</van-button>
|
||||
<van-button type="primary" block :loading="formLoading" @click="submitSeconded(true)">同意</van-button>
|
||||
</div>
|
||||
</div>
|
||||
</proposal-info>
|
||||
</div>
|
||||
<script nonce="${cspNonce!}">
|
||||
<!--#include("../../common/info.js"){}#-->
|
||||
|
||||
new Vue({
|
||||
el: "#app",
|
||||
store,
|
||||
components: {
|
||||
"proposal-info": PROPOSAL_INFO
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
bizId: "",
|
||||
action: "view",
|
||||
curTaskCode: "",
|
||||
formData: {},
|
||||
formLoading: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isApproval() {
|
||||
return this.action === "approval"
|
||||
},
|
||||
pageTitle() {
|
||||
return this.isApproval ? "提案附议" : "提案详情"
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* 提交附议结果。
|
||||
* isAgree 为 true 表示同意、false 表示不同意;接口返回 Result,code 为 0 表示提交成功。
|
||||
*/
|
||||
submitSeconded(isAgree) {
|
||||
this.$refs.formRef.validate()
|
||||
.then(() => this.$dialog.confirm({title: "提示", message: "您确定要提交吗?"}))
|
||||
.then(() => {
|
||||
this.formLoading = true
|
||||
if (this.curTaskCode === "second") {
|
||||
return this.$axios.post("/platform/proposal/seconded/executeTask", {
|
||||
data: JSON.stringify({
|
||||
...this.formData,
|
||||
submitType: isAgree ? 1 : 20
|
||||
})
|
||||
})
|
||||
}
|
||||
return this.$axios.post("/platform/proposal/seconded/updateInfo", {
|
||||
proposalId: this.formData.proposalId,
|
||||
taskId: this.formData.taskId,
|
||||
taskActorUserId: this.formData.taskActorUserId,
|
||||
opinion: this.formData.tf_opinion,
|
||||
submitType: isAgree ? 1 : 2
|
||||
})
|
||||
})
|
||||
.then((res) => {
|
||||
if (res && res.code === 0) {
|
||||
this.markListCacheCompleted()
|
||||
this.$toast.success(res.msg)
|
||||
this.historyBack()
|
||||
}
|
||||
})
|
||||
.catch(() => {})
|
||||
.finally(() => {
|
||||
this.formLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 附议成功后标记已处理的提案主键。
|
||||
* 返回未附议列表时据此移除原记录,并改用相邻卡片恢复浏览位置。
|
||||
*/
|
||||
markListCacheCompleted() {
|
||||
const cacheKey = "proposal:seconded:h5:list-state"
|
||||
try {
|
||||
const cacheText = sessionStorage.getItem(cacheKey)
|
||||
if (!cacheText) return
|
||||
const cache = JSON.parse(cacheText)
|
||||
cache.completedBizId = this.bizId
|
||||
cache.time = Date.now()
|
||||
sessionStorage.setItem(cacheKey, JSON.stringify(cache))
|
||||
} catch (error) {
|
||||
sessionStorage.removeItem(cacheKey)
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
const params = new URLSearchParams(window.location.search)
|
||||
// bizId、taskId、taskActorUserId 和 curTaskCode 分别用于详情查询、任务定位、附议人校验和提交链路选择。
|
||||
this.bizId = params.get("bizId") || ""
|
||||
this.action = params.get("action") || "view"
|
||||
this.curTaskCode = params.get("curTaskCode") || ""
|
||||
if (this.isApproval) {
|
||||
this.$set(this.formData, "processTaskId", params.get("taskId") || "")
|
||||
this.$set(this.formData, "taskId", params.get("taskId") || "")
|
||||
this.$set(this.formData, "proposalId", this.bizId)
|
||||
this.$set(this.formData, "taskActorUserId", params.get("taskActorUserId") || "")
|
||||
this.$set(this.formData, "taskName", params.get("taskName") || "提案附议")
|
||||
this.$set(this.formData, "tf_opinion", "同意该提案")
|
||||
}
|
||||
if (!this.bizId) {
|
||||
this.$toast.fail("缺少提案参数")
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
+31
-15
@@ -7,9 +7,12 @@ layout("/layouts/platform_h5.html"){
|
||||
height: 26px;
|
||||
}
|
||||
</style>
|
||||
<style id="style-proposal-task-popup-h5">
|
||||
<!--#include("../../common/info.css"){}#-->
|
||||
</style>
|
||||
|
||||
<div id="app">
|
||||
<van-nav-bar title="承办单位意见" left-text="返回" left-arrow @click-left="historyBack" fixed placeholder></van-nav-bar>
|
||||
<van-nav-bar title="承办单位意见" left-text="返回" left-arrow @click-left="handlePageBack" fixed placeholder></van-nav-bar>
|
||||
|
||||
<van-sticky offset-top="46px">
|
||||
<van-search
|
||||
@@ -43,28 +46,30 @@ layout("/layouts/platform_h5.html"){
|
||||
</template>
|
||||
<template #actions="{index,row}">
|
||||
<div class="action-btn" @click="onView(row)">
|
||||
<i class="fa fa-eye"></i>
|
||||
<van-icon class="proposal-action-icon" name="eye-o"></van-icon>
|
||||
<span>查看</span>
|
||||
</div>
|
||||
<div class="action-btn" @click="openSuggestion(row)" v-if="pageForm.approval === true">
|
||||
<i class="fa fa-eye"></i>
|
||||
<van-icon class="proposal-action-icon" name="eye-o"></van-icon>
|
||||
<span>查看意见</span>
|
||||
</div>
|
||||
<div class="action-btn" @click="onAudit(row)">
|
||||
<i class="fa fa-edit"></i>
|
||||
<van-icon class="proposal-action-icon" name="edit"></van-icon>
|
||||
<span>反馈意见</span>
|
||||
</div>
|
||||
</template>
|
||||
</table-list>
|
||||
|
||||
<van-action-sheet v-model="visible" title="意见信息">
|
||||
<div class="detail-container">
|
||||
<van-popup v-model="visible" position="right" class="proposal-full-popup" :close-on-click-overlay="false" get-container="#app">
|
||||
<div class="proposal-full-popup__page">
|
||||
<van-nav-bar @click-left="closeSuggestion" left-arrow left-text="返回" title="意见信息" placeholder fixed></van-nav-bar>
|
||||
<div class="proposal-full-popup__scroll detail-container">
|
||||
<van-cell-group :key="index" v-for="item,index in suggestionList">
|
||||
<template #title>
|
||||
<div style="display: flex; justify-content: space-between; align-items: center">
|
||||
<div>{{ '意见' + (index + 1) }}</div>
|
||||
<div>
|
||||
<van-button type="danger" @click="onDelete(item)" size="small">删除</van-button>
|
||||
<van-button type="danger" @click="onDelete(item)" size="small"><van-icon name="delete-o"></van-icon> 删除</van-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -76,14 +81,19 @@ layout("/layouts/platform_h5.html"){
|
||||
<span v-html="item.opinion"></span>
|
||||
</van-cell>
|
||||
</van-cell-group>
|
||||
</div>
|
||||
</div>
|
||||
</van-action-sheet>
|
||||
</van-popup>
|
||||
<proposal-task-popup ref="taskPopup" kind="suggestion" page-key="proposal-suggestion-task" @success="doSearch"></proposal-task-popup>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
<!--#include("../../common/info.js"){}#-->
|
||||
<!--#include("../../common/task-popup.js"){}#-->
|
||||
new Vue({
|
||||
el: "#app",
|
||||
store,
|
||||
components: {"proposal-task-popup": PROPOSAL_TASK_POPUP},
|
||||
data() {
|
||||
return {
|
||||
pageForm: {
|
||||
@@ -99,9 +109,13 @@ layout("/layouts/platform_h5.html"){
|
||||
sessionOptions: [],
|
||||
suggestionList: [],
|
||||
visible: false,
|
||||
historyLayerPageKey: "proposal-suggestion-list"
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
registerHistoryLayers() { window.h5HistoryLayerManager.register(this.historyLayerPageKey, (stack) => this.$set(this, "visible", stack.includes("opinions"))) },
|
||||
handlePageBack() { if (window.h5HistoryLayerManager.stack.length) { window.h5HistoryLayerManager.close(); return } historyBack() },
|
||||
closeSuggestion() { window.h5HistoryLayerManager.close("opinions") },
|
||||
onDelete(row) {
|
||||
this.$dialog.confirm({
|
||||
title: "提示",
|
||||
@@ -111,7 +125,7 @@ layout("/layouts/platform_h5.html"){
|
||||
.then(res => {
|
||||
if(res.code === 0) {
|
||||
this.$toast.success(res.msg)
|
||||
this.visible = false
|
||||
this.closeSuggestion()
|
||||
this.doSearch()
|
||||
} else {
|
||||
this.$message.fail(res.msg)
|
||||
@@ -124,12 +138,12 @@ layout("/layouts/platform_h5.html"){
|
||||
proposalId: row.id,
|
||||
}).then(res => {
|
||||
if(res.code === 0) {
|
||||
this.suggestionList = res.data
|
||||
this.$set(this, "suggestionList", res.data)
|
||||
if(this.suggestionList.length === 0) {
|
||||
this.$toast('暂无意见数')
|
||||
return
|
||||
}
|
||||
this.visible = true
|
||||
window.h5HistoryLayerManager.open("opinions")
|
||||
} else {
|
||||
this.$toast.fail(res.msg)
|
||||
}
|
||||
@@ -155,19 +169,21 @@ layout("/layouts/platform_h5.html"){
|
||||
})
|
||||
},
|
||||
onAudit(row) {
|
||||
this.$pjaxReplace("/platform/proposal/suggestion/info/h5?bizId=" + encodeURIComponent(row.id) + "&action=approval")
|
||||
this.$refs.taskPopup.open(row, "approval")
|
||||
},
|
||||
onView(row) {
|
||||
this.$pjaxReplace("/platform/proposal/suggestion/info/h5?bizId=" + encodeURIComponent(row.id) + "&action=view")
|
||||
this.$refs.taskPopup.open(row, "view")
|
||||
},
|
||||
doSearch() {
|
||||
this.$nextTick(() => {
|
||||
this.pageForm.pageNumber = 1
|
||||
this.pageForm.totalCount = 0
|
||||
this.$set(this.pageForm, "pageNumber", 1)
|
||||
this.$set(this.pageForm, "totalCount", 0)
|
||||
this.$refs.tableListRef.doSearch()
|
||||
})
|
||||
}
|
||||
},
|
||||
created() { this.registerHistoryLayers() },
|
||||
beforeDestroy() { window.h5HistoryLayerManager.unregister(this.historyLayerPageKey) }
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
-118
@@ -1,118 +0,0 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_h5.html"){
|
||||
#-->
|
||||
<style id="style-proposal-info-h5">
|
||||
<!--#include("../../common/info.css"){}#-->
|
||||
</style>
|
||||
<div id="app" v-cloak>
|
||||
<van-nav-bar @click-left="historyBack" left-arrow left-text="返回" :title="pageTitle" placeholder fixed></van-nav-bar>
|
||||
<proposal-info v-if="bizId" :biz-id="bizId">
|
||||
<div v-if="isApproval">
|
||||
<div class="process-title">承办单位意见</div>
|
||||
<van-form ref="formRef">
|
||||
<van-field
|
||||
v-model="formData.result"
|
||||
name="result"
|
||||
label="承办意向"
|
||||
placeholder="请选择承办意向"
|
||||
:rules="[{ required: true, message: '请选择承办意向' }]"
|
||||
required
|
||||
is-link
|
||||
@click="showPicker = true"
|
||||
></van-field>
|
||||
<van-popup v-model="showPicker" position="bottom">
|
||||
<van-picker
|
||||
show-toolbar
|
||||
:columns="dict.type.UNDERTAKE_SUGGESTION.map(item => item.code)"
|
||||
@confirm="onResultConfirm"
|
||||
@cancel="showPicker = false"
|
||||
></van-picker>
|
||||
</van-popup>
|
||||
<van-field
|
||||
v-model="formData.opinion"
|
||||
name="opinion"
|
||||
label="反馈意见"
|
||||
placeholder="请输入反馈意见"
|
||||
:rules="[{ required: true, message: '请输入反馈意见' }]"
|
||||
required
|
||||
show-word-limit
|
||||
></van-field>
|
||||
</van-form>
|
||||
<div style="display: flex; justify-content: space-between; column-gap: 10px; padding: 10px">
|
||||
<van-button block :disabled="formLoading" @click="historyBack">取消</van-button>
|
||||
<van-button type="primary" block :loading="formLoading" @click="doSubmit">提交</van-button>
|
||||
</div>
|
||||
</div>
|
||||
</proposal-info>
|
||||
</div>
|
||||
<script nonce="${cspNonce!}">
|
||||
<!--#include("../../common/info.js"){}#-->
|
||||
|
||||
new Vue({
|
||||
el: "#app",
|
||||
store,
|
||||
dicts: ["UNDERTAKE_SUGGESTION"],
|
||||
components: {
|
||||
"proposal-info": PROPOSAL_INFO
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
bizId: "",
|
||||
action: "view",
|
||||
formData: {},
|
||||
formLoading: false,
|
||||
showPicker: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isApproval() {
|
||||
return this.action === "approval"
|
||||
},
|
||||
pageTitle() {
|
||||
return this.isApproval ? "承办单位意见" : "提案详情"
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onResultConfirm(value) {
|
||||
this.$set(this.formData, "result", value)
|
||||
this.showPicker = false
|
||||
},
|
||||
/**
|
||||
* 提交承办单位意见;参数包含 proposalId、result 和 opinion,接口返回 Result。
|
||||
*/
|
||||
doSubmit() {
|
||||
this.$refs.formRef.validate()
|
||||
.then(() => this.$dialog.confirm({title: "提示", message: "您确定要提交吗?"}))
|
||||
.then(() => {
|
||||
this.formLoading = true
|
||||
return this.$axios.post("/platform/proposal/suggestion/suggest", this.formData)
|
||||
})
|
||||
.then((res) => {
|
||||
if (res && res.code === 0) {
|
||||
this.$toast.success(res.msg)
|
||||
this.historyBack()
|
||||
}
|
||||
})
|
||||
.catch(() => {})
|
||||
.finally(() => {
|
||||
this.formLoading = false
|
||||
})
|
||||
}
|
||||
},
|
||||
created() {
|
||||
const params = new URLSearchParams(window.location.search)
|
||||
// bizId 为提案详情查询和承办单位意见保存共同使用的提案主键。
|
||||
this.bizId = params.get("bizId") || ""
|
||||
this.action = params.get("action") || "view"
|
||||
if (this.isApproval) {
|
||||
this.$set(this.formData, "proposalId", this.bizId)
|
||||
}
|
||||
if (!this.bizId) {
|
||||
this.$toast.fail("缺少提案参数")
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
+17
-265
@@ -229,6 +229,9 @@ layout("/layouts/platform_h5.html"){
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style id="style-proposal-task-popup-h5">
|
||||
<!--#include("../../common/info.css"){}#-->
|
||||
</style>
|
||||
<div id="app" v-cloak>
|
||||
<div class="proposal-unit-reply-page">
|
||||
<van-nav-bar @click-left="historyBack" left-arrow left-text="返回" title="承办单位答复" placeholder fixed></van-nav-bar>
|
||||
@@ -304,22 +307,22 @@ layout("/layouts/platform_h5.html"){
|
||||
</template>
|
||||
<template #actions="{index,row}">
|
||||
<div class="action-btn" @click="onView(row,index)">
|
||||
<i class="fa fa-eye"></i>
|
||||
<van-icon class="proposal-action-icon" name="eye-o"></van-icon>
|
||||
<span>查看</span>
|
||||
</div>
|
||||
<div class="action-btn" v-if="row.taskState === 10" @click="onApproval(row,index)">
|
||||
<i class="fa fa-edit"></i>
|
||||
<van-icon class="proposal-action-icon" name="edit"></van-icon>
|
||||
<span>答复</span>
|
||||
</div>
|
||||
<div class="action-btn delete" v-if="row.canRevoke" @click="onRevoke(row)">
|
||||
<i class="fa fa-reply"></i>
|
||||
<van-icon class="proposal-action-icon" name="revoke"></van-icon>
|
||||
<span>撤回</span>
|
||||
</div>
|
||||
|
||||
<!-- 承办单位领导、超级管理员才能转办。 -->
|
||||
<div class="action-btn" v-if="!pageForm.approval && $auth.hasRoleOr('SYSADMIN,PROPOSAL_UNIT_LEADER')"
|
||||
@click="openTransfer(row)">
|
||||
<i class="fa fa-arrow-right"></i>
|
||||
<van-icon class="proposal-action-icon" name="exchange"></van-icon>
|
||||
<span>转交</span>
|
||||
</div>
|
||||
</template>
|
||||
@@ -328,10 +331,13 @@ layout("/layouts/platform_h5.html"){
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<transfer ref="transferRef"></transfer>
|
||||
<transfer ref="transferRef" @success="doSearch"></transfer>
|
||||
<proposal-task-popup ref="taskPopup" kind="unitReply" page-key="proposal-unit-reply-task" @success="doSearch"></proposal-task-popup>
|
||||
</div>
|
||||
<script nonce="${cspNonce!}">
|
||||
<!--#include("transfer.js"){}#-->
|
||||
<!--#include("../../common/info.js"){}#-->
|
||||
<!--#include("../../common/task-popup.js"){}#-->
|
||||
|
||||
const vue = new Vue({
|
||||
el: "#app",
|
||||
@@ -355,19 +361,14 @@ layout("/layouts/platform_h5.html"){
|
||||
{text: "未审核", value: "0"},
|
||||
{text: "已审核", value: "1"}
|
||||
],
|
||||
pendingListCache: null
|
||||
}
|
||||
},
|
||||
components: {
|
||||
"transfer": transfer
|
||||
"transfer": transfer,
|
||||
"proposal-task-popup": PROPOSAL_TASK_POPUP
|
||||
},
|
||||
methods: {
|
||||
onReady() {
|
||||
if (this.pendingListCache) {
|
||||
this.restoreListCache()
|
||||
this.listSession(true)
|
||||
return
|
||||
}
|
||||
this.listSession(false)
|
||||
},
|
||||
|
||||
@@ -392,257 +393,11 @@ layout("/layouts/platform_h5.html"){
|
||||
},
|
||||
|
||||
onView(row, index) {
|
||||
this.saveListCache(row, index)
|
||||
this.$pjaxReplace("/platform/proposal/unitReply/info/h5?bizId=" + encodeURIComponent(row.id) + "&action=view")
|
||||
this.$refs.taskPopup.open(row, "view")
|
||||
},
|
||||
|
||||
onApproval(row, index) {
|
||||
this.saveListCache(row, index)
|
||||
const params = new URLSearchParams()
|
||||
params.set("bizId", row.id)
|
||||
params.set("action", "approval")
|
||||
params.set("taskId", row.taskId)
|
||||
params.set("taskKey", row.taskKey || "")
|
||||
params.set("taskName", row.taskName || "承办单位答复")
|
||||
params.set("underTakeName", row.underTakeName || "")
|
||||
params.set("underTakeIsMaster", row.underTakeIsMaster ? "1" : "0")
|
||||
this.$pjaxReplace("/platform/proposal/unitReply/info/h5?" + params.toString())
|
||||
},
|
||||
|
||||
getListCacheKey() {
|
||||
return "proposal:unit-reply:h5:list-state"
|
||||
},
|
||||
|
||||
getListCacheTokenParam() {
|
||||
return "unitReplyListCacheToken"
|
||||
},
|
||||
|
||||
getCurrentListCacheToken() {
|
||||
return new URLSearchParams(window.location.search).get(this.getListCacheTokenParam()) || ""
|
||||
},
|
||||
|
||||
/**
|
||||
* 将承办单位答复列表缓存标识绑定到当前历史记录。
|
||||
* PJAX 返回时仅恢复当前历史记录对应的筛选条件、分页数据和滚动快照。
|
||||
*/
|
||||
bindListCacheToken(token) {
|
||||
const currentUrl = new URL(window.location.href)
|
||||
currentUrl.searchParams.set(this.getListCacheTokenParam(), token)
|
||||
const currentState = window.history.state ? {...window.history.state} : null
|
||||
if (currentState && currentState.url) {
|
||||
currentState.url = currentUrl.toString()
|
||||
}
|
||||
window.history.replaceState(currentState, document.title, currentUrl.toString())
|
||||
if ($.pjax && $.pjax.state) {
|
||||
$.pjax.state.url = currentUrl.toString()
|
||||
}
|
||||
},
|
||||
|
||||
// 用户主动搜索、切换届次或审核状态时使旧返回缓存失效。
|
||||
clearListCache() {
|
||||
const token = this.getCurrentListCacheToken()
|
||||
if (!token) return
|
||||
const currentUrl = new URL(window.location.href)
|
||||
currentUrl.searchParams.delete(this.getListCacheTokenParam())
|
||||
const currentState = window.history.state ? {...window.history.state} : null
|
||||
if (currentState && currentState.url) {
|
||||
currentState.url = currentUrl.toString()
|
||||
}
|
||||
window.history.replaceState(currentState, document.title, currentUrl.toString())
|
||||
if ($.pjax && $.pjax.state) {
|
||||
$.pjax.state.url = currentUrl.toString()
|
||||
}
|
||||
sessionStorage.removeItem(this.getListCacheKey())
|
||||
},
|
||||
|
||||
// platform_h5 的实际滚动区域是 page-wrapper,列表位置必须基于该容器保存和恢复。
|
||||
getListScrollContainer() {
|
||||
return document.querySelector(".page-wrapper") || document.scrollingElement || document.documentElement
|
||||
},
|
||||
|
||||
/**
|
||||
* 进入查看或答复详情前保存列表现场。
|
||||
* 承办答复可能一案多任务,因此 row 和相邻锚点均使用唯一 taskId,不能使用重复的提案 id。
|
||||
*/
|
||||
saveListCache(row, index) {
|
||||
const tableList = this.$refs.tableListRef
|
||||
if (!tableList) return
|
||||
const cacheToken = Date.now() + "-" + Math.random().toString(36).slice(2)
|
||||
const tableState = typeof tableList.getListState === "function"
|
||||
? tableList.getListState()
|
||||
: {
|
||||
tableData: JSON.parse(JSON.stringify(tableList.tableData || [])),
|
||||
localPageForm: JSON.parse(JSON.stringify(tableList.localPageForm || this.pageForm)),
|
||||
tableFinished: !!tableList.tableFinished
|
||||
}
|
||||
const cards = document.querySelectorAll(".proposal-unit-reply-list .table-list-item")
|
||||
const currentCard = cards[index]
|
||||
const scrollContainer = this.getListScrollContainer()
|
||||
const cache = {
|
||||
time: Date.now(),
|
||||
token: cacheToken,
|
||||
pageForm: JSON.parse(JSON.stringify(this.pageForm)),
|
||||
tableState: tableState,
|
||||
completedTaskId: "",
|
||||
anchor: {
|
||||
taskId: row.taskId,
|
||||
previousTaskId: index > 0 && tableState.tableData[index - 1]
|
||||
? tableState.tableData[index - 1].taskId
|
||||
: "",
|
||||
nextTaskId: tableState.tableData[index + 1] ? tableState.tableData[index + 1].taskId : "",
|
||||
viewportTop: currentCard ? currentCard.getBoundingClientRect().top : 0,
|
||||
scrollTop: scrollContainer ? scrollContainer.scrollTop : 0
|
||||
}
|
||||
}
|
||||
try {
|
||||
sessionStorage.setItem(this.getListCacheKey(), JSON.stringify(cache))
|
||||
this.bindListCacheToken(cacheToken)
|
||||
} catch (error) {
|
||||
sessionStorage.removeItem(this.getListCacheKey())
|
||||
}
|
||||
},
|
||||
|
||||
// 仅恢复当前历史记录对应且十分钟内有效的承办单位答复列表缓存。
|
||||
prepareListCache() {
|
||||
try {
|
||||
const cacheToken = this.getCurrentListCacheToken()
|
||||
if (!cacheToken) return
|
||||
const cacheText = sessionStorage.getItem(this.getListCacheKey())
|
||||
if (!cacheText) return
|
||||
const cache = JSON.parse(cacheText)
|
||||
if (!cache || cache.token !== cacheToken || !cache.tableState) return
|
||||
if (Date.now() - cache.time > 10 * 60 * 1000) {
|
||||
this.clearListCache()
|
||||
return
|
||||
}
|
||||
Object.keys(cache.pageForm || {}).forEach((key) => {
|
||||
this.$set(this.pageForm, key, cache.pageForm[key])
|
||||
})
|
||||
this.$set(this, "pendingListCache", cache)
|
||||
} catch (error) {
|
||||
sessionStorage.removeItem(this.getListCacheKey())
|
||||
}
|
||||
},
|
||||
|
||||
// 普通查看返回恢复旧快照;答复完成返回重新查询,避免未审核列表继续显示已处理任务。
|
||||
restoreListCache() {
|
||||
const cache = this.pendingListCache
|
||||
const tableList = this.$refs.tableListRef
|
||||
if (!cache || !tableList) return
|
||||
const anchor = cache.anchor || {}
|
||||
if (cache.completedTaskId) {
|
||||
this.refreshCompletedListCache(cache)
|
||||
return
|
||||
}
|
||||
this.applyListCache(cache.tableState, anchor.taskId, anchor)
|
||||
},
|
||||
|
||||
/**
|
||||
* 按离开前已加载页数重新获取答复后的列表。
|
||||
* 返回值转换为 TableList 状态,并优先定位下一任务,没有下一任务时定位上一任务。
|
||||
*/
|
||||
refreshCompletedListCache(cache) {
|
||||
const originalPageSize = Number(cache.pageForm.pageSize || 10)
|
||||
const loadedCount = Math.max(cache.tableState.tableData.length, originalPageSize)
|
||||
const loadedPageCount = Math.max(1, Math.ceil(loadedCount / originalPageSize))
|
||||
const requestForm = {
|
||||
...cache.pageForm,
|
||||
pageNumber: 1,
|
||||
pageSize: loadedPageCount * originalPageSize
|
||||
}
|
||||
const loading = createListLoading()
|
||||
this.$axios.post("/platform/proposal/unitReply/pageData", requestForm, {h5SkeletonLoading: true})
|
||||
.then((res) => {
|
||||
if (res.code !== 0) {
|
||||
this.applyCompletedCacheFallback(cache)
|
||||
return
|
||||
}
|
||||
const freshState = {
|
||||
tableData: res.data.list || [],
|
||||
localPageForm: {
|
||||
...cache.pageForm,
|
||||
pageNumber: loadedPageCount,
|
||||
pageSize: originalPageSize,
|
||||
totalCount: res.data.totalCount
|
||||
},
|
||||
tableFinished: (res.data.list || []).length >= res.data.totalCount
|
||||
}
|
||||
const anchor = cache.anchor || {}
|
||||
this.applyListCache(freshState, anchor.nextTaskId || anchor.previousTaskId, anchor)
|
||||
})
|
||||
.catch(() => {
|
||||
this.applyCompletedCacheFallback(cache)
|
||||
})
|
||||
.finally(() => {
|
||||
loading.close()
|
||||
})
|
||||
},
|
||||
|
||||
// 答复后刷新失败时只处理已完成 taskId,避免误删同一提案下的其他承办任务。
|
||||
applyCompletedCacheFallback(cache) {
|
||||
const tableState = cache.tableState
|
||||
const completedIndex = tableState.tableData.findIndex((item) => String(item.taskId) === String(cache.completedTaskId))
|
||||
if (completedIndex >= 0 && cache.pageForm.approval === false) {
|
||||
tableState.tableData.splice(completedIndex, 1)
|
||||
if (tableState.localPageForm && tableState.localPageForm.totalCount > 0) {
|
||||
tableState.localPageForm.totalCount--
|
||||
}
|
||||
} else if (completedIndex >= 0) {
|
||||
this.$set(tableState.tableData[completedIndex], "taskState", 20)
|
||||
}
|
||||
const anchor = cache.anchor || {}
|
||||
this.applyListCache(tableState, anchor.nextTaskId || anchor.previousTaskId, anchor)
|
||||
},
|
||||
|
||||
/**
|
||||
* 恢复 TableList 数据并将目标任务卡片放回离开页面前的视口位置。
|
||||
* sticky 吸顶会改变一次布局,因此首次滚动后再执行一次位置校正。
|
||||
*/
|
||||
applyListCache(tableState, targetTaskId, anchor) {
|
||||
const tableList = this.$refs.tableListRef
|
||||
if (!tableList) return
|
||||
if (typeof tableList.restoreListState === "function") {
|
||||
if (!tableList.restoreListState(tableState)) return
|
||||
} else {
|
||||
this.$set(tableList, "tableData", tableState.tableData || [])
|
||||
this.$set(tableList, "localPageForm", {...tableList.localPageForm, ...(tableState.localPageForm || {})})
|
||||
this.$set(tableList, "tableFinished", !!tableState.tableFinished)
|
||||
this.$set(tableList, "tableLoading", false)
|
||||
this.$set(tableList, "tableRefreshing", false)
|
||||
tableList.$emit("update:page_form", {...tableList.localPageForm})
|
||||
}
|
||||
this.$set(this, "pendingListCache", null)
|
||||
this.$nextTick(() => {
|
||||
setTimeout(() => {
|
||||
const cards = Array.from(document.querySelectorAll(".proposal-unit-reply-list .table-list-item"))
|
||||
const scrollContainer = this.getListScrollContainer()
|
||||
if (!scrollContainer) return
|
||||
const candidateTaskIds = [targetTaskId, anchor.nextTaskId, anchor.previousTaskId]
|
||||
.filter((taskId) => taskId)
|
||||
.map((taskId) => String(taskId))
|
||||
.filter((taskId, index, values) => values.indexOf(taskId) === index)
|
||||
let targetIndex = -1
|
||||
candidateTaskIds.some((candidateTaskId) => {
|
||||
targetIndex = (tableState.tableData || [])
|
||||
.findIndex((item) => String(item.taskId) === candidateTaskId)
|
||||
return targetIndex >= 0
|
||||
})
|
||||
const targetCard = targetIndex >= 0 ? cards[targetIndex] : null
|
||||
if (targetCard) {
|
||||
const restoreTargetCard = () => {
|
||||
if (!targetCard.isConnected) return
|
||||
const targetTop = scrollContainer.scrollTop
|
||||
+ targetCard.getBoundingClientRect().top
|
||||
- Number(anchor.viewportTop || 0)
|
||||
scrollContainer.scrollTo(0, Math.max(0, targetTop))
|
||||
}
|
||||
restoreTargetCard()
|
||||
setTimeout(restoreTargetCard, 100)
|
||||
return
|
||||
}
|
||||
scrollContainer.scrollTo(0, Number(anchor.scrollTop || 0))
|
||||
}, 0)
|
||||
})
|
||||
this.$refs.taskPopup.open(row, "approval")
|
||||
},
|
||||
|
||||
onRevoke(row) {
|
||||
@@ -665,17 +420,14 @@ layout("/layouts/platform_h5.html"){
|
||||
},
|
||||
|
||||
doSearch() {
|
||||
this.clearListCache()
|
||||
this.$nextTick(() => {
|
||||
this.pageForm.pageNumber = 1
|
||||
this.pageForm.totalCount = 0
|
||||
this.$set(this.pageForm, "pageNumber", 1)
|
||||
this.$set(this.pageForm, "totalCount", 0)
|
||||
this.$refs.tableListRef.doSearch()
|
||||
})
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.prepareListCache()
|
||||
if (this.pendingListCache) return
|
||||
const tab = new URLSearchParams(window.location.search).get("tab")
|
||||
if (tab === "done") {
|
||||
this.$set(this.pageForm, "approval", true)
|
||||
|
||||
-188
@@ -1,188 +0,0 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_h5.html"){
|
||||
#-->
|
||||
<style id="style-proposal-info-h5">
|
||||
<!--#include("../../common/info.css"){}#-->
|
||||
</style>
|
||||
<div id="app" v-cloak>
|
||||
<van-nav-bar @click-left="historyBack" left-arrow left-text="返回" :title="pageTitle" placeholder fixed></van-nav-bar>
|
||||
<proposal-info v-if="bizId" :biz-id="bizId">
|
||||
<div v-if="isApproval">
|
||||
<div class="process-title">{{formData.taskName}}</div>
|
||||
<van-form ref="formRef">
|
||||
<van-field :value="formData.underTakeName" label="承办单位" readonly></van-field>
|
||||
<van-field
|
||||
v-model="formData.tf_implementStateName"
|
||||
name="tf_implementStateName"
|
||||
label="落实情况"
|
||||
placeholder="请选择落实情况"
|
||||
:rules="[{ required: true, message: '请选择落实情况' }]"
|
||||
required
|
||||
is-link
|
||||
@click="showImplementPicker = true"
|
||||
></van-field>
|
||||
<van-popup v-model="showImplementPicker" position="bottom">
|
||||
<van-picker
|
||||
show-toolbar
|
||||
:columns="dict.type.PROPOSAL_REPLY_IMPLEMENT.map(item => ({text: item.label, value: item.code}))"
|
||||
@confirm="onImplementConfirm"
|
||||
@cancel="showImplementPicker = false"
|
||||
></van-picker>
|
||||
</van-popup>
|
||||
<van-field
|
||||
v-model="formData.tf_opinion"
|
||||
name="tf_opinion"
|
||||
label="答复内容"
|
||||
placeholder="请输入答复内容"
|
||||
:rules="[{ required: true, message: '请填写答复内容' }]"
|
||||
required
|
||||
maxlength="100"
|
||||
show-word-limit
|
||||
></van-field>
|
||||
<van-field
|
||||
v-if="supportCandidate && formData.underTakeIsMaster"
|
||||
v-model="formData.tf_nextNodeOperatorName"
|
||||
name="tf_nextNodeOperatorName"
|
||||
label="校领导"
|
||||
placeholder="请选择校领导"
|
||||
:rules="[{ required: true, message: '请选择校领导' }]"
|
||||
required
|
||||
is-link
|
||||
@click="showCandidatesPicker = true"
|
||||
></van-field>
|
||||
<van-popup v-model="showCandidatesPicker" position="bottom">
|
||||
<van-picker
|
||||
show-toolbar
|
||||
:columns="candidates.map(item => ({text: item.userName, value: item.userId}))"
|
||||
@confirm="onCandidatesConfirm"
|
||||
@cancel="showCandidatesPicker = false"
|
||||
></van-picker>
|
||||
</van-popup>
|
||||
</van-form>
|
||||
<div style="display: flex; justify-content: space-between; column-gap: 10px; padding: 10px">
|
||||
<van-button block :disabled="formLoading" @click="historyBack">取消</van-button>
|
||||
<van-button type="primary" block :loading="formLoading" @click="handleTaskAction">提交</van-button>
|
||||
</div>
|
||||
</div>
|
||||
</proposal-info>
|
||||
</div>
|
||||
<script nonce="${cspNonce!}">
|
||||
<!--#include("../../common/info.js"){}#-->
|
||||
|
||||
new Vue({
|
||||
el: "#app",
|
||||
store,
|
||||
dicts: ["PROPOSAL_REPLY_IMPLEMENT"],
|
||||
components: {
|
||||
"proposal-info": PROPOSAL_INFO
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
bizId: "",
|
||||
action: "view",
|
||||
formData: {},
|
||||
formLoading: false,
|
||||
showImplementPicker: false,
|
||||
supportCandidate: false,
|
||||
candidates: [],
|
||||
showCandidatesPicker: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isApproval() {
|
||||
return this.action === "approval"
|
||||
},
|
||||
pageTitle() {
|
||||
return this.isApproval ? "承办单位答复" : "提案详情"
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* taskId 为当前 WF 任务主键;接口返回 candidates 候选人数组和 support 是否需要选择候选人。
|
||||
*/
|
||||
loadCandidates(taskId) {
|
||||
this.$axios.post("/flow/common/candidate", {taskId: taskId}).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.candidates = res.data.candidates
|
||||
this.supportCandidate = res.data.support
|
||||
}
|
||||
})
|
||||
},
|
||||
onImplementConfirm(value) {
|
||||
this.$set(this.formData, "tf_implementStateName", value.text)
|
||||
this.$set(this.formData, "tf_implementState", value.value)
|
||||
this.showImplementPicker = false
|
||||
},
|
||||
onCandidatesConfirm(value) {
|
||||
this.$set(this.formData, "tf_nextNodeOperatorName", value.text)
|
||||
this.$set(this.formData, "tf_nextNodeOperator", value.value)
|
||||
this.showCandidatesPicker = false
|
||||
},
|
||||
/**
|
||||
* 提交承办单位答复;请求 data 包含任务、落实情况、答复内容及可选校领导,返回 Result。
|
||||
*/
|
||||
handleTaskAction() {
|
||||
this.$refs.formRef.validate()
|
||||
.then(() => this.$dialog.confirm({title: "提示", message: "您确定要提交吗?"}))
|
||||
.then(() => {
|
||||
const submitData = {...this.formData, submitType: 1}
|
||||
delete submitData.underTakeIsMaster
|
||||
delete submitData.underTakeName
|
||||
this.formLoading = true
|
||||
return this.$axios.post("/flow/common/executeTask", {data: JSON.stringify(submitData)})
|
||||
})
|
||||
.then((res) => {
|
||||
if (res && res.code === 0) {
|
||||
this.markListCacheCompleted()
|
||||
this.$toast.success(res.msg)
|
||||
this.historyBack()
|
||||
}
|
||||
})
|
||||
.catch(() => {})
|
||||
.finally(() => {
|
||||
this.formLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 答复成功后记录已处理 WF 任务主键。
|
||||
* 返回列表时按原筛选和已加载范围刷新数据,只移除本次完成的承办任务。
|
||||
*/
|
||||
markListCacheCompleted() {
|
||||
const cacheKey = "proposal:unit-reply:h5:list-state"
|
||||
try {
|
||||
const cacheText = sessionStorage.getItem(cacheKey)
|
||||
if (!cacheText) return
|
||||
const cache = JSON.parse(cacheText)
|
||||
cache.completedTaskId = this.formData.processTaskId || ""
|
||||
cache.time = Date.now()
|
||||
sessionStorage.setItem(cacheKey, JSON.stringify(cache))
|
||||
} catch (error) {
|
||||
sessionStorage.removeItem(cacheKey)
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
const params = new URLSearchParams(window.location.search)
|
||||
// bizId 用于详情查询,其余参数用于恢复当前承办答复任务的表单上下文。
|
||||
this.bizId = params.get("bizId") || ""
|
||||
this.action = params.get("action") || "view"
|
||||
if (this.isApproval) {
|
||||
const taskId = params.get("taskId") || ""
|
||||
this.$set(this.formData, "processTaskId", taskId)
|
||||
this.$set(this.formData, "taskKey", params.get("taskKey") || "")
|
||||
this.$set(this.formData, "taskName", params.get("taskName") || "承办单位答复")
|
||||
this.$set(this.formData, "proposalId", this.bizId)
|
||||
this.$set(this.formData, "underTakeName", params.get("underTakeName") || "")
|
||||
this.$set(this.formData, "underTakeIsMaster", params.get("underTakeIsMaster") === "1")
|
||||
this.loadCandidates(taskId)
|
||||
}
|
||||
if (!this.bizId) {
|
||||
this.$toast.fail("缺少提案参数")
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
+38
-136
@@ -1,147 +1,49 @@
|
||||
const transfer = {
|
||||
template: /*language=HTML*/ `
|
||||
<van-action-sheet v-model="showTransferDialog" title="提案转办">
|
||||
<div class="transfer-dialog">
|
||||
<!-- 提案信息 -->
|
||||
<div class="proposal-info-card">
|
||||
<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>
|
||||
|
||||
<!-- 用户选择 -->
|
||||
<van-field v-model="searchKeyword" label="转交给" placeholder="搜索用户" required readonly @click="showUserList=true"></van-field>
|
||||
<van-popup v-model="showUserList" position="bottom">
|
||||
<van-search v-model="keyword" placeholder="搜索用户" @search="selectTransferUser(keyword)" @cancel="showUserList=false"></van-search>
|
||||
<van-empty v-if="transferUserOptions.length === 0" class="empty-tip">请搜索需要转办的用户</van-empty>
|
||||
<van-cell v-for="item in transferUserOptions" :key="item.id" :title="item.username" @click="selectUser(item)"></van-cell>
|
||||
</van-popup>
|
||||
|
||||
<!-- 底部按钮 -->
|
||||
<div class="button-group">
|
||||
<van-button block plain @click="showTransferDialog = false" class="cancel-btn">取消</van-button>
|
||||
<van-button block type="info" @click="handleTransfer" class="submit-btn">提交</van-button>
|
||||
<van-popup v-model="showTransferDialog" position="right" class="proposal-full-popup" :close-on-click-overlay="false" get-container="#app">
|
||||
<div class="proposal-full-popup__page">
|
||||
<van-nav-bar @click-left="closeTransfer" left-arrow left-text="返回" title="提案转办" placeholder fixed></van-nav-bar>
|
||||
<div class="proposal-full-popup__scroll transfer-dialog">
|
||||
<div class="proposal-info-card">
|
||||
<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>
|
||||
<van-field v-model="searchKeyword" label="转交给" placeholder="搜索用户" required readonly is-link @click="openUserList"></van-field>
|
||||
</div>
|
||||
<div class="button-group"><van-button block plain @click="closeTransfer">取消</van-button><van-button block type="info" @click="handleTransfer">提交</van-button></div>
|
||||
</div>
|
||||
</van-action-sheet>
|
||||
<van-popup v-model="showUserList" position="bottom" :close-on-click-overlay="false">
|
||||
<van-search v-model="keyword" placeholder="搜索用户" @search="selectTransferUser(keyword)" @cancel="closeUserList"></van-search>
|
||||
<van-empty v-if="transferUserOptions.length === 0" class="empty-tip">请搜索需要转办的用户</van-empty>
|
||||
<van-cell v-for="item in transferUserOptions" :key="item.id" :title="item.username" @click="selectUser(item)"></van-cell>
|
||||
</van-popup>
|
||||
<van-dialog :value="confirmVisible" title="提示" :message="confirmMessage" show-cancel-button @confirm="confirmTransfer" @cancel="closeConfirm"></van-dialog>
|
||||
</van-popup>
|
||||
`,
|
||||
data() {
|
||||
return {
|
||||
showTransferDialog: false,
|
||||
transferForm: {},
|
||||
transferUserOptions: [],
|
||||
searchKeyword: '',
|
||||
showUserList: false,
|
||||
keyword: ''
|
||||
return {showTransferDialog:false,transferForm:{},transferUserOptions:[],searchKeyword:"",showUserList:false,keyword:"",confirmVisible:false,historyLayerPageKey:"proposal-unit-reply-transfer",unsubscribeHistoryLayer:null}
|
||||
},
|
||||
computed: {
|
||||
confirmMessage() {
|
||||
const item=this.transferUserOptions.find((option) => option.id === this.transferForm.userId)
|
||||
return "您确定要将" + (this.transferForm.name || "") + "提案转交给" + (item ? item.username : "") + "办理吗?"
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
openTransfer(row) {
|
||||
this.showTransferDialog = true
|
||||
this.transferForm = { taskId: row.taskId, name: row.name, code: row.code, delegationName: row.delegationName }
|
||||
this.searchKeyword = ''
|
||||
},
|
||||
selectUser(item) {
|
||||
this.transferForm.userId = item.id
|
||||
this.searchKeyword = item.username
|
||||
this.showUserList = false
|
||||
},
|
||||
selectTransferUser(keyword) {
|
||||
this.$axios.post("/platform/proposal/unitReply/selectViceUser", {keyword}).then(res => {
|
||||
if (res.code === 0) this.transferUserOptions = res.data
|
||||
})
|
||||
},
|
||||
|
||||
// 转办
|
||||
handleTransfer() {
|
||||
if (!this.transferForm.userId) {
|
||||
this.$toast('请选择转交用户')
|
||||
return
|
||||
}
|
||||
|
||||
const transferUserName = this.transferUserOptions.find(item => item.id === this.transferForm.userId)?.username
|
||||
const name = this.transferForm.name
|
||||
|
||||
this.$dialog.confirm({
|
||||
title: '提示',
|
||||
message: `您确定要将` + name + `提案转交给` + transferUserName + `办理吗?`,
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消'
|
||||
}).then(() => {
|
||||
this.$axios.post('/platform/proposal/unitReply/transfer', this.transferForm).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.$toast.success(res.msg)
|
||||
this.showTransferDialog = false
|
||||
this.doSearch()
|
||||
}
|
||||
})
|
||||
}).catch(() => {
|
||||
// 取消操作
|
||||
})
|
||||
}
|
||||
syncLayers(stack) { this.$set(this,"showTransferDialog",stack.includes("transfer")); this.$set(this,"showUserList",stack.includes("user-list")); this.$set(this,"confirmVisible",stack.includes("confirm")) },
|
||||
openTransfer(row) { this.$set(this,"transferForm",{taskId:row.taskId,name:row.name,code:row.code,delegationName:row.delegationName}); this.$set(this,"searchKeyword",""); window.h5HistoryLayerManager.open("transfer") },
|
||||
closeTransfer() { window.h5HistoryLayerManager.close("transfer") },
|
||||
openUserList() { window.h5HistoryLayerManager.open("user-list") },
|
||||
closeUserList() { window.h5HistoryLayerManager.close("user-list") },
|
||||
closeConfirm() { window.h5HistoryLayerManager.close("confirm") },
|
||||
selectUser(item) { this.$set(this.transferForm,"userId",item.id); this.$set(this,"searchKeyword",item.username); this.closeUserList() },
|
||||
/** keyword 为姓名关键字,接口返回可转交用户数组。 */
|
||||
selectTransferUser(keyword) { this.$axios.post("/platform/proposal/unitReply/selectViceUser",{keyword:keyword}).then((res) => { if (res.code === 0) this.$set(this,"transferUserOptions",res.data || []) }) },
|
||||
handleTransfer() { if (!this.transferForm.userId) { this.$toast("请选择转交用户"); return } window.h5HistoryLayerManager.open("confirm") },
|
||||
/** 提交 taskId 和 userId 完成转办,成功后清理弹层并通知父列表刷新。 */
|
||||
confirmTransfer() { this.$axios.post("/platform/proposal/unitReply/transfer",this.transferForm).then((res) => { if (res.code === 0) { this.$toast.success(res.msg); window.h5HistoryLayerManager.closeAll(() => this.$emit("success")) } }) }
|
||||
},
|
||||
style: /*language=CSS*/ `
|
||||
.transfer-dialog {
|
||||
height: 100%;
|
||||
background: #fff;
|
||||
padding: 16px 16px 65px;
|
||||
}
|
||||
|
||||
.proposal-info-card {
|
||||
background: #f8f9fa;
|
||||
border-radius: 8px;
|
||||
padding: 16px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.proposal-info-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.info-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.info-item label {
|
||||
font-size: 12px;
|
||||
color: #969799;
|
||||
}
|
||||
|
||||
.info-item span {
|
||||
font-size: 14px;
|
||||
color: #323233;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.button-group {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
padding: 16px;
|
||||
background: #fff;
|
||||
border-top: 1px solid #ebedf0;
|
||||
z-index: 10;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
column-gap: 10px;
|
||||
padding: 10px
|
||||
}
|
||||
|
||||
.cancel-btn,
|
||||
.submit-btn {
|
||||
|
||||
}
|
||||
|
||||
.empty-tip {
|
||||
text-align: center;
|
||||
padding: 50px 16px;
|
||||
color: #969799;
|
||||
font-size: 14px;
|
||||
}
|
||||
`
|
||||
created() { window.h5HistoryLayerManager.ensureRegistered(this.historyLayerPageKey); this.$set(this,"unsubscribeHistoryLayer",window.h5HistoryLayerManager.subscribe((stack) => this.syncLayers(stack))) },
|
||||
beforeDestroy() { if (this.unsubscribeHistoryLayer) this.unsubscribeHistoryLayer(); if (window.h5HistoryLayerManager.pageKey === this.historyLayerPageKey) window.h5HistoryLayerManager.unregister(this.historyLayerPageKey) }
|
||||
}
|
||||
|
||||
+55
-4
@@ -1,8 +1,11 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_h5.html"){
|
||||
#-->
|
||||
<style>
|
||||
<!--#include("../../common/info.css"){}#-->
|
||||
</style>
|
||||
<div id="app" v-cloak>
|
||||
<van-nav-bar @click-left="historyBack" left-arrow left-text="返回" title="团长审核" placeholder fixed></van-nav-bar>
|
||||
<van-nav-bar @click-left="handlePageBack" left-arrow left-text="返回" title="团长审核" placeholder fixed></van-nav-bar>
|
||||
<van-sticky offset-top="46px">
|
||||
<van-search
|
||||
v-model="pageForm.name"
|
||||
@@ -35,17 +38,32 @@ layout("/layouts/platform_h5.html"){
|
||||
</template>
|
||||
<template #actions="{index,row}">
|
||||
<div class="action-btn" @click="onView(row)">
|
||||
<i class="fa fa-eye"></i>
|
||||
<van-icon class="proposal-action-icon" name="eye-o"></van-icon>
|
||||
<span>查看</span>
|
||||
</div>
|
||||
</template>
|
||||
</table-list>
|
||||
|
||||
<van-popup v-model="detailVisible" class="proposal-full-popup" position="right"
|
||||
:close-on-click-overlay="false" safe-area-inset-bottom>
|
||||
<div class="proposal-full-popup__page">
|
||||
<van-nav-bar title="提案详情" left-arrow left-text="返回" fixed
|
||||
@click-left="closeHistoryLayer('detail')"></van-nav-bar>
|
||||
<div class="proposal-full-popup__scroll">
|
||||
<proposal-info v-if="detailVisible && detailBizId" :biz-id="detailBizId" :visible="detailVisible"></proposal-info>
|
||||
</div>
|
||||
</div>
|
||||
</van-popup>
|
||||
|
||||
</div>
|
||||
<script nonce="${cspNonce!}">
|
||||
<!--#include("../../common/info.js"){}#-->
|
||||
const vue = new Vue({
|
||||
el: "#app",
|
||||
store,
|
||||
components: {
|
||||
"proposal-info": PROPOSAL_INFO
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
pageForm: {
|
||||
@@ -60,10 +78,34 @@ layout("/layouts/platform_h5.html"){
|
||||
|
||||
sessionOptions: [],
|
||||
formData: {},
|
||||
showApprovalForm: false
|
||||
showApprovalForm: false,
|
||||
detailVisible: false,
|
||||
detailBizId: "",
|
||||
historyLayerPageKey: "proposal-vice-delegation-h5"
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
registerHistoryLayers() {
|
||||
if (!window.h5HistoryLayerManager) return
|
||||
window.h5HistoryLayerManager.register(this.historyLayerPageKey, (stack) => {
|
||||
this.$set(this, "detailVisible", stack.includes("detail"))
|
||||
})
|
||||
},
|
||||
openHistoryLayer(layerName) {
|
||||
if (window.h5HistoryLayerManager && window.h5HistoryLayerManager.open(layerName)) return
|
||||
if (layerName === "detail") this.$set(this, "detailVisible", true)
|
||||
},
|
||||
closeHistoryLayer(layerName) {
|
||||
if (window.h5HistoryLayerManager && window.h5HistoryLayerManager.close(layerName)) return
|
||||
if (layerName === "detail") this.$set(this, "detailVisible", false)
|
||||
},
|
||||
handlePageBack() {
|
||||
if (window.h5HistoryLayerManager && window.h5HistoryLayerManager.stack.length) {
|
||||
window.h5HistoryLayerManager.close()
|
||||
return
|
||||
}
|
||||
this.historyBack()
|
||||
},
|
||||
onReady() {
|
||||
this.listSession()
|
||||
},
|
||||
@@ -85,7 +127,8 @@ layout("/layouts/platform_h5.html"){
|
||||
},
|
||||
|
||||
onView(row) {
|
||||
this.$pjaxReplace("/platform/proposal/vice/delegation/info/h5?bizId=" + encodeURIComponent(row.id))
|
||||
this.$set(this, "detailBizId", row.id)
|
||||
this.openHistoryLayer("detail")
|
||||
},
|
||||
|
||||
doSearch() {
|
||||
@@ -95,6 +138,14 @@ layout("/layouts/platform_h5.html"){
|
||||
this.$refs.tableListRef.doSearch()
|
||||
})
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.registerHistoryLayers()
|
||||
},
|
||||
beforeDestroy() {
|
||||
if (window.h5HistoryLayerManager) {
|
||||
window.h5HistoryLayerManager.unregister(this.historyLayerPageKey)
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
-36
@@ -1,36 +0,0 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_h5.html"){
|
||||
#-->
|
||||
<style id="style-proposal-info-h5">
|
||||
<!--#include("../../common/info.css"){}#-->
|
||||
</style>
|
||||
<div id="app" v-cloak>
|
||||
<van-nav-bar @click-left="historyBack" left-arrow left-text="返回" title="提案详情" placeholder fixed></van-nav-bar>
|
||||
<proposal-info v-if="bizId" :biz-id="bizId"></proposal-info>
|
||||
</div>
|
||||
<script nonce="${cspNonce!}">
|
||||
<!--#include("../../common/info.js"){}#-->
|
||||
|
||||
new Vue({
|
||||
el: "#app",
|
||||
store,
|
||||
components: {
|
||||
"proposal-info": PROPOSAL_INFO
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
bizId: ""
|
||||
}
|
||||
},
|
||||
created() {
|
||||
// bizId 为提案主键,公共详情组件根据该参数返回提案详情对象和流程记录数组。
|
||||
this.bizId = new URLSearchParams(window.location.search).get("bizId") || ""
|
||||
if (!this.bizId) {
|
||||
this.$toast.fail("缺少提案参数")
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
+53
-16
@@ -353,7 +353,7 @@ layout("/layouts/platform_h5.html"){
|
||||
</style>
|
||||
|
||||
<div id="app" v-cloak>
|
||||
<van-nav-bar title="撰写提案" left-text="返回" left-arrow @click-left="historyBack" placeholder fixed z-index="999"
|
||||
<van-nav-bar title="撰写提案" left-text="返回" left-arrow @click-left="handlePageBack" placeholder fixed z-index="999"
|
||||
class="custom-nav"></van-nav-bar>
|
||||
|
||||
<div class="proposal-write-page">
|
||||
@@ -409,7 +409,7 @@ layout("/layouts/platform_h5.html"){
|
||||
@click="setVisibleState('showSessionPicker', true)"
|
||||
:rules="[{ required: true, message: '请选择所属教代会' }]"
|
||||
></van-field>
|
||||
<van-popup v-model="showSessionPicker" position="bottom" round get-container="#app">
|
||||
<van-popup v-model="showSessionPicker" position="bottom" round :close-on-click-overlay="false" get-container="#app">
|
||||
<van-picker
|
||||
show-toolbar
|
||||
:columns="sessionOptions.map(item => ({text: item.fullName, value: item.id}))"
|
||||
@@ -436,7 +436,7 @@ layout("/layouts/platform_h5.html"){
|
||||
@click="setVisibleState('showCommitteePicker', true)"
|
||||
:rules="[{ required: true, message: '请选择所属委员会' }]"
|
||||
></van-field>
|
||||
<van-popup v-model="showCommitteePicker" position="bottom" round get-container="#app">
|
||||
<van-popup v-model="showCommitteePicker" position="bottom" round :close-on-click-overlay="false" get-container="#app">
|
||||
<van-picker
|
||||
show-toolbar
|
||||
:columns="committeeOptions.map(item => ({text: item.name, value: item.id}))"
|
||||
@@ -489,7 +489,7 @@ layout("/layouts/platform_h5.html"){
|
||||
:rules="[{ required: true, message: '请选择提案方式' }]"
|
||||
required
|
||||
></van-field>
|
||||
<van-popup v-model="showSourcePicker" position="bottom" round get-container="#app">
|
||||
<van-popup v-model="showSourcePicker" position="bottom" round :close-on-click-overlay="false" get-container="#app">
|
||||
<van-picker
|
||||
show-toolbar
|
||||
:columns="sourceOptions.map(item => ({text: item.name, value: item.code}))"
|
||||
@@ -555,7 +555,7 @@ layout("/layouts/platform_h5.html"){
|
||||
</section>
|
||||
|
||||
<!-- 各选择器沿用原始数据源与回显逻辑。 -->
|
||||
<van-popup v-model="showTypePicker" position="bottom" round get-container="#app">
|
||||
<van-popup v-model="showTypePicker" position="bottom" round :close-on-click-overlay="false" get-container="#app">
|
||||
<van-picker
|
||||
show-toolbar
|
||||
:columns="typeOptions.map(item => ({text: item.name, value: item.id}))"
|
||||
@@ -564,7 +564,7 @@ layout("/layouts/platform_h5.html"){
|
||||
></van-picker>
|
||||
</van-popup>
|
||||
|
||||
<van-popup v-model="showSuggestionUnitPicker" position="bottom" :style="{ height: '70%' }" round get-container="#app">
|
||||
<van-popup v-model="showSuggestionUnitPicker" position="bottom" :style="{ height: '70%' }" round :close-on-click-overlay="false" get-container="#app">
|
||||
<div class="suggestion-unit-picker">
|
||||
<div class="picker-toolbar">
|
||||
<button type="button" class="picker-cancel" @click="onSuggestionUnitCancel">取消</button>
|
||||
@@ -626,7 +626,9 @@ layout("/layouts/platform_h5.html"){
|
||||
<van-action-sheet v-model="noticeDialogVisible"
|
||||
title="提案撰写须知"
|
||||
cancel-text="我已知晓"
|
||||
close-on-click-action>
|
||||
close-on-click-action
|
||||
:close-on-click-overlay="false"
|
||||
@cancel="setVisibleState('noticeDialogVisible', false)">
|
||||
<div class="notice-dialog-content" v-html="proposalConfig.writeRemind"></div>
|
||||
</van-action-sheet>
|
||||
</div>
|
||||
@@ -670,10 +672,18 @@ layout("/layouts/platform_h5.html"){
|
||||
showSuggestionUnitPicker: false,
|
||||
selectedSuggestionUnits: [], // 当前选中的承办单位
|
||||
suggestionUnitSearchText: '', // 搜索文本
|
||||
filteredSuggestionUnits: [] // 过滤后的承办单位列表
|
||||
filteredSuggestionUnits: [], // 过滤后的承办单位列表
|
||||
historyLayerPageKey: "proposal-write"
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handlePageBack() {
|
||||
if (window.h5HistoryLayerManager.stack.length) {
|
||||
window.h5HistoryLayerManager.close();
|
||||
return;
|
||||
}
|
||||
historyBack();
|
||||
},
|
||||
/**
|
||||
* 更新页面弹层显示状态,避免在模板事件中直接为 Vue 数据赋值。
|
||||
* @param {String} stateName showSessionPicker、showSourcePicker 等弹层状态字段名。
|
||||
@@ -681,7 +691,30 @@ layout("/layouts/platform_h5.html"){
|
||||
* @return {void} 无返回值,仅更新当前页面状态。
|
||||
*/
|
||||
setVisibleState(stateName, visible) {
|
||||
this.$set(this, stateName, visible);
|
||||
const layerName = {
|
||||
showSessionPicker: "session-picker",
|
||||
showSourcePicker: "source-picker",
|
||||
showTypePicker: "type-picker",
|
||||
showCommitteePicker: "committee-picker",
|
||||
showSuggestionUnitPicker: "suggestion-unit-picker",
|
||||
noticeDialogVisible: "notice"
|
||||
}[stateName];
|
||||
if (visible) {
|
||||
window.h5HistoryLayerManager.open(layerName);
|
||||
return;
|
||||
}
|
||||
window.h5HistoryLayerManager.close(layerName);
|
||||
},
|
||||
|
||||
registerHistoryLayers() {
|
||||
window.h5HistoryLayerManager.register(this.historyLayerPageKey, (stack) => {
|
||||
this.$set(this, "showSessionPicker", stack.includes("session-picker"));
|
||||
this.$set(this, "showSourcePicker", stack.includes("source-picker"));
|
||||
this.$set(this, "showTypePicker", stack.includes("type-picker"));
|
||||
this.$set(this, "showCommitteePicker", stack.includes("committee-picker"));
|
||||
this.$set(this, "showSuggestionUnitPicker", stack.includes("suggestion-unit-picker"));
|
||||
this.$set(this, "noticeDialogVisible", stack.includes("notice"));
|
||||
});
|
||||
},
|
||||
|
||||
// 选择器确认事件
|
||||
@@ -691,33 +724,33 @@ layout("/layouts/platform_h5.html"){
|
||||
if (selectedOption) {
|
||||
this.$set(this.formData, 'sessionName', selectedOption.fullName);
|
||||
}
|
||||
this.showSessionPicker = false;
|
||||
this.setVisibleState("showSessionPicker", false);
|
||||
this.meetingChange(value.value);
|
||||
},
|
||||
|
||||
onSourceConfirm(value) {
|
||||
this.formData.source = value.value;
|
||||
this.$set(this.formData, 'sourceName', value.text);
|
||||
this.showSourcePicker = false;
|
||||
this.setVisibleState("showSourcePicker", false);
|
||||
},
|
||||
|
||||
onTypeConfirm(value) {
|
||||
this.$set(this.formData, 'typeId', value.value);
|
||||
this.$set(this.formData, 'typeName', value.text);
|
||||
this.showTypePicker = false;
|
||||
this.setVisibleState("showTypePicker", false);
|
||||
},
|
||||
|
||||
onSuggestionUnitConfirm() {
|
||||
// 将选中的承办单位保存到表单数据中
|
||||
this.formData.suggestUnits = [...this.selectedSuggestionUnits];
|
||||
this.showSuggestionUnitPicker = false;
|
||||
this.setVisibleState("showSuggestionUnitPicker", false);
|
||||
},
|
||||
|
||||
onSuggestionUnitCancel() {
|
||||
// 取消时恢复到之前的选择状态
|
||||
this.selectedSuggestionUnits = [...this.formData.suggestUnits];
|
||||
this.suggestionUnitSearchText = '';
|
||||
this.showSuggestionUnitPicker = false;
|
||||
this.setVisibleState("showSuggestionUnitPicker", false);
|
||||
},
|
||||
|
||||
// 切换承办单位选择状态
|
||||
@@ -750,7 +783,7 @@ layout("/layouts/platform_h5.html"){
|
||||
onCommitteeConfirm(value) {
|
||||
this.formData.committeeId = value.value;
|
||||
this.$set(this.formData, 'committeeName', value.text);
|
||||
this.showCommitteePicker = false;
|
||||
this.setVisibleState("showCommitteePicker", false);
|
||||
},
|
||||
|
||||
// 保存草稿:校验当前表单后保存 ProposalInfo,接口成功时返回提案数据并回到我的提案。
|
||||
@@ -1049,7 +1082,7 @@ layout("/layouts/platform_h5.html"){
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.noticeDialogVisible = true;
|
||||
this.setVisibleState("noticeDialogVisible", true);
|
||||
this.listOpenSession(false);
|
||||
|
||||
// 设置用户信息
|
||||
@@ -1063,10 +1096,14 @@ layout("/layouts/platform_h5.html"){
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.registerHistoryLayers();
|
||||
this.init();
|
||||
this.listSuggestUnit();
|
||||
this.getProposalConfig();
|
||||
},
|
||||
beforeDestroy() {
|
||||
window.h5HistoryLayerManager.unregister(this.historyLayerPageKey);
|
||||
},
|
||||
watch: {
|
||||
// 监听suggestUnitOptions变化,初始化过滤列表
|
||||
suggestUnitOptions: {
|
||||
|
||||
Reference in New Issue
Block a user