This commit is contained in:
2026-05-26 16:39:30 +08:00
parent 194aa4ff0a
commit b2dd2681a2
34 changed files with 5058 additions and 785 deletions
@@ -0,0 +1,145 @@
package io.v.nutz.zhgh.mobile.proposal;
import cn.hutool.core.util.StrUtil;
import io.v.nutz.base.annontation.ViReturn;
import io.v.nutz.base.query.PageForm;
import io.v.nutz.sys.models.Sys_signature;
import io.v.nutz.sys.services.SysSignatureService;
import io.v.nutz.web.commons.utils.ShiroUtil;
import io.v.nutz.zhgh.proposal.constants.ProposalState;
import io.v.nutz.zhgh.proposal.constants.ProposalToDoHandler;
import io.v.nutz.zhgh.proposal.models.ProposalAudit;
import io.v.nutz.zhgh.proposal.models.ProposalBranchLeaderSuffixAudit;
import io.v.nutz.zhgh.proposal.models.ProposalInfo;
import io.v.nutz.zhgh.proposal.models.ProposalReply;
import io.v.nutz.zhgh.proposal.models.ProposalSearch;
import io.v.nutz.zhgh.proposal.models.ProposalUndertake;
import io.v.nutz.zhgh.proposal.services.ProposalBranchLeaderSuffixAuditService;
import io.v.nutz.zhgh.proposal.services.ProposalInfoService;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Chain;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.util.NutMap;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.POST;
import org.nutz.mvc.annotation.Param;
/**
* 手机端分管校领导审批承办答复。
*/
@IocBean
@Ok("json:full")
@At("/mobile/proposal/branchLeaderSuffixAudit")
public class MProposalBranchLeaderSuffixAuditController {
@Inject
private Dao dao;
@Inject
private ProposalInfoService proposalInfoService;
@Inject
private ProposalBranchLeaderSuffixAuditService proposalBranchLeaderSuffixAuditService;
@Inject
private SysSignatureService sysSignatureService;
@At("")
@Ok("beetl:/mobile/proposal/branchLeaderSuffixAudit/list.html")
@RequiresPermissions("proposal.transact.branchLeaderSuffixAudit")
public void index() {
}
@At("/view")
@Ok("beetl:/mobile/proposal/branchLeaderSuffixAudit/audit.html")
@RequiresPermissions("proposal.transact.branchLeaderSuffixAudit")
public void view() {
}
/**
* 手机端分管校领导审批列表。
* 参数说明:
* page:分页参数,包含 pageNumber、pageSize、排序字段等;
* search:筛选参数,meetingId 为届次、proposalTypeId 为提案类型、proposalResultCode 为立案结果、isAudit 表示是否已完成分管校领导审批;
* 返回值:分页结果,list 中包含提案基础信息、承办单位、审批状态、pblsaId 等字段。
*/
@At
@ViReturn
@RequiresPermissions("proposal.transact.branchLeaderSuffixAudit")
public Object pageData(PageForm page, ProposalSearch search) {
Cnd cnd = Cnd.NEW();
proposalInfoService.sortAndSearch(cnd, page, search);
return proposalBranchLeaderSuffixAuditService.pageData(page, cnd, search);
}
/**
* 查询手机端分管校领导审批办理信息。
* 参数说明:
* pblsaIdproposal_branch_leader_suffix_audit 表主键;
* 返回值:NutMap,包含 proposalId、underTakeId、underTakeNames、stateCode、isAudit,用于详情页判断是否显示审核表单。
*/
@At
@ViReturn
@RequiresPermissions("proposal.transact.branchLeaderSuffixAudit")
public Object getAuditInfo(@Param("pblsaId") String pblsaId) {
ProposalBranchLeaderSuffixAudit suffixAudit = dao.fetch(ProposalBranchLeaderSuffixAudit.class, pblsaId);
if (suffixAudit == null) {
return NutMap.NEW();
}
ProposalInfo proposalInfo = dao.fetch(ProposalInfo.class, suffixAudit.getProposalId());
ProposalUndertake undertake = dao.fetch(ProposalUndertake.class, suffixAudit.getUnderTakeId());
ProposalReply reply = dao.fetch(ProposalReply.class,
Cnd.where("proposalId", "=", suffixAudit.getProposalId())
.and("replyUnitId", "=", suffixAudit.getUnderTakeId()));
return NutMap.NEW()
.addv("pblsaId", suffixAudit.getId())
.addv("proposalId", suffixAudit.getProposalId())
.addv("underTakeId", suffixAudit.getUnderTakeId())
.addv("underTakeNames", undertake == null ? "" : undertake.getUnitName())
.addv("undertakeType", reply == null ? "" : reply.getUndertakeType())
.addv("stateCode", proposalInfo == null ? null : proposalInfo.getStateCode())
.addv("isAudit", suffixAudit.getIsAudit());
}
/**
* 手机端提交分管校领导审批。
* 参数说明:
* sign:签名图片数据,可为空,传入后保存为签名记录并写入审核记录 signId;
* auditProposalAudit 审核对象,需包含 proposalId、username、loginName、auditTime、opinion 等字段;
* pblsaIdproposal_branch_leader_suffix_audit 表主键,用于定位本次分管校领导审批记录;
* 返回值:无业务数据,成功时由 ViReturn 包装为成功响应。
*/
@At
@POST
@ViReturn
@RequiresPermissions("proposal.transact.branchLeaderSuffixAudit")
@Aop(TransAop.READ_COMMITTED)
public Object doAudit(@Param(value = "sign", required = false) String sign,
@Param("audit") ProposalAudit audit,
@Param("pblsaId") String pblsaId) {
String signId = null;
if (StrUtil.isNotBlank(sign)) {
signId = sysSignatureService.insert(new Sys_signature(sign)).getId();
}
audit.setUserId(ShiroUtil.getUserId());
audit.setSignId(signId);
dao.insert(audit);
dao.update(ProposalBranchLeaderSuffixAudit.class,
Chain.make("isAudit", true).add("auditId", audit.getId()),
Cnd.where("id", "=", pblsaId));
dao.update(ProposalInfo.class, Chain.make("stateCode", ProposalState.FEEDBACKSCORE), Cnd.where("id", "=", audit.getProposalId()));
ProposalToDoHandler.COMPLETE_BRANCH_LEADER_SUFFIX_AUDIT_TASK.exec(audit.getProposalId(), NutMap.NEW().addv("pblsaId", pblsaId).addv("opinion", audit.getOpinion()));
ProposalToDoHandler.CREATE_FEEDBACK_TASK.exec(audit.getProposalId(), null);
return null;
}
}
@@ -0,0 +1,116 @@
package io.v.nutz.zhgh.mobile.proposal;
import cn.hutool.core.util.StrUtil;
import io.v.nutz.base.annontation.ViReturn;
import io.v.nutz.base.query.PageForm;
import io.v.nutz.sys.models.Sys_signature;
import io.v.nutz.zhgh.proposal.models.ProposalAudit;
import io.v.nutz.zhgh.proposal.models.ProposalSearch;
import io.v.nutz.zhgh.proposal.services.ProposalCaseService;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Dao;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.POST;
import org.nutz.mvc.annotation.Param;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* 手机端提案工作组预立案审核。
*/
@IocBean
@Ok("json:full")
@At("/mobile/proposal/case")
public class MProposalCaseController {
@Inject
private ProposalCaseService proposalCaseService;
@Inject
private Dao dao;
@At("")
@Ok("beetl:/mobile/proposal/case/list.html")
@RequiresPermissions("proposal.transact.case")
public void index() {
}
@At("/view")
@Ok("beetl:/mobile/proposal/case/audit.html")
@RequiresPermissions("proposal.transact.case")
public void view() {
}
/**
* 手机端预立案审核列表。
* 参数说明:
* page:分页参数,包含 pageNumber、pageSize、排序字段等;
* search:筛选参数,meetingId 为届次、proposalTypeId 为提案类型、proposalResultCode 为立案结果、isAudit 表示是否已完成预立案审核;
* 返回值:分页结果,list 中包含提案基础信息、状态、类型、届次、代表团、立案结果等字段。
*/
@At
@ViReturn
@RequiresPermissions("proposal.transact.case")
public Object pageData(PageForm page, ProposalSearch search) {
return proposalCaseService.pageData(page, search);
}
/**
* 手机端承办单位下拉数据。
* 参数说明:无;
* 返回值:承办单位列表,每项包含 id、unitName、unitCode、leader 等字段,leader 为该承办单位对应领导姓名。
*/
@At
@ViReturn
@RequiresPermissions("proposal.transact.case")
public Object getUnderTakeAndLeader() {
return proposalCaseService.getUnderTakeAndLeader();
}
/**
* 手机端提交预立案审核。
* 参数说明:
* auditProposalAudit 审核对象,包含 username、loginName、auditTime、opinion 等审核字段;
* resultCode:立案结果,取 proposal_result 字典 code,如 determine、opinion、notGive
* determineTypeCode:立案类型,可为空;
* typeId:提案类型 id
* hostUnit:主办单位 id
* helpUnit:协办单位 id 数组,可为空;
* sign:签名图片数据,可为空;
* proposalIds:审核提案 id 数组,手机端单条审核时传当前提案 id;
* auditType:审核类型,手机端单条审核传 one;
* flag:审核动作,1 为提交通过,2 为退回修改;
* 返回值:无业务数据,成功时由 ViReturn 包装为成功响应。
*/
@At("/audit")
@POST
@ViReturn
@RequiresPermissions("proposal.transact.case")
@Aop(TransAop.READ_COMMITTED)
public Object audit(@Param("audit") ProposalAudit audit,
@Param("resultCode") String resultCode,
@Param(value = "determineTypeCode", required = false) String determineTypeCode,
@Param("typeId") String typeId,
@Param("hostUnit") String hostUnit,
@Param(value = "helpUnit", required = false) String[] helpUnit,
@Param(value = "sign", required = false) String sign,
@Param("proposalIds") String[] proposalIds,
@Param("auditType") String auditType,
@Param("flag") int flag) {
if (StrUtil.isNotBlank(sign)) {
String signId = dao.insert(new Sys_signature(sign)).getId();
audit.setSignId(signId);
}
audit.setFlag(flag == 1);
List<String> helpUnitList = helpUnit == null ? Collections.emptyList() : Arrays.asList(helpUnit);
proposalCaseService.audit(Arrays.asList(proposalIds), resultCode, determineTypeCode, hostUnit, helpUnitList, typeId, audit, auditType, flag);
return null;
}
}
@@ -0,0 +1,68 @@
package io.v.nutz.zhgh.mobile.proposal;
import io.v.nutz.base.annontation.ViReturn;
import io.v.nutz.base.query.PageForm;
import io.v.nutz.zhgh.proposal.models.ProposalSearch;
import io.v.nutz.zhgh.proposal.services.ProposalCaseReadService;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.Param;
/**
* 手机端提案工作组成员意见审核。
*/
@IocBean
@Ok("json:full")
@At("/mobile/proposal/caseRead")
public class MProposalCaseReadController {
@Inject
private ProposalCaseReadService proposalCaseReadService;
@At("")
@Ok("beetl:/mobile/proposal/caseRead/list.html")
@RequiresPermissions("proposal.transact.caseRead")
public void index() {
}
@At("/view")
@Ok("beetl:/mobile/proposal/caseRead/audit.html")
@RequiresPermissions("proposal.transact.caseRead")
public void view() {
}
/**
* 手机端审核列表。
* 参数说明:
* page:分页参数,包含 pageNumber、pageSize、排序字段等;
* search:筛选参数,meetingId 为届次、proposalTypeId 为提案类型、proposalResultCode 为立案结果、isAudit 表示是否已提交成员意见;
* 返回值:分页结果,list 中包含提案基础信息、状态、类型、届次、代表团、立案结果以及当前用户是否已发表意见 isOpinion。
*/
@At
@ViReturn
@RequiresPermissions("proposal.transact.caseRead")
public Object pageData(PageForm page, ProposalSearch search) {
return proposalCaseReadService.pageData(page, search);
}
/**
* 提交手机端成员意见。
* 参数说明:
* sign:签名图片数据,保存后写入审核记录 signId;
* auditProposalAudit 的 JSON 字符串,需包含 proposalId、username、loginName、auditTime、opinion、other、determineTypeCode 等审核字段;
* proposalId:被审核的提案 id
* 返回值:无业务数据,成功时由 ViReturn 包装为成功响应。
*/
@At
@ViReturn
@RequiresPermissions("proposal.transact.caseRead")
public Object putSuggestion(@Param(value = "sign", required = false) String sign,
@Param("audit") String audit,
@Param("proposalId") String proposalId) {
proposalCaseReadService.putSuggestion(sign, audit, proposalId);
return null;
}
}
@@ -0,0 +1,155 @@
package io.v.nutz.zhgh.mobile.proposal;
import cn.hutool.core.util.StrUtil;
import io.v.nutz.base.annontation.ViReturn;
import io.v.nutz.base.query.PageForm;
import io.v.nutz.base.utils.Roles;
import io.v.nutz.sys.models.Sys_signature;
import io.v.nutz.sys.models.Sys_user_role;
import io.v.nutz.zhgh.proposal.models.ProposalAudit;
import io.v.nutz.zhgh.proposal.models.ProposalReply;
import io.v.nutz.zhgh.proposal.models.ProposalSearch;
import io.v.nutz.zhgh.proposal.services.ProposalCaseConfirmService;
import io.v.nutz.zhgh.proposal.services.ProposalCaseService;
import io.v.nutz.zhgh.proposal.services.ProposalInfoService;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.FieldFilter;
import org.nutz.dao.util.Daos;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Lang;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.POST;
import org.nutz.mvc.annotation.Param;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* 手机端提案工作组正式立案审核。
*/
@IocBean
@Ok("json:full")
@At("/mobile/proposal/caseUnit")
public class MProposalCaseUnitController {
@Inject
private ProposalCaseConfirmService proposalCaseConfirmService;
@Inject
private ProposalCaseService proposalCaseService;
@Inject
private ProposalInfoService proposalInfoService;
@Inject
private Dao dao;
@At("")
@Ok("beetl:/mobile/proposal/caseUnit/list.html")
@RequiresPermissions("proposal.transact.caseUnit")
public void index() {
}
@At("/view")
@Ok("beetl:/mobile/proposal/caseUnit/audit.html")
@RequiresPermissions("proposal.transact.caseUnit")
public void view() {
}
/**
* 手机端正式立案审核列表。
* 参数说明:
* page:分页参数,包含 pageNumber、pageSize、排序字段等;
* search:筛选参数,meetingId 为届次、proposalTypeId 为提案类型、proposalResultCode 为立案结果、isAudit 表示是否已完成正式立案审核;
* 返回值:分页结果,list 中包含提案基础信息、状态、类型、届次、代表团、立案结果、审核状态等字段。
*/
@At
@ViReturn
@RequiresPermissions("proposal.transact.caseUnit")
public Object pageData(PageForm page, ProposalSearch search) {
return proposalCaseConfirmService.pageData(page, search);
}
/**
* 手机端承办单位下拉数据。
* 参数说明:无;
* 返回值:承办单位列表,每项包含 id、unitName、unitCode、leader 等字段,leader 为该承办单位对应领导姓名。
*/
@At
@ViReturn
@RequiresPermissions("proposal.transact.caseUnit")
public Object getUnderTakeAndLeader() {
return proposalCaseService.getUnderTakeAndLeader();
}
/**
* 查询该提案当前已分配的承办单位。
* 参数说明:
* proposalId:提案 id
* 返回值:承办单位列表,每项包含 replyUnitId 与 undertakeTypeundertakeType 为 1 表示主办、2 表示协办。
*/
@At
@ViReturn
@RequiresPermissions("proposal.transact.caseUnit")
public Object queryUnderTakeByProposalId(String proposalId) {
FieldFilter ff = FieldFilter.create(ProposalReply.class, "^replyUnitId|undertakeType$");
return Daos.ext(proposalInfoService.dao(), ff).query(ProposalReply.class, Cnd.where("proposalId", "=", proposalId));
}
/**
* 检查主办单位是否已配置答复人和分管领导。
* 参数说明:
* hostUnit:主办单位 id
* 返回值:boolean,true 表示该单位至少配置了承办人和分管领导角色,可提交正式立案。
*/
@At
@ViReturn
@RequiresPermissions("proposal.transact.caseUnit")
public Object checkUnderTakeUser(String hostUnit) {
String[] roleIds = Lang.array(Roles.CONTRACTOR_PERSON, Roles.IN_CHARGE_LEADER);
int count = dao.count(Sys_user_role.class, Cnd.where("cbdwid", "=", hostUnit).and("roleId", "in", roleIds));
return count >= 2;
}
/**
* 手机端提交正式立案审核。
* 参数说明:
* auditProposalAudit 审核对象,包含 username、loginName、auditTime、opinion 等审核字段;
* resultCode:立案结果,取 proposal_result 字典 code,如 determine、opinion、notGive
* determineTypeCode:立案类型,可为空;
* typeId:提案类型 id
* hostUnit:主办单位 id
* helpUnit:协办单位 id 数组,可为空;
* sign:签名图片数据,可为空;
* proposalIds:审核提案 id 数组,手机端单条审核时传当前提案 id,若存在并案则传并案提案 id 集合;
* 返回值:无业务数据,成功时由 ViReturn 包装为成功响应。
*/
@At("/audit")
@POST
@ViReturn
@RequiresPermissions("proposal.transact.caseUnit")
@Aop(TransAop.READ_COMMITTED)
public Object audit(@Param("audit") ProposalAudit audit,
@Param("resultCode") String resultCode,
@Param(value = "determineTypeCode", required = false) String determineTypeCode,
@Param(value = "typeId", required = false) String typeId,
@Param("hostUnit") String hostUnit,
@Param(value = "helpUnit", required = false) String[] helpUnit,
@Param(value = "sign", required = false) String sign,
@Param("proposalIds") String[] proposalIds) {
if (StrUtil.isNotBlank(sign)) {
String signId = dao.insert(new Sys_signature(sign)).getId();
audit.setSignId(signId);
}
List<String> helpUnitList = helpUnit == null ? Collections.emptyList() : Arrays.asList(helpUnit);
proposalCaseConfirmService.audit(Arrays.asList(proposalIds), resultCode, determineTypeCode, hostUnit, helpUnitList, typeId, audit);
return null;
}
}
@@ -2,6 +2,7 @@ package io.v.nutz.zhgh.mobile.proposal;
import io.v.nutz.base.annontation.ViReturn;
import io.v.nutz.base.utils.Roles;
import io.v.nutz.base.utils.Vi;
import io.v.nutz.base.dao.CndPlus;
import io.v.nutz.base.query.PageForm;
import io.v.nutz.zhgh.proposal.constants.ProposalState;
@@ -9,6 +10,7 @@ import io.v.nutz.zhgh.proposal.models.ProposalSearch;
import io.v.nutz.zhgh.proposal.services.ProposalInfoService;
import io.v.nutz.web.commons.utils.ShiroUtil;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.nutz.dao.Cnd;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.dao.util.cri.SqlExpressionGroup;
@@ -53,8 +55,17 @@ public class MProposalDelegationController {
if (!ShiroUtil.hasAnyRoles("tamange,sysadmin")) {
Sql sql = Sqls.create("SELECT dbtid FROM sys_user_role sur LEFT JOIN proposal_info info ON info.teacherMeetingId = sur.jdhid WHERE sur.roleId = @roleId AND sur.userId = @userId").setParam("roleId", Roles.DBT_TZ).setParam("userId", userId);
cnd.and("info.delegationId", "IN", sql);
cnd.and(Cnd.exps("info.delegationUnionId", "=", Vi.getUnionId()).or("info.delegationUnionId", "is", null));
}
if (Strings.isNotBlank(search.getIsAudit())) {
if (search.getIsAudit().equals("true")) {
cnd.and(Cnd.exps("info.stateCode", ">", ProposalState.DELEGATION));
} else {
cnd.and("info.stateCode", "=", ProposalState.DELEGATION);
}
} else {
cnd.and(Cnd.exps("info.stateCode", ">=", ProposalState.DELEGATION));
}
cnd.and("info.stateCode", search.getIsAudit().equals("true") ? ">" : "=", ProposalState.DELEGATION);
if (Strings.isNotBlank(search.getSearchKeyWord())) {
SqlExpressionGroup sqlExpressionGroup = new SqlExpressionGroup();
sqlExpressionGroup.andLike("info.proposalName", search.getSearchKeyWord());
@@ -0,0 +1,92 @@
package io.v.nutz.zhgh.mobile.proposal;
import cn.hutool.core.util.StrUtil;
import io.v.nutz.base.annontation.ViReturn;
import io.v.nutz.base.query.PageForm;
import io.v.nutz.zhgh.proposal.models.ProposalFeedback;
import io.v.nutz.zhgh.proposal.models.ProposalSearch;
import io.v.nutz.zhgh.proposal.services.ProposalFeedBackService;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.POST;
import org.nutz.mvc.annotation.Param;
/**
* 手机端提案反馈评价。
*/
@IocBean
@Ok("json:full")
@At("/mobile/proposal/feedback")
public class MProposalFeedbackScoreController {
@Inject
private ProposalFeedBackService proposalFeedBackService;
@At("")
@Ok("beetl:/mobile/proposal/feedback/list.html")
@RequiresPermissions("proposal.transact.feedback")
public void index() {
}
@At("/view")
@Ok("beetl:/mobile/proposal/feedback/audit.html")
@RequiresPermissions("proposal.transact.feedback")
public void view() {
}
/**
* 手机端反馈评价列表。
* 参数说明:
* page:分页参数,包含 pageNumber、pageSize、searchKeyWord
* search:筛选参数,meetingId 为届次、proposalTypeId 为提案类型、proposalResultCode 为立案结果、isAudit 表示是否已反馈;
* 返回值:分页结果,list 中为 NutMap,用于手机端列表展示和待反馈状态判断。
*/
@At
@ViReturn
@RequiresPermissions("proposal.transact.feedback")
public Object pageData(PageForm page, ProposalSearch search) {
return proposalFeedBackService.pageData(page, search);
}
/**
* 查询手机端反馈办理信息。
* 参数说明:
* proposalIdproposal_info 表主键;
* 返回值:NutMap,包含 proposalId、stateCode、handle,用于详情页判断是否显示反馈表单。
*/
@At
@ViReturn
@RequiresPermissions("proposal.transact.feedback")
public Object getFeedbackInfo(@Param("proposalId") String proposalId) {
return proposalFeedBackService.getFeedbackInfo(proposalId);
}
/**
* 手机端提交反馈评价。
* 参数说明:
* feedBackProposalFeedback 反馈对象,需包含 proposalId、feedbackCode、feedbackOpinion
* scoreSign:反馈人签名图片数据,可为空,传入后保存到 scoreSignId
* 返回值:无业务数据,成功时由 ViReturn 包装为成功响应。
*/
@At
@POST
@ViReturn
@RequiresPermissions("proposal.transact.feedback")
@Aop(TransAop.READ_COMMITTED)
public Object doFeedback(@Param("feedBack") ProposalFeedback proposalFeedback,
@Param(value = "scoreSign", required = false) String scoreSign) {
if (proposalFeedback == null || StrUtil.isBlank(proposalFeedback.getProposalId())) {
throw new RuntimeException("提案信息不能为空");
}
if (StrUtil.isBlank(proposalFeedback.getFeedbackCode())) {
throw new RuntimeException("请选择办理结果评价");
}
proposalFeedBackService.doFeedback(proposalFeedback, scoreSign);
return null;
}
}
@@ -69,8 +69,8 @@ public enum ProposalToDoHandler {
List.of(loginName),
"/platform/proposal/transact/seconded",
"/platform/proposal/transact/seconded",
"/platform/proposal/transact/seconded",
"/platform/proposal/transact/seconded");
"/mobile/proposal/seconded",
"/mobile/proposal/seconded");
}
localProcessService.updateProcessNodeName("proposal_info@" + proposalId, "邀请附议人");
}
@@ -4,18 +4,16 @@ import cn.hutool.core.util.StrUtil;
import io.v.nutz.base.annontation.ViReturn;
import io.v.nutz.base.query.PageForm;
import io.v.nutz.sys.services.SysLocalProcessService;
import io.v.nutz.sys.models.Sys_signature;
import io.v.nutz.zhgh.proposal.models.ProposalAudit;
import io.v.nutz.zhgh.proposal.models.ProposalSearch;
import io.v.nutz.zhgh.proposal.services.ProposalAuditService;
import io.v.nutz.zhgh.proposal.services.ProposalCaseService;
import io.v.nutz.zhgh.proposal.services.ProposalInfoService;
import io.v.nutz.sys.models.Sys_signature;
import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Dao;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
@@ -73,27 +71,7 @@ public class ProposalCaseController {
@ViReturn
@RequiresPermissions(value = {"proposal.transact.case", "offerAdvice.schoolUnionAudit"}, logical = Logical.OR)
public Object getUnderTakeAndLeader() {
Sql sql = Sqls.create("""
SELECT
pu.*,
(
SELECT
GROUP_CONCAT( su.username )
FROM
sys_user_role sur
LEFT JOIN sys_user su ON sur.userId = su.id
WHERE
sur.cbdwid = pu.id
AND sur.roleId = '153cba3fb88b4c88b7c1002f0eb63749'
) leader
FROM
proposal_undertake pu
WHERE
pu.isEnable = 1
ORDER BY
pu.unitCode ASC
""");
return proposalInfoService.listMap(sql);
return proposalCaseService.getUnderTakeAndLeader();
}
/**
@@ -1,38 +1,23 @@
package io.v.nutz.zhgh.proposal.controller.transact;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.wizzer.framework.page.Pagination;
import io.v.nutz.base.annontation.ViReturn;
import io.v.nutz.base.utils.MsgApi;
import io.v.nutz.base.utils.Roles;
import io.v.nutz.base.dao.CndPlus;
import io.v.nutz.base.query.PageForm;
import io.v.nutz.zhgh.proposal.constants.ProposalConstant;
import io.v.nutz.zhgh.proposal.constants.ProposalState;
import io.v.nutz.zhgh.proposal.constants.ProposalStateDirectionEnum;
import io.v.nutz.zhgh.proposal.constants.ProposalToDoHandler;
import io.v.nutz.zhgh.proposal.models.ProposalAudit;
import io.v.nutz.zhgh.proposal.models.ProposalInfo;
import io.v.nutz.zhgh.proposal.models.ProposalSearch;
import io.v.nutz.zhgh.proposal.services.ProposalCaseReadService;
import io.v.nutz.zhgh.proposal.services.ProposalInfoService;
import io.v.nutz.sys.models.Sys_signature;
import io.v.nutz.sys.models.Sys_user_role;
import io.v.nutz.sys.models.User;
import io.v.nutz.sys.services.SysSignatureService;
import io.v.nutz.web.commons.utils.ShiroUtil;
import io.v.nutz.zhgh.proposal.services.ProposalProcessService;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.dao.util.cri.Static;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.json.Json;
import org.nutz.lang.Lang;
import org.nutz.lang.Strings;
import org.nutz.lang.util.NutMap;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
@@ -51,6 +36,8 @@ public class ProposalCaseReadController {
private ProposalInfoService proposalInfoService;
@Inject
private ProposalProcessService proposalProcessService;
@Inject
private ProposalCaseReadService proposalCaseReadService;
@Inject
private Dao dao;
@@ -65,73 +52,7 @@ public class ProposalCaseReadController {
@ViReturn
@RequiresPermissions("proposal.transact.caseRead")
public Object pageData(PageForm page, ProposalSearch search) {
CndPlus cnd = CndPlus.create();
Sql sql = Sqls.create("""
SELECT
info.*,
su.username,
su.loginname,
state.stateName,
state.stateColor,
type.typeCode,
type.typeName,
jdh.jdhallname meetingName,
dbt.dbtname delegationName,
dbt.`code` delegationCode,
manner.`name` mannerName,
result.`name` resultName,
$temp_sql
FROM
proposal_info info
LEFT JOIN `user` su ON su.id = info.createUser
LEFT JOIN proposal_state state ON state.stateCode = info.stateCode
LEFT JOIN proposal_type type ON type.id = info.typeId
LEFT JOIN jdh_jdhxx jdh ON jdh.id = info.teacherMeetingId
LEFT JOIN jdh_dbt dbt ON dbt.id = info.delegationId
LEFT JOIN sys_dict manner ON manner.`code` = info.mannerCode
LEFT JOIN sys_dict result ON result.`code` = info.resultCode
$condition
""").setParam("userId", ShiroUtil.getPrincipalProperty("id"));
/* StringBuffer tempStr = new StringBuffer("""
(JSON_CONTAINS(JSON_EXTRACT( membersOpinions, '$[*].userId' ), '\\"%s\\"') = 1) AS isOpinion
""".formatted(ShiroUtil.getUserId()));
sql.setVar("temp_sql", tempStr);*/
StringBuffer tempStr = new StringBuffer("""
FIND_IN_SET(( SELECT id FROM proposal_audit WHERE proposalId = info.id AND userId = '%s' AND other IS NOT NULL limit 1), info.membersOpinions )is not null isOpinion
""".formatted(ShiroUtil.getUserId()));
sql.setVar("temp_sql", tempStr);
if (Strings.isNotBlank(search.getIsAudit())) {
if (search.getIsAudit().equals("true")) {
cnd.and(new Static("FIND_IN_SET(( SELECT id FROM proposal_audit WHERE proposalId = info.id AND userId = '%s' AND other IS NOT NULL limit 1), info.membersOpinions )is not null".formatted(ShiroUtil.getUserId())));
// cnd.and(new Static("JSON_CONTAINS(JSON_EXTRACT( info.membersOpinions, '$[*].userId' ), '\"%s\"') = 1".formatted(ShiroUtil.getUserId())));
} else {
cnd.and(new Static("FIND_IN_SET(( SELECT id FROM proposal_audit WHERE proposalId = info.id AND userId = '%s' AND other IS NOT NULL limit 1), info.membersOpinions ) is null".formatted(ShiroUtil.getUserId())));
// cnd.and(new Static("(JSON_CONTAINS(JSON_EXTRACT( info.membersOpinions, '$[*].userId' ), '\"%s\"') = 0 or JSON_CONTAINS(JSON_EXTRACT( info.membersOpinions, '$[*].userId' ), '\"%s\"') is null)".formatted(ShiroUtil.getUserId(), ShiroUtil.getUserId())));
}
}
cnd.and("info.stateCode", ">", ProposalState.DELEGATION);
cnd.asc("info.stateCode");
// proposalInfoService.sortAndSearch(cnd,page,search);
Pagination pagination = (Pagination) proposalInfoService.initSql(sql, page, search, cnd);
// List<NutMap> list = pagination.getList();
// for (NutMap map : list) {
// if (StrUtil.isNotBlank(search.getIsAudit()) && "true".equals(search.getIsAudit())) {
// String membersOpinions = map.getString("membersOpinions");
// List<String> mlist = Json.fromJsonAsList(String.class, membersOpinions);
// map.putAll(getCommitteeOpinion(mlist));
// } else {
// map.putAll(NutMap.NEW().addv("caseNum", "暂无")
// .addv("opinionNum", "暂无").addv("notGiveNum", "暂无"));
// }
// }
// pagination.setList(list);
return pagination;
return proposalCaseReadService.pageData(page, search);
}
@@ -153,9 +74,6 @@ public class ProposalCaseReadController {
}
@Inject
private SysSignatureService sysSignatureService;
/**
* 委员会成员意见
*
@@ -167,29 +85,7 @@ public class ProposalCaseReadController {
@ViReturn
@RequiresPermissions("proposal.transact.caseRead")
public Object putSuggestion(String sign, @Param("audit") String audit, @Param("proposalId") String proposalId) {
ProposalInfo proposalInfo = proposalInfoService.fetch(proposalId);
String signId = sysSignatureService.insert(new Sys_signature(sign)).getId();
ProposalAudit proposalAudit = Json.fromJson(ProposalAudit.class, audit);
proposalAudit.setSignId(signId);
proposalAudit.setUserId(ShiroUtil.getUserId());
if (!proposalAudit.getOther().equals(ProposalConstant.DETERMINE)) {
proposalAudit.setDetermineTypeCode(null);
}
dao.insert(proposalAudit);
/*List<NutMap> membersOpinions = proposalInfo.getMembersOpinions() == null ? new ArrayList<>() : proposalInfo.getMembersOpinions();
membersOpinions.add(NutMap.NEW().addv("userId", ShiroUtil.getUserId()).addv("auditId", insertAudit.getId()));
proposalInfo.setMembersOpinions(membersOpinions);*/
List<String> membersOpinions = proposalInfo.getMembersOpinions() == null ? new ArrayList<>() : proposalInfo.getMembersOpinions();
membersOpinions.add(proposalAudit.getId());
proposalInfo.setMembersOpinions(membersOpinions);
proposalInfoService.updateIgnoreNull(proposalInfo);
// // 提案小组组长审核后,修改提案状态之后,流程开始往下走
// proposalInfo.setStateCode(proposalProcessService.getStateCode(proposalId, ProposalStateDirectionEnum.NEXT, false));
// ProposalToDoHandler.COMPLETE_PROPOSAL_TEAM_LEADER_REVIEW_TASK.exec(proposalInfo.getId(), NutMap.NEW().setv("opinion", "提案工作组组长审阅完成"));
// // 创建校党委审议待办
// ProposalToDoHandler.CREATE_CASE_TASK.exec(proposalInfo.getId(), NutMap.NEW().setv("opinion", "提案工作组组长审阅完成"));
proposalCaseReadService.putSuggestion(sign, audit, proposalId);
return null;
}
@@ -0,0 +1,28 @@
package io.v.nutz.zhgh.proposal.services;
import io.v.nutz.base.query.PageForm;
import io.v.nutz.zhgh.proposal.models.ProposalSearch;
/**
* 提案工作组成员意见审核公共服务。
*/
public interface ProposalCaseReadService {
/**
* 查询提案工作组成员意见列表。
*
* @param page 分页参数,包含 pageNumber、pageSize、排序字段等
* @param search 查询参数,meetingId 为届次、proposalTypeId 为提案类型、proposalResultCode 为立案结果、isAudit 表示是否已提交成员意见
* @return 分页结果,list 中包含提案基础信息、状态、类型、届次、代表团、立案结果以及当前用户是否已发表意见 isOpinion
*/
Object pageData(PageForm page, ProposalSearch search);
/**
* 保存提案工作组成员意见。
*
* @param sign 签名图片数据,保存后关联到审核记录
* @param audit ProposalAudit 的 JSON 字符串,包含审核人、审核时间、审核意见、立案意见等字段
* @param proposalId 提案 id
*/
void putSuggestion(String sign, String audit, String proposalId);
}
@@ -5,6 +5,7 @@ import io.v.nutz.base.query.PageForm;
import io.v.nutz.zhgh.proposal.models.ProposalAudit;
import io.v.nutz.zhgh.proposal.models.ProposalSearch;
import io.v.nutz.base.service.ViService;
import org.nutz.lang.util.NutMap;
import java.util.List;
import java.util.Map;
@@ -23,6 +24,13 @@ public interface ProposalCaseService extends ViService {
*/
Pagination pageData(PageForm pageForm, ProposalSearch search);
/**
* 获取开启的承办单位及单位领导信息。
*
* @return 承办单位列表,包含承办单位基础字段以及 leader 领导姓名串
*/
List<NutMap> getUnderTakeAndLeader();
/**
* 立案
@@ -1,13 +1,42 @@
package io.v.nutz.zhgh.proposal.services;
import io.v.nutz.zhgh.proposal.models.ProposalFeedback;
import io.v.nutz.zhgh.proposal.models.ProposalSearch;
import io.v.nutz.base.service.ViService;
import io.v.nutz.base.query.PageForm;
import cn.wizzer.framework.page.Pagination;
import org.nutz.lang.util.NutMap;
import java.util.List;
public interface ProposalFeedBackService extends ViService<ProposalFeedback> {
/**
* 手机端反馈评价列表。
* 参数说明:
* page:分页参数,包含 pageNumber、pageSize、searchKeyWord 等;
* search:筛选参数,meetingId 为届次、proposalTypeId 为提案类型、proposalResultCode 为立案结果、isAudit 表示是否已反馈;
* 返回值:分页结果,list 中为 NutMap,包含提案基础字段和 isFeedback。
*/
Pagination pageData(PageForm page, ProposalSearch search);
/**
* 查询手机端反馈办理状态。
* 参数说明:
* proposalIdproposal_info 表主键;
* 返回值:NutMap,包含 stateCode 和 handlehandle 为 true 时手机端展示反馈表单。
*/
NutMap getFeedbackInfo(String proposalId);
/**
* 提交提案反馈评价。
* 参数说明:
* proposalFeedback:反馈实体,必须包含 proposalId、feedbackCode、feedbackOpinion 等反馈内容;
* scoreSign:反馈人签名图片数据,可为空;
* 返回值:无业务数据,成功后更新提案流程状态并处理待办。
*/
void doFeedback(ProposalFeedback proposalFeedback, String scoreSign);
/**
* @param proposalId 提案id
* @return
@@ -0,0 +1,119 @@
package io.v.nutz.zhgh.proposal.services.impl;
import cn.wizzer.framework.page.Pagination;
import io.v.nutz.base.dao.CndPlus;
import io.v.nutz.base.query.PageForm;
import io.v.nutz.zhgh.proposal.constants.ProposalConstant;
import io.v.nutz.zhgh.proposal.constants.ProposalState;
import io.v.nutz.zhgh.proposal.models.ProposalAudit;
import io.v.nutz.zhgh.proposal.models.ProposalInfo;
import io.v.nutz.zhgh.proposal.models.ProposalSearch;
import io.v.nutz.zhgh.proposal.services.ProposalCaseReadService;
import io.v.nutz.zhgh.proposal.services.ProposalInfoService;
import io.v.nutz.sys.models.Sys_signature;
import io.v.nutz.sys.services.SysSignatureService;
import io.v.nutz.web.commons.utils.ShiroUtil;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Dao;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.dao.util.cri.Static;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.json.Json;
import org.nutz.lang.Strings;
import java.util.ArrayList;
import java.util.List;
/**
* 提案工作组成员意见审核公共服务实现。
*/
@IocBean
public class ProposalCaseReadServiceImpl implements ProposalCaseReadService {
@Inject
private ProposalInfoService proposalInfoService;
@Inject
private SysSignatureService sysSignatureService;
@Inject
private Dao dao;
@Override
public Object pageData(PageForm page, ProposalSearch search) {
CndPlus cnd = CndPlus.create();
Sql sql = Sqls.create("""
SELECT
info.*,
su.username,
su.loginname,
state.stateName,
state.stateColor,
type.typeCode,
type.typeName,
jdh.jdhallname meetingName,
dbt.dbtname delegationName,
dbt.`code` delegationCode,
manner.`name` mannerName,
result.`name` resultName,
$temp_sql
FROM
proposal_info info
LEFT JOIN `user` su ON su.id = info.createUser
LEFT JOIN proposal_state state ON state.stateCode = info.stateCode
LEFT JOIN proposal_type type ON type.id = info.typeId
LEFT JOIN jdh_jdhxx jdh ON jdh.id = info.teacherMeetingId
LEFT JOIN jdh_dbt dbt ON dbt.id = info.delegationId
LEFT JOIN sys_dict manner ON manner.`code` = info.mannerCode
LEFT JOIN sys_dict result ON result.`code` = info.resultCode
$condition
""").setParam("userId", ShiroUtil.getPrincipalProperty("id"));
// 与 PC 端原查询保持一致:当前用户的 proposal_audit 记录必须存在于 membersOpinions 中才算已提交成员意见。
String userId = ShiroUtil.getUserId();
sql.setVar("temp_sql", """
FIND_IN_SET(( SELECT id FROM proposal_audit WHERE proposalId = info.id AND userId = '%s' AND other IS NOT NULL limit 1), info.membersOpinions )is not null isOpinion
""".formatted(userId));
if (Strings.isNotBlank(search.getIsAudit())) {
if ("true".equals(search.getIsAudit())) {
cnd.and(new Static("FIND_IN_SET(( SELECT id FROM proposal_audit WHERE proposalId = info.id AND userId = '%s' AND other IS NOT NULL limit 1), info.membersOpinions )is not null".formatted(userId)));
} else {
cnd.and(new Static("FIND_IN_SET(( SELECT id FROM proposal_audit WHERE proposalId = info.id AND userId = '%s' AND other IS NOT NULL limit 1), info.membersOpinions ) is null".formatted(userId)));
}
}
cnd.and("info.stateCode", ">", ProposalState.DELEGATION);
cnd.asc("info.stateCode");
Pagination pagination = (Pagination) proposalInfoService.initSql(sql, page, search, cnd);
return pagination;
}
/**
* 保存提案工作组成员意见,并把审核记录 id 追加到提案 membersOpinions。
* sign 为签名图片数据,audit 为 ProposalAudit JSONproposalId 为提案 id
* audit.other 表示立案意见,非确定立案时会清空 determineTypeCode,避免残留立案类型。
*/
@Override
@Aop(TransAop.READ_COMMITTED)
public void putSuggestion(String sign, String audit, String proposalId) {
ProposalInfo proposalInfo = proposalInfoService.fetch(proposalId);
String signId = sysSignatureService.insert(new Sys_signature(sign)).getId();
ProposalAudit proposalAudit = Json.fromJson(ProposalAudit.class, audit);
proposalAudit.setSignId(signId);
proposalAudit.setUserId(ShiroUtil.getUserId());
if (!proposalAudit.getOther().equals(ProposalConstant.DETERMINE)) {
proposalAudit.setDetermineTypeCode(null);
}
dao.insert(proposalAudit);
// membersOpinions 保存审核记录 id,保持 PC 端和手机端列表判断、详情展示一致。
List<String> membersOpinions = proposalInfo.getMembersOpinions() == null ? new ArrayList<>() : proposalInfo.getMembersOpinions();
membersOpinions.add(proposalAudit.getId());
proposalInfo.setMembersOpinions(membersOpinions);
proposalInfoService.updateIgnoreNull(proposalInfo);
}
}
@@ -117,6 +117,31 @@ public class ProposalCaseServiceImpl extends ViServiceImpl implements ProposalCa
return pagination;
}
@Override
public List<NutMap> getUnderTakeAndLeader() {
Sql sql = Sqls.create("""
SELECT
pu.*,
(
SELECT
GROUP_CONCAT( su.username )
FROM
sys_user_role sur
LEFT JOIN sys_user su ON sur.userId = su.id
WHERE
sur.cbdwid = pu.id
AND sur.roleId = '153cba3fb88b4c88b7c1002f0eb63749'
) leader
FROM
proposal_undertake pu
WHERE
pu.isEnable = 1
ORDER BY
pu.unitCode ASC
""");
return listMap(sql);
}
@Override
@Aop(TransAop.READ_COMMITTED)
public void audit(List<String> proposalIds, String resultCode, String determineTypeCode, String hostUnit, List<String> helpUnits, String typeId, ProposalAudit audit, String auditType, int flag) {
@@ -1,13 +1,31 @@
package io.v.nutz.zhgh.proposal.services.impl;
import cn.hutool.core.util.StrUtil;
import cn.wizzer.framework.page.Pagination;
import io.v.nutz.base.query.PageForm;
import io.v.nutz.zhgh.proposal.models.ProposalFeedback;
import io.v.nutz.zhgh.proposal.models.ProposalInfo;
import io.v.nutz.zhgh.proposal.models.ProposalReply;
import io.v.nutz.zhgh.proposal.models.ProposalSearch;
import io.v.nutz.zhgh.proposal.models.ProposalUndertake;
import io.v.nutz.zhgh.proposal.constants.ProposalConstant;
import io.v.nutz.zhgh.proposal.constants.ProposalState;
import io.v.nutz.zhgh.proposal.constants.ProposalToDoHandler;
import io.v.nutz.zhgh.proposal.services.ProposalFeedBackService;
import io.v.nutz.base.service.impl.ViServiceImpl;
import io.v.nutz.sys.models.Sys_signature;
import io.v.nutz.sys.services.SysSignatureService;
import io.v.nutz.web.commons.utils.ShiroUtil;
import io.v.nutz.base.utils.DateUtil;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Chain;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.dao.util.cri.SqlExpressionGroup;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.json.Json;
import org.nutz.lang.Lang;
@@ -23,6 +41,136 @@ public class ProposalFeedBackServiceImpl extends ViServiceImpl<ProposalFeedback>
super(dao);
}
@Inject
private SysSignatureService sysSignatureService;
@Override
public Pagination pageData(PageForm page, ProposalSearch search) {
Sql sql = Sqls.create("""
SELECT
info.*,
su.username,
su.loginname,
state.stateName,
state.stateColor,
type.typeName,
jdh.jdhallname meetingName,
dbt.dbtname delegationName,
manner.`name` mannerName,
result.`name` resultName,
(
SELECT count(1) > 0
FROM proposal_conjoin
WHERE JSON_CONTAINS(proposalIds, JSON_QUOTE(info.id))
) AS isConjoin,
(
SELECT count(1)
FROM proposal_feedback pf
WHERE pf.proposalId = info.id
) AS feedbackCount
FROM
proposal_info info
LEFT JOIN `user` su ON su.id = info.createUser
LEFT JOIN proposal_state state ON state.stateCode = info.stateCode
LEFT JOIN proposal_type type ON type.id = info.typeId
LEFT JOIN jdh_jdhxx jdh ON jdh.id = info.teacherMeetingId
LEFT JOIN jdh_dbt dbt ON dbt.id = info.delegationId
LEFT JOIN sys_dict manner ON manner.`code` = info.mannerCode
LEFT JOIN sys_dict result ON result.`code` = info.resultCode
$condition
""");
Cnd cnd = Cnd.NEW();
if (!ShiroUtil.hasAnyRoles("sysadmin, tamange,A06")) {
cnd.and("info.createUser", "=", ShiroUtil.getUserId());
}
if (StrUtil.isNotBlank(search.getSearchKeyWord())) {
SqlExpressionGroup keywordGroup = new SqlExpressionGroup();
keywordGroup.orLike("info.proposalName", search.getSearchKeyWord());
keywordGroup.orLike("info.proposalCode", search.getSearchKeyWord());
cnd.and(keywordGroup);
}
cnd.andEX("info.teacherMeetingId", "=", search.getMeetingId());
cnd.andEX("info.typeId", "=", search.getProposalTypeId());
cnd.andEX("info.resultCode", "=", search.getProposalResultCode());
if (StrUtil.isBlank(search.getIsAudit())) {
SqlExpressionGroup allGroup = new SqlExpressionGroup();
allGroup.or("info.stateCode", "=", ProposalState.FEEDBACKSCORE);
allGroup.or("info.stateCode", ">", ProposalState.FEEDBACKSCORE);
allGroup.orGT("(SELECT count(1) FROM proposal_feedback pf WHERE pf.proposalId = info.id)", 0);
cnd.and(allGroup);
} else if ("true".equals(search.getIsAudit())) {
SqlExpressionGroup feedbackGroup = new SqlExpressionGroup();
feedbackGroup.or("info.stateCode", ">", ProposalState.FEEDBACKSCORE);
feedbackGroup.orGT("(SELECT count(1) FROM proposal_feedback pf WHERE pf.proposalId = info.id)", 0);
cnd.and(feedbackGroup);
} else if ("false".equals(search.getIsAudit())) {
cnd.and("info.stateCode", "=", ProposalState.FEEDBACKSCORE);
}
cnd.asc("info.proposalCode").desc("info.createTime");
sql.setCondition(cnd);
Pagination pagination = listPageMap(page.getPageNumber(), page.getPageSize(), sql);
List<NutMap> list = pagination.getList(NutMap.class);
list.forEach(v -> {
int feedbackCount = v.getInt("feedbackCount", 0);
Integer stateCode = v.getInt("stateCode");
v.setv("isFeedback", feedbackCount > 0 || (stateCode != null && stateCode > ProposalState.FEEDBACKSCORE));
});
pagination.setList(list);
return pagination;
}
@Override
public NutMap getFeedbackInfo(String proposalId) {
ProposalInfo proposalInfo = dao().fetch(ProposalInfo.class, Cnd.where("id", "=", proposalId));
return NutMap.NEW()
.addv("proposalId", proposalId)
.addv("stateCode", proposalInfo == null ? null : proposalInfo.getStateCode())
.addv("handle", proposalInfo != null && proposalInfo.getStateCode() != null && proposalInfo.getStateCode().equals(ProposalState.FEEDBACKSCORE));
}
@Override
@Aop(TransAop.READ_COMMITTED)
public void doFeedback(ProposalFeedback proposalFeedback, String scoreSign) {
if (StrUtil.isNotBlank(scoreSign)) {
Sys_signature signature = sysSignatureService.insert(new Sys_signature(scoreSign));
proposalFeedback.setScoreSignId(signature.getId());
}
int feedbackCount = count(Cnd.where("proposalId", "=", proposalFeedback.getProposalId()));
proposalFeedback.setFeedbackPerson(ShiroUtil.getUserId());
proposalFeedback.setFeedbackNumber(feedbackCount + 1);
proposalFeedback.setFeedbackTime(DateUtil.getDateTime());
insert(proposalFeedback);
ProposalToDoHandler.COMPLETE_FEEDBACK_TASK.exec(proposalFeedback.getProposalId(), NutMap.NEW().addv("opinion", proposalFeedback.getFeedbackOpinion()));
ProposalReply lastReply = dao().fetch(ProposalReply.class, Cnd.where("proposalId", "=", proposalFeedback.getProposalId()).and("undertakeType", "=", 1));
if (lastReply == null) {
throw new RuntimeException("未找到主办单位办理记录,无法提交反馈评价");
}
// 不满意时需要主办单位二次答复,其他评价结果直接结束当前提案流程。
if (ProposalConstant.NOT_SATISFIED.equals(proposalFeedback.getFeedbackCode())) {
dao().update(ProposalInfo.class, Chain.make("stateCode", ProposalState.UNITREPLY), Cnd.where("id", "=", proposalFeedback.getProposalId()));
ProposalReply newReply = new ProposalReply();
newReply.setProposalId(lastReply.getProposalId());
newReply.setUndertakeType(lastReply.getUndertakeType());
newReply.setReplyUnitId(lastReply.getReplyUnitId());
newReply.setReplyNumber(lastReply.getReplyNumber() + 1);
newReply.setIsReply(false);
newReply.setIsLeaderAudit(false);
dao().insert(newReply);
ProposalToDoHandler.CREATE_UNDERTAKE_TASK.exec(proposalFeedback.getProposalId(), null);
} else {
dao().update(ProposalInfo.class, Chain.make("stateCode", ProposalState.FINISH), Cnd.where("id", "=", lastReply.getProposalId()));
ProposalToDoHandler.COMPLETE_PROCESS.exec(lastReply.getProposalId(), null);
}
}
@Override
public List<NutMap> getFeedbackList(String proposalId) {
Sql sql = Sqls.create("""
@@ -0,0 +1,161 @@
.list-card {
--card-accent: #2563eb;
--card-bg: #ffffff;
--card-title: #111827;
--card-label: #8e969f;
--card-value: #374151;
--card-line: #f3f4f6;
--card-shadow: 0 14px 34px rgba(15, 23, 42, 0.07);
--badge-bg: #eef2ff;
--badge-color: #3730a3;
margin: 12px 14px;
padding: 15px 16px;
background: var(--card-bg);
border-radius: 14px;
box-shadow: var(--card-shadow);
line-height: 1.5;
font-size: 13px;
overflow: hidden;
}
.list-card:active {
background: #fbfcfe;
transform: scale(0.998);
}
.list-card .card-header {
position: relative;
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 12px;
padding: 1px 0 13px 12px;
}
.list-card .card-header::before {
content: "";
position: absolute;
left: 0;
top: 3px;
width: 3px;
height: 18px;
border-radius: 999px;
background: var(--card-accent);
}
.list-card .card-header::after {
content: "";
position: absolute;
left: 0;
right: 0;
bottom: 0;
height: 1px;
background: var(--card-line);
}
.list-card .card-title {
flex: 1;
min-width: 0;
color: var(--card-title);
font-size: 15px;
font-weight: 700;
line-height: 22px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.list-card .card-body {
display: grid;
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
column-gap: 18px;
row-gap: 10px;
padding: 13px 0;
}
.list-card .card-item {
min-width: 0;
display: flex;
align-items: baseline;
gap: 2px;
}
.list-card .card-label {
flex: none;
color: var(--card-label);
}
.list-card .card-value {
min-width: 0;
color: var(--card-value);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.list-card .card-footer {
position: relative;
padding-top: 12px;
color: var(--card-value);
}
.list-card .card-footer::before {
content: "";
position: absolute;
left: 0;
right: 0;
top: 0;
height: 1px;
background: var(--card-line);
}
.list-card .badge {
flex: none;
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 50px;
padding: 3px 9px;
border-radius: 999px;
color: var(--badge-color);
background: var(--badge-bg);
font-size: 12px;
font-weight: 600;
line-height: 16px;
white-space: nowrap;
}
.list-card .badge-draft {
--badge-bg: #F1F5F9;
--badge-color: #64748B;
}
.list-card .badge-green {
--badge-bg: #e7f7ee;
--badge-color: #047857;
}
.list-card .badge-blue {
--badge-bg: #eaf3ff;
--badge-color: #1d4ed8;
}
.list-card .badge-gray {
--badge-bg: #f2f4f7;
--badge-color: #667085;
}
.list-card .badge-red {
--badge-bg: #fff0ef;
--badge-color: #b42318;
}
@media (max-width: 360px) {
.list-card {
padding: 14px;
}
.list-card .card-body {
grid-template-columns: minmax(0, 1fr);
}
}
@@ -0,0 +1,448 @@
.info-page-container {
min-height: 100%;
padding: 1px 0 12px;
background: #F7F8FA;
}
.info-card {
margin: 12px;
padding: 16px;
background: #ffffff;
border-radius: 16px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.02);
}
.info-section-title {
position: relative;
display: flex;
align-items: center;
min-height: 22px;
margin-bottom: 16px;
padding-left: 12px;
color: #1D2129;
font-size: 16px;
font-weight: 700;
line-height: 22px;
}
.info-section-title::before {
content: "";
position: absolute;
left: 0;
top: 4px;
width: 4px;
height: 14px;
border-radius: 999px;
background: #1890ff;
}
.info-row {
display: flex;
justify-content: space-between;
gap: 12px;
line-height: 22px;
}
.info-row + .info-row {
margin-top: 12px;
}
.info-label {
flex: 0 0 90px;
color: #86909C;
font-size: 14px;
}
.info-value {
flex: 1;
min-width: 0;
color: #1D2129;
font-size: 14px;
font-weight: 600;
text-align: right;
word-break: break-all;
}
.info-value.is-long {
text-align: left;
white-space: normal;
}
.info-long-block {
margin-top: 14px;
padding-top: 14px;
border-top: 1px solid #F2F3F5;
}
.info-long-title {
margin-bottom: 8px;
color: #86909C;
font-size: 14px;
}
.info-long-content {
color: #1D2129;
font-size: 14px;
font-weight: 500;
line-height: 1.7;
word-break: break-word;
}
.info-input-area {
margin-top: 12px;
}
.info-input-area .van-cell-group,
.info-input-area .van-cell {
background: transparent;
}
.info-input-area .van-cell::after,
.info-input-area .van-cell-group::after {
border: 0;
}
.info-input-area .van-field {
margin-top: 10px;
padding: 12px;
border-radius: 8px;
background: #F2F3F5;
}
.info-input-area .van-field__label {
color: #4E5969;
font-size: 14px;
font-weight: 600;
}
.info-input-area .van-field__control {
color: #1D2129;
font-size: 14px;
background: transparent;
}
.info-input-title {
margin-bottom: 10px;
color: #1D2129;
font-size: 15px;
font-weight: 700;
}
.info-cell-form {
background: #ffffff;
}
.info-cell-form .info-row,
.info-cell-form .info-picker-card .van-field,
.info-cell-form > .van-field {
margin: 0;
padding: 13px 0;
border-bottom: 1px solid #F2F3F5;
border-radius: 0;
background: #ffffff;
line-height: 22px;
}
.info-cell-form .info-row + .info-row {
margin-top: 0;
}
.info-cell-form .info-label,
.info-cell-form .van-field__label,
.info-cell-form .info-picker-label {
flex: 0 0 90px;
width: 90px;
margin-right: 12px;
color: #86909c;
font-size: 14px;
font-weight: 400;
line-height: 22px;
}
.info-cell-form .info-value,
.info-cell-form .van-field__control {
color: #1d2129;
font-size: 14px;
font-weight: 500;
line-height: 22px;
text-align: right;
}
.info-cell-form .info-value.is-long {
text-align: right;
}
.info-cell-form .van-field__control::placeholder {
color: #c9cdd4;
font-weight: 400;
}
.info-cell-form .van-field__right-icon {
color: #86909c;
}
.info-cell-form .van-cell--required::before {
top: 50%;
left: -8px;
transform: translateY(-50%);
}
.info-cell-form .info-multi-value-field .van-field__body {
align-items: flex-start;
}
.info-cell-form .info-multi-value-field .van-field__right-icon {
padding-top: 1px;
}
.info-multi-value {
flex: 1;
min-width: 0;
color: #1d2129;
font-size: 14px;
font-weight: 500;
line-height: 22px;
text-align: right;
white-space: normal;
word-break: break-all;
}
.info-multi-placeholder {
color: #c9cdd4;
font-weight: 400;
}
.info-cell-form .van-radio-group {
width: 100%;
padding-top: 2px;
}
.info-cell-form .van-radio {
line-height: 22px;
}
.info-textarea-field {
padding-top: 12px;
}
.info-textarea-label {
margin-bottom: 6px;
color: #86909c;
font-size: 14px;
line-height: 22px;
}
.info-required-label::before {
content: "*";
margin-right: 2px;
color: #ee0a24;
}
.info-cell-form .info-textarea-field .van-field {
margin: 0;
padding: 12px;
border: 0;
border-radius: 8px;
background: #f2f3f5;
}
.info-cell-form .info-textarea-field .van-field__control {
min-height: 96px;
text-align: left;
}
.info-cell-form .info-textarea-field .van-field__word-limit {
color: #c9cdd4;
font-size: 12px;
}
.info-footer-actions {
padding: 20px 0 4px;
}
.info-cell-form .info-footer-actions .van-button {
height: 44px;
border-radius: 8px;
font-size: 15px;
font-weight: 500;
}
.info-cell-form .info-ghost-button {
border: 1px solid #4e5969;
background: #ffffff;
color: #4e5969;
}
.info-cell-form .info-primary-button {
border: 0;
color: #ffffff;
}
.unit-select-toolbar {
display: flex;
align-items: center;
justify-content: space-between;
height: 44px;
}
.unit-select-title {
color: #1D2129;
font-size: 16px;
font-weight: 600;
}
.unit-select-cancel,
.unit-select-confirm {
height: 100%;
padding: 0 16px;
border: 0;
background: transparent;
font-size: 14px;
}
.unit-select-cancel {
color: #969799;
}
.unit-select-confirm {
color: #576b95;
}
.unit-select-list {
max-height: 320px;
overflow-y: auto;
padding: 4px 16px 16px;
}
.unit-select-list .van-checkbox {
align-items: flex-start;
overflow: visible;
}
.unit-select-list .van-checkbox__label {
flex: 1;
min-width: 0;
white-space: normal;
word-break: break-all;
line-height: 22px;
}
.info-sign-image {
overflow: hidden;
margin-top: 12px;
padding: 10px;
border-radius: 12px;
background: #F7F8FA;
}
.info-record + .info-record {
margin-top: 16px;
padding-top: 16px;
border-top: 1px solid #F2F3F5;
}
.info-record-title {
margin-bottom: 12px;
color: #4E5969;
font-size: 14px;
font-weight: 700;
}
.info-collapse {
overflow: hidden;
border-radius: 12px;
background: #F7F8FA;
}
.info-inner-collapse {
margin-top: 14px;
}
.info-collapse .van-cell {
padding: 12px 14px;
background: transparent;
}
.info-collapse .van-cell::after,
.info-collapse .van-collapse-item__wrapper::after {
border: 0;
}
.info-collapse .van-cell__title {
min-width: 0;
color: #1D2129;
font-size: 14px;
font-weight: 700;
}
.info-collapse-title {
display: flex;
align-items: center;
justify-content: space-between;
gap: 10px;
min-width: 0;
padding-right: 8px;
}
.info-collapse-title-text {
overflow: hidden;
min-width: 0;
text-overflow: ellipsis;
white-space: nowrap;
}
.info-collapse .van-collapse-item__content {
padding: 12px 14px 14px;
background: #ffffff;
}
.info-collapse-row {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
padding: 10px 0;
}
.info-collapse-row + .info-collapse-row,
.info-collapse-group + .info-collapse-group {
border-top: 1px solid #F2F3F5;
}
.info-collapse-group {
padding: 12px 0;
}
.info-collapse-group:first-child {
padding-top: 0;
}
.info-collapse-group:last-child {
padding-bottom: 0;
}
.info-status {
flex: 0 0 auto;
padding: 3px 9px;
border-radius: 999px;
color: #64748B;
font-size: 12px;
font-weight: 600;
line-height: 18px;
background: #F1F5F9;
}
.info-status.is-success {
color: #16A34A;
background: #ECFDF3;
}
.info-status.is-danger {
color: #EF4444;
background: #FEF2F2;
}
.info-status.is-muted {
color: #64748B;
background: #F1F5F9;
}
@@ -1,245 +1,477 @@
<template>
<div>
<div class="info-page-container">
<template name="提案基本信息">
<div class="van-cell-group__title" style="padding: 5px 0 0 0 !important;">
<div class="van-sidebar-item van-sidebar-item--select">
提案基本信息
<section class="info-card">
<div class="info-section-title">提案基本信息</div>
<div class="info-row">
<span class="info-label">提案名称</span>
<span class="info-value is-long">{{ viewData.proposalName }}</span>
</div>
</div>
<van-cell-group>
<van-collapse v-model="secondedActiveNames" :border="false" accordion>
<van-collapse-item name="1">
<div class="info-row">
<span class="info-label">提案编号</span>
<span class="info-value">{{ viewData.proposalCode }}</span>
</div>
<div class="info-row">
<span class="info-label">提案时间</span>
<span class="info-value">{{ viewData.createTime }}</span>
</div>
<div class="info-row">
<span class="info-label">教代会届次</span>
<span class="info-value">{{ viewData.meetingName }}</span>
</div>
<div class="info-row">
<span class="info-label">代表工会</span>
<span class="info-value">{{ viewData.unionName }}</span>
</div>
<div class="info-row">
<span class="info-label">{{ viewData.mannerCode !== 'W03' ? '代表团名称' : '委员会名称' }}</span>
<span class="info-value">
{{ viewData.mannerCode !== 'W03' ? viewData.delegationName : viewData.committeeName }}
</span>
</div>
<div class="info-row">
<span class="info-label">提案类型</span>
<span class="info-value">{{ viewData.typeName }}</span>
</div>
<div class="info-row">
<span class="info-label">提案方式</span>
<span class="info-value">{{ viewData.mannerName }}</span>
</div>
<div class="info-row">
<span class="info-label">立案结果</span>
<span class="info-value">{{ viewData.resultName ? viewData.resultName : '暂无' }}</span>
</div>
<div class="info-row">
<span class="info-label">建议落实部门</span>
<span class="info-value">{{ viewData.implementUnitName || '暂无' }}</span>
</div>
<div class="info-row">
<span class="info-label">提案状态</span>
<span class="info-value" :style="'color:'+viewData.stateColor">{{ viewData.stateName }}</span>
</div>
<div class="info-row">
<span class="info-label">提案人</span>
<span class="info-value">{{ viewData.createUserName }}({{ viewData.loginname }})</span>
</div>
<div class="info-long-block" v-if="viewData.undertake&&viewData.undertake.length>0">
<div class="info-long-title">承办单位</div>
<div class="info-row" v-for="(item,index) in viewData.undertake">
<span class="info-label">{{ item.undertakeType === 1 ? '主办' : '协办' }}</span>
<span class="info-value is-long">{{ item.unitName }}</span>
</div>
</div>
<div class="info-long-block">
<div class="info-long-title">案由</div>
<div class="info-long-content" v-html="viewData.brief"></div>
</div>
<div class="info-long-block">
<div class="info-long-title">建议措施</div>
<div class="info-long-content" v-html="viewData.measures"></div>
</div>
<div class="info-long-block" v-if="viewData.createUserSign">
<div class="info-long-title">签字</div>
<div class="info-sign-image">
<van-image width="200" height="100" :src="viewData.createUserSign"/>
</div>
</div>
<div class="info-long-block">
<div class="info-long-title">附件</div>
<upload v-if="viewData.files&&viewData.files.length" :del="false" :files.sync="viewData.files" view></upload>
<div class="info-long-content" v-else></div>
</div>
</section>
</template>
<template v-if="viewData.isConjoin !== 0 && viewData.conJoinList && viewData.conJoinList.length>0" name="提案并案信息">
<section class="info-card">
<div class="info-section-title">提案并案信息</div>
<van-collapse class="info-collapse" v-model="undertakeActiveNames" :border="false">
<van-collapse-item v-for="(item,index) in viewData.conJoinList" :name="'conJoin-' + index">
<template #title>
<div>提案名称&emsp;&emsp;{{ viewData.proposalName }}
<van-icon name="question-o"/>
</div>
{{ item.proposalName }}
</template>
<van-cell :value="viewData.proposalCode" title="提案编号"></van-cell>
<van-cell title="提案时间">{{ viewData.createTime }}</van-cell>
<van-cell title="教代会届次">{{ viewData.meetingName }}</van-cell>
<van-cell title="代表工会">{{ viewData.unionName }}</van-cell>
<van-cell title="代表团名称">{{ viewData.delegationName }}</van-cell>
<van-cell title="提案类型">{{ viewData.typeName }}</van-cell>
<van-cell title="提案方式">{{ viewData.mannerName }}</van-cell>
<van-cell title="立案结果">{{ viewData.resultName ? viewData.resultName : '暂无' }}</van-cell>
<van-cell title="建议落实部门">{{ viewData.implementUnitName || '暂无' }}</van-cell>
<van-cell title="提案状态"><span :style="'color:'+viewData.stateColor">{{ viewData.stateName }}</span>
</van-cell>
</van-collapse-item>
<van-cell title="提&emsp14;&emsp14;案&emsp14;&emsp14;人">
{{ viewData.createUserName }}({{ viewData.loginname }})
</van-cell>
<van-collapse-item v-if="viewData.undertake&&viewData.undertake.length>0" name="3" title="承办单位">
<span v-if="!viewData.undertake">暂未分配</span>
<van-cell v-for="(item,index) in viewData.undertake" v-else
:title="item.undertakeType === 1 ? '主办' : '协办'">
{{ item.unitName }}
</van-cell>
</van-collapse-item>
<van-collapse-item name="4" title="案&emsp;&emsp;由">
<span v-html="viewData.brief"></span>
</van-collapse-item>
<van-collapse-item name="5" title="建议措施">
<span v-html="viewData.measures"></span>
</van-collapse-item>
</van-collapse>
<van-collapse v-model="createUserSignNames" :border="false" v-if="viewData.createUserSign">
<van-collapse-item name="1" title="签&emsp;&emsp;字">
<van-image width="200" height="100" :src="viewData.createUserSign" v-if="viewData.createUserSign"/>
<span v-else>暂无</span>
<div class="info-row">
<span class="info-label">提案编号</span>
<span class="info-value">{{ item.proposalCode }}</span>
</div>
<div class="info-row">
<span class="info-label">提案人</span>
<span class="info-value">{{ item.username }}</span>
</div>
</van-collapse-item>
</van-collapse>
<!-- <van-cell title="附件">
<div v-for="(obj,index) in viewData.files" class="text-nowrap color-puple"
@click="previewFile(obj.filepath,obj.filename,viewData.files,index)">
{{ obj.filename }}
</div>
</van-cell>-->
</van-cell-group>
</section>
</template>
<template v-if="viewData.seconded" name="附议信息">
<div class="van-cell-group__title" style="padding: 5px 0 0 0 !important;">
<div class="van-sidebar-item van-sidebar-item--select">
附议信息
</div>
</div>
<van-collapse v-model="secondedNames" :border="false">
<van-collapse-item name="1" title="附&emsp14;&emsp14;议&emsp14;&emsp14;人">
<van-cell v-for="(item,index) in viewData.seconded"
:value="item.isAgree === true ? '同意' : item.isAgree === false ? '拒绝' : '未附议'">
<section class="info-card">
<div class="info-section-title">附议信息</div>
<van-collapse class="info-collapse" v-model="secondedNames" :border="false">
<van-collapse-item v-for="(item,index) in viewData.seconded" :name="'seconded-' + index">
<template #title>
<span>{{ item.username }}({{ item.unitname }})</span>
<div class="info-collapse-title">
<span class="info-collapse-title-text">{{ item.username }}({{ item.unitname }})</span>
<span class="info-status"
:class="item.isAgree === true ? 'is-success' : item.isAgree === false ? 'is-danger' : 'is-muted'">
{{ item.isAgree === true ? '同意' : item.isAgree === false ? '拒绝' : '未附议' }}
</span>
</div>
</template>
</van-cell>
</van-collapse-item>
</van-collapse>
<div class="info-row">
<span class="info-label">邀请时间</span>
<span class="info-value">{{ item.inviteTime || '暂无' }}</span>
</div>
<div class="info-row">
<span class="info-label">附议时间</span>
<span class="info-value">{{ item.secondedTime || '暂无' }}</span>
</div>
</van-collapse-item>
</van-collapse>
</section>
</template>
<template v-if="viewData.delegationAudit&&viewData.delegationAudit.length>0" name="团长审核信息">
<div class="van-cell-group__title" style="padding: 5px 0 0 0 !important;">
<div class="van-sidebar-item van-sidebar-item--select">
团长审核信息
<section class="info-card">
<div class="info-section-title">团长审核信息</div>
<div class="info-record" v-for="(item,index) in viewData.delegationAudit">
<div class="info-record-title" v-if="viewData.delegationAudit.length>1">审核记录{{ index + 1 }}</div>
<div class="info-row">
<span class="info-label">审核人</span>
<span class="info-value">{{ item.username }}-{{ item.loginName }}</span>
</div>
<div class="info-row">
<span class="info-label">审核时间</span>
<span class="info-value">{{ item.auditTime }}</span>
</div>
<div class="info-row">
<span class="info-label">审核结果</span>
<span class="info-value">{{ item.flag ? '通过' : '退回' }}</span>
</div>
<div class="info-long-block">
<div class="info-long-title">审核意见</div>
<div class="info-long-content">{{ item.opinion }}</div>
</div>
<div class="info-long-block" v-if="item.auditSign">
<div class="info-long-title">签字</div>
<div class="info-sign-image">
<van-image width="200" height="100" :src="item.auditSign"/>
</div>
</div>
</div>
</div>
<van-cell-group v-for="(item,index) in viewData.delegationAudit" class="info">
<van-cell title="审核时间">{{ item.auditTime }}</van-cell>
<van-cell title="审核结果">{{ item.flag ? '通过' : '退回' }}</van-cell>
<van-cell title="审核意见">{{ item.opinion }}</van-cell>
<van-cell title="签&emsp;&emsp;字" v-if="item.auditSign">
<van-image width="200" height="100" :src="item.auditSign" v-if="item.auditSign"/>
<span v-else>暂无</span>
</van-cell>
</section>
</template>
</van-cell-group>
<template v-if="viewData.membersOpinions&&viewData.membersOpinions.length>0" name="提案工作组意见">
<section class="info-card">
<div class="info-section-title">提案工作组意见</div>
<div class="info-record" v-for="(item,index) in viewData.membersOpinions">
<div class="info-record-title" v-if="viewData.membersOpinions.length>1">审核记录{{ index + 1 }}</div>
<div class="info-row">
<span class="info-label">审核人</span>
<span class="info-value">{{ item.username }}-{{ item.loginName }}</span>
</div>
<div class="info-row">
<span class="info-label">立案意见</span>
<span class="info-value">{{ item.dictName || '暂无' }}</span>
</div>
<div class="info-row">
<span class="info-label">审核时间</span>
<span class="info-value">{{ item.auditTime }}</span>
</div>
<div class="info-long-block">
<div class="info-long-title">审核意见</div>
<div class="info-long-content">{{ item.opinion }}</div>
</div>
<div class="info-long-block" v-if="item.auditSign">
<div class="info-long-title">签字</div>
<div class="info-sign-image">
<van-image width="200" height="100" :src="item.auditSign"/>
</div>
</div>
</div>
</section>
</template>
<template v-if="viewData.caseAuditId && viewData.caseAudit" name="提案工作组预立案">
<section class="info-card">
<div class="info-section-title">提案工作组预立案</div>
<div class="info-record" v-for="(item,index) in toArray(viewData.caseAudit)">
<div class="info-record-title" v-if="toArray(viewData.caseAudit).length>1">审核记录{{ index + 1 }}</div>
<div class="info-row">
<span class="info-label">审核人</span>
<span class="info-value">{{ item.username }}-{{ item.loginName }}</span>
</div>
<div class="info-row">
<span class="info-label">审核结果</span>
<span class="info-value">{{ item.flag ? '通过' : '退回修改' }}</span>
</div>
<div class="info-row">
<span class="info-label">审核时间</span>
<span class="info-value">{{ item.auditTime }}</span>
</div>
<div class="info-long-block" v-if="viewData.resultCode!=='notGive'">
<div class="info-long-title">承办单位</div>
<div class="info-long-content" v-if="hostUnit">
{{ hostUnit }}主办<template v-if="helpUnit&&helpUnit.length>0">{{ helpUnit }}协办</template>
</div>
<div class="info-long-content" v-else>暂未分配</div>
</div>
<div class="info-long-block">
<div class="info-long-title">审核意见</div>
<div class="info-long-content">{{ item.opinion }}</div>
</div>
<div class="info-long-block" v-if="item.auditSign">
<div class="info-long-title">签字</div>
<div class="info-sign-image">
<van-image width="200" height="100" :src="item.auditSign"/>
</div>
</div>
</div>
</section>
</template>
<template v-if="viewData.secretaryAudit&&viewData.secretaryAudit.length>0" name="提案委员会立案信息">
<div class="van-cell-group__title" style="padding: 5px 0 0 0 !important;">
<div class="van-sidebar-item van-sidebar-item--select">
提案委员会立案信息
<section class="info-card">
<div class="info-section-title">提案委员会立案信息</div>
<div class="info-record" v-for="(item,index) in viewData.secretaryAudit">
<div class="info-record-title" v-if="viewData.secretaryAudit.length>1">立案审核{{ index + 1 }}</div>
<div class="info-row">
<span class="info-label">审核时间</span>
<span class="info-value">{{ item.auditTime }}</span>
</div>
<div class="info-row">
<span class="info-label">立案编号</span>
<span class="info-value">{{ viewData.caseCode }}</span>
</div>
<div class="info-row">
<span class="info-label">审核结果</span>
<span class="info-value">{{ viewData.resultName }}</span>
</div>
<div class="info-long-block">
<div class="info-long-title">承办单位</div>
<div class="info-long-content" v-if="!viewData.undertake">暂未分配</div>
<div class="info-row" v-for="(undertake,index) in viewData.undertake" v-else>
<span class="info-label">{{ undertake.undertakeType === 1 ? '主办' : '协办' }}</span>
<span class="info-value is-long">{{ undertake.unitName }}</span>
</div>
</div>
<div class="info-long-block">
<div class="info-long-title">审核意见</div>
<div class="info-long-content">{{ item.opinion }}</div>
</div>
</div>
</div>
<van-cell-group v-for="item in viewData.secretaryAudit" class="info">
<van-cell title="审核时间">{{ item.auditTime }}</van-cell>
<van-cell title="立案编号">{{ viewData.caseCode }}</van-cell>
<van-cell title="审核结果">{{ viewData.resultName }}</van-cell>
<van-cell v-if="!viewData.undertake" title="承办单位">暂未分配</van-cell>
<van-collapse v-else v-model="undertakeActiveNames">
<van-collapse-item name="1" title="承办单位">
<van-cell v-for="(item,index) in viewData.undertake"
:title="item.undertakeType === 1 ? '主办' : '协办'">
{{ item.unitName }}
</van-cell>
</van-collapse-item>
</van-collapse>
<van-cell title="审核意见">{{ item.opinion }}</van-cell>
</van-cell-group>
</section>
</template>
<template v-if="viewData.caseAudit && viewData.caseAudit.length > 0" name="确认承办单位">
<div class="van-cell-group__title" style="padding: 5px 0 0 0 !important;">
<div class="van-sidebar-item van-sidebar-item--select">
确认承办单位
<template v-if="viewData.underTakeFirstOpinion&&viewData.underTakeFirstOpinion.length>0" name="承办单位意见">
<section class="info-card">
<div class="info-section-title">承办单位意见</div>
<div class="info-record" v-for="(item,index) in viewData.underTakeFirstOpinion">
<div class="info-record-title" v-if="viewData.underTakeFirstOpinion.length>1">意见记录{{ index + 1 }}</div>
<div class="info-row">
<span class="info-label">承办单位</span>
<span class="info-value">{{ item.underTakeName }}</span>
</div>
<div class="info-row">
<span class="info-label">时间</span>
<span class="info-value">{{ item.opionTime }}</span>
</div>
<div class="info-row">
<span class="info-label">审核结果</span>
<span class="info-value">{{ item.canTake ? '同意承办' : '无法承办' }}</span>
</div>
<div class="info-long-block">
<div class="info-long-title">意见</div>
<div class="info-long-content">{{ item.opinion }}</div>
</div>
</div>
</div>
<van-cell-group class="info">
<van-cell title="审核时间">{{ viewData.caseAudit.auditTime }}</van-cell>
<van-cell title="立案结果">{{ viewData.resultName }}</van-cell>
<van-collapse v-model="undertakeActiveNames">
<van-collapse-item name="2" title="承办单位">
<span v-if="!viewData.undertake">暂未分配</span>
<van-cell v-for="(item,index) in viewData.undertake" v-else
:title="item.undertakeType === 1 ? '主办' : '协办'">
{{ item.unitName }}
</van-cell>
</van-collapse-item>
</van-collapse>
<van-cell title="审核意见">{{ viewData.caseAudit.opinion }}</van-cell>
</section>
</template>
</van-cell-group>
<template v-if="viewData.caseUnitAuditId && viewData.caseUnitAudit" name="提案工作组正式立案">
<section class="info-card">
<div class="info-section-title">提案工作组正式立案</div>
<div class="info-row">
<span class="info-label">审核人</span>
<span class="info-value">{{ viewData.caseUnitAudit.username }}-{{ viewData.caseUnitAudit.loginName }}</span>
</div>
<div class="info-row">
<span class="info-label">审核结果</span>
<span class="info-value">{{ viewData.resultName }}</span>
</div>
<div class="info-row">
<span class="info-label">审核时间</span>
<span class="info-value">{{ viewData.caseUnitAudit.auditTime }}</span>
</div>
<div class="info-long-block" v-if="viewData.resultCode!=='notGive'">
<div class="info-long-title">承办单位</div>
<div class="info-long-content" v-if="!viewData.undertake">暂未分配</div>
<div class="info-row" v-for="(item,index) in viewData.undertake" v-else>
<span class="info-label">{{ item.undertakeType === 1 ? '主办' : '协办' }}</span>
<span class="info-value is-long">{{ item.unitName }}</span>
</div>
</div>
<div class="info-long-block">
<div class="info-long-title">审核意见</div>
<div class="info-long-content">{{ viewData.caseUnitAudit.opinion }}</div>
</div>
<div class="info-long-block" v-if="viewData.caseUnitAudit.auditSign">
<div class="info-long-title">签字</div>
<div class="info-sign-image">
<van-image width="200" height="100" :src="viewData.caseUnitAudit.auditSign"/>
</div>
</div>
</section>
</template>
<template v-if="viewData.makeLeader" name="分管校领导批示信息">
<div class="van-cell-group__title" style="padding: 5px 0 0 0 !important;">
<div class="van-sidebar-item van-sidebar-item--select">
分管校领导批示信息
</div>
</div>
<van-cell-group class="info">
<van-collapse v-model="undertakeActiveNames">
<van-collapse-item v-for="(v,k) in viewData.makeLeader" name="3">
<!--({{ v[0].undertakeType === 1 ? '主办' : '协办' }}) -->
<section class="info-card">
<div class="info-section-title">分管校领导批示信息</div>
<van-collapse class="info-collapse" v-model="undertakeActiveNames" :border="false">
<van-collapse-item v-for="(v,k) in viewData.makeLeader" :name="'makeLeader-' + k">
<template #title>
{{ v[0].unitName }}
</template>
<template v-for="item in v">
<van-cell title="批示时间"> {{ item.auditTime }}</van-cell>
<van-cell title="批示意见"> {{ item.opinion }}</van-cell>
</template>
<div class="info-collapse-group" v-for="item in v">
<div class="info-row">
<span class="info-label">批示时间</span>
<span class="info-value">{{ item.auditTime }}</span>
</div>
<div class="info-long-block">
<div class="info-long-title">批示意见</div>
<div class="info-long-content">{{ item.opinion }}</div>
</div>
</div>
</van-collapse-item>
</van-collapse>
</van-cell-group>
</section>
</template>
<template v-if="viewData.replyInfo && viewData.replyInfo.length>0 && viewData.replyInfo.some(v=>v.isReply)"
<template v-if="viewData.replyInfo && viewData.replyInfo.length>0 && viewData.replyInfo.some(v=>v.isReply || v.leaderCheckResult!=null)"
name="承办单位答复">
<div class="van-cell-group__title" style="padding: 5px 0 0 0 !important;">
<div class="van-sidebar-item van-sidebar-item--select">
承办单位答复信息
</div>
</div>
<van-cell-group class="info">
<van-collapse v-model="undertakeActiveNames">
<van-collapse-item v-for="item in viewData.replyInfo" :name="item.unitName">
<section class="info-card">
<div class="info-section-title">承办单位办理信息</div>
<van-collapse class="info-collapse" v-model="undertakeActiveNames" :border="false">
<van-collapse-item v-for="item in viewData.replyInfo.filter(v=>v.isReply || v.leaderCheckResult!=null)"
:name="'reply-' + item.unitName">
<template #title>
{{ item.unitName }}
{{ item.unitName }}({{ item.undertakeType === 1 ? '主办' : '协办' }})
</template>
<van-cell title="答复时间"> {{ item.replyTime }}</van-cell>
<van-cell title="落实情况"> {{ item.implementState }}</van-cell>
<van-cell title="答复信息">
<span v-html="item.replyContent"></span>
</van-cell>
<van-panel>
<template #header>
<div class="van-cell van-panel__header">
<div class="van-cell__title">
附件
</div>
</div>
</template>
<div style="padding: 5px 16px">
<upload v-if="item.replyFiles&&item.replyFiles.length>0" :del="false" :files.sync="item.files"
view></upload>
<span v-else>暂无</span>
<div class="info-row">
<span class="info-label">办理人</span>
<span class="info-value">{{ item.dfrUserName || '暂无' }}</span>
</div>
<div class="info-row">
<span class="info-label">办理时间</span>
<span class="info-value">{{ item.replyTime }}</span>
</div>
<div class="info-row">
<span class="info-label">办理次数</span>
<span class="info-value">{{ item.replyNumber }}</span>
</div>
<div class="info-row">
<span class="info-label">落实情况</span>
<span class="info-value">{{ item.implementState }}</span>
</div>
<div class="info-long-block">
<div class="info-long-title">办理内容</div>
<div class="info-long-content" v-html="item.replyContent"></div>
</div>
<div class="info-long-block" v-if="item.replySignData">
<div class="info-long-title">承办单位签字</div>
<div class="info-sign-image">
<van-image width="200" height="100" :src="item.replySignData"/>
</div>
</van-panel>
</div>
<div class="info-long-block">
<div class="info-long-title">附件</div>
<upload v-if="item.files&&item.files.length>0" :del="false" :files.sync="item.files" view></upload>
<div class="info-long-content" v-else>暂无</div>
</div>
</van-collapse-item>
</van-collapse>
</van-cell-group>
</section>
</template>
<template v-if="viewData.branchLeaderSuffixAuditOpinion&&viewData.branchLeaderSuffixAuditOpinion.length>0"
name="分管校领导审批">
<section class="info-card">
<div class="info-section-title">分管校领导审批</div>
<div class="info-record" v-for="(item,index) in viewData.branchLeaderSuffixAuditOpinion">
<div class="info-record-title" v-if="viewData.branchLeaderSuffixAuditOpinion.length>1">
审批记录{{ index + 1 }}
</div>
<div class="info-row">
<span class="info-label">审批人</span>
<span class="info-value">{{ item.username }}</span>
</div>
<div class="info-row">
<span class="info-label">审批时间</span>
<span class="info-value">{{ item.auditTime }}</span>
</div>
<div class="info-long-block">
<div class="info-long-title">审批意见</div>
<div class="info-long-content">{{ item.opinion }}</div>
</div>
<div class="info-long-block" v-if="item.auditSign">
<div class="info-long-title">分管校领导签字</div>
<div class="info-sign-image">
<van-image width="200" height="100" :src="item.auditSign"/>
</div>
</div>
</div>
</section>
</template>
<template v-if="viewData.feedback&&viewData.feedback.length>0" name="反馈评分信息">
<div class="van-cell-group__title" style="padding: 5px 0 0 0 !important;">
<div class="van-sidebar-item van-sidebar-item--select">
反馈评分信息
</div>
</div>
<van-cell-group class="info">
<template v-for="item in viewData.feedback">
<van-cell title="反馈时间">{{ item.feedbackTime }}</van-cell>
<van-cell title="反馈结果">{{ item.feedbackResult }}</van-cell>
<van-cell title="反馈意见"><span v-html="item.feedbackOpinion"></span></van-cell>
<van-panel>
<template #header>
<div class="van-cell van-panel__header">
<div class="van-cell__title">
附件
</div>
</div>
</template>
<div style="padding: 5px 16px">
<upload :del="false" :files.sync="item.files" view></upload>
<section class="info-card">
<div class="info-section-title">反馈评分信息</div>
<div class="info-record" v-for="(item,index) in viewData.feedback">
<div class="info-record-title" v-if="viewData.feedback.length>1">反馈记录{{ index + 1 }}</div>
<div class="info-row">
<span class="info-label">反馈人</span>
<span class="info-value">{{ item.username }}({{ item.loginname }})</span>
</div>
<div class="info-row">
<span class="info-label">反馈时间</span>
<span class="info-value">{{ item.feedbackTime }}</span>
</div>
<div class="info-row">
<span class="info-label">反馈次数</span>
<span class="info-value">{{ item.feedbackNumber }}</span>
</div>
<div class="info-row">
<span class="info-label">办理评价</span>
<span class="info-value">{{ item.feedbackResult }}</span>
</div>
<div class="info-long-block">
<div class="info-long-title">反馈意见</div>
<div class="info-long-content" v-html="item.feedbackOpinion"></div>
</div>
<div class="info-long-block" v-if="item.scoreSign">
<div class="info-long-title">反馈人签字</div>
<div class="info-sign-image">
<van-image width="200" height="100" :src="item.scoreSign"/>
</div>
</van-panel>
</template>
</van-cell-group>
</div>
<div class="info-long-block">
<div class="info-long-title">附件</div>
<upload v-if="item.files&&item.files.length" :del="false" :files.sync="item.files" view></upload>
<div class="info-long-content" v-else></div>
</div>
</div>
</section>
</template>
<template v-if="handle">
<div id="wechat_proposal_handle">
<div id="wechat_proposal_handle" class="info-card info-input-area">
<slot name="handle"></slot>
</div>
</template>
@@ -268,6 +500,9 @@ module.exports = {
createUserSignNames: [],
undertakeActiveNames: [],
briefActiveNames: [],
hostUnit: '',
helpUnit: [],
unitOptions: [],
viewData: {},
}
},
@@ -291,27 +526,69 @@ module.exports = {
'upload': httpVueLoader('/components/plugins/VantFileUpload.vue'),
},
methods: {
async openView(id) {
this.viewData = await getProposalInfo(id)
if (this.viewData.files) {
this.viewData.files = JSON.parse(this.viewData.files)
// 将 PC 端可能返回的对象或数组统一转换为数组,方便手机端模板用同一套 v-for 渲染审核记录。
toArray(data) {
if (!data) {
return []
}
if (this.viewData.replyInfo) {
const keys = Object.keys(this.viewData.replyInfo)
keys.map(k => {
if (this.viewData.replyInfo[k].replyFiles != null) {
this.viewData.replyInfo[k].replyFiles = JSON.parse(this.viewData.replyInfo[k].replyFiles)
return Array.isArray(data) ? data : [data]
},
// 解析后端返回的附件 JSON 字符串;如果已经是数组则原样返回,返回值统一交给 upload 组件展示。
parseList(data) {
if (!data) {
return []
}
return typeof data === 'string' ? JSON.parse(data) : data
},
// 根据预立案审核记录里的 other.hostUnit/helpUnit 转换主办、协办单位名称,用于对齐 PC 端承办单位展示。
setCaseAuditUnits() {
const caseAudit = this.toArray(this.viewData.caseAudit)[0]
this.hostUnit = ''
this.helpUnit = []
if (!caseAudit || this.viewData.resultCode === 'notGive' || !caseAudit.other) {
return
}
const other = typeof caseAudit.other === 'string' ? JSON.parse(caseAudit.other) : caseAudit.other
const host = this.unitOptions.find(v => v.id === other.hostUnit)
if (host) {
this.hostUnit = host.unitName
}
if (other.helpUnit && other.helpUnit.length > 0) {
const helpUnit = []
other.helpUnit.forEach((v, i) => {
const unit = this.unitOptions.find(z => other.helpUnit[i] === z.id)
if (unit) {
helpUnit.push(unit.unitName)
}
})
if (this.viewData.feedback && this.viewData.feedback.length > 0) {
this.viewData.feedback.map(v => {
v.files = JSON.parse(v.files)
this.helpUnit = helpUnit.join('、')
}
},
// 查询提案详情并处理手机端展示所需的数据结构:附件转数组、答复附件转 files、反馈附件转数组。
openView(id) {
return getProposalInfo(id).then((data) => {
this.viewData = data
if (this.viewData.files) {
this.$set(this.viewData, 'files', this.parseList(this.viewData.files))
}
if (this.viewData.replyInfo) {
const keys = Object.keys(this.viewData.replyInfo)
keys.map(k => {
if (this.viewData.replyInfo[k].replyFiles != null) {
this.$set(this.viewData.replyInfo[k], 'files', this.parseList(this.viewData.replyInfo[k].replyFiles))
}
})
}
}
if (this.viewData.feedback && this.viewData.feedback.length > 0) {
this.viewData.feedback.map(v => {
this.$set(v, 'files', this.parseList(v.files))
})
}
this.setCaseAuditUnits()
this.activeName = this.handle ? "999" : "1"
this.activeName = this.handle ? "999" : "1"
})
},
previewFile(filepath, filename, fileList, index) {
const doctype = ['doc', 'docx', 'xls', 'xlsx'];
@@ -334,7 +611,7 @@ module.exports = {
}
})
const viewer = new Viewer(ele, {
title: function (img, obj) {
title: (img, obj) => {
return img.getAttribute("alt");
}
});
@@ -354,11 +631,15 @@ module.exports = {
}
}
},
async created() {
await this.openView(this.proposal_id)
if (this.handle) {
window.scrollTo(0, document.getElementById('wechat_proposal_handle').offsetTop)
}
created() {
getProposalUndertake().then((data) => {
this.unitOptions = data
return this.openView(this.proposal_id)
}).then(() => {
if (this.handle) {
window.scrollTo(0, document.getElementById('wechat_proposal_handle').offsetTop)
}
})
}
}
</script>
@@ -368,17 +649,4 @@ module.exports = {
color: #323233 !important;
}
.van-cell-group__title {
padding-left: 0 !important;
}
.van-sidebar-item {
font-size: 16px !important;
text-indent: 4px !important;
}
.van-sidebar-item--select::before {
left: 5px !important;
}
</style>
@@ -13,6 +13,8 @@
<link rel="stylesheet" href="${base!}/assets/mobile/css/theme.css">
<link rel="stylesheet" href="${base!}/assets/mobile/css/main.css">
<link rel="stylesheet" href="${base!}/assets/mobile/css/universal-info.css">
<link rel="stylesheet" href="${base!}/assets/mobile/css/list-card.css">
<link rel="stylesheet" href="${base!}/assets/mobile/css/pdfh5.css">
@@ -0,0 +1,152 @@
<!--#
layout("/mobile/platform.html"){
#-->
<div id="app" v-cloak>
<van-nav-bar title="校领导审批" fixed placeholder :left-arrow="leftArrow" safe-area-inset-top
@click-left="pjaxReplace('/mobile/proposal/branchLeaderSuffixAudit')"></van-nav-bar>
<proposal-info :proposal_id="proposalId" title="校领导审批" :handle="handle" ref="info">
<template #handle>
<div class="info-section-title">分管校领导审批</div>
<van-form class="info-cell-form">
<div class="info-row" v-if="underTakeNames">
<span class="info-label">承办单位</span>
<span class="info-value is-long">{{underTakeNames}}</span>
</div>
<div class="info-row">
<span class="info-label">审核人</span>
<span class="info-value">{{formData.username}}</span>
</div>
<div class="info-row">
<span class="info-label">审核时间</span>
<span class="info-value">{{formData.auditTime}}</span>
</div>
<div class="info-textarea-field">
<div class="info-textarea-label info-required-label">审批意见</div>
<van-field
v-model="formData.opinion"
rows="4"
autosize
type="textarea"
maxlength="1000"
placeholder="请填写您的审批意见"
show-word-limit
></van-field>
</div>
<van-row class="info-footer-actions" type="flex" gutter="10">
<van-col span="12">
<van-button block class="info-ghost-button" :loading="formLoading"
@click="pjaxReplace('/mobile/proposal/branchLeaderSuffixAudit')">
取消
</van-button>
</van-col>
<van-col span="12">
<van-button :color="themeColor" block class="info-primary-button" :loading="formLoading"
@click="doAudit">
提交
</van-button>
</van-col>
</van-row>
</van-form>
</template>
</proposal-info>
</div>
<script>
const vue = new Vue({
el: '#app',
mixins: [mobileMixins],
data() {
return {
leftArrow: false,
handle: false,
proposalId: GetQueryString('proposal_id'),
pblsaId: GetQueryString('pblsaId'),
underTakeId: '',
underTakeNames: '',
formLoading: false,
formData: {
username: "${@shiro.getPrincipalProperty('username')}",
loginName: "${@shiro.getPrincipalProperty('loginname')}",
auditTime: moment().format('YYYY-MM-DD'),
opinion: '同意办结',
sign: '',
proposalId: GetQueryString('proposal_id')
}
}
},
components: {
'proposal-info': httpVueLoader('/components/proposal/mobile/ProposalInfo.vue?v=' + new Date().getTime()),
},
methods: {
loadAuditInfo() {
$.get('/mobile/proposal/branchLeaderSuffixAudit/getAuditInfo', {
pblsaId: this.pblsaId
}).then((res) => {
const data = res.data || {}
this.$set(this, 'underTakeId', data.underTakeId || '')
this.$set(this, 'underTakeNames', data.underTakeNames || '')
this.handle = data.stateCode === 700 && data.isAudit !== true
})
},
validateForm() {
if (!this.pblsaId) {
vant.Toast('审批记录不存在')
return false
}
if (!this.formData.opinion) {
vant.Toast('请填写审批意见')
return false
}
return true
},
doAudit() {
if (!this.validateForm() || this.formLoading) {
return
}
vant.Dialog.confirm({
title: '提示',
message: '您确定要提交审批意见吗?',
}).then(() => {
this.formLoading = true
$.post('/mobile/proposal/branchLeaderSuffixAudit/doAudit', {
audit: JSON.stringify(this.formData),
pblsaId: this.pblsaId,
sign: this.formData.sign
}).then((res) => {
if (res.code === 0) {
this.$toast.success('提交成功')
this.handle = false
this.$refs.info.openView(this.proposalId)
} else {
this.$toast.fail(res.msg || '提交失败,请联系管理员')
}
}).always(() => {
this.formLoading = false
})
})
}
},
created() {
if (GetQueryString('mobile')) {
this.leftArrow = true
}
const proposalId = GetQueryString('proposal_id')
const bizKey = GetQueryString('biz_key')
if (proposalId === '' || bizKey === '') {
vant.Dialog.alert({
title: '提示',
message: '非法参数',
showConfirmButton: false
})
return
}
this.loadAuditInfo()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,196 @@
<!--#
layout("/mobile/platform.html"){
#-->
<div id="app" v-cloak>
<m-page-loading v-if="mLoading"></m-page-loading>
<van-nav-bar
title="校领导审批"
left-arrow
placeholder
fixed
@click-left="pjaxReplace('/mobile/index')"
></van-nav-bar>
<div class="search-fixed">
<van-search
v-model="pageForm.searchKeyWord"
shape="round"
maxlength="10"
@search="doSearch"
placeholder="请输入提案名称或者提案编号进行查询"
></van-search>
<van-dropdown-menu>
<van-dropdown-item v-model="pageForm.meetingId" :options="sessionList"
@change="doSearch"></van-dropdown-item>
<van-dropdown-item v-model="pageForm.proposalTypeId" :options="proposalTypeList"
@change="doSearch"></van-dropdown-item>
<van-dropdown-item v-model="pageForm.proposalResultCode" :options="resultList"
@change="doSearch"></van-dropdown-item>
</van-dropdown-menu>
<van-tabs v-model="pageForm.isAudit" @change="doSearch">
<van-tab title="全部" name=""></van-tab>
<van-tab title="已审批" name="true"></van-tab>
<van-tab title="待审批" name="false"></van-tab>
</van-tabs>
</div>
<div style="margin: 170px auto 0">
<van-list
v-if="pageForm.meetingId"
v-model="mLoading"
:immediate-check="false"
:finished="finished"
:finished-text="tableData.length>0?'没有更多了':''"
@load="onLoad">
<div v-for="o in tableData" class="list-card" :style="{'--card-accent': o.stateColor || '#2563eb'}"
@click="openView(o)">
<div class="card-header">
<div class="card-title">
{{o.proposalName}}
</div>
<span class="badge" :class="o.isAudit ? 'badge-blue' : 'badge-draft'">
{{o.isAudit ? '已审批' : '待审批'}}
</span>
</div>
<div class="card-body">
<div class="card-item">
<span class="card-label">提案编号:</span>
<span class="card-value">{{o.proposalCode}}</span>
</div>
<div class="card-item">
<span class="card-label">提案类型:</span>
<span class="card-value">{{o.typeName}}</span>
</div>
<div class="card-item">
<span class="card-label">代表团:</span>
<span class="card-value">{{o.delegationName}}</span>
</div>
<div class="card-item">
<span class="card-label">提案届次:</span>
<span class="card-value">{{o.meetingName}}</span>
</div>
<div class="card-item">
<span class="card-label">提案状态:</span>
<span class="card-value">{{o.stateName}}</span>
</div>
<div class="card-item">
<span class="card-label">承办单位:</span>
<span class="card-value">{{o.underTakeNames}}</span>
</div>
</div>
<div class="card-footer" v-if="o.resultName">
<span class="card-label">立案结果:</span>
<span class="card-value">{{o.resultName}}</span>
</div>
</div>
</van-list>
<van-empty
v-if="mLoading==false&&tableData.length==0"
class="custom-image"
image="/none.svg"
description="暂无数据"
></van-empty>
</div>
</div>
<script>
const vue = new Vue({
el: '#app',
mixins: [mobileMixins],
data() {
return {
pageForm: {
isAudit: 'false'
},
sessionList: [],
proposalTypeList: [],
resultList: [],
listLoading: false
}
},
methods: {
doSearch() {
this.$set(this.pageForm, 'pageNumber', 1)
this.tableData = []
this.finished = false
this.onLoad()
},
onLoad() {
if (this.listLoading || this.finished) {
return
}
this.listLoading = true
this.mLoading = true
$.post(loc() + '/pageData', this.pageForm)
.then((res) => {
if (res.code === 0) {
this.tableData = this.tableData.concat(res.data.list)
if (this.tableData.length >= res.data.totalCount) {
this.finished = true
} else {
this.$set(this.pageForm, 'pageNumber', this.pageForm.pageNumber + 1)
}
}
})
.always(() => {
this.listLoading = false
this.mLoading = false
})
},
openView(row) {
window.location.href = '/mobile/proposal/branchLeaderSuffixAudit/view?biz_key=' + row.id
+ '&proposal_id=' + row.id
+ '&pblsaId=' + row.pblsaId
+ '&mobile=' + true
},
loadOptions() {
$.get('/mobile/proposal/common/getAllSession')
.then((res) => {
this.sessionList = res.data
if (this.sessionList && this.sessionList.length > 0) {
this.$set(this.pageForm, 'meetingId', this.sessionList[0].value)
}
})
.then(() => $.get('/mobile/proposal/common/getProposalType'))
.then((res) => {
this.proposalTypeList = res.data
if (this.proposalTypeList && this.proposalTypeList.length > 0) {
this.$set(this.pageForm, 'proposalTypeId', this.proposalTypeList[0].value)
}
})
.then(() => $.get('/mobile/proposal/common/getProposalDict'))
.then((res) => {
this.resultList = res.data
if (this.resultList && this.resultList.length > 0) {
this.$set(this.pageForm, 'proposalResultCode', this.resultList[0].value)
}
this.onLoad()
})
}
},
created() {
this.$set(this.pageForm, 'pageNumber', 1)
this.$set(this.pageForm, 'pageSize', 5)
this.$set(this.pageForm, 'totalCount', 0)
this.loadOptions()
}
})
window.addEventListener('pageshow', (e) => {
if (e.persisted || (window.performance && window.performance.navigation.type === 2)) {
vue.$set(vue.pageForm, 'pageNumber', 1)
vue.$set(vue.pageForm, 'meetingId', null)
vue.tableData = []
vue.finished = false
vue.loadOptions()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,511 @@
<!--#
layout("/mobile/platform.html"){
#-->
<div id="app" v-cloak>
<van-nav-bar title="提案工作组预立案" fixed placeholder :left-arrow="leftArrow" safe-area-inset-top
@click-left="pjaxReplace('/mobile/proposal/case')"></van-nav-bar>
<proposal-info :proposal_id="proposalId" title="提案工作组预立案" :handle="handle" ref="info">
<template #handle>
<div class="info-section-title">预立案审核</div>
<van-form class="info-cell-form">
<div class="info-row">
<span class="info-label">审核人</span>
<span class="info-value">{{formData.username}}</span>
</div>
<div class="info-row">
<span class="info-label">审核时间</span>
<span class="info-value">{{formData.auditTime}}</span>
</div>
<div class="info-picker-card">
<van-field
:value="resultCodeName"
clickable
input-align="right"
label="立案结果"
label-class="info-picker-label"
name="resultCode"
placeholder="请选择立案结果"
required
readonly
right-icon="arrow"
@click="showResultCodePicker = true"
></van-field>
</div>
<van-popup position="bottom" round v-model="showResultCodePicker">
<van-picker
:columns="resultPickerOptions"
@cancel="showResultCodePicker = false"
@confirm="onResultCodeConfirm"
show-toolbar
></van-picker>
</van-popup>
<div class="info-picker-card">
<van-field
:value="typeName"
clickable
input-align="right"
label="提案类型"
label-class="info-picker-label"
name="typeId"
placeholder="请选择提案类型"
required
readonly
right-icon="arrow"
@click="showTypePicker = true"
></van-field>
</div>
<van-popup position="bottom" round v-model="showTypePicker">
<van-picker
:columns="typePickerOptions"
@cancel="showTypePicker = false"
@confirm="onTypeConfirm"
show-toolbar
></van-picker>
</van-popup>
<div class="info-picker-card" v-if="formData.resultCode=='notGive'">
<van-field
:value="formData.noFilingReason"
clickable
input-align="right"
label="理由列表"
label-class="info-picker-label"
name="noFilingReason"
placeholder="请选择理由列表"
readonly
right-icon="arrow"
@click="showNoFilingReasonPicker = true"
></van-field>
</div>
<van-popup position="bottom" round v-model="showNoFilingReasonPicker">
<van-picker
:columns="noFilingReason"
@cancel="showNoFilingReasonPicker = false"
@confirm="onNoFilingReasonConfirm"
show-toolbar
></van-picker>
</van-popup>
<template v-if="formData.resultCode!='notGive'">
<div class="info-picker-card">
<van-field
:value="hostUnitName"
clickable
input-align="right"
label="主办单位"
label-class="info-picker-label"
name="hostUnit"
placeholder="请选择主办单位"
:required="formData.resultCode !== 'notGive'"
readonly
right-icon="arrow"
@click="openHostUnitPicker"
></van-field>
</div>
<van-popup position="bottom" round v-model="showHostUnitPicker">
<div class="unit-select-toolbar">
<button class="unit-select-cancel" type="button" @click="onHostUnitCancel">取消</button>
<div class="unit-select-title">主办单位</div>
<button class="unit-select-confirm" type="button" @click="onHostUnitConfirm">确定</button>
</div>
<van-search
placeholder="请输入单位名称搜索"
v-model="hostUnitSearchKey"
></van-search>
<van-picker
:columns="hostUnitPickerOptions"
@change="onHostUnitPickerChange"
></van-picker>
<van-empty description="暂无匹配单位" v-if="hostUnitPickerOptions.length === 0"></van-empty>
</van-popup>
<div class="info-row" v-if="formData.hostUnit">
<span class="info-label">主办领导</span>
<span class="info-value is-long">{{hostUnitLeader}}</span>
</div>
<div class="info-picker-card">
<van-field
class="info-multi-value-field"
clickable
input-align="right"
label="协办单位"
label-class="info-picker-label"
name="helpUnit"
placeholder="请选择协办单位"
readonly
right-icon="arrow"
@click="openHelpUnitPicker"
>
<template #input>
<div class="info-multi-value" v-if="helpUnitName">{{helpUnitName}}</div>
<div class="info-multi-value info-multi-placeholder" v-else>请选择协办单位</div>
</template>
</van-field>
</div>
<van-popup position="bottom" round v-model="showHelpUnitPicker">
<div class="unit-select-toolbar">
<button class="unit-select-cancel" type="button" @click="onHelpUnitCancel">取消</button>
<div class="unit-select-title">协办单位</div>
<button class="unit-select-confirm" type="button" @click="onHelpUnitConfirm">确定</button>
</div>
<van-search
placeholder="请输入单位名称搜索"
v-model="helpUnitSearchKey"
></van-search>
<div class="unit-select-list">
<van-checkbox-group v-model="checkedHelpUnit" direction="vertical">
<van-checkbox
v-for="item in filterHelpUnitOptions"
:key="item.id"
:name="item.id"
style="margin: 10px 0"
>
{{item.unitName}}
</van-checkbox>
</van-checkbox-group>
<van-empty description="暂无匹配单位" v-if="filterHelpUnitOptions.length === 0"></van-empty>
</div>
</van-popup>
<div class="info-row" v-if="formData.helpUnit && formData.helpUnit.length>0">
<span class="info-label">协办领导</span>
<span class="info-value is-long">{{helpUnitLeader}}</span>
</div>
</template>
<div class="info-textarea-field">
<div class="info-textarea-label info-required-label">审核意见</div>
<van-field
v-model="formData.opinion"
rows="4"
autosize
type="textarea"
maxlength="500"
placeholder="请填写您的审核意见"
show-word-limit
></van-field>
</div>
<van-row class="info-footer-actions" type="flex" gutter="10">
<van-col span="12">
<van-button block class="info-ghost-button" :loading="formLoading" @click="doAudit(2)">
退回修改
</van-button>
</van-col>
<van-col span="12">
<van-button :color="themeColor" block class="info-primary-button" :loading="formLoading"
@click="doAudit(1)">
提交
</van-button>
</van-col>
</van-row>
</van-form>
</template>
</proposal-info>
</div>
<script>
const vue = new Vue({
el: '#app',
mixins: [mobileMixins],
data() {
return {
leftArrow: false,
handle: false,
proposalId: GetQueryString('proposal_id'),
formLoading: false,
showResultCodePicker: false,
showTypePicker: false,
showNoFilingReasonPicker: false,
showHostUnitPicker: false,
showHelpUnitPicker: false,
hostUnitSearchKey: '',
helpUnitSearchKey: '',
checkedHostUnit: '',
checkedHelpUnit: [],
resultOptions: [],
typeOptions: [],
unitOptions: [],
noFilingReason: [],
proposalStateCode: null,
formData: {
username: "${@shiro.getPrincipalProperty('username')}",
loginName: "${@shiro.getPrincipalProperty('loginname')}",
auditTime: moment().format('YYYY-MM-DD'),
resultCode: '',
hostUnit: '',
helpUnit: [],
opinion: '经提案工作组审理,该提案返回修改。',
noFilingReason: '',
sign: '',
typeId: '',
determineTypeCode: '',
proposalId: GetQueryString('proposal_id')
}
}
},
computed: {
// 将接口返回的不同字段统一成 Picker 的 text/value 结构,text 用于展示,value 回写原表单提交字段。
resultPickerOptions() {
return this.resultOptions.map(v => {
return {
text: v.name,
value: v.code
}
})
},
typePickerOptions() {
return this.typeOptions.map(v => {
return {
text: v.typeName,
value: v.id
}
})
},
unitPickerOptions() {
return this.unitOptions.map(v => {
return {
text: v.unitName,
value: v.id
}
})
},
hostUnitPickerOptions() {
const key = this.hostUnitSearchKey ? this.hostUnitSearchKey.trim() : ''
return this.unitOptions.filter(v => {
return !key || v.unitName.includes(key)
}).map(v => {
return {
text: v.unitName,
value: v.id
}
})
},
filterHelpUnitOptions() {
const key = this.helpUnitSearchKey ? this.helpUnitSearchKey.trim() : ''
return this.unitOptions.filter(v => {
return !key || v.unitName.includes(key)
})
},
resultCodeName() {
const result = this.resultOptions.find(v => v.code === this.formData.resultCode)
return result ? result.name : ''
},
typeName() {
const type = this.typeOptions.find(v => v.id === this.formData.typeId)
return type ? type.typeName : ''
},
hostUnitName() {
const hostUnit = this.unitOptions.find(v => v.id === this.formData.hostUnit)
return hostUnit ? hostUnit.unitName : ''
},
helpUnitName() {
const helpUnits = this.unitOptions.filter(v => this.formData.helpUnit.includes(v.id)).map(v => v.unitName)
return helpUnits && helpUnits.length > 0 ? helpUnits.toString() : ''
},
hostUnitLeader() {
const hostUnit = this.unitOptions.find(v => v.id === this.formData.hostUnit)
return hostUnit && hostUnit.leader ? hostUnit.leader : '无'
},
helpUnitLeader() {
const helpUnits = this.unitOptions.filter(v => this.formData.helpUnit.includes(v.id)).map(v => {
return v.leader ? v.leader : '无'
})
return helpUnits && helpUnits.length > 0 ? helpUnits.toString() : '无'
}
},
components: {
'proposal-info': httpVueLoader('/components/proposal/mobile/ProposalInfo.vue?v=' + new Date().getTime()),
},
methods: {
initHandleState() {
$.post('/platform/proposal/common/getProposalStateCode', {
proposal_id: this.proposalId
}).then((res) => {
this.proposalStateCode = res.data
this.handle = this.proposalStateCode === 300
})
},
loadProposalInfo() {
getProposalInfo(this.proposalId).then((data) => {
if (data && data.typeId) {
this.$set(this.formData, 'typeId', data.typeId)
}
})
},
loadOptions() {
$.get('/platform/proposal/common/getDictByCode', {
code: 'proposal_result'
}).then((res) => {
this.resultOptions = res.data
}).then(() => $.get('/mobile/proposal/case/getUnderTakeAndLeader'))
.then((res) => {
this.unitOptions = res.data
})
.then(() => $.get('/platform/proposal/common/getProposalConfig'))
.then((res) => {
this.noFilingReason = res.data.noFilingReason
})
.then(() => $.get('/platform/proposal/common/getProposalType'))
.then((res) => {
this.typeOptions = res.data
})
},
// 选择立案结果后同步原 resultCode 字段,并复用原有联动逻辑清理承办单位和刷新审核意见。
onResultCodeConfirm(value) {
this.$set(this.formData, 'resultCode', value.value)
this.resultCodeChange(value.value)
this.showResultCodePicker = false
},
// 选择提案类型后只回写 typeId,提交时继续使用后端原有参数结构。
onTypeConfirm(value) {
this.$set(this.formData, 'typeId', value.value)
this.showTypePicker = false
},
onNoFilingReasonConfirm(value) {
this.$set(this.formData, 'noFilingReason', value)
this.$set(this.formData, 'opinion', '经提案工作组审理,该提案不予立案。' + value)
this.showNoFilingReasonPicker = false
},
// 打开主办单位弹框时先暂存当前值,搜索和滚动选择不会立即影响原表单。
openHostUnitPicker() {
this.hostUnitSearchKey = ''
this.checkedHostUnit = this.formData.hostUnit || (this.hostUnitPickerOptions[0] ? this.hostUnitPickerOptions[0].value : '')
this.showHostUnitPicker = true
},
onHostUnitCancel() {
this.showHostUnitPicker = false
},
onHostUnitPickerChange(picker, value) {
this.checkedHostUnit = value && value.value ? value.value : ''
},
// 确认主办单位后回写 hostUnit,主办领导展示通过 computed 自动从 unitOptions 中匹配。
onHostUnitConfirm() {
if (!this.checkedHostUnit) {
return
}
this.$set(this.formData, 'hostUnit', this.checkedHostUnit)
this.showHostUnitPicker = false
},
// 打开协办单位弹框时先复制当前值,取消选择时不会影响原表单,确定后再统一回写。
openHelpUnitPicker() {
this.checkedHelpUnit = this.formData.helpUnit.concat()
this.helpUnitSearchKey = ''
this.showHelpUnitPicker = true
},
onHelpUnitCancel() {
this.checkedHelpUnit = this.formData.helpUnit.concat()
this.showHelpUnitPicker = false
},
onHelpUnitConfirm() {
this.$set(this.formData, 'helpUnit', this.checkedHelpUnit.concat())
this.showHelpUnitPicker = false
},
resultCodeChange(code) {
this.$set(this.formData, 'hostUnit', '')
this.$set(this.formData, 'helpUnit', [])
this.$set(this.formData, 'noFilingReason', '')
this.checkedHelpUnit = []
if (code === 'opinion') {
this.$set(this.formData, 'opinion', '经提案工作组审理,该提案作为意见建议。')
} else if (code === 'notGive') {
this.$set(this.formData, 'opinion', '经提案工作组审理,该提案不予立案。')
} else if (code) {
this.$set(this.formData, 'opinion', '经提案工作组审理,该提案确定立案。')
} else {
this.$set(this.formData, 'opinion', '经提案工作组审理,该提案返回修改。')
}
},
validateForm(flag) {
if (!this.formData.typeId) {
vant.Toast('请选择提案类型')
return false
}
if (flag === 1 && !this.formData.resultCode) {
vant.Toast('请选择立案结果')
return false
}
if (flag === 1 && this.formData.resultCode !== 'notGive' && !this.formData.hostUnit) {
vant.Toast('请选择主办单位')
return false
}
if (this.formData.helpUnit.find(v => v === this.formData.hostUnit)) {
vant.Toast('协办单位中不能包含主办单位')
return false
}
if (!this.formData.opinion) {
vant.Toast('请填写审核意见')
return false
}
return true
},
doAudit(flag) {
if (!this.validateForm(flag) || this.formLoading) {
return
}
const msg = flag === 2 ? '请确认是否退回到团长?' : this.formData.resultCode === 'notGive' ? '该提案不予立案,提交后将完结,请确认!' : '请确认是否提交该提案?'
vant.Dialog.confirm({
title: '提示',
message: msg,
}).then(() => {
this.formLoading = true
$.post('/mobile/proposal/case/audit', {
audit: JSON.stringify(this.formData),
resultCode: this.formData.resultCode,
typeId: this.formData.typeId,
hostUnit: this.formData.hostUnit,
helpUnit: JSON.stringify(this.formData.helpUnit),
sign: this.formData.sign,
determineTypeCode: this.formData.determineTypeCode,
proposalIds: JSON.stringify([this.proposalId]),
auditType: 'one',
flag: flag
}).then((res) => {
if (res.code === 0) {
this.$toast.success('提交成功')
this.handle = false
this.$refs.info.openView(this.proposalId)
} else {
this.$toast.fail(res.msg || '提交失败,请联系管理员')
}
}).always(() => {
this.formLoading = false
})
})
}
},
watch: {
hostUnitPickerOptions(value) {
if (!this.showHostUnitPicker) {
return
}
if (!value.some(v => v.value === this.checkedHostUnit)) {
this.checkedHostUnit = value[0] ? value[0].value : ''
}
}
},
created() {
if (GetQueryString('mobile')) {
this.leftArrow = true
}
const proposalId = GetQueryString('proposal_id')
const bizKey = GetQueryString('biz_key')
if (proposalId === '' || bizKey === '') {
vant.Dialog.alert({
title: '提示',
message: '非法参数',
showConfirmButton: false
})
return
}
this.loadOptions()
this.loadProposalInfo()
this.initHandleState()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,193 @@
<!--#
layout("/mobile/platform.html"){
#-->
<div id="app" v-cloak>
<m-page-loading v-if="mLoading"></m-page-loading>
<van-nav-bar
title="提案工作组预立案"
left-arrow
placeholder
fixed
@click-left="pjaxReplace('/mobile/index')"
></van-nav-bar>
<div class="search-fixed">
<van-search
v-model="pageForm.searchKeyWord"
shape="round"
maxlength="10"
@search="doSearch"
placeholder="请输入提案名称或者提案编号进行查询"
></van-search>
<van-dropdown-menu>
<van-dropdown-item v-model="pageForm.meetingId" :options="sessionList"
@change="doSearch"></van-dropdown-item>
<van-dropdown-item v-model="pageForm.proposalTypeId" :options="proposalTypeList"
@change="doSearch"></van-dropdown-item>
<van-dropdown-item v-model="pageForm.proposalResultCode" :options="resultList"
@change="doSearch"></van-dropdown-item>
</van-dropdown-menu>
<van-tabs v-model="pageForm.isAudit" @change="doSearch">
<van-tab title="全部" name=""></van-tab>
<van-tab title="已审核" name="true"></van-tab>
<van-tab title="待审核" name="false"></van-tab>
</van-tabs>
</div>
<div style="margin: 170px auto 0">
<van-list
v-if="pageForm.meetingId"
v-model="mLoading"
:immediate-check="false"
:finished="finished"
:finished-text="tableData.length>0?'没有更多了':''"
@load="onLoad">
<div v-for="o in tableData" class="list-card" :style="{'--card-accent': o.stateColor || '#2563eb'}"
@click="openView(o)">
<div class="card-header">
<div class="card-title">
{{o.proposalName}}
</div>
<span class="badge" :class="o.stateCode === 300 ? 'badge-draft' : 'badge-blue'">
{{o.stateCode === 300 ? '待审核' : '已审核'}}
</span>
</div>
<div class="card-body">
<div class="card-item">
<span class="card-label">提案编号:</span>
<span class="card-value">{{o.proposalCode}}</span>
</div>
<div class="card-item">
<span class="card-label">提案类型:</span>
<span class="card-value">{{o.typeName}}</span>
</div>
<div class="card-item">
<span class="card-label">代表团:</span>
<span class="card-value">{{o.delegationName}}</span>
</div>
<div class="card-item">
<span class="card-label">提案届次:</span>
<span class="card-value">{{o.meetingName}}</span>
</div>
<div class="card-item">
<span class="card-label">提案状态:</span>
<span class="card-value">{{o.stateName}}</span>
</div>
<div class="card-item">
<span class="card-label">是否并案:</span>
<span class="card-value">{{o.stateCode === 300 ? '暂无' : o.isConjoin === 1 ? '是' : '否'}}</span>
</div>
</div>
<div class="card-footer" v-if="o.resultName">
<span class="card-label">立案结果:</span>
<span class="card-value">{{o.resultName}}</span>
</div>
</div>
</van-list>
<van-empty
v-if="mLoading==false&&tableData.length==0"
class="custom-image"
image="/none.svg"
description="暂无数据"
></van-empty>
</div>
</div>
<script>
const vue = new Vue({
el: '#app',
mixins: [mobileMixins],
data() {
return {
pageForm: {
isAudit: 'false'
},
sessionList: [],
proposalTypeList: [],
resultList: [],
listLoading: false
}
},
methods: {
doSearch() {
this.$set(this.pageForm, 'pageNumber', 1)
this.tableData = []
this.finished = false
this.onLoad()
},
onLoad() {
if (this.listLoading || this.finished) {
return
}
this.listLoading = true
this.mLoading = true
$.post(loc() + '/pageData', this.pageForm)
.then((res) => {
if (res.code === 0) {
this.tableData = this.tableData.concat(res.data.list)
if (this.tableData.length >= res.data.totalCount) {
this.finished = true
} else {
this.$set(this.pageForm, 'pageNumber', this.pageForm.pageNumber + 1)
}
}
})
.always(() => {
this.listLoading = false
this.mLoading = false
})
},
openView(row) {
window.location.href = '/mobile/proposal/case/view?biz_key=' + row.id + '&proposal_id=' + row.id + '&stateCode=' + row.stateCode + '&mobile=' + true
},
loadOptions() {
$.get('/mobile/proposal/common/getAllSession')
.then((res) => {
this.sessionList = res.data
if (this.sessionList && this.sessionList.length > 0) {
this.$set(this.pageForm, 'meetingId', this.sessionList[0].value)
}
})
.then(() => $.get('/mobile/proposal/common/getProposalType'))
.then((res) => {
this.proposalTypeList = res.data
if (this.proposalTypeList && this.proposalTypeList.length > 0) {
this.$set(this.pageForm, 'proposalTypeId', this.proposalTypeList[0].value)
}
})
.then(() => $.get('/mobile/proposal/common/getProposalDict'))
.then((res) => {
this.resultList = res.data
if (this.resultList && this.resultList.length > 0) {
this.$set(this.pageForm, 'proposalResultCode', this.resultList[0].value)
}
this.onLoad()
})
}
},
created() {
this.$set(this.pageForm, 'pageNumber', 1)
this.$set(this.pageForm, 'pageSize', 5)
this.$set(this.pageForm, 'totalCount', 0)
this.loadOptions()
}
})
window.addEventListener('pageshow', (e) => {
if (e.persisted || (window.performance && window.performance.navigation.type === 2)) {
vue.$set(vue.pageForm, 'pageNumber', 1)
vue.$set(vue.pageForm, 'meetingId', null)
vue.tableData = []
vue.finished = false
vue.loadOptions()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,147 @@
<!--#
layout("/mobile/platform.html"){
#-->
<div id="app" v-cloak>
<van-nav-bar title="提案工作组意见" fixed placeholder :left-arrow="leftArrow" safe-area-inset-top
@click-left="pjaxReplace('/mobile/proposal/caseRead')"></van-nav-bar>
<proposal-info :proposal_id="proposalId" title="提案工作组意见" :handle="handle" ref="info">
<template #handle>
<div class="van-cell-group__title" style="padding: 5px 0 0 0 !important;">
<div class="van-sidebar-item van-sidebar-item--select">
成员意见
</div>
</div>
<van-form>
<van-cell-group class="info">
<van-cell title="审核人" :value="formData.username"></van-cell>
<van-cell title="审核时间" :value="formData.auditTime"></van-cell>
<van-field name="other" label="立案意见">
<template #input>
<van-radio-group v-model="formData.other" direction="vertical">
<van-radio v-for="item in resultOptions" :name="item.code" style="margin: 8px 0">
{{item.name}}
</van-radio>
</van-radio-group>
</template>
</van-field>
<van-field
input-align="right"
v-model="formData.opinion"
rows="3"
autosize
label="审核意见"
type="textarea"
maxlength="1000"
placeholder="请填写您的意见"
show-word-limit
></van-field>
</van-cell-group>
<van-row type="flex" style="padding: 20px 10px">
<van-button :color="themeColor" block size="large" :loading="formLoading" @click="doAudit">提交
</van-button>
</van-row>
</van-form>
</template>
</proposal-info>
</div>
<script>
const vue = new Vue({
el: '#app',
mixins: [mobileMixins],
data() {
return {
leftArrow: false,
handle: false,
proposalId: GetQueryString('proposal_id'),
formLoading: false,
resultOptions: [],
proposalStateCode: null,
formData: {
username: "${@shiro.getPrincipalProperty('username')}",
loginName: "${@shiro.getPrincipalProperty('loginname')}",
auditTime: moment().format('YYYY-MM-DD'),
opinion: '',
sign: '',
other: 'determine',
determineTypeCode: 'ordinary',
proposalId: GetQueryString('proposal_id')
}
}
},
components: {
'proposal-info': httpVueLoader('/components/proposal/mobile/ProposalInfo.vue?v=' + new Date().getTime()),
},
methods: {
initHandleState() {
$.post('/platform/proposal/common/getProposalStateCode', {
proposal_id: this.proposalId
}).then((res) => {
const isOpinion = GetQueryString('isOpinion')
this.proposalStateCode = res.data
this.handle = this.proposalStateCode === 300 && isOpinion !== 'true' && isOpinion !== '1'
})
},
loadResultOptions() {
$.get('/platform/proposal/common/getDictByCode', {
code: 'proposal_result'
}).then((res) => {
this.resultOptions = res.data
})
},
doAudit() {
if (!this.formData.other) {
vant.Toast('请选择立案意见')
return
}
if (this.formLoading) {
return
}
vant.Dialog.confirm({
title: '提示',
message: '您确定提交该提案的成员意见吗?',
}).then(() => {
this.formLoading = true
$.post('/mobile/proposal/caseRead/putSuggestion', {
audit: JSON.stringify(this.formData),
sign: this.formData.sign,
proposalId: this.proposalId
}).then((res) => {
if (res.code === 0) {
this.$toast.success('提交成功')
this.handle = false
this.$refs.info.openView(this.proposalId)
} else {
this.$toast.fail(res.msg || '提交失败,请联系管理员')
}
}).always(() => {
this.formLoading = false
})
})
}
},
created() {
if (GetQueryString('mobile')) {
this.leftArrow = true
}
const proposalId = GetQueryString('proposal_id')
const bizKey = GetQueryString('biz_key')
if (proposalId === '' || bizKey === '') {
vant.Dialog.alert({
title: '提示',
message: '非法参数',
showConfirmButton: false
})
return
}
this.loadResultOptions()
this.initHandleState()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,184 @@
<!--#
layout("/mobile/platform.html"){
#-->
<div id="app" v-cloak>
<m-page-loading v-if="mLoading"></m-page-loading>
<van-nav-bar
title="提案工作组意见"
left-arrow
placeholder
fixed
@click-left="pjaxReplace('/mobile/index')"
></van-nav-bar>
<div class="search-fixed">
<van-search
v-model="pageForm.searchKeyWord"
shape="round"
maxlength="10"
@search="doSearch"
placeholder="请输入提案名称或者提案编号进行查询"
></van-search>
<van-dropdown-menu>
<van-dropdown-item v-model="pageForm.meetingId" :options="sessionList"
@change="doSearch"></van-dropdown-item>
<van-dropdown-item v-model="pageForm.proposalTypeId" :options="proposalTypeList"
@change="doSearch"></van-dropdown-item>
<van-dropdown-item v-model="pageForm.proposalResultCode" :options="resultList"
@change="doSearch"></van-dropdown-item>
</van-dropdown-menu>
<van-tabs v-model="pageForm.isAudit" @change="doSearch">
<van-tab title="全部" name=""></van-tab>
<van-tab title="已建议" name="true"></van-tab>
<van-tab title="未建议" name="false"></van-tab>
</van-tabs>
</div>
<div style="margin: 170px auto 0">
<van-list
v-if="pageForm.meetingId"
v-model="mLoading"
:immediate-check="false"
:finished="finished"
:finished-text="tableData.length>0?'没有更多了':''"
@load="onLoad">
<div v-for="o in tableData" class="list-card" :style="{'--card-accent': o.stateColor || '#2563eb'}" @click="openView(o)">
<div class="card-header">
<div class="card-title">
{{o.proposalName}}
</div>
<span class="badge badge-blue">
{{o.stateName}}
</span>
</div>
<div class="card-body">
<div class="card-item">
<span class="card-label">提案编号:</span>
<span class="card-value">{{o.proposalCode}}</span>
</div>
<div class="card-item">
<span class="card-label">提案类型:</span>
<span class="card-value">{{o.typeName}}</span>
</div>
<div class="card-item">
<span class="card-label">代表团:</span>
<span class="card-value">{{o.delegationName}}</span>
</div>
<div class="card-item">
<span class="card-label">提案届次:</span>
<span class="card-value">{{o.meetingName}}</span>
</div>
</div>
<div class="card-footer" v-if="o.resultName">
<span class="card-label">立案结果:</span>
<span class="card-value">{{o.resultName}}</span>
</div>
</div>
</van-list>
<van-empty
v-if="mLoading==false&&tableData.length==0"
class="custom-image"
image="/none.svg"
description="暂无数据"
></van-empty>
</div>
</div>
<script>
const vue = new Vue({
el: '#app',
mixins: [mobileMixins],
data() {
return {
pageForm: {
isAudit: 'false'
},
sessionList: [],
proposalTypeList: [],
resultList: [],
listLoading: false
}
},
methods: {
doSearch() {
this.$set(this.pageForm, 'pageNumber', 1)
this.tableData = []
this.finished = false
this.onLoad()
},
onLoad() {
if (this.listLoading || this.finished) {
return
}
this.listLoading = true
this.mLoading = true
$.post(loc() + '/pageData', this.pageForm)
.then((res) => {
if (res.code === 0) {
this.tableData = this.tableData.concat(res.data.list)
if (this.tableData.length >= res.data.totalCount) {
this.finished = true
} else {
this.$set(this.pageForm, 'pageNumber', this.pageForm.pageNumber + 1)
}
}
})
.always(() => {
this.listLoading = false
this.mLoading = false
})
},
openView(row) {
window.location.href = '/mobile/proposal/caseRead/view?biz_key=' + row.id + '&proposal_id=' + row.id + '&isOpinion=' + row.isOpinion + '&mobile=' + true
},
loadOptions() {
$.get('/mobile/proposal/common/getAllSession')
.then((res) => {
this.sessionList = res.data
if (this.sessionList && this.sessionList.length > 0) {
this.$set(this.pageForm, 'meetingId', this.sessionList[0].value)
}
})
.then(() => $.get('/mobile/proposal/common/getProposalType'))
.then((res) => {
this.proposalTypeList = res.data
if (this.proposalTypeList && this.proposalTypeList.length > 0) {
this.$set(this.pageForm, 'proposalTypeId', this.proposalTypeList[0].value)
}
})
.then(() => $.get('/mobile/proposal/common/getProposalDict'))
.then((res) => {
this.resultList = res.data
if (this.resultList && this.resultList.length > 0) {
this.$set(this.pageForm, 'proposalResultCode', this.resultList[0].value)
}
this.onLoad()
})
}
},
created() {
this.$set(this.pageForm, 'pageNumber', 1)
this.$set(this.pageForm, 'pageSize', 5)
this.$set(this.pageForm, 'totalCount', 0)
this.loadOptions()
}
})
window.addEventListener('pageshow', (e) => {
if (e.persisted || (window.performance && window.performance.navigation.type === 2)) {
vue.$set(vue.pageForm, 'pageNumber', 1)
vue.$set(vue.pageForm, 'meetingId', null)
vue.tableData = []
vue.finished = false
vue.loadOptions()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,515 @@
<!--#
layout("/mobile/platform.html"){
#-->
<div id="app" v-cloak>
<van-nav-bar title="提案工作组正式立案" fixed placeholder :left-arrow="leftArrow" safe-area-inset-top
@click-left="pjaxReplace('/mobile/proposal/caseUnit')"></van-nav-bar>
<proposal-info :proposal_id="proposalId" title="提案工作组正式立案" :handle="handle" ref="info">
<template #handle>
<div class="info-section-title">正式立案审核</div>
<van-form class="info-cell-form">
<div class="info-row">
<span class="info-label">审核人</span>
<span class="info-value">{{formData.username}}</span>
</div>
<div class="info-row">
<span class="info-label">审核时间</span>
<span class="info-value">{{formData.auditTime}}</span>
</div>
<div class="info-picker-card">
<van-field
:value="resultCodeName"
clickable
input-align="right"
label="立案结果"
label-class="info-picker-label"
name="resultCode"
placeholder="请选择立案结果"
required
readonly
right-icon="arrow"
@click="showResultCodePicker = true"
></van-field>
</div>
<van-popup position="bottom" round v-model="showResultCodePicker">
<van-picker
:columns="resultPickerOptions"
@cancel="showResultCodePicker = false"
@confirm="onResultCodeConfirm"
show-toolbar
></van-picker>
</van-popup>
<div class="info-picker-card">
<van-field
:value="typeName"
clickable
input-align="right"
label="提案类型"
label-class="info-picker-label"
name="typeId"
placeholder="请选择提案类型"
required
readonly
right-icon="arrow"
@click="showTypePicker = true"
></van-field>
</div>
<van-popup position="bottom" round v-model="showTypePicker">
<van-picker
:columns="typePickerOptions"
@cancel="showTypePicker = false"
@confirm="onTypeConfirm"
show-toolbar
></van-picker>
</van-popup>
<template v-if="formData.resultCode!='notGive'">
<div class="info-picker-card">
<van-field
:value="hostUnitName"
clickable
input-align="right"
label="主办单位"
label-class="info-picker-label"
name="hostUnit"
placeholder="请选择主办单位"
:required="formData.resultCode !== 'notGive'"
readonly
right-icon="arrow"
@click="openHostUnitPicker"
></van-field>
</div>
<van-popup position="bottom" round v-model="showHostUnitPicker">
<div class="unit-select-toolbar">
<button class="unit-select-cancel" type="button" @click="onHostUnitCancel">取消</button>
<div class="unit-select-title">主办单位</div>
<button class="unit-select-confirm" type="button" @click="onHostUnitConfirm">确定</button>
</div>
<van-search
placeholder="请输入单位名称搜索"
v-model="hostUnitSearchKey"
></van-search>
<van-picker
:columns="hostUnitPickerOptions"
@change="onHostUnitPickerChange"
></van-picker>
<van-empty description="暂无匹配单位" v-if="hostUnitPickerOptions.length === 0"></van-empty>
</van-popup>
<div class="info-row" v-if="formData.hostUnit">
<span class="info-label">主办领导</span>
<span class="info-value is-long">{{hostUnitLeader}}</span>
</div>
<div class="info-picker-card">
<van-field
class="info-multi-value-field"
clickable
input-align="right"
label="协办单位"
label-class="info-picker-label"
name="helpUnit"
placeholder="请选择协办单位"
readonly
right-icon="arrow"
@click="openHelpUnitPicker"
>
<template #input>
<div class="info-multi-value" v-if="helpUnitName">{{helpUnitName}}</div>
<div class="info-multi-value info-multi-placeholder" v-else>请选择协办单位</div>
</template>
</van-field>
</div>
<van-popup position="bottom" round v-model="showHelpUnitPicker">
<div class="unit-select-toolbar">
<button class="unit-select-cancel" type="button" @click="onHelpUnitCancel">取消</button>
<div class="unit-select-title">协办单位</div>
<button class="unit-select-confirm" type="button" @click="onHelpUnitConfirm">确定</button>
</div>
<van-search
placeholder="请输入单位名称搜索"
v-model="helpUnitSearchKey"
></van-search>
<div class="unit-select-list">
<van-checkbox-group v-model="checkedHelpUnit" direction="vertical">
<van-checkbox
v-for="item in filterHelpUnitOptions"
:key="item.id"
:name="item.id"
style="margin: 10px 0"
>
{{item.unitName}}
</van-checkbox>
</van-checkbox-group>
<van-empty description="暂无匹配单位" v-if="filterHelpUnitOptions.length === 0"></van-empty>
</div>
</van-popup>
<div class="info-row" v-if="formData.helpUnit && formData.helpUnit.length>0">
<span class="info-label">协办领导</span>
<span class="info-value is-long">{{helpUnitLeader}}</span>
</div>
</template>
<div class="info-textarea-field">
<div class="info-textarea-label info-required-label">审核意见</div>
<van-field
v-model="formData.opinion"
rows="4"
autosize
type="textarea"
maxlength="500"
placeholder="请填写工作会的审核意见"
show-word-limit
></van-field>
</div>
<van-row class="info-footer-actions" type="flex" gutter="10">
<van-col span="12">
<van-button block class="info-ghost-button" :loading="formLoading"
@click="pjaxReplace('/mobile/proposal/caseUnit')">
取消
</van-button>
</van-col>
<van-col span="12">
<van-button :color="themeColor" block class="info-primary-button" :loading="formLoading"
@click="doAudit">
提交
</van-button>
</van-col>
</van-row>
</van-form>
</template>
</proposal-info>
</div>
<script>
const vue = new Vue({
el: '#app',
mixins: [mobileMixins],
data() {
return {
leftArrow: false,
handle: false,
proposalId: GetQueryString('proposal_id'),
formLoading: false,
showResultCodePicker: false,
showTypePicker: false,
showHostUnitPicker: false,
showHelpUnitPicker: false,
hostUnitSearchKey: '',
helpUnitSearchKey: '',
checkedHostUnit: '',
checkedHelpUnit: [],
resultOptions: [],
typeOptions: [],
unitOptions: [],
proposalStateCode: null,
proposalIds: [GetQueryString('proposal_id')],
formData: {
username: "${@shiro.getPrincipalProperty('username')}",
loginName: "${@shiro.getPrincipalProperty('loginname')}",
auditTime: moment().format('YYYY-MM-DD'),
resultCode: 'determine',
hostUnit: '',
helpUnit: [],
opinion: '经提案委员会审理,该提案确定立案。',
sign: '',
typeId: '',
determineTypeCode: '',
proposalId: GetQueryString('proposal_id')
}
}
},
computed: {
// 将字典和实体列表统一成 Picker 的 text/value 结构,确认时回写原提交字段。
resultPickerOptions() {
return this.resultOptions.map(v => {
return {
text: v.name,
value: v.code
}
})
},
typePickerOptions() {
return this.typeOptions.map(v => {
return {
text: v.typeName,
value: v.id
}
})
},
hostUnitPickerOptions() {
const key = this.hostUnitSearchKey ? this.hostUnitSearchKey.trim() : ''
return this.unitOptions.filter(v => {
return !key || v.unitName.includes(key)
}).map(v => {
return {
text: v.unitName,
value: v.id
}
})
},
filterHelpUnitOptions() {
const key = this.helpUnitSearchKey ? this.helpUnitSearchKey.trim() : ''
return this.unitOptions.filter(v => {
return !key || v.unitName.includes(key)
})
},
resultCodeName() {
const result = this.resultOptions.find(v => v.code === this.formData.resultCode)
return result ? result.name : ''
},
typeName() {
const type = this.typeOptions.find(v => v.id === this.formData.typeId)
return type ? type.typeName : ''
},
hostUnitName() {
const hostUnit = this.unitOptions.find(v => v.id === this.formData.hostUnit)
return hostUnit ? hostUnit.unitName : ''
},
helpUnitName() {
const helpUnits = this.unitOptions.filter(v => this.formData.helpUnit.includes(v.id)).map(v => v.unitName)
return helpUnits && helpUnits.length > 0 ? helpUnits.toString() : ''
},
hostUnitLeader() {
const hostUnit = this.unitOptions.find(v => v.id === this.formData.hostUnit)
return hostUnit && hostUnit.leader ? hostUnit.leader : '无'
},
helpUnitLeader() {
const helpUnits = this.unitOptions.filter(v => this.formData.helpUnit.includes(v.id)).map(v => {
return v.leader ? v.leader : '无'
})
return helpUnits && helpUnits.length > 0 ? helpUnits.toString() : '无'
}
},
components: {
'proposal-info': httpVueLoader('/components/proposal/mobile/ProposalInfo.vue?v=' + new Date().getTime()),
},
methods: {
initHandleState() {
$.post('/platform/proposal/common/getProposalStateCode', {
proposal_id: this.proposalId
}).then((res) => {
this.proposalStateCode = res.data
this.handle = this.proposalStateCode === 400
})
},
loadProposalInfo() {
getProposalInfo(this.proposalId).then((data) => {
if (data && data.typeId) {
this.$set(this.formData, 'typeId', data.typeId)
}
if (data && data.resultCode) {
this.$set(this.formData, 'resultCode', data.resultCode)
this.setOpinionByResultCode(data.resultCode)
}
if (data && data.determineTypeCode) {
this.$set(this.formData, 'determineTypeCode', data.determineTypeCode)
}
})
},
loadUnderTake() {
$.get('/mobile/proposal/caseUnit/queryUnderTakeByProposalId', {
proposalId: this.proposalId
}).then((res) => {
const underTakes = res.data || []
const hostUnit = underTakes.find(v => v.undertakeType === 1)
if (hostUnit) {
this.$set(this.formData, 'hostUnit', hostUnit.replyUnitId)
}
this.$set(this.formData, 'helpUnit', underTakes.filter(v => v.undertakeType === 2).map(v => v.replyUnitId))
})
},
loadConjoinProposal() {
$.get('/platform/proposal/common/findConjoinProposal', {
proposalId: this.proposalId
}).then((res) => {
const proposals = res.data || []
if (proposals.length > 0) {
this.proposalIds = proposals.map(v => v.id)
}
})
},
loadOptions() {
$.get('/platform/proposal/common/getDictByCode', {
code: 'proposal_result'
}).then((res) => {
this.resultOptions = res.data
}).then(() => $.get('/mobile/proposal/caseUnit/getUnderTakeAndLeader'))
.then((res) => {
this.unitOptions = res.data
})
.then(() => $.get('/platform/proposal/common/getProposalType'))
.then((res) => {
this.typeOptions = res.data
})
.then(() => {
this.loadUnderTake()
})
},
onResultCodeConfirm(value) {
this.$set(this.formData, 'resultCode', value.value)
this.resultCodeChange(value.value)
this.showResultCodePicker = false
},
onTypeConfirm(value) {
this.$set(this.formData, 'typeId', value.value)
this.showTypePicker = false
},
openHostUnitPicker() {
this.hostUnitSearchKey = ''
this.checkedHostUnit = this.formData.hostUnit || (this.hostUnitPickerOptions[0] ? this.hostUnitPickerOptions[0].value : '')
this.showHostUnitPicker = true
},
onHostUnitCancel() {
this.showHostUnitPicker = false
},
onHostUnitPickerChange(picker, value) {
this.checkedHostUnit = value && value.value ? value.value : ''
},
onHostUnitConfirm() {
if (!this.checkedHostUnit) {
return
}
this.$set(this.formData, 'hostUnit', this.checkedHostUnit)
this.showHostUnitPicker = false
},
openHelpUnitPicker() {
this.checkedHelpUnit = this.formData.helpUnit.concat()
this.helpUnitSearchKey = ''
this.showHelpUnitPicker = true
},
onHelpUnitCancel() {
this.checkedHelpUnit = this.formData.helpUnit.concat()
this.showHelpUnitPicker = false
},
onHelpUnitConfirm() {
this.$set(this.formData, 'helpUnit', this.checkedHelpUnit.concat())
this.showHelpUnitPicker = false
},
resultCodeChange(code) {
this.$set(this.formData, 'hostUnit', '')
this.$set(this.formData, 'helpUnit', [])
this.checkedHelpUnit = []
this.setOpinionByResultCode(code)
},
setOpinionByResultCode(code) {
if (code === 'opinion') {
this.$set(this.formData, 'opinion', '经提案委员会审理,该提案作为意见建议。')
} else if (code === 'notGive') {
this.$set(this.formData, 'opinion', '经提案委员会审理,该提案不予立案。')
} else {
this.$set(this.formData, 'opinion', '经提案委员会审理,该提案确定立案。')
}
},
validateForm() {
if (!this.formData.typeId) {
vant.Toast('请选择提案类型')
return false
}
if (!this.formData.resultCode) {
vant.Toast('请选择立案结果')
return false
}
if (this.formData.resultCode !== 'notGive' && !this.formData.hostUnit) {
vant.Toast('请选择主办单位')
return false
}
if (this.formData.helpUnit.find(v => v === this.formData.hostUnit)) {
vant.Toast('协办单位中不能包含主办单位')
return false
}
if (!this.formData.opinion) {
vant.Toast('请填写审核意见')
return false
}
return true
},
doAudit() {
if (!this.validateForm() || this.formLoading) {
return
}
const submitAudit = () => {
vant.Dialog.confirm({
title: '提示',
message: '最终确定立案和承办单位,不可撤回请确认!',
}).then(() => {
this.formLoading = true
$.post('/mobile/proposal/caseUnit/audit', {
audit: JSON.stringify(this.formData),
resultCode: this.formData.resultCode,
typeId: this.formData.typeId,
hostUnit: this.formData.hostUnit,
helpUnit: JSON.stringify(this.formData.helpUnit),
sign: this.formData.sign,
determineTypeCode: this.formData.determineTypeCode,
proposalIds: JSON.stringify(this.proposalIds)
}).then((res) => {
if (res.code === 0) {
this.$toast.success('提交成功')
this.handle = false
this.$refs.info.openView(this.proposalId)
} else {
this.$toast.fail(res.msg || '提交失败,请联系管理员')
}
}).always(() => {
this.formLoading = false
})
})
}
if (this.formData.resultCode === 'notGive') {
submitAudit()
return
}
$.get('/mobile/proposal/caseUnit/checkUnderTakeUser', {
hostUnit: this.formData.hostUnit
}).then((res) => {
if (res.data) {
submitAudit()
} else {
vant.Dialog.alert({
title: '提示',
message: '请先设置主办单位分管校领导或答复人后再进行提交!'
})
}
})
}
},
watch: {
hostUnitPickerOptions(value) {
if (!this.showHostUnitPicker) {
return
}
if (!value.some(v => v.value === this.checkedHostUnit)) {
this.checkedHostUnit = value[0] ? value[0].value : ''
}
}
},
created() {
if (GetQueryString('mobile')) {
this.leftArrow = true
}
const proposalId = GetQueryString('proposal_id')
const bizKey = GetQueryString('biz_key')
if (proposalId === '' || bizKey === '') {
vant.Dialog.alert({
title: '提示',
message: '非法参数',
showConfirmButton: false
})
return
}
this.loadOptions()
this.loadProposalInfo()
this.loadConjoinProposal()
this.initHandleState()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,193 @@
<!--#
layout("/mobile/platform.html"){
#-->
<div id="app" v-cloak>
<m-page-loading v-if="mLoading"></m-page-loading>
<van-nav-bar
title="提案工作组正式立案"
left-arrow
placeholder
fixed
@click-left="pjaxReplace('/mobile/index')"
></van-nav-bar>
<div class="search-fixed">
<van-search
v-model="pageForm.searchKeyWord"
shape="round"
maxlength="10"
@search="doSearch"
placeholder="请输入提案名称或者提案编号进行查询"
></van-search>
<van-dropdown-menu>
<van-dropdown-item v-model="pageForm.meetingId" :options="sessionList"
@change="doSearch"></van-dropdown-item>
<van-dropdown-item v-model="pageForm.proposalTypeId" :options="proposalTypeList"
@change="doSearch"></van-dropdown-item>
<van-dropdown-item v-model="pageForm.proposalResultCode" :options="resultList"
@change="doSearch"></van-dropdown-item>
</van-dropdown-menu>
<van-tabs v-model="pageForm.isAudit" @change="doSearch">
<van-tab title="全部" name=""></van-tab>
<van-tab title="已审核" name="true"></van-tab>
<van-tab title="待审核" name="false"></van-tab>
</van-tabs>
</div>
<div style="margin: 170px auto 0">
<van-list
v-if="pageForm.meetingId"
v-model="mLoading"
:immediate-check="false"
:finished="finished"
:finished-text="tableData.length>0?'没有更多了':''"
@load="onLoad">
<div v-for="o in tableData" class="list-card" :style="{'--card-accent': o.stateColor || '#2563eb'}"
@click="openView(o)">
<div class="card-header">
<div class="card-title">
{{o.proposalName}}
</div>
<span class="badge" :class="o.stateCode === 400 ? 'badge-draft' : 'badge-blue'">
{{o.stateCode === 400 ? '待审核' : '已审核'}}
</span>
</div>
<div class="card-body">
<div class="card-item">
<span class="card-label">提案编号:</span>
<span class="card-value">{{o.proposalCode}}</span>
</div>
<div class="card-item">
<span class="card-label">提案类型:</span>
<span class="card-value">{{o.typeName}}</span>
</div>
<div class="card-item">
<span class="card-label">代表团:</span>
<span class="card-value">{{o.delegationName}}</span>
</div>
<div class="card-item">
<span class="card-label">提案届次:</span>
<span class="card-value">{{o.meetingName}}</span>
</div>
<div class="card-item">
<span class="card-label">提案状态:</span>
<span class="card-value">{{o.stateName}}</span>
</div>
<div class="card-item">
<span class="card-label">是否并案:</span>
<span class="card-value">{{o.isConjoin === 1 ? '是' : '否'}}</span>
</div>
</div>
<div class="card-footer" v-if="o.resultName">
<span class="card-label">立案结果:</span>
<span class="card-value">{{o.resultName}}</span>
</div>
</div>
</van-list>
<van-empty
v-if="mLoading==false&&tableData.length==0"
class="custom-image"
image="/none.svg"
description="暂无数据"
></van-empty>
</div>
</div>
<script>
const vue = new Vue({
el: '#app',
mixins: [mobileMixins],
data() {
return {
pageForm: {
isAudit: 'false'
},
sessionList: [],
proposalTypeList: [],
resultList: [],
listLoading: false
}
},
methods: {
doSearch() {
this.$set(this.pageForm, 'pageNumber', 1)
this.tableData = []
this.finished = false
this.onLoad()
},
onLoad() {
if (this.listLoading || this.finished) {
return
}
this.listLoading = true
this.mLoading = true
$.post(loc() + '/pageData', this.pageForm)
.then((res) => {
if (res.code === 0) {
this.tableData = this.tableData.concat(res.data.list)
if (this.tableData.length >= res.data.totalCount) {
this.finished = true
} else {
this.$set(this.pageForm, 'pageNumber', this.pageForm.pageNumber + 1)
}
}
})
.always(() => {
this.listLoading = false
this.mLoading = false
})
},
openView(row) {
window.location.href = '/mobile/proposal/caseUnit/view?biz_key=' + row.id + '&proposal_id=' + row.id + '&stateCode=' + row.stateCode + '&mobile=' + true
},
loadOptions() {
$.get('/mobile/proposal/common/getAllSession')
.then((res) => {
this.sessionList = res.data
if (this.sessionList && this.sessionList.length > 0) {
this.$set(this.pageForm, 'meetingId', this.sessionList[0].value)
}
})
.then(() => $.get('/mobile/proposal/common/getProposalType'))
.then((res) => {
this.proposalTypeList = res.data
if (this.proposalTypeList && this.proposalTypeList.length > 0) {
this.$set(this.pageForm, 'proposalTypeId', this.proposalTypeList[0].value)
}
})
.then(() => $.get('/mobile/proposal/common/getProposalDict'))
.then((res) => {
this.resultList = res.data
if (this.resultList && this.resultList.length > 0) {
this.$set(this.pageForm, 'proposalResultCode', this.resultList[0].value)
}
this.onLoad()
})
}
},
created() {
this.$set(this.pageForm, 'pageNumber', 1)
this.$set(this.pageForm, 'pageSize', 5)
this.$set(this.pageForm, 'totalCount', 0)
this.loadOptions()
}
})
window.addEventListener('pageshow', (e) => {
if (e.persisted || (window.performance && window.performance.navigation.type === 2)) {
vue.$set(vue.pageForm, 'pageNumber', 1)
vue.$set(vue.pageForm, 'meetingId', null)
vue.tableData = []
vue.finished = false
vue.loadOptions()
}
})
</script>
<!--#
}
#-->
@@ -1,47 +1,61 @@
<!--#
layout("/mobile/platform.html"){
#-->
<div id="app" v-cloak>
<van-nav-bar title="团长审核" fixed placeholder safe-area-inset-top @click-left="pjaxReplace('/mobile/index')"
<van-nav-bar title="团长审核" fixed placeholder safe-area-inset-top @click-left="pjaxReplace('/mobile/proposal/delegation')"
:left-arrow="leftArrow"></van-nav-bar>
<proposal-info :proposal_id="proposalId" title="团长审核" :handle="handle" ref="info">
<template #handle>
<div class="van-cell-group__title" style="padding: 5px 0 0 0 !important;">
<div class="van-sidebar-item van-sidebar-item--select">
团长审核
<div class="info-section-title">团长审核</div>
<van-form class="info-cell-form">
<div class="info-row">
<span class="info-label">审核人</span>
<span class="info-value">{{formData.username}}</span>
</div>
</div>
<van-form>
<van-cell-group class="info">
<van-cell title="审核时间" :value="formData.auditTime"></van-cell>
<div class="info-row">
<span class="info-label">审核时间</span>
<span class="info-value">{{formData.auditTime}}</span>
</div>
<div class="info-textarea-field">
<div class="info-textarea-label info-required-label">审核意见</div>
<van-field
input-align="right"
v-model="formData.opinion"
rows="2"
rows="4"
autosize
label="审核意见"
type="textarea"
maxlength="1000"
placeholder="请输入审核意见"
placeholder="请填写审核意见"
show-word-limit
></van-field>
</van-cell-group>
</div>
<van-row type="flex" :gutter="20" style="padding: 20px 0px">
<van-col span="12" style="padding: 0 10px">
<van-button plain size="large" @click="doAudit(0)">退回</van-button>
<div class="info-long-block" v-if="isSign">
<div class="info-long-title info-required-label">签字</div>
<mobile-sign ref="signature" :my_sign.sync="formData.sign"></mobile-sign>
</div>
<van-row class="info-footer-actions" type="flex" gutter="10">
<van-col span="8">
<van-button block class="info-ghost-button" :loading="formLoading" @click="doAudit(2)">
建议撤销
</van-button>
</van-col>
<van-col span="12" style="padding: 0 10px">
<van-button :color="themeColor" block size="large" @click="doAudit(1)">通过</van-button>
<van-col span="8">
<van-button block class="info-ghost-button" :loading="formLoading" @click="doAudit(0)">
返回修改
</van-button>
</van-col>
<van-col span="8">
<van-button :color="themeColor" block class="info-primary-button" :loading="formLoading"
@click="doAudit(1)">
通过
</van-button>
</van-col>
</van-row>
</van-form>
</template>
</proposal-info>
</div>
<script>
@@ -51,13 +65,16 @@ layout("/mobile/platform.html"){
data() {
return {
leftArrow: false,
handle: true,
handle: false,
proposalId: GetQueryString('proposal_id'),
formLoading: false,
isSign: false,
formData: {
username: "${@shiro.getPrincipalProperty('username')}",
loginName: "${@shiro.getPrincipalProperty('loginname')}",
auditTime: moment().format('YYYY-MM-DD'),
opinion: '',
auditTime: moment().format('YYYY-MM-DD HH:mm:ss'),
opinion: '同意该提案!',
sign: '',
proposalId: GetQueryString('proposal_id')
}
}
@@ -66,72 +83,101 @@ layout("/mobile/platform.html"){
'proposal-info': httpVueLoader('/components/proposal/mobile/ProposalInfo.vue?v=' + new Date().getTime()),
},
methods: {
async doAudit(flag) {
if (this.formData.opinion === '') {
vant.Toast('请输入审核意见');
loadHandleState() {
$.post('/platform/proposal/common/getProposalStateCode', {
proposal_id: this.proposalId
}).then((res) => {
this.handle = res.data === 200
})
},
loadSignState() {
$.get('/platform/proposal/common/getProposalNeedSignStateCode')
.then((res) => {
const signStates = res.data || []
this.isSign = signStates.map(v => v.stateCode).includes(200)
})
},
validateForm() {
if (!this.proposalId) {
vant.Toast('提案信息不存在')
return false
}
if (!this.formData.opinion) {
vant.Toast('请输入审核意见')
return false
}
if (this.isSign && !this.formData.sign) {
vant.Toast('请签字')
return false
}
return true
},
setDefaultOpinion(flag) {
if (flag !== 1 && this.formData.opinion === '同意该提案!') {
if (flag === 2) {
this.$set(this.formData, 'opinion', '建议撤销该提案!')
} else {
this.$set(this.formData, 'opinion', '返回修改该提案!')
}
}
},
getConfirmMessage(flag) {
if (flag === 1) {
return '您是否要通过该提案?'
}
if (flag === 2) {
return '您确定要建议撤销该提案吗?'
}
return '该提案将返回至撰写人,修改后需重新邀请附议,请确认是否返回修改?'
},
doAudit(flag) {
if (!this.validateForm() || this.formLoading) {
return
}
const res = flag === 1 ? '通过' : '退回'
vant.Dialog.confirm({
title: '提示',
message: '您确定' + res + '该提案吗?',
}).then(async () => {
const loading = this.$toast({
duration: 0,
message: '提交中...',
forbidClick: true,
loadingType: 'spinner',
type: 'loading',
overlay: true
});
const resp = await $.post("/platform/proposal/transact/audit/doAudit", {
message: this.getConfirmMessage(flag),
}).then(() => {
this.setDefaultOpinion(flag)
this.formLoading = true
$.post('/platform/proposal/transact/audit/doAudit', {
audit: JSON.stringify(this.formData),
sign: this.formData.sign,
flag: flag
})
if (resp.code === 0) {
setTimeout(async () => {
loading.type = 'success'
loading.message = '提交成功'
loading.close()
this.handle = await mProposal.GetProposalStateCode(this.proposalId) === 200
}).then((res) => {
if (res.code === 0) {
this.$toast.success('提交成功')
this.handle = false
this.$refs.info.openView(this.proposalId)
}, 1200)
} else {
loading.type = 'fail'
loading.message = '提交失败,请联系管理员'
}
} else {
this.$toast.fail(res.msg || '提交失败,请联系管理员')
}
}).always(() => {
this.formLoading = false
})
})
}
},
async created() {
if (GetQueryString("mobile")) this.leftArrow = true
const proposal_id = GetQueryString("proposal_id")
const biz_key = GetQueryString("biz_key")
if (proposal_id === '' || biz_key === '') {
created() {
if (GetQueryString('mobile')) {
this.leftArrow = true
}
const proposalId = GetQueryString('proposal_id')
const bizKey = GetQueryString('biz_key')
if (proposalId === '' || bizKey === '') {
vant.Dialog.alert({
title: '提示',
message: '非法参数',
showConfirmButton: false
}).then(() => {
})
return
}
this.handle = await mProposal.GetProposalStateCode(this.proposalId) === 200
const lastIndex = window.location.href.lastIndexOf('&')
if (window.location.href.substr(lastIndex + 1, 6) === 'ticket') {
window.document.location.replace(window.location.href.substring(0, lastIndex))
}
this.loadHandleState()
this.loadSignState()
}
})
</script>
<!--#
}
#-->
@@ -1,45 +1,10 @@
<!--#
layout("/mobile/platform.html"){
#-->
<style>
.van-doc-card {
margin: 14px;
padding: 12px 12px 12px 12px;
background-color: #fff;
border-radius: 10px;
box-shadow: 0 8px 12px #ebedf0;
line-height: 20px;
font-size: 12px;
position: relative;
}
.van-divider {
margin: 12px 0 12px 0px;
border-color: lightgray;
}
.van-button--small {
border-top-right-radius: 16px;
border-bottom-left-radius: 16px;
height: 26px;
}
.van-col {
line-height: 25px;
}
.title_span {
font-size: 16px;
font-weight: bold;
position: absolute;
left: -1px;
top: 11px;
}
</style>
<div id="app" v-cloak>
<m-page-loading v-if="mLoading"></m-page-loading>
<van-nav-bar
title="团长审"
title="团长审"
left-arrow
placeholder
fixed
@@ -50,13 +15,10 @@ layout("/mobile/platform.html"){
<van-search
v-model="pageForm.searchKeyWord"
shape="round"
maxlength="10"
maxlength="20"
@search="doSearch"
placeholder="请输入提案名称或者提案编号进行查询"
>
</van-search>
></van-search>
<van-dropdown-menu>
<van-dropdown-item v-model="pageForm.meetingId" :options="sessionList"
@@ -67,51 +29,61 @@ layout("/mobile/platform.html"){
@change="doSearch"></van-dropdown-item>
</van-dropdown-menu>
<van-tabs v-model="pageForm.isAudit" @click="doSearch">
<van-tab title="未审核" :name="false"></van-tab>
<van-tab title="已审核" :name="true"></van-tab>
<van-tabs v-model="pageForm.isAudit" @change="doSearch">
<van-tab title="全部" name=""></van-tab>
<van-tab title="已审核" name="true"></van-tab>
<van-tab title="待审核" name="false"></van-tab>
</van-tabs>
</div>
<div style="margin: 170px auto 0">
<van-list
v-if="pageForm.meetingId"
v-model="mLoading"
:immediate-check="false"
:finished="finished"
:finished-text="tableData.length>0?'没有更多了':''"
@load="onLoad">
<div v-for="o in tableData" class="van-doc-card" @click="openView(o.id)">
<div @click="openView(o.id)">
<div>
<div class="van-ellipsis"
style="font-size: 13px;font-weight: bold;flex: 1;width:80%;overflow: hidden;white-space: nowrap">
<span class="title_span" :style="'color:'+o.stateColor">|</span>提案名称:{{o.proposalName}}
</div>
<div style="position: absolute; right: 14px;top: 12.3px;text-align: right">
<van-tag :style="'color:'+o.stateColor" size="medium" plain round type="primary">{{
o.stateName }}
</van-tag>
</div>
<div v-for="o in tableData" class="list-card" :style="{'--card-accent': o.stateColor || '#2563eb'}"
@click="openView(o)">
<div class="card-header">
<div class="card-title">
{{o.proposalName}}
</div>
<van-divider></van-divider>
<div>
<van-row>
<van-col span="12"><span style="color: grey">提案编号:</span>{{o.proposalCode}}</van-col>
<van-col span="12"><span style="color: grey">提案类型:</span>{{o.typeName}}</van-col>
</van-row>
<van-row>
<van-col span="12" style="overflow: hidden;white-space: nowrap;text-overflow: ellipsis;">
<span style="color: grey">&ensp;&ensp;团:</span>{{o.delegationName}}
</van-col>
<van-col span="12"><span style="color: grey">提案届次:</span>{{o.meetingName}}</van-col>
</van-row>
<van-divider></van-divider>
<span class="badge" :class="o.stateCode === 200 ? 'badge-draft' : 'badge-blue'">
{{o.stateCode === 200 ? '待审核' : '已审核'}}
</span>
</div>
<div class="card-body">
<div class="card-item">
<span class="card-label">提案编号:</span>
<span class="card-value">{{o.proposalCode}}</span>
</div>
<div class="train-title" style="margin-top: 11px">
<span style="color: grey">立案结果</span>{{o.resultName ? o.resultName : '暂无'}}
<div class="card-item">
<span class="card-label">提案类型</span>
<span class="card-value">{{o.typeName}}</span>
</div>
<div class="card-item">
<span class="card-label">代表团:</span>
<span class="card-value">{{o.delegationName}}</span>
</div>
<div class="card-item">
<span class="card-label">提案届次:</span>
<span class="card-value">{{o.meetingName}}</span>
</div>
<div class="card-item">
<span class="card-label">提案状态:</span>
<span class="card-value">{{o.stateName}}</span>
</div>
<div class="card-item">
<span class="card-label">审核状态:</span>
<span class="card-value">{{o.stateCode === 200 ? '待审核' : '已审核'}}</span>
</div>
</div>
<div class="card-footer" v-if="o.resultName">
<span class="card-label">立案结果:</span>
<span class="card-value">{{o.resultName}}</span>
</div>
</div>
</van-list>
<van-empty
@@ -125,107 +97,94 @@ layout("/mobile/platform.html"){
</div>
<script>
let vue = new Vue({
const vue = new Vue({
el: '#app',
mixins: [mobileMixins],
data() {
return {
pageForm: {
isAudit: false
isAudit: 'false'
},
list: [],
state: '0',
loading: false,
finished: false,
refreshing: false,
sessionList: [],
delegationList: [],
proposalTypeList: [],
resultList: []
resultList: [],
listLoading: false
}
},
methods: {
doSearch() {
this.pageForm.pageNumber = 1
this.$set(this.pageForm, 'pageNumber', 1)
this.tableData = []
this.finished = false
this.onLoad()
},
async onLoad() {
this.mLoading = true
$.post(loc() + '/pageData', this.pageForm).then(res => {
if (res.code === 0) {
this.tableData = this.tableData.concat(res.data.list)
if (this.tableData.length === res.data.totalCount) {
this.finished = true
} else {
this.pageForm.pageNumber++
}
}
this.mLoading = false
})
},
openAudit(id) {
this.formData = {
proposalId: id,
username: "${@shiro.getPrincipalProperty('username')}",
loginName: "${@shiro.getPrincipalProperty('loginname')}",
auditTime: moment().format('YYYY-MM-DD'),
opinion: '',
sign: '',
onLoad() {
if (this.listLoading || this.finished) {
return
}
this.state = '0'
this.show = true
},
validateForm(action, done) {
done(false)
},
async doHandle() {
this.$refs['handleForm'].validate().then(valid => {
$.post('/platform/proposal/transact/audit/doAudit', {
audit: JSON.stringify(this.formData),
flag: this.state === 0
}).then((res) => {
console.log(res)
this.listLoading = true
this.mLoading = true
$.post(loc() + '/pageData', this.pageForm)
.then((res) => {
if (res.code === 0) {
this.show = false
this.pageForm = {
pageNumber: 1,
pageSize: 5,
totalCount: 0
this.tableData = this.tableData.concat(res.data.list)
if (this.tableData.length >= res.data.totalCount) {
this.finished = true
} else {
this.$set(this.pageForm, 'pageNumber', this.pageForm.pageNumber + 1)
}
this.tableData = []
this.onLoad()
vant.Toast.success('审核成功!')
} else {
vant.Toast.error('审核失败!')
}
})
})
.always(() => {
this.listLoading = false
this.mLoading = false
})
},
openView(id) {
window.location.href = '/mobile/proposal/delegation/view?biz_key=' + id + '&proposal_id=' + id + '&mobile=' + true
openView(row) {
window.location.href = '/mobile/proposal/delegation/view?biz_key=' + row.id
+ '&proposal_id=' + row.id
+ '&mobile=' + true
},
loadOptions() {
$.get('/mobile/proposal/common/getAllSession')
.then((res) => {
this.sessionList = res.data
if (this.sessionList && this.sessionList.length > 0) {
this.$set(this.pageForm, 'meetingId', this.sessionList[0].value)
}
})
.then(() => $.get('/mobile/proposal/common/getProposalType'))
.then((res) => {
this.proposalTypeList = res.data
if (this.proposalTypeList && this.proposalTypeList.length > 0) {
this.$set(this.pageForm, 'proposalTypeId', this.proposalTypeList[0].value)
}
})
.then(() => $.get('/mobile/proposal/common/getProposalDict'))
.then((res) => {
this.resultList = res.data
if (this.resultList && this.resultList.length > 0) {
this.$set(this.pageForm, 'proposalResultCode', this.resultList[0].value)
}
this.onLoad()
})
}
},
async created() {
this.sessionList = await mProposal.getAllSession()
this.proposalTypeList = await mProposal.getProposalType()
this.resultList = await mProposal.getProposalDict()
if (this.sessionList && this.sessionList.length > 0) {
this.$set(this.pageForm, "meetingId", this.sessionList[0].value)
}
if (this.proposalTypeList && this.proposalTypeList.length > 0) {
this.$set(this.pageForm, "proposalTypeId", this.proposalTypeList[0].value)
}
if (this.resultList && this.resultList.length > 0) {
this.$set(this.pageForm, "proposalResultCode", this.resultList[0].value)
}
created() {
this.$set(this.pageForm, 'pageNumber', 1)
this.$set(this.pageForm, 'pageSize', 5)
this.$set(this.pageForm, 'totalCount', 0)
this.loadOptions()
}
})
window.addEventListener('pageshow', e => {
window.addEventListener('pageshow', (e) => {
if (e.persisted || (window.performance && window.performance.navigation.type === 2)) {
vue.onLoad()
vue.$set(vue.pageForm, 'pageNumber', 1)
vue.$set(vue.pageForm, 'meetingId', null)
vue.tableData = []
vue.finished = false
vue.loadOptions()
}
})
@@ -0,0 +1,189 @@
<!--#
layout("/mobile/platform.html"){
#-->
<div id="app" v-cloak>
<van-nav-bar title="反馈评价" fixed placeholder :left-arrow="leftArrow" safe-area-inset-top
@click-left="pjaxReplace('/mobile/proposal/feedback')"></van-nav-bar>
<proposal-info :proposal_id="proposalId" title="反馈评价" :handle="handle" ref="info">
<template #handle>
<div class="info-section-title">反馈评价</div>
<van-form class="info-cell-form">
<div class="info-row">
<span class="info-label">反馈人</span>
<span class="info-value">{{formData.username}}</span>
</div>
<div class="info-row">
<span class="info-label">反馈时间</span>
<span class="info-value">{{formData.feedbackTime}}</span>
</div>
<div class="info-long-block">
<div class="info-long-title info-required-label">办理结果评价</div>
<van-radio-group v-model="formData.feedbackCode" direction="vertical">
<van-radio
v-for="item in feedbackOptions"
:key="item.code"
:name="item.code"
style="margin: 12px 0">
{{item.name}}
</van-radio>
</van-radio-group>
<div class="info-long-content" style="color: #1989fa">
提示:如果您选择不满意则需要主办单位二次答复
</div>
</div>
<div class="info-textarea-field">
<div class="info-textarea-label info-required-label">反馈意见</div>
<van-field
v-model="formData.feedbackOpinion"
rows="4"
autosize
type="textarea"
maxlength="1000"
placeholder="请填写反馈意见"
show-word-limit
></van-field>
</div>
<div class="info-long-block" v-if="isSign">
<div class="info-long-title info-required-label">签字</div>
<mobile-sign ref="signature" :my_sign.sync="formData.scoreSign"></mobile-sign>
</div>
<van-row class="info-footer-actions" type="flex" gutter="10">
<van-col span="12">
<van-button block class="info-ghost-button" :loading="formLoading"
@click="pjaxReplace('/mobile/proposal/feedback')">
取消
</van-button>
</van-col>
<van-col span="12">
<van-button :color="themeColor" block class="info-primary-button" :loading="formLoading"
@click="doFeedback">
提交
</van-button>
</van-col>
</van-row>
</van-form>
</template>
</proposal-info>
</div>
<script>
const vue = new Vue({
el: '#app',
mixins: [mobileMixins],
data() {
return {
leftArrow: false,
handle: false,
proposalId: GetQueryString('proposal_id'),
formLoading: false,
feedbackOptions: [],
isSign: false,
formData: {
username: "${@shiro.getPrincipalProperty('username')}",
feedbackTime: moment().format('YYYY-MM-DD'),
feedbackCode: 'satisfied',
feedbackCodeByUnderTake: '很好',
feedbackOpinion: '同意办结',
scoreSign: '',
proposalId: GetQueryString('proposal_id')
}
}
},
components: {
'proposal-info': httpVueLoader('/components/proposal/mobile/ProposalInfo.vue?v=' + new Date().getTime()),
},
methods: {
loadFeedbackInfo() {
$.get('/mobile/proposal/feedback/getFeedbackInfo', {
proposalId: this.proposalId
}).then((res) => {
const data = res.data || {}
this.handle = data.handle === true
})
},
loadOptions() {
$.get('/platform/proposal/common/getDictByCode', {
code: 'proposal_feedback'
}).then((res) => {
this.feedbackOptions = res.data || []
if (this.feedbackOptions.length > 0 && !this.formData.feedbackCode) {
this.$set(this.formData, 'feedbackCode', this.feedbackOptions[0].code)
}
}).then(() => $.get('/platform/proposal/common/getProposalNeedSignStateCode'))
.then((res) => {
const signStates = res.data || []
this.isSign = signStates.map(v => v.stateCode).includes(700)
})
},
validateForm() {
if (!this.proposalId) {
vant.Toast('提案信息不存在')
return false
}
if (!this.formData.feedbackCode) {
vant.Toast('请选择办理结果评价')
return false
}
if (!this.formData.feedbackOpinion) {
vant.Toast('请填写反馈意见')
return false
}
if (this.isSign && !this.formData.scoreSign) {
vant.Toast('请签字')
return false
}
return true
},
doFeedback() {
if (!this.validateForm() || this.formLoading) {
return
}
vant.Dialog.confirm({
title: '提示',
message: '您确定要提交反馈评价吗?',
}).then(() => {
this.formLoading = true
$.post('/mobile/proposal/feedback/doFeedback', {
feedBack: JSON.stringify(this.formData),
scoreSign: this.formData.scoreSign
}).then((res) => {
if (res.code === 0) {
this.$toast.success('提交成功')
this.handle = false
this.$refs.info.openView(this.proposalId)
} else {
this.$toast.fail(res.msg || '提交失败,请联系管理员')
}
}).always(() => {
this.formLoading = false
})
})
}
},
created() {
if (GetQueryString('mobile')) {
this.leftArrow = true
}
const proposalId = GetQueryString('proposal_id')
const bizKey = GetQueryString('biz_key')
if (proposalId === '' || bizKey === '') {
vant.Dialog.alert({
title: '提示',
message: '非法参数',
showConfirmButton: false
})
return
}
this.loadOptions()
this.loadFeedbackInfo()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,195 @@
<!--#
layout("/mobile/platform.html"){
#-->
<div id="app" v-cloak>
<m-page-loading v-if="mLoading"></m-page-loading>
<van-nav-bar
title="反馈评价"
left-arrow
placeholder
fixed
@click-left="pjaxReplace('/mobile/index')"
></van-nav-bar>
<div class="search-fixed">
<van-search
v-model="pageForm.searchKeyWord"
shape="round"
maxlength="20"
@search="doSearch"
placeholder="请输入提案名称或者提案编号进行查询"
></van-search>
<van-dropdown-menu>
<van-dropdown-item v-model="pageForm.meetingId" :options="sessionList"
@change="doSearch"></van-dropdown-item>
<van-dropdown-item v-model="pageForm.proposalTypeId" :options="proposalTypeList"
@change="doSearch"></van-dropdown-item>
<van-dropdown-item v-model="pageForm.proposalResultCode" :options="resultList"
@change="doSearch"></van-dropdown-item>
</van-dropdown-menu>
<van-tabs v-model="pageForm.isAudit" @change="doSearch">
<van-tab title="全部" name=""></van-tab>
<van-tab title="已反馈" name="true"></van-tab>
<van-tab title="待反馈" name="false"></van-tab>
</van-tabs>
</div>
<div style="margin: 170px auto 0">
<van-list
v-if="pageForm.meetingId"
v-model="mLoading"
:immediate-check="false"
:finished="finished"
:finished-text="tableData.length>0?'没有更多了':''"
@load="onLoad">
<div v-for="o in tableData" class="list-card" :style="{'--card-accent': o.stateColor || '#2563eb'}"
@click="openView(o)">
<div class="card-header">
<div class="card-title">
{{o.proposalName}}
</div>
<span class="badge" :class="o.isFeedback ? 'badge-blue' : 'badge-draft'">
{{o.isFeedback ? '已反馈' : '待反馈'}}
</span>
</div>
<div class="card-body">
<div class="card-item">
<span class="card-label">提案编号:</span>
<span class="card-value">{{o.proposalCode}}</span>
</div>
<div class="card-item">
<span class="card-label">提案类型:</span>
<span class="card-value">{{o.typeName}}</span>
</div>
<div class="card-item">
<span class="card-label">代表团:</span>
<span class="card-value">{{o.delegationName}}</span>
</div>
<div class="card-item">
<span class="card-label">提案届次:</span>
<span class="card-value">{{o.meetingName}}</span>
</div>
<div class="card-item">
<span class="card-label">提案状态:</span>
<span class="card-value">{{o.stateName}}</span>
</div>
<div class="card-item">
<span class="card-label">是否并案:</span>
<span class="card-value">{{o.isConjoin ? '是' : '否'}}</span>
</div>
</div>
<div class="card-footer" v-if="o.resultName">
<span class="card-label">立案结果:</span>
<span class="card-value">{{o.resultName}}</span>
</div>
</div>
</van-list>
<van-empty
v-if="mLoading==false&&tableData.length==0"
class="custom-image"
image="/none.svg"
description="暂无数据"
></van-empty>
</div>
</div>
<script>
const vue = new Vue({
el: '#app',
mixins: [mobileMixins],
data() {
return {
pageForm: {
isAudit: 'false'
},
sessionList: [],
proposalTypeList: [],
resultList: [],
listLoading: false
}
},
methods: {
doSearch() {
this.$set(this.pageForm, 'pageNumber', 1)
this.tableData = []
this.finished = false
this.onLoad()
},
onLoad() {
if (this.listLoading || this.finished) {
return
}
this.listLoading = true
this.mLoading = true
$.post(loc() + '/pageData', this.pageForm)
.then((res) => {
if (res.code === 0) {
this.tableData = this.tableData.concat(res.data.list)
if (this.tableData.length >= res.data.totalCount) {
this.finished = true
} else {
this.$set(this.pageForm, 'pageNumber', this.pageForm.pageNumber + 1)
}
}
})
.always(() => {
this.listLoading = false
this.mLoading = false
})
},
openView(row) {
window.location.href = '/mobile/proposal/feedback/view?biz_key=' + row.id
+ '&proposal_id=' + row.id
+ '&mobile=' + true
},
loadOptions() {
$.get('/mobile/proposal/common/getAllSession')
.then((res) => {
this.sessionList = res.data
if (this.sessionList && this.sessionList.length > 0) {
this.$set(this.pageForm, 'meetingId', this.sessionList[0].value)
}
})
.then(() => $.get('/mobile/proposal/common/getProposalType'))
.then((res) => {
this.proposalTypeList = res.data
if (this.proposalTypeList && this.proposalTypeList.length > 0) {
this.$set(this.pageForm, 'proposalTypeId', this.proposalTypeList[0].value)
}
})
.then(() => $.get('/mobile/proposal/common/getProposalDict'))
.then((res) => {
this.resultList = res.data
if (this.resultList && this.resultList.length > 0) {
this.$set(this.pageForm, 'proposalResultCode', this.resultList[0].value)
}
this.onLoad()
})
}
},
created() {
this.$set(this.pageForm, 'pageNumber', 1)
this.$set(this.pageForm, 'pageSize', 5)
this.$set(this.pageForm, 'totalCount', 0)
this.loadOptions()
}
})
window.addEventListener('pageshow', (e) => {
if (e.persisted || (window.performance && window.performance.navigation.type === 2)) {
vue.$set(vue.pageForm, 'pageNumber', 1)
vue.$set(vue.pageForm, 'meetingId', null)
vue.tableData = []
vue.finished = false
vue.loadOptions()
}
})
</script>
<!--#
}
#-->
@@ -1,22 +1,55 @@
<!--#
layout("/mobile/platform.html"){
#-->
<div id="app" v-cloak>
<style>
.seconded-audit-page {
padding-bottom: 86px;
}
.seconded-audit-page .seconded-audit-actions {
position: fixed;
right: 0;
bottom: 0;
left: 0;
z-index: 99;
display: flex;
gap: 10px;
box-sizing: border-box;
padding: 10px 16px calc(10px + env(safe-area-inset-bottom));
background: #ffffff;
box-shadow: 0 -4px 16px rgba(15, 23, 42, 0.08);
}
.seconded-audit-page .seconded-audit-actions .van-button {
flex: 1;
height: 44px;
border-radius: 8px;
font-size: 15px;
font-weight: 500;
}
.seconded-audit-page .seconded-audit-actions .info-ghost-button {
border: 1px solid #dcdfe6;
background: #ffffff;
color: #606266;
}
.seconded-audit-page .seconded-audit-actions .info-primary-button {
border: 1px solid #006d75;
background: #006d75;
color: #ffffff;
}
</style>
<div id="app" class="seconded-audit-page" v-cloak>
<van-nav-bar title="附议提案" fixed placeholder :left-arrow="leftArrow" safe-area-inset-top
@click-left="pjaxReplace('/mobile/proposal/seconded')"></van-nav-bar>
<proposal-info :proposal_id="proposalId" ref="pi"></proposal-info>
<van-row v-if="secondedInfo.isAgree==null">
<div class="van-cell-group__title" style="padding: 5px 0 0 0 !important;">
<div class="van-sidebar-item van-sidebar-item--select">
附议提案
</div>
</div>
<div style="display: flex;justify-content: space-around;padding: 5px 0 20px 0;">
<van-button :color="themeColor" plain style="flex: 1;margin: 0 10px 0 10px" @click="openDialog(false)">拒绝
</van-button>
<van-button :color="themeColor" style="flex: 1;margin: 0 10px 0 10px" @click="openDialog(true)">同意
</van-button>
<van-row v-if="secondedInfo.isAgree==null" class="info-section">
<div class="info-section-title">附议提案</div>
<div class="info-footer-actions seconded-audit-actions">
<van-button block class="info-ghost-button" :loading="formLoading" @click="openDialog(false)">拒绝</van-button>
<van-button block class="info-primary-button" :loading="formLoading" @click="openDialog(true)">同意</van-button>
</div>
</van-row>
@@ -31,6 +64,7 @@ layout("/mobile/platform.html"){
return {
leftArrow: false,
proposalId: GetQueryString('proposal_id'),
formLoading: false,
secondedInfo: {
isAgree: false
}
@@ -41,36 +75,28 @@ layout("/mobile/platform.html"){
},
methods: {
openDialog(flag) {
if (this.formLoading) return
const res = flag === true ? '通过' : '拒绝'
vant.Dialog.confirm({
title: '提示',
message: '您确定' + res + '附议该提案吗?',
}).then(async () => {
const loading = this.$toast({
duration: 0,
message: '提交中...',
forbidClick: true,
loadingType: 'spinner',
type: 'loading',
overlay: true
});
const resp = await $.post("/platform/proposal/transact/seconded/doAudit", {
}).then(() => {
this.formLoading = true
$.post("/platform/proposal/transact/seconded/doAudit", {
secondedId: this.secondedInfo.id,
proposalId: this.proposalId,
flag: flag
})
if (resp.code === 0) {
setTimeout(async () => {
loading.close()
}).then((resp) => {
if (resp.code === 0) {
this.$refs.pi.openView(this.proposalId)
this.getSecondedCount()
this.$toast.success("操作成功")
}, 1200)
} else {
loading.close()
this.$toast.fail("操作失败,请及时联系管理员")
}
} else {
this.$toast.fail(resp.msg || "操作失败,请及时联系管理员")
}
}).always(() => {
this.formLoading = false
})
})
},
getSecondedCount() {
@@ -78,12 +104,12 @@ layout("/mobile/platform.html"){
$.post("/mobile/proposal/seconded/getSecondedCount", {
proposalId: this.proposalId,
id: biz_key
}).then(res => {
}).then((res) => {
this.secondedInfo = res.data
})
}
},
async created() {
created() {
if (GetQueryString("mobile")) this.leftArrow = true
const proposal_id = GetQueryString("proposal_id")
const biz_key = GetQueryString("biz_key")
@@ -1,41 +1,6 @@
<!--#
layout("/mobile/platform.html"){
#-->
<style>
.van-doc-card {
margin: 14px;
padding: 12px 12px 12px 12px;
background-color: #fff;
border-radius: 10px;
box-shadow: 0 8px 12px #ebedf0;
line-height: 20px;
font-size: 12px;
position: relative;
}
.van-divider {
margin: 12px 0 12px 0px;
border-color: lightgray;
}
.van-button--small {
border-top-right-radius: 16px;
border-bottom-left-radius: 16px;
height: 26px;
}
.van-col {
line-height: 25px;
}
.title_span {
font-size: 16px;
font-weight: bold;
position: absolute;
left: -1px;
top: 11px;
}
</style>
<div id="app" v-cloak>
<m-page-loading v-if="mLoading"></m-page-loading>
<van-nav-bar
@@ -50,79 +15,72 @@ layout("/mobile/platform.html"){
<van-search
v-model="pageForm.searchKeyWord"
shape="round"
maxlength="10"
maxlength="20"
@search="doSearch"
placeholder="请输入提案名称或者提案编号进行查询"
>
</van-search>
></van-search>
<van-dropdown-menu>
<van-dropdown-item v-model="pageForm.meetingId" :options="sessionList"
@change="doSearch"></van-dropdown-item>
<van-dropdown-item v-model="pageForm.proposalTypeId" :options="proposalTypeList"
@change="doSearch"></van-dropdown-item>
<!-- <van-dropdown-item v-model="pageForm.proposalResultCode" :options="resultList"
@change="doSearch"></van-dropdown-item>-->
</van-dropdown-menu>
<van-tabs v-model="pageForm.isAudit" @change="doSearch()">
<van-tab title="附议" :name="false"></van-tab>
<van-tab title="已附议" :name="true"></van-tab>
<van-tabs v-model="pageForm.isAudit" @change="doSearch">
<van-tab title="待附议" name="false"></van-tab>
<van-tab title="附议" name="true"></van-tab>
</van-tabs>
</div>
<div style="margin: 170px auto 0">
<van-list
v-model="mLoading" :immediate-check="false"
v-if="pageForm.meetingId"
v-model="mLoading"
:immediate-check="false"
:finished="finished"
:finished-text="tableData.length>0?'没有更多了':''"
@load="onLoad">
<div v-for="o in tableData" class="van-doc-card">
<div @click="openView(o.id,o.secondedId)">
<div>
<div class="van-ellipsis"
style="font-size: 13px;font-weight: bold;flex: 1;width:80%;overflow: hidden;white-space: nowrap">
<span class="title_span" :style="'color:'+o.stateColor">|</span>提案名称:{{o.proposalName}}
</div>
<div style="position: absolute; right: 14px;top: 12.3px;text-align: right" v-if="!o.isAgree">
<van-tag :style="'color:'+o.stateColor" size="medium" plain round type="primary">附议
</van-tag>
</div>
<div v-for="o in tableData" class="list-card" :style="{'--card-accent': o.stateColor || '#2563eb'}"
@click="openView(o)">
<div class="card-header">
<div class="card-title">
{{o.proposalName}}
</div>
<van-divider></van-divider>
<div>
<van-row>
<van-col span="12"><span style="color: grey">提案编号:</span>{{o.proposalCode}}</van-col>
<van-col span="12"><span style="color: grey">提案类型:</span>{{o.typeName}}</van-col>
</van-row>
<van-row>
<van-col span="12" style="overflow: hidden;white-space: nowrap;text-overflow: ellipsis;">
<span style="color: grey">&ensp;&ensp;团:</span>{{o.delegationName}}
</van-col>
<van-col span="12"><span style="color: grey">提案届次:</span>{{o.meetingName}}</van-col>
</van-row>
<van-divider></van-divider>
<span class="badge" :class="getAgreeBadgeClass(o)">
{{getAgreeText(o)}}
</span>
</div>
<div class="card-body">
<div class="card-item">
<span class="card-label">提案编号:</span>
<span class="card-value">{{o.proposalCode}}</span>
</div>
<div class="train-title" style="margin-top: 11px">
<span style="color: grey">立案结果</span>{{o.resultName ? o.resultName : '暂无'}}
<span style="color: grey;margin-left: 24%;">&ensp;&ensp;人:</span>{{o.secondedUserName}}
<div class="card-item">
<span class="card-label">提案类型</span>
<span class="card-value">{{o.typeName}}</span>
</div>
<div class="card-item">
<span class="card-label">代表团:</span>
<span class="card-value">{{o.delegationName}}</span>
</div>
<div class="card-item">
<span class="card-label">提案届次:</span>
<span class="card-value">{{o.meetingName}}</span>
</div>
<div class="card-item">
<span class="card-label">提案状态:</span>
<span class="card-value">{{o.stateName}}</span>
</div>
<div class="card-item">
<span class="card-label">附议人:</span>
<span class="card-value">{{o.secondedUserName}}</span>
</div>
</div>
<!-- <van-cell-group inset>
<van-cell title="提案名称" :border="false">
<div style="display: flex;align-items: center">
<span :style="{color:themeColor}" style="font-size: 16px" class="van-ellipsis">{{o.proposalName}}</span>
</div>
</van-cell>
<van-cell :border="false" title="提案编号">{{o.proposalCode}}</van-cell>
<van-cell :border="false" title="附&emsp14;&emsp14;议&emsp14;&emsp14;人">{{o.secondedUserName}}</van-cell>
<van-cell :border="false" title="提案类型">{{o.typeName}}</van-cell>
<van-cell :border="false" title="提案状态">
<span :style="'color:'+o.stateColor">{{ o.stateName }}</span>
</van-cell>
</van-cell-group>-->
<div class="card-footer">
<span class="card-label">立案结果:</span>
<span class="card-value">{{o.resultName ? o.resultName : '暂无'}}</span>
</div>
</div>
</van-list>
<van-empty
@@ -142,95 +100,98 @@ layout("/mobile/platform.html"){
data() {
return {
pageForm: {
isAudit: false
isAudit: 'false'
},
list: [],
state: '0',
loading: false,
finished: false,
refreshing: false,
sessionList: [],
delegationList: [],
proposalTypeList: [],
resultList: [],
auditList: [
{text: '未附议', value: false},
{text: '已附议', value: true},
]
listLoading: false
}
},
methods: {
getAgreeText(row) {
if (row.isAgree === true || row.isAgree === 1) {
return '已同意'
}
if (row.isAgree === false || row.isAgree === 0) {
return '已拒绝'
}
return '待附议'
},
getAgreeBadgeClass(row) {
if (row.isAgree === true || row.isAgree === 1) {
return 'badge-green'
}
if (row.isAgree === false || row.isAgree === 0) {
return 'badge-red'
}
return 'badge-draft'
},
doSearch() {
this.pageForm.pageNumber = 1
this.$set(this.pageForm, 'pageNumber', 1)
this.tableData = []
this.finished = false
this.onLoad()
},
async onLoad() {
onLoad() {
if (this.listLoading || this.finished) {
return
}
this.listLoading = true
this.mLoading = true
$.post(loc() + '/pageData', this.pageForm).then(res => {
if (res.code === 0) {
this.tableData = this.tableData.concat(res.data.list)
if (this.tableData.length >= res.data.totalCount) {
this.finished = true
} else {
this.pageForm.pageNumber++
}
}
this.mLoading = false
})
},
doAudit(flag, row) {
const {id, secondedId} = row
let res = flag === true ? '通过' : '拒绝'
vant.Dialog.confirm({
title: '提示',
message: '您确定' + res + '吗?',
}).then(() => {
$.post('/platform/proposal/transact/seconded/doAudit', {
secondedId: secondedId,
proposalId: id,
flag: flag
}).then(res => {
$.post(loc() + '/pageData', this.pageForm)
.then((res) => {
if (res.code === 0) {
this.pageForm = {
pageNumber: 1,
pageSize: 5,
totalCount: 0
this.tableData = this.tableData.concat(res.data.list)
if (this.tableData.length >= res.data.totalCount) {
this.finished = true
} else {
this.$set(this.pageForm, 'pageNumber', this.pageForm.pageNumber + 1)
}
this.tableData = []
this.onLoad()
vant.Toast.success('提交成功!')
}
})
}).catch(() => {
})
.always(() => {
this.listLoading = false
this.mLoading = false
})
},
openView(id, secondedId) {
window.location.href = '/mobile/proposal/seconded/view?biz_key=' + secondedId + '&proposal_id=' + id + '&mobile=' + true
openView(row) {
window.location.href = '/mobile/proposal/seconded/view?biz_key=' + row.secondedId
+ '&proposal_id=' + row.id
+ '&mobile=' + true
},
loadOptions() {
$.get('/mobile/proposal/common/getAllSession')
.then((res) => {
this.sessionList = res.data
if (this.sessionList && this.sessionList.length > 0) {
this.$set(this.pageForm, 'meetingId', this.sessionList[0].value)
}
})
.then(() => $.get('/mobile/proposal/common/getProposalType'))
.then((res) => {
this.proposalTypeList = res.data
if (this.proposalTypeList && this.proposalTypeList.length > 0) {
this.$set(this.pageForm, 'proposalTypeId', this.proposalTypeList[0].value)
}
this.onLoad()
})
}
},
async created() {
this.sessionList = await mProposal.getAllSession()
this.proposalTypeList = await mProposal.getProposalType()
this.resultList = await mProposal.getProposalDict()
if (this.sessionList && this.sessionList.length > 0) {
this.$set(this.pageForm, "meetingId", this.sessionList[0].value)
}
if (this.proposalTypeList && this.proposalTypeList.length > 0) {
this.$set(this.pageForm, "proposalTypeId", this.proposalTypeList[0].value)
}
if (this.resultList && this.resultList.length > 0) {
this.$set(this.pageForm, "proposalResultCode", this.resultList[0].value)
}
this.onLoad()
created() {
this.$set(this.pageForm, 'pageNumber', 1)
this.$set(this.pageForm, 'pageSize', 5)
this.$set(this.pageForm, 'totalCount', 0)
this.loadOptions()
},
})
window.addEventListener('pageshow', e => {
window.addEventListener('pageshow', (e) => {
if (e.persisted || (window.performance && window.performance.navigation.type === 2)) {
vue.onLoad()
vue.$set(vue.pageForm, 'pageNumber', 1)
vue.$set(vue.pageForm, 'meetingId', null)
vue.tableData = []
vue.finished = false
vue.loadOptions()
}
})
@@ -231,6 +231,20 @@ layout("/layouts/platform.html"){
v-loading="formLoading">
<vi-title title="福利项目信息"></vi-title>
<el-form-item label="沿用项目" v-if="!formData.id">
<el-select @change="reuseProjectChange"
clearable
filterable
placeholder="请选择需要沿用的历史福利项目"
style="width: 100%"
v-model="reuseProjectId">
<el-option :key="item.value"
:label="item.label"
:value="item.value"
v-for="item in reuseProjectOptions"></el-option>
</el-select>
</el-form-item>
<el-form-item label="项目名称" prop="name">
<el-input maxlength="100" placeholder="项目名称" v-model="formData.name"></el-input>
</el-form-item>
@@ -310,7 +324,8 @@ layout("/layouts/platform.html"){
</el-switch>
</el-form-item>
</el-col>-->
</el-row>
<el-row>
<el-col span="4" v-if="formData.isRoutine">
<el-form-item label="是否多选" prop="isCheckBox">
<el-switch
@@ -338,7 +353,6 @@ layout("/layouts/platform.html"){
</el-form-item>
</el-col>
</template>
</el-row>
<el-form-item label="人员核对名单" prop="taskId" v-if="formData.isYearBirthday">
@@ -458,24 +472,24 @@ layout("/layouts/platform.html"){
>
<el-form :model="formData" label-width="80px" ref="sendForm">
<!-- <el-form-item
:rules="[{required: true, message: '请选择发送方式', trigger: ['blur', 'change']}]"
label="发送方式"
prop="sendTypes">
<el-checkbox-group size="medium" v-model="formData.sendTypes">
<el-checkbox border label="SMS">短信发送</el-checkbox>
<el-checkbox border label="WeChat">微信发送</el-checkbox>
</el-checkbox-group>
</el-form-item>
-->
<!-- <el-form-item
:rules="[{required: true, message: '请选择发送方式', trigger: ['blur', 'change']}]"
label="发送方式"
prop="sendTypes">
<el-checkbox-group size="medium" v-model="formData.sendTypes">
<el-checkbox border label="SMS">短信发送</el-checkbox>
<el-checkbox border label="WeChat">微信发送</el-checkbox>
</el-checkbox-group>
</el-form-item>
-->
<el-form-item
:rules="[{required: true, message: '请输入发送标题', trigger: ['blur', 'change']}]"
label="发送标题"
prop="title">
:rules="[{required: true, message: '请输入发送标题', trigger: ['blur', 'change']}]"
label="发送标题"
prop="title">
<el-input
:rows="6"
placeholder="请输入发送标题"
v-model="formData.title">
:rows="6"
placeholder="请输入发送标题"
v-model="formData.title">
</el-input>
</el-form-item>
@@ -563,6 +577,8 @@ layout("/layouts/platform.html"){
sendMsgDialogVisible: false,
memberCheckTaskOptions: [],
reuseProjectId: null,
reuseProjectOptions: [],
}
},
components: {
@@ -573,6 +589,95 @@ layout("/layouts/platform.html"){
'send-msg': httpVueLoader('/components/plugins/SendMsgByGroupId.vue'),
},
methods: {
getReuseProjectOptions(projectOptions) {
let options = []
projectOptions.forEach(yearItem => {
if (yearItem.children && yearItem.children.length > 0) {
yearItem.children.forEach(project => {
options.push({
label: yearItem.label + " - " + project.label,
value: project.value
})
})
}
})
return options
},
resetReuseProjectIds(project) {
if (project.welfareProjectSubjects && project.welfareProjectSubjects.length > 0) {
project.welfareProjectSubjects.forEach(subject => {
subject.id = null
subject.projectId = null
if (subject.options && subject.options.length > 0) {
subject.options.forEach(option => {
option.id = null
option.subjectId = null
option.selectCount = null
option.rank = null
if (!option.optionNameId) {
option.optionNameId = ""
}
})
}
})
}
},
resetReuseConditionStructure(project) {
project.conditionStructureId = null
if (project.conditionStructure) {
project.conditionStructure.id = null
if (project.conditionStructure.conditions && project.conditionStructure.conditions.length > 0) {
project.conditionStructure.conditions.forEach(condition => {
condition.id = null
condition.structureId = null
})
}
}
},
reuseProjectChange(projectId) {
if (!projectId) {
return
}
this.formLoading = true
$.get(loc() + "/findOne", {id: projectId})
.then((resp) => {
if (resp.code === 0) {
const data = clone(resp.data)
data.id = null
data.taskId = null
data.year = null
data.created = null
data.choiceTimeStart = ""
data.choiceTimeEnd = ""
data.provideTimeStart = ""
data.provideTimeEnd = ""
data.overdueChoiceTimeEnd = ""
data.choiceTime = []
data.provideTime = []
this.resetReuseConditionStructure(data)
data.flexibleGifts = data.flexibleGifts || [{}]
const idx = data.flexibleGifts.findIndex(v => v.isDefault)
data.defaultFlexibleGifts = idx < 0 ? 0 : idx
if (!data.welfareProjectSubjects || data.welfareProjectSubjects.length === 0) {
data.welfareProjectSubjects = []
} else {
this.resetReuseProjectIds(data)
}
this.formData = data
this.$nextTick(() => {
if (this.$refs.form) {
this.$refs.form.clearValidate()
}
})
this.$message.success("已沿用所选项目配置,请确认项目名称、时间和发放范围")
} else {
this.$message.warning(resp.msg)
}
})
.always(() => {
this.formLoading = false
})
},
async getMemberCheckTaskOptions() {
const resp = await $.get('/platform/welfareMember/check/task/getAllTask', {year: this.pageForm.year})
this.memberCheckTaskOptions = resp.data.filter(item => item.welfareCheckFilterMode === 2)
@@ -631,7 +736,7 @@ layout("/layouts/platform.html"){
},
isCheckBoxChange() {
if (this.formData.welfareProjectSubjects && this.formData.welfareProjectSubjects.length > 0) {
this.formData.welfareProjectSubjects.forEach(v=> {
this.formData.welfareProjectSubjects.forEach(v => {
v.subjectType = this.formData.isCheckBox ? this.formData.isCheckBox : 'radio'
})
} else {
@@ -772,6 +877,7 @@ layout("/layouts/platform.html"){
welfareProjectSubjects: [],
flexibleGifts: [{}]
}
this.reuseProjectId = null
this.$refs.guava.edit()
if (this.$refs.form)
this.$refs.form.resetFields();
@@ -946,6 +1052,9 @@ layout("/layouts/platform.html"){
const personType = await getDictOptions("PERSON_TYPE")
const userState = await getDictOptions("USER_STATE")
this.getMemberCheckTaskOptions();
getWelfareProjects().then((options) => {
this.reuseProjectOptions = this.getReuseProjectOptions(options)
})
this.fields = this.fields.concat([{
label: '人员类型',
value: 'personType',