Compare commits
9
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c1ac3db4bf | ||
|
|
6c6caa2558 | ||
|
|
35877f4b5c | ||
|
|
001d456513 | ||
|
|
65f340e3b0 | ||
|
|
29260423d5 | ||
|
|
d8e7adfe9a | ||
|
|
bc1b3bf7fe | ||
|
|
59fd83ba24 |
@@ -6,6 +6,8 @@ import com.budwk.app.base.exception.BaseException;
|
||||
import com.budwk.app.sys.models.Sys_file;
|
||||
import com.budwk.app.sys.models.Sys_office_template;
|
||||
import com.budwk.app.sys.utils.SysFileMinIoUtil;
|
||||
import com.deepoove.poi.XWPFTemplate;
|
||||
import com.deepoove.poi.config.Configure;
|
||||
import com.deepoove.poi.data.ByteArrayPictureRenderData;
|
||||
import com.deepoove.poi.data.PictureRenderData;
|
||||
import com.deepoove.poi.data.PictureType;
|
||||
@@ -18,6 +20,12 @@ import org.nutz.ioc.loader.annotation.IocBean;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@@ -66,6 +74,88 @@ public class SysOfficeTemplateUtil {
|
||||
return new ByteArrayInputStream(fileBytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一渲染 DOC/DOCX 模板,保留调用方的循环表格等策略;模板输入流由调用方关闭。
|
||||
*/
|
||||
public byte[] renderTemplate(InputStream input, Object data, Configure config, boolean pdf, String context) throws Exception {
|
||||
if (input == null) throw new BaseException("模板文件不存在");
|
||||
byte[] templateBytes = input.readAllBytes();
|
||||
try (ByteArrayInputStream formatInput = new ByteArrayInputStream(templateBytes)) {
|
||||
if (com.aspose.words.FileFormatUtil.detectFileFormat(formatInput).getLoadFormat() != com.aspose.words.LoadFormat.DOCX) {
|
||||
try (ByteArrayInputStream source = new ByteArrayInputStream(templateBytes);
|
||||
ByteArrayOutputStream converted = new ByteArrayOutputStream()) {
|
||||
new com.aspose.words.Document(source).save(converted, com.aspose.words.SaveFormat.DOCX);
|
||||
templateBytes = converted.toByteArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
byte[] wordBytes;
|
||||
try (ByteArrayInputStream templateInput = new ByteArrayInputStream(templateBytes);
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
XWPFTemplate template = XWPFTemplate.compile(templateInput, config == null ? Configure.builder().build() : config)) {
|
||||
template.render(data).write(output);
|
||||
wordBytes = output.toByteArray();
|
||||
} catch (Exception e) {
|
||||
log.error("[Office模板渲染] Word模板渲染失败,context={}", context, e);
|
||||
throw e;
|
||||
}
|
||||
log.info("[Office模板渲染] Word渲染完成,context={}, templateBytes={}, outputBytes={}", context, templateBytes.length, wordBytes.length);
|
||||
if (!pdf) return wordBytes;
|
||||
try (ByteArrayInputStream wordInput = new ByteArrayInputStream(wordBytes);
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream()) {
|
||||
com.aspose.words.Document document = new com.aspose.words.Document(wordInput);
|
||||
configureDocumentFonts(document, context);
|
||||
com.aspose.words.PdfSaveOptions options = new com.aspose.words.PdfSaveOptions();
|
||||
options.setFontEmbeddingMode(com.aspose.words.PdfFontEmbeddingMode.EMBED_ALL);
|
||||
document.save(output, options);
|
||||
log.info("[Office模板渲染] PDF转换完成,context={}, outputBytes={}", context, output.size());
|
||||
return output.toByteArray();
|
||||
} catch (Exception e) {
|
||||
log.error("[Office模板渲染] PDF转换失败,context={}", context, e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private void configureDocumentFonts(com.aspose.words.Document document, String context) throws Exception {
|
||||
com.aspose.words.FontSettings settings = new com.aspose.words.FontSettings();
|
||||
List<com.aspose.words.FontSourceBase> sources = new ArrayList<>(List.of(settings.getFontsSources()));
|
||||
Set<String> folders = new LinkedHashSet<>();
|
||||
String windowsDir = System.getenv("WINDIR");
|
||||
if (StrUtil.isNotBlank(windowsDir)) folders.add(new File(windowsDir, "Fonts").getPath());
|
||||
String localAppData = System.getenv("LOCALAPPDATA");
|
||||
if (StrUtil.isNotBlank(localAppData)) folders.add(new File(localAppData, "Microsoft/Windows/Fonts").getPath());
|
||||
folders.add(new File(System.getProperty("user.dir"), "fonts").getPath());
|
||||
for (String folder : folders) {
|
||||
File directory = new File(folder);
|
||||
log.info("[Office模板渲染] 字体目录,context={}, path={}, readable={}", context, folder, directory.isDirectory() && directory.canRead());
|
||||
if (directory.isDirectory() && directory.canRead()) sources.add(new com.aspose.words.FolderFontSource(folder, true));
|
||||
}
|
||||
settings.setFontsSources(sources.toArray(new com.aspose.words.FontSourceBase[0]));
|
||||
Set<String> availableFonts = new LinkedHashSet<>();
|
||||
for (com.aspose.words.FontSourceBase source : sources) {
|
||||
for (com.aspose.words.PhysicalFontInfo font : source.getAvailableFonts()) availableFonts.add(font.getFontFamilyName());
|
||||
}
|
||||
String chineseFont = null;
|
||||
for (String candidate : List.of("SimSun", "宋体", "Microsoft YaHei", "微软雅黑", "DengXian", "等线", "SimHei", "黑体", "FangSong", "仿宋", "Noto Serif CJK SC", "Noto Sans CJK SC")) {
|
||||
if (availableFonts.contains(candidate)) {
|
||||
chineseFont = candidate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
log.info("[Office模板渲染] 中文字体选择,context={}, fontCount={}, chineseFont={}", context, availableFonts.size(), chineseFont);
|
||||
if (chineseFont != null) {
|
||||
settings.getSubstitutionSettings().getDefaultFontSubstitution().setDefaultFontName(chineseFont);
|
||||
for (String name : List.of("宋体", "SimSun", "新宋体", "NSimSun", "黑体", "SimHei", "仿宋", "FangSong", "楷体", "KaiTi", "微软雅黑", "Microsoft YaHei")) {
|
||||
if (!availableFonts.contains(name)) settings.getSubstitutionSettings().getTableSubstitution().setSubstitutes(name, chineseFont);
|
||||
}
|
||||
} else {
|
||||
log.warn("[Office模板渲染] 未发现常用中文字体,context={}, availableFonts={}", context, availableFonts);
|
||||
}
|
||||
settings.getFallbackSettings().loadMsOfficeFallbackSettings();
|
||||
document.setFontSettings(settings);
|
||||
document.setWarningCallback(warning -> log.warn("[Office模板渲染] 字体或排版警告,context={}, type={}, detail={}", context, warning.getWarningType(), warning.getDescription()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 签字url转换为poi的图片对象
|
||||
*
|
||||
@@ -77,13 +167,7 @@ public class SysOfficeTemplateUtil {
|
||||
public PictureRenderData createPictureRenderData(int width, int height, String url) {
|
||||
try {
|
||||
byte[] bytes = getFileBytesByUrl(url);
|
||||
// if (StrUtil.isBlank(url)) {
|
||||
// return null;
|
||||
// }
|
||||
// int startIndex = url.indexOf("id=") + "id=".length();
|
||||
// String id = url.substring(startIndex);
|
||||
// Sys_file sysFile = dao.fetch(Sys_file.class, id);
|
||||
// byte[] bytes = SysFileMinIoUtil.getFileBytes(sysFile.getBucket(), sysFile.getStoragePath());
|
||||
log.info("[Office图片读取] 创建图片渲染数据,referenceLength={}, byteCount={}, width={}, height={}", StrUtil.nullToEmpty(url).length(), bytes == null ? null : bytes.length, width, height);
|
||||
ByteArrayPictureRenderData pictureRenderData = new ByteArrayPictureRenderData(bytes, PictureType.PNG);
|
||||
PictureStyle pictureStyle = new PictureStyle();
|
||||
pictureStyle.setWidth(width);
|
||||
@@ -91,7 +175,7 @@ public class SysOfficeTemplateUtil {
|
||||
pictureRenderData.setPictureStyle(pictureStyle);
|
||||
return pictureRenderData;
|
||||
} catch (Exception e) {
|
||||
log.error("文件转换PictureRenderData错误,文件路径:{},{}", url, e.getMessage());
|
||||
log.error("[Office图片读取] 创建图片渲染数据失败,referenceLength={}", StrUtil.nullToEmpty(url).length(), e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -140,13 +224,20 @@ public class SysOfficeTemplateUtil {
|
||||
public byte[] getFileBytesByUrl(String url) {
|
||||
try {
|
||||
if (StrUtil.isBlank(url)) {
|
||||
log.warn("[Office图片读取] 图片引用为空");
|
||||
return null;
|
||||
}
|
||||
int startIndex = url.indexOf("id=") + "id=".length();
|
||||
String id = url.substring(startIndex);
|
||||
String logFileId = url.contains("id=") ? id : "未识别id参数";
|
||||
log.info("[Office图片读取] 解析文件引用,fileId={}, hasIdParameter={}", logFileId, url.contains("id="));
|
||||
Sys_file sysFile = dao.fetch(Sys_file.class, id);
|
||||
return SysFileMinIoUtil.getFileBytes(sysFile.getBucket(), sysFile.getStoragePath());
|
||||
log.info("[Office图片读取] 查询文件记录,fileId={}, found={}, bucket={}, storagePathPresent={}", logFileId, sysFile != null, sysFile == null ? null : sysFile.getBucket(), sysFile != null && StrUtil.isNotBlank(sysFile.getStoragePath()));
|
||||
byte[] bytes = SysFileMinIoUtil.getFileBytes(sysFile.getBucket(), sysFile.getStoragePath());
|
||||
log.info("[Office图片读取] 读取存储文件完成,fileId={}, byteCount={}", logFileId, bytes == null ? null : bytes.length);
|
||||
return bytes;
|
||||
} catch (Exception e) {
|
||||
log.error("[Office图片读取] 读取图片失败,referenceLength={}", StrUtil.nullToEmpty(url).length(), e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
+3
@@ -606,6 +606,9 @@ public class TourMySignupController {
|
||||
if (StrUtil.isBlank(ledger.getMobile())) {
|
||||
return Result.error("手机号不能为空");
|
||||
}
|
||||
if (!ledger.getMobile().matches("^1[3-9]\\d{9}$")) {
|
||||
return Result.error("请输入正确的11位手机号");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
+3
@@ -841,6 +841,9 @@ public class TourSignupController {
|
||||
if (StrUtil.isBlank(ledger.getMobile())) {
|
||||
return Result.error("手机号不能为空");
|
||||
}
|
||||
if (!ledger.getMobile().matches("^1[3-9]\\d{9}$")) {
|
||||
return Result.error("请输入正确的11位手机号");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
+32
-26
@@ -28,10 +28,10 @@ import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.zhgh.staffbenefit.condolence.model.Condolence;
|
||||
import com.budwk.app.zhgh.staffbenefit.condolence.model.CondolenceType;
|
||||
import com.budwk.app.zhgh.staffbenefit.condolence.service.CondolenceService;
|
||||
import com.deepoove.poi.XWPFTemplate;
|
||||
import com.deepoove.poi.data.PictureRenderData;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Sqls;
|
||||
@@ -47,8 +47,6 @@ import org.nutz.mvc.annotation.Ok;
|
||||
import org.nutz.mvc.annotation.Param;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
|
||||
@@ -59,6 +57,7 @@ import java.util.List;
|
||||
* @Version 1.0
|
||||
* @Description TODO
|
||||
*/
|
||||
@Slf4j
|
||||
@IocBean
|
||||
@At("/platform/condolence/mine")
|
||||
@Api("职工慰问我的")
|
||||
@@ -157,6 +156,7 @@ public class CondolenceMineController {
|
||||
@ApiOperation("导出职工慰问申请表")
|
||||
@SaCheckPermission("condolence.mine")
|
||||
public void doExportApply(String id, HttpServletResponse response, Boolean print) throws Exception {
|
||||
log.info("[职工慰问导出] 开始,applyId={}, userId={}, format={}", id, SecurityUtil.getUserId(), Boolean.TRUE.equals(print) ? "PDF" : "Word");
|
||||
Condolence condolence = condolenceService.fetch(id);
|
||||
if (condolence == null) throw new BaseException("该条记录不存在");
|
||||
if (!SecurityUtil.getUserId().equals(condolence.getCreatedBy())) {
|
||||
@@ -167,36 +167,32 @@ public class CondolenceMineController {
|
||||
if (instance == null || !ProcessInstanceStateEnum.FINISHED.getCode().equals(instance.getState())) {
|
||||
throw new BaseException("只能导出已完成的申请");
|
||||
}
|
||||
log.info("[职工慰问导出] 流程已完成,applyId={}, instanceId={}, state={}, applicantSignPresent={}", id, instance.getId(), instance.getState(), StrUtil.isNotBlank(condolence.getSignature()));
|
||||
NutMap docData = Lang.obj2nutmap(condolence);
|
||||
docData.put("payUserName", StrUtil.nullToEmpty(condolence.getBankUserName()));
|
||||
CondolenceType type = condolenceService.dao().fetch(CondolenceType.class, condolence.getType());
|
||||
docData.put("typeName", type == null ? "" : type.getName());
|
||||
docData.put("signature", "");
|
||||
docData.put("signature", null);
|
||||
if (StrUtil.isNotBlank(condolence.getSignature())) {
|
||||
PictureRenderData signature = sysOfficeTemplateUtil.createPictureRenderData(90, 40, condolence.getSignature());
|
||||
if (signature == null) throw new BaseException("申请人签字图片读取失败");
|
||||
docData.put("signature", signature);
|
||||
}
|
||||
fillApplyApprovals(docData, instance);
|
||||
for (String field : List.of("signature", "firstApprovalSign", "secondApprovalSign", "thirdApprovalSign", "fourthApprovalSign")) {
|
||||
Object value = docData.get(field);
|
||||
log.info("[职工慰问导出] 渲染前图片字段,applyId={}, instanceId={}, field={}, valueType={}", id, instance.getId(), field, value == null ? "null" : value.getClass().getName());
|
||||
}
|
||||
String fileName = "重庆工贸职业技术学院职工慰问申请表_" + StrUtil.nullToEmpty(condolence.getHelpUserName());
|
||||
try (InputStream input = getClass().getResourceAsStream("/templates/condolence/重庆工贸职业技术学院职工慰问申请表.doc");
|
||||
ByteArrayOutputStream templateOutput = new ByteArrayOutputStream();
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream()) {
|
||||
try (InputStream input = getClass().getResourceAsStream("/templates/condolence/重庆工贸职业技术学院职工慰问申请表.doc")) {
|
||||
if (input == null) throw new BaseException("职工慰问申请表模板不存在");
|
||||
com.aspose.words.Document document = new com.aspose.words.Document(input);
|
||||
document.save(templateOutput, com.aspose.words.SaveFormat.DOCX);
|
||||
try (ByteArrayInputStream templateInput = new ByteArrayInputStream(templateOutput.toByteArray())) {
|
||||
XWPFTemplate.compile(templateInput).render(docData).writeAndClose(output);
|
||||
}
|
||||
if (Boolean.TRUE.equals(print)) {
|
||||
try (ByteArrayInputStream wordInput = new ByteArrayInputStream(output.toByteArray());
|
||||
ByteArrayOutputStream pdfOutput = new ByteArrayOutputStream()) {
|
||||
new com.aspose.words.Document(wordInput).save(pdfOutput, com.aspose.words.SaveFormat.PDF);
|
||||
CommonDownloadUtil.download(fileName + ".pdf", pdfOutput.toByteArray(), response);
|
||||
}
|
||||
} else {
|
||||
CommonDownloadUtil.download(fileName + ".docx", output.toByteArray(), response);
|
||||
}
|
||||
boolean pdf = Boolean.TRUE.equals(print);
|
||||
byte[] bytes = sysOfficeTemplateUtil.renderTemplate(input, docData, null, pdf, "condolence:" + id);
|
||||
log.info("[职工慰问导出] 渲染完成,applyId={}, format={}, outputBytes={}", id, pdf ? "PDF" : "Word", bytes.length);
|
||||
CommonDownloadUtil.download(fileName + (pdf ? ".pdf" : ".docx"), bytes, response);
|
||||
} catch (Exception e) {
|
||||
log.error("[职工慰问导出] 模板渲染或文件输出失败,applyId={}, instanceId={}, format={}", id, instance.getId(), Boolean.TRUE.equals(print) ? "PDF" : "Word", e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -206,29 +202,39 @@ public class CondolenceMineController {
|
||||
String[] fields = {"firstApproval", "secondApproval", "thirdApproval", "fourthApproval"};
|
||||
List<String> suffixes = List.of("Opinion", "Sign", "Year", "Month", "Day");
|
||||
for (String field : fields) {
|
||||
for (String suffix : suffixes) docData.put(field + suffix, "");
|
||||
for (String suffix : suffixes) docData.put(field + suffix, "Sign".equals(suffix) ? null : "");
|
||||
}
|
||||
List<ProcessTask> tasks = condolenceService.dao().query(ProcessTask.class,
|
||||
Cnd.where("processInstanceId", "=", instance.getId()).asc("id"));
|
||||
log.info("[职工慰问导出] 查询审批记录,applyId={}, instanceId={}, taskCount={}, expectedTaskKeys={}", instance.getBusinessNo(), instance.getId(), tasks.size(), List.of(taskKeys));
|
||||
for (ProcessTask task : tasks) {
|
||||
ProcessTaskVO taskVO = flowEngine.processTaskService().findById(task.getId());
|
||||
if ("startTask".equals(task.getTaskName()) || (taskVO.getExt() != null && Boolean.TRUE.equals(taskVO.getExt().getBool("isFirstTaskNode")))) {
|
||||
log.info("[职工慰问导出] 审批记录,instanceId={}, taskId={}, taskKey={}, displayName={}, state={}, finishTime={}, isFirstTaskNode={}, matchedApproval={}", instance.getId(), task.getId(), task.getTaskName(), task.getDisplayName(), task.getTaskState(), task.getFinishTime(), taskVO.getExt() == null ? null : taskVO.getExt().get("isFirstTaskNode"), List.of(taskKeys).contains(task.getTaskName()));
|
||||
if ("startTask".equals(task.getTaskName()) || (!List.of(taskKeys).contains(task.getTaskName())
|
||||
&& taskVO.getExt() != null && Boolean.TRUE.equals(taskVO.getExt().getBool("isFirstTaskNode")))) {
|
||||
log.info("[职工慰问导出] 申请节点重置本轮审批字段,instanceId={}, taskId={}, taskKey={}", instance.getId(), task.getId(), task.getTaskName());
|
||||
// 重新申请后,仅导出本轮审批记录。
|
||||
for (String field : fields) {
|
||||
for (String suffix : suffixes) docData.put(field + suffix, "");
|
||||
for (String suffix : suffixes) docData.put(field + suffix, "Sign".equals(suffix) ? null : "");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
for (int i = 0; i < taskKeys.length; i++) {
|
||||
if (!taskKeys[i].equals(task.getTaskName())) continue;
|
||||
for (String suffix : suffixes) docData.put(fields[i] + suffix, "");
|
||||
if (!ProcessTaskStateEnum.FINISHED.getCode().equals(task.getTaskState())) continue;
|
||||
for (String suffix : suffixes) docData.put(fields[i] + suffix, "Sign".equals(suffix) ? null : "");
|
||||
if (!ProcessTaskStateEnum.FINISHED.getCode().equals(task.getTaskState())) {
|
||||
log.info("[职工慰问导出] 跳过未完成审批,instanceId={}, taskId={}, field={}, state={}", instance.getId(), task.getId(), fields[i], task.getTaskState());
|
||||
continue;
|
||||
}
|
||||
Dict data = taskVO.getExt() == null ? Dict.create() : taskVO.getTaskFormData();
|
||||
log.info("[职工慰问导出] 读取审批表单,instanceId={}, taskId={}, field={}, formKeys={}, signPresent={}, signReferenceLength={}", instance.getId(), task.getId(), fields[i], data.keySet(), StrUtil.isNotBlank(data.getStr("sign")), StrUtil.nullToEmpty(data.getStr("sign")).length());
|
||||
if (StrUtil.isBlank(data.getStr("sign"))) log.warn("[职工慰问导出] 已完成审批缺少签名字段,instanceId={}, taskId={}, field={}", instance.getId(), task.getId(), fields[i]);
|
||||
docData.put(fields[i] + "Opinion", StrUtil.nullToEmpty(data.getStr("opinion")));
|
||||
if (StrUtil.isNotBlank(data.getStr("sign"))) {
|
||||
PictureRenderData signature = sysOfficeTemplateUtil.createPictureRenderData(90, 40, data.getStr("sign"));
|
||||
if (signature == null) throw new BaseException("审批签字图片读取失败");
|
||||
docData.put(fields[i] + "Sign", signature);
|
||||
log.info("[职工慰问导出] 审批签名填充完成,instanceId={}, taskId={}, field={}", instance.getId(), task.getId(), fields[i] + "Sign");
|
||||
}
|
||||
docData.put(fields[i] + "Year", task.getFinishTime() == null ? "" : DateUtil.format(task.getFinishTime(), "yyyy"));
|
||||
docData.put(fields[i] + "Month", task.getFinishTime() == null ? "" : DateUtil.format(task.getFinishTime(), "M"));
|
||||
|
||||
+16
-39
@@ -9,7 +9,6 @@ import cn.dev33.satoken.annotation.SaCheckLogin;
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.alibaba.excel.EasyExcel;
|
||||
@@ -18,7 +17,6 @@ import com.budwk.app.base.page.Pagination;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.base.utils.CommonDownloadUtil;
|
||||
import com.budwk.app.base.utils.MoneyUtil;
|
||||
import com.budwk.app.base.utils.OfficePlusUtil;
|
||||
import com.budwk.app.base.utils.SysOfficeTemplateUtil;
|
||||
import com.budwk.app.flow.engine.FlowEngine;
|
||||
import com.budwk.app.flow.entity.ProcessInstance;
|
||||
@@ -39,7 +37,6 @@ import com.budwk.app.zhgh.staffbenefit.difficulthelp.service.DifficultHelpCommon
|
||||
import com.budwk.app.zhgh.staffbenefit.difficulthelp.vo.DifficultHelpPageParam;
|
||||
import com.budwk.app.zhgh.staffbenefit.difficulthelp.vo.moneyImportVo;
|
||||
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.aidFund.param.AidFundPageForm;
|
||||
import com.deepoove.poi.XWPFTemplate;
|
||||
import com.deepoove.poi.config.Configure;
|
||||
import com.deepoove.poi.data.PictureRenderData;
|
||||
import com.deepoove.poi.plugin.table.LoopRowTableRenderPolicy;
|
||||
@@ -74,8 +71,6 @@ import javax.servlet.http.HttpServletResponse;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.*;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
@@ -319,9 +314,9 @@ public class DifficultHelpReadingController {
|
||||
LoopRowTableRenderPolicy policy = new LoopRowTableRenderPolicy();
|
||||
Configure config = Configure.builder().bind("familyList", policy).build();
|
||||
|
||||
XWPFTemplate.compile(sysOfficeTemplateUtil.getTemplate("difficulty_apply"), config)
|
||||
.render(docData)
|
||||
.write(zipOutputStream);
|
||||
try (InputStream input = sysOfficeTemplateUtil.getTemplate("difficulty_apply")) {
|
||||
zipOutputStream.write(sysOfficeTemplateUtil.renderTemplate(input, docData, config, false, "difficulthelp:batch:" + record.getString("id")));
|
||||
}
|
||||
zipOutputStream.closeEntry();
|
||||
}
|
||||
zipOutputStream.flush();
|
||||
@@ -379,17 +374,18 @@ public class DifficultHelpReadingController {
|
||||
String[] taskKeys = {"36ebafda-44c2-4bd3-bd7f-10839a575a0d", "715ece82-4ae3-433c-ad18-ed875f45d1e3", "e405f96c-5fc0-4f63-b323-e69dfe853253"};
|
||||
String[] fields = {"firstApproval", "secondApproval", "thirdApproval"};
|
||||
for (String field : fields) {
|
||||
for (String suffix : List.of("", "Opinion", "User", "Date", "Year", "Month", "Day", "Sign")) docData.put(field + suffix, "");
|
||||
for (String suffix : List.of("", "Opinion", "User", "Date", "Year", "Month", "Day", "Sign")) docData.put(field + suffix, "Sign".equals(suffix) ? null : "");
|
||||
}
|
||||
ProcessInstance instance = dao.fetch(ProcessInstance.class, Cnd.where("businessNo", "=", businessId).desc("id"));
|
||||
if (instance == null) return;
|
||||
List<ProcessTask> tasks = dao.query(ProcessTask.class, Cnd.where("processInstanceId", "=", instance.getId()).asc("id"));
|
||||
for (ProcessTask task : tasks) {
|
||||
ProcessTaskVO taskVO = flowEngine.processTaskService().findById(task.getId());
|
||||
if ("startTask".equals(task.getTaskName()) || (taskVO.getExt() != null && Boolean.TRUE.equals(taskVO.getExt().getBool("isFirstTaskNode")))) {
|
||||
if ("startTask".equals(task.getTaskName()) || (!List.of(taskKeys).contains(task.getTaskName())
|
||||
&& taskVO.getExt() != null && Boolean.TRUE.equals(taskVO.getExt().getBool("isFirstTaskNode")))) {
|
||||
// 重新申请后,仅导出本轮审批,避免混入上一次退回或撤销前的意见。
|
||||
for (String field : fields) {
|
||||
for (String suffix : List.of("", "Opinion", "User", "Date", "Year", "Month", "Day", "Sign")) docData.put(field + suffix, "");
|
||||
for (String suffix : List.of("", "Opinion", "User", "Date", "Year", "Month", "Day", "Sign")) docData.put(field + suffix, "Sign".equals(suffix) ? null : "");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@@ -453,22 +449,9 @@ public class DifficultHelpReadingController {
|
||||
String fileName = FileUtil.mainName(sysOfficeTemplateUtil.getTemplateFileName(templateName)) + "_" + difficultHelp.getUserName() + "_" +
|
||||
DateUtil.format(difficultHelp.getApplyTime(), "yyyyMMdd") + ".pdf";
|
||||
|
||||
try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {
|
||||
XWPFTemplate.compile(getApplyTemplate(templateName),config)
|
||||
.render(docData)
|
||||
.writeAndClose(byteArrayOutputStream);
|
||||
byte[] bytes = byteArrayOutputStream.toByteArray();
|
||||
File sourceFile = File.createTempFile("file_convert_origin", ".docx");
|
||||
Files.write(sourceFile.toPath(), bytes, StandardOpenOption.WRITE);
|
||||
|
||||
File pdfFile = File.createTempFile("file_convert", ".pdf");
|
||||
OfficePlusUtil.convert(sourceFile.getPath(), pdfFile.getPath());
|
||||
CommonDownloadUtil.download(fileName, IoUtil.readBytes(FileUtil.getInputStream(pdfFile)), response);
|
||||
// 删除临时文件
|
||||
FileUtil.del(sourceFile);
|
||||
FileUtil.del(pdfFile.toPath());
|
||||
} catch (IOException e) {
|
||||
log.error("困难慰问申请表导出PDF失败,id:{},错误信息:{}", difficultHelp.getId(), e.getMessage());
|
||||
try (InputStream input = getApplyTemplate(templateName)) {
|
||||
byte[] bytes = sysOfficeTemplateUtil.renderTemplate(input, docData, config, true, "difficulthelp:" + difficultHelp.getId());
|
||||
CommonDownloadUtil.download(fileName, bytes, response);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -478,13 +461,9 @@ public class DifficultHelpReadingController {
|
||||
String fileName = FileUtil.mainName(sysOfficeTemplateUtil.getTemplateFileName(templateName)) + "_" + difficultHelp.getUserName() + "_" +
|
||||
DateUtil.format(difficultHelp.getApplyTime(), "yyyyMMdd") + ".docx";
|
||||
|
||||
try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {
|
||||
XWPFTemplate.compile(getApplyTemplate(templateName),config)
|
||||
.render(docData)
|
||||
.writeAndClose(byteArrayOutputStream);
|
||||
CommonDownloadUtil.download(fileName, byteArrayOutputStream.toByteArray(), response);
|
||||
} catch (IOException e) {
|
||||
log.error("困难慰问申请表导出Word失败,id:{},错误信息:{}", difficultHelp.getId(), e.getMessage());
|
||||
try (InputStream input = getApplyTemplate(templateName)) {
|
||||
byte[] bytes = sysOfficeTemplateUtil.renderTemplate(input, docData, config, false, "difficulthelp:" + difficultHelp.getId());
|
||||
CommonDownloadUtil.download(fileName, bytes, response);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -562,15 +541,13 @@ public class DifficultHelpReadingController {
|
||||
throw new RuntimeException("导出Excel汇总表失败:" + e.getMessage());
|
||||
}
|
||||
} else if ("docx".equals(flag)) {
|
||||
try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
|
||||
try (InputStream input = sysOfficeTemplateUtil.getTemplate(resource)) {
|
||||
Configure config = Configure.builder()
|
||||
.bind("da", new LoopRowTableRenderPolicy())
|
||||
.build();
|
||||
|
||||
XWPFTemplate.compile(sysOfficeTemplateUtil.getTemplate(resource), config)
|
||||
.render(result)
|
||||
.writeAndClose(out);
|
||||
CommonDownloadUtil.download(fileName + ".docx", out.toByteArray(), response);
|
||||
byte[] bytes = sysOfficeTemplateUtil.renderTemplate(input, result, config, false, "difficulthelp:summary:" + resource);
|
||||
CommonDownloadUtil.download(fileName + ".docx", bytes, response);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -735,7 +735,6 @@ public class WelfareListServiceImpl extends BaseServiceImpl<WelfareList> impleme
|
||||
entities.add(new ExcelExportEntity("在职状态", "userState", 20));
|
||||
entities.add(new ExcelExportEntity("所属工会", "welfareUnionName", 20));
|
||||
entities.add(new ExcelExportEntity("所属单位", "welfareUnitName", 20));
|
||||
entities.add(new ExcelExportEntity("三级单位", "threeUnitName", 20));
|
||||
entities.add(new ExcelExportEntity("备注", "remark", 20));
|
||||
|
||||
// 设置导出参数
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
progress
|
||||
:accept="accept"
|
||||
:max-count="upload_number"
|
||||
:upload-text="upload_text"
|
||||
title=""
|
||||
description=""
|
||||
tip=""
|
||||
@@ -50,6 +51,11 @@ module.exports = {
|
||||
default: 1,
|
||||
required: false
|
||||
},
|
||||
upload_text: {
|
||||
type: String,
|
||||
default: "",
|
||||
required: false
|
||||
},
|
||||
// 上传返回id或url
|
||||
upload_result_type: {
|
||||
type: String,
|
||||
@@ -101,6 +107,7 @@ module.exports = {
|
||||
this.fileList = val.map((v) => {
|
||||
return {
|
||||
...v,
|
||||
file: v.file || { name: v.name },
|
||||
status: null,
|
||||
isImage: ["jpg", "jpeg", "png", "gif", "bmp", "webp"].includes(v.name.split(".").pop().toLowerCase())
|
||||
}
|
||||
@@ -118,6 +125,7 @@ module.exports = {
|
||||
this.fileList = val.map((v) => {
|
||||
return {
|
||||
...v,
|
||||
file: v.file || { name: v.name },
|
||||
url: v.url ? v.url : v.response?.data,
|
||||
isImage: ["jpg", "jpeg", "png", "gif", "bmp", "webp"].includes(v.name.split(".").pop().toLowerCase()),
|
||||
status: null
|
||||
@@ -171,8 +179,8 @@ module.exports = {
|
||||
f.url = resp.data
|
||||
f.response = resp
|
||||
f.percentage = 100
|
||||
f.isImage = true
|
||||
delete f.file
|
||||
f.isImage = ["jpg", "jpeg", "png", "gif", "bmp", "webp"].includes(f.name.split(".").pop().toLowerCase())
|
||||
f.file = { name: f.name }
|
||||
delete f.content
|
||||
} else {
|
||||
f.status = "fail"
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -131,7 +131,7 @@ layout("/layouts/platform.html"){
|
||||
<el-option v-for="item in organizationTypeOptions" :key="item.code" :label="item.name" :value="item.code"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="所属工会" prop="unionId">
|
||||
<el-form-item label="所属工会" prop="unionId" :required="formData.organizationType !== 'schoolUnion'">
|
||||
<el-select v-model="formData.unionId" clearable filterable placeholder="请选择所属工会" style="width: 100%" :disabled="isUnionDisabled()">
|
||||
<el-option v-for="item in unionOptions" :key="item.id" :label="item.name" :value="item.id"></el-option>
|
||||
</el-select>
|
||||
@@ -255,7 +255,9 @@ layout("/layouts/platform.html"){
|
||||
}
|
||||
}
|
||||
const validatePeople = (rule, value, callback) => {
|
||||
if (!value || value <= 0) {
|
||||
if (value === null || value === undefined || value === "") {
|
||||
callback(new Error("必填"))
|
||||
} else if (!value || value <= 0) {
|
||||
callback(new Error("人数必须大于0"))
|
||||
} else if (this.batchForm.minGroupPeople && this.batchForm.maxGroupPeople
|
||||
&& this.batchForm.minGroupPeople > this.batchForm.maxGroupPeople) {
|
||||
@@ -317,15 +319,15 @@ layout("/layouts/platform.html"){
|
||||
},
|
||||
batchRules: {
|
||||
lineId: [{ required: true, message: "必填", trigger: ["blur", "change"] }],
|
||||
signupStartTime: [{ validator: validateBatchTime, trigger: ["blur", "change"] }],
|
||||
signupEndTime: [{ validator: validateBatchTime, trigger: ["blur", "change"] }],
|
||||
travelStartTime: [{ validator: validateBatchTime, trigger: ["blur", "change"] }],
|
||||
travelEndTime: [{ validator: validateBatchTime, trigger: ["blur", "change"] }],
|
||||
signupStartTime: [{ required: true, validator: validateBatchTime, trigger: ["blur", "change"] }],
|
||||
signupEndTime: [{ required: true, validator: validateBatchTime, trigger: ["blur", "change"] }],
|
||||
travelStartTime: [{ required: true, validator: validateBatchTime, trigger: ["blur", "change"] }],
|
||||
travelEndTime: [{ required: true, validator: validateBatchTime, trigger: ["blur", "change"] }],
|
||||
contactName: [{ required: true, message: "必填", trigger: ["blur", "change"] }],
|
||||
contactPhone: [{ validator: validateMobile, trigger: ["blur", "change"] }],
|
||||
minGroupPeople: [{ validator: validatePeople, trigger: ["blur", "change"] }],
|
||||
maxGroupPeople: [{ validator: validatePeople, trigger: ["blur", "change"] }],
|
||||
estimatedCost: [{ validator: validateMoney, trigger: ["blur", "change"] }]
|
||||
contactPhone: [{ required: true, validator: validateMobile, trigger: ["blur", "change"] }],
|
||||
minGroupPeople: [{ required: true, validator: validatePeople, trigger: ["blur", "change"] }],
|
||||
maxGroupPeople: [{ required: true, validator: validatePeople, trigger: ["blur", "change"] }],
|
||||
estimatedCost: [{ required: true, validator: validateMoney, trigger: ["blur", "change"] }]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -216,7 +216,7 @@ layout("/layouts/platform.html"){
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="身份证号">
|
||||
<el-form-item label="身份证号" prop="idCard" :rules="requiredRules" required>
|
||||
<el-input v-model="signupForm.idCard" readonly></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
@@ -233,8 +233,8 @@ layout("/layouts/platform.html"){
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="手机号" required>
|
||||
<el-input v-model="signupForm.mobile" maxlength="30" placeholder="请输入手机号"></el-input>
|
||||
<el-form-item label="手机号" prop="mobile" :rules="mobileRules" required>
|
||||
<el-input v-model="signupForm.mobile" maxlength="11" placeholder="请输入手机号"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
@@ -325,17 +325,17 @@ layout("/layouts/platform.html"){
|
||||
<el-form :model="directRelativeForm" label-width="110px" ref="directRelativeForm">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="亲属姓名">
|
||||
<el-form-item label="亲属姓名" prop="relativeName" :rules="requiredRules" required>
|
||||
<el-input v-model="directRelativeForm.relativeName" maxlength="100" placeholder="请输入亲属姓名"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="所在单位">
|
||||
<el-form-item label="所在单位" prop="unitName" :rules="requiredRules" required>
|
||||
<el-input v-model="directRelativeForm.unitName" maxlength="100" placeholder="请输入所在单位"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="亲属关系">
|
||||
<el-form-item label="亲属关系" prop="relationshipCode" :rules="requiredRules" required>
|
||||
<el-select v-model="directRelativeForm.relationshipCode" clearable placeholder="请选择亲属关系" style="width: 100%" @change="directRelativeChange">
|
||||
<el-option v-for="item in directRelativeOptions" :key="item.code" :label="item.name" :value="item.code"></el-option>
|
||||
</el-select>
|
||||
@@ -344,12 +344,12 @@ layout("/layouts/platform.html"){
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="线路名称">
|
||||
<el-form-item label="线路名称" prop="lineName" :rules="requiredRules" required>
|
||||
<el-input v-model="directRelativeForm.lineName" maxlength="100" placeholder="请输入线路名称"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="出行开始日期">
|
||||
<el-form-item label="出行开始日期" prop="travelStartTime" :rules="requiredRules" required>
|
||||
<el-date-picker
|
||||
v-model="directRelativeForm.travelStartTime"
|
||||
type="date"
|
||||
@@ -360,7 +360,7 @@ layout("/layouts/platform.html"){
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="出行结束日期">
|
||||
<el-form-item label="出行结束日期" prop="travelEndTime" :rules="requiredRules" required>
|
||||
<el-date-picker
|
||||
v-model="directRelativeForm.travelEndTime"
|
||||
type="date"
|
||||
@@ -379,34 +379,48 @@ layout("/layouts/platform.html"){
|
||||
<div class="tour-actions">
|
||||
<el-button size="medium" type="primary" icon="el-icon-plus" :disabled="!signupForm.hasFamily" @click="addFamily">增加一条</el-button>
|
||||
</div>
|
||||
<el-table :data="familyData" border :size="tableSize" empty-text="暂无亲属信息">
|
||||
<el-form :model="{ rows: familyData }" ref="familyForm" label-width="0">
|
||||
<el-table class="tour-family-table" :data="familyData" border :size="tableSize" empty-text="暂无亲属信息">
|
||||
<el-table-column label="序号" type="index" width="70" align="center" header-align="center"></el-table-column>
|
||||
<el-table-column label="家属姓名" min-width="130" align="center" header-align="center">
|
||||
<template slot-scope="{row}">
|
||||
<template slot="header"><span style="color: #f56c6c">*</span> 家属姓名</template>
|
||||
<template slot-scope="{row, $index}">
|
||||
<el-form-item :prop="'rows.' + $index + '.familyName'" :rules="requiredRules">
|
||||
<el-input v-model="row.familyName" maxlength="100" placeholder="请输入"></el-input>
|
||||
</el-form-item>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="性别" width="110" align="center" header-align="center">
|
||||
<template slot-scope="{row}">
|
||||
<template slot="header"><span style="color: #f56c6c">*</span> 性别</template>
|
||||
<template slot-scope="{row, $index}">
|
||||
<el-form-item :prop="'rows.' + $index + '.gender'" :rules="requiredRules">
|
||||
<el-select v-model="row.gender" clearable placeholder="请选择">
|
||||
<el-option label="男" value="男"></el-option>
|
||||
<el-option label="女" value="女"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="身份证号码" min-width="180" align="center" header-align="center">
|
||||
<template slot-scope="{row}">
|
||||
<template slot-scope="{row, $index}">
|
||||
<el-form-item :prop="'rows.' + $index + '.idCard'" :rules="[{ required: familyContactRequired(row), validator: validateFamilyIdCard, trigger: ['blur', 'change'] }]">
|
||||
<el-input v-model="row.idCard" maxlength="18" :placeholder="familyContactRequired(row) ? '16岁及以上必填' : '选填'" @blur="normalizeFamilyIdCard(row)"></el-input>
|
||||
</el-form-item>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="手机号" min-width="150" align="center" header-align="center">
|
||||
<template slot-scope="{row}">
|
||||
<template slot-scope="{row, $index}">
|
||||
<el-form-item :prop="'rows.' + $index + '.mobile'" :rules="[{ required: familyContactRequired(row), message: '必填', trigger: ['blur', 'change'] }]">
|
||||
<el-input v-model="row.mobile" maxlength="30" :placeholder="familyContactRequired(row) ? '16岁及以上必填' : '选填'"></el-input>
|
||||
</el-form-item>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="年龄" width="110" align="center" header-align="center">
|
||||
<template slot-scope="{row}">
|
||||
<template slot="header"><span style="color: #f56c6c">*</span> 年龄</template>
|
||||
<template slot-scope="{row, $index}">
|
||||
<el-form-item :prop="'rows.' + $index + '.age'" :rules="requiredRules">
|
||||
<el-input-number v-model="row.age" :min="0" :max="120" :precision="0" controls-position="right" style="width: 100%"></el-input-number>
|
||||
</el-form-item>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column v-if="fillBedInfo" label="床型" min-width="120" align="center" header-align="center">
|
||||
@@ -427,10 +441,13 @@ layout("/layouts/platform.html"){
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="关系" width="120" align="center" header-align="center">
|
||||
<template slot-scope="{row}">
|
||||
<template slot="header"><span style="color: #f56c6c">*</span> 关系</template>
|
||||
<template slot-scope="{row, $index}">
|
||||
<el-form-item :prop="'rows.' + $index + '.relationship'" :rules="requiredRules">
|
||||
<el-select v-model="row.relationship" clearable placeholder="请选择">
|
||||
<el-option v-for="item in familyRelationshipOptions" :key="item.code" :label="item.name" :value="item.name"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="90" align="center" header-align="center" fixed="right">
|
||||
@@ -439,6 +456,8 @@ layout("/layouts/platform.html"){
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div v-if="familyValidationAttempted && familyData.length === 0" class="el-form-item__error" style="position: static">必填</div>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<span slot="footer" class="dialog-footer">
|
||||
@@ -520,6 +539,10 @@ layout("/layouts/platform.html"){
|
||||
</div>
|
||||
|
||||
<style>
|
||||
/* 覆盖全局表格 div 文字颜色,保留输入组件下方校验提示的红色。 */
|
||||
.tour-family-table.el-table td.el-table__cell .el-form-item__error {
|
||||
color: #f56c6c;
|
||||
}
|
||||
.tour-section {
|
||||
margin-top: 10px;
|
||||
padding: 0 2px;
|
||||
@@ -763,6 +786,12 @@ layout("/layouts/platform.html"){
|
||||
fillBedInfo: true,
|
||||
signupForm: {},
|
||||
familyData: [],
|
||||
familyValidationAttempted: false,
|
||||
requiredRules: [{ required: true, message: "必填", trigger: ["blur", "change"] }],
|
||||
mobileRules: [
|
||||
{ required: true, message: "必填", trigger: ["blur", "change"] },
|
||||
{ pattern: /^1[3-9]\d{9}$/, message: "请输入正确的11位手机号", trigger: ["blur", "change"] }
|
||||
],
|
||||
bedTypeOptions: [],
|
||||
familyRelationshipOptions: [],
|
||||
directRelativeOptions: [],
|
||||
@@ -1161,6 +1190,11 @@ layout("/layouts/platform.html"){
|
||||
this.signupForm.hasFamily = true
|
||||
}
|
||||
this.signupVisible = true
|
||||
this.$nextTick(() => {
|
||||
;[this.$refs.signupForm, this.$refs.directRelativeForm, this.$refs.familyForm].forEach(form => {
|
||||
if (form) form.clearValidate()
|
||||
})
|
||||
})
|
||||
} else {
|
||||
this.$message.warning(res.msg || "查询失败")
|
||||
}
|
||||
@@ -1231,29 +1265,22 @@ layout("/layouts/platform.html"){
|
||||
this.signupForm.hasFamily = false
|
||||
}
|
||||
},
|
||||
// 家属表格按行校验,缺失项显示在对应输入组件下方。
|
||||
validateFamilies() {
|
||||
if (!this.allowFamily || !this.signupForm.hasFamily) return true
|
||||
if (this.familyData.length === 0) {
|
||||
this.$message.warning("请添加亲属信息")
|
||||
return false
|
||||
this.familyValidationAttempted = true
|
||||
if (this.familyData.length === 0) return false
|
||||
return new Promise(resolve => this.$refs.familyForm.validate(valid => resolve(valid)))
|
||||
},
|
||||
// 未满16岁的家属允许不填身份证,已填写时仍检查格式。
|
||||
validateFamilyIdCard(rule, value, callback) {
|
||||
if (!value) {
|
||||
callback(rule.required ? new Error("必填") : undefined)
|
||||
} else if (!this.isValidIdCard(value)) {
|
||||
callback(new Error("请输入正确的身份证号码"))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
const invalidBase = this.familyData.some(item => !item.familyName || item.age === null || item.age === undefined
|
||||
|| !item.gender || !item.relationship)
|
||||
if (invalidBase) {
|
||||
this.$message.warning("请完善亲属姓名、年龄、性别和与本人关系")
|
||||
return false
|
||||
}
|
||||
const invalidContact = this.familyData.some(item => this.familyContactRequired(item) && (!item.idCard || !item.mobile))
|
||||
if (invalidContact) {
|
||||
this.$message.warning("年满16周岁的亲属必须填写身份证号码和手机号")
|
||||
return false
|
||||
}
|
||||
const invalidIdCard = this.familyData.some(item => item.idCard && !this.isValidIdCard(item.idCard))
|
||||
if (invalidIdCard) {
|
||||
this.$message.warning("请输入正确的身份证号码")
|
||||
return false
|
||||
}
|
||||
return true
|
||||
},
|
||||
familyContactRequired(family) {
|
||||
return family && family.age !== null && family.age !== undefined && Number(family.age) >= 16
|
||||
@@ -1269,39 +1296,17 @@ layout("/layouts/platform.html"){
|
||||
},
|
||||
validateDirectRelative() {
|
||||
if (!this.isDirectFamilyLine(this.signupForm)) return true
|
||||
if (!this.directRelativeForm.relativeName) {
|
||||
this.$message.warning("请输入亲属姓名")
|
||||
return false
|
||||
}
|
||||
if (!this.directRelativeForm.unitName) {
|
||||
this.$message.warning("请输入亲属所在单位")
|
||||
return false
|
||||
}
|
||||
if (!this.directRelativeForm.relationshipCode) {
|
||||
this.$message.warning("请选择亲属关系")
|
||||
return false
|
||||
}
|
||||
if (!this.directRelativeForm.lineName) {
|
||||
this.$message.warning("请输入直系亲属线路名称")
|
||||
return false
|
||||
}
|
||||
if (!this.directRelativeForm.travelStartTime) {
|
||||
this.$message.warning("请选择出行开始日期")
|
||||
return false
|
||||
}
|
||||
if (!this.directRelativeForm.travelEndTime) {
|
||||
this.$message.warning("请选择出行结束日期")
|
||||
return false
|
||||
}
|
||||
return true
|
||||
return new Promise(resolve => this.$refs.directRelativeForm.validate(valid => resolve(valid)))
|
||||
},
|
||||
submitSignup() {
|
||||
if (!this.signupForm.idCard || !this.signupForm.mobile) {
|
||||
this.$message.warning("请完善报名人身份证号码和手机号")
|
||||
return
|
||||
}
|
||||
if (!this.validateFamilies()) return
|
||||
if (!this.validateDirectRelative()) return
|
||||
async submitSignup() {
|
||||
if (this.signupLoading) return
|
||||
// 同时校验各区域,一次展示所有字段错误,通过后才提交报名。
|
||||
const results = await Promise.all([
|
||||
new Promise(resolve => this.$refs.signupForm.validate(valid => resolve(valid))),
|
||||
this.validateFamilies(),
|
||||
this.validateDirectRelative()
|
||||
])
|
||||
if (results.some(valid => !valid)) return
|
||||
const families = this.allowFamily && this.signupForm.hasFamily ? this.familyData : []
|
||||
const form = Object.assign({}, this.signupForm, {
|
||||
families: JSON.stringify(families),
|
||||
@@ -1352,6 +1357,7 @@ layout("/layouts/platform.html"){
|
||||
}).catch(() => {})
|
||||
},
|
||||
destroySignup() {
|
||||
this.familyValidationAttempted = false
|
||||
this.signupForm = {}
|
||||
this.familyData = []
|
||||
this.directRelativeForm = {}
|
||||
|
||||
@@ -182,7 +182,7 @@ layout("/layouts/platform.html"){
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col v-if="formData.outProvinceRatioType === '固定人数'" :span="12">
|
||||
<el-form-item label="固定人数" prop="outProvinceFixedPeople">
|
||||
<el-form-item label="固定人数" prop="outProvinceFixedPeople" :required="formData.outProvinceRatioType === '固定人数'">
|
||||
<el-input-number v-model="formData.outProvinceFixedPeople" :controls="false" :min="0" :precision="0" placeholder="请输入固定人数" style="width: 100%"></el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
@@ -366,7 +366,9 @@ layout("/layouts/platform.html"){
|
||||
}
|
||||
const checkOutProvinceFixedPeople = (rule, value, callback) => {
|
||||
if (this.formData.outProvinceRatioType === "固定人数"
|
||||
&& (value === null || value === undefined || value === "" || value < 0)) {
|
||||
&& (value === null || value === undefined || value === "")) {
|
||||
callback(new Error("必填"))
|
||||
} else if (this.formData.outProvinceRatioType === "固定人数" && value < 0) {
|
||||
callback(new Error("固定人数必须大于等于0"))
|
||||
} else {
|
||||
callback()
|
||||
|
||||
@@ -113,7 +113,7 @@ layout("/layouts/platform.html"){
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="身份证号">
|
||||
<el-form-item label="身份证号" prop="idCard" :rules="requiredRules" required>
|
||||
<el-input v-model="signupForm.idCard" readonly></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
@@ -130,8 +130,8 @@ layout("/layouts/platform.html"){
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="手机号" required>
|
||||
<el-input v-model="signupForm.mobile" maxlength="30" placeholder="请输入手机号"></el-input>
|
||||
<el-form-item label="手机号" prop="mobile" :rules="mobileRules" required>
|
||||
<el-input v-model="signupForm.mobile" maxlength="11" placeholder="请输入手机号"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
@@ -222,17 +222,17 @@ layout("/layouts/platform.html"){
|
||||
<el-form :model="directRelativeForm" label-width="110px" ref="directRelativeForm">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="亲属姓名">
|
||||
<el-form-item label="亲属姓名" prop="relativeName" :rules="requiredRules" required>
|
||||
<el-input v-model="directRelativeForm.relativeName" maxlength="100" placeholder="请输入亲属姓名"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="所在单位">
|
||||
<el-form-item label="所在单位" prop="unitName" :rules="requiredRules" required>
|
||||
<el-input v-model="directRelativeForm.unitName" maxlength="100" placeholder="请输入所在单位"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="亲属关系">
|
||||
<el-form-item label="亲属关系" prop="relationshipCode" :rules="requiredRules" required>
|
||||
<el-select v-model="directRelativeForm.relationshipCode" clearable placeholder="请选择亲属关系" style="width: 100%" @change="directRelativeChange">
|
||||
<el-option v-for="item in directRelativeOptions" :key="item.code" :label="item.name" :value="item.code"></el-option>
|
||||
</el-select>
|
||||
@@ -241,12 +241,12 @@ layout("/layouts/platform.html"){
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="线路名称">
|
||||
<el-form-item label="线路名称" prop="lineName" :rules="requiredRules" required>
|
||||
<el-input v-model="directRelativeForm.lineName" maxlength="100" placeholder="请输入线路名称"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="出行开始日期">
|
||||
<el-form-item label="出行开始日期" prop="travelStartTime" :rules="requiredRules" required>
|
||||
<el-date-picker
|
||||
v-model="directRelativeForm.travelStartTime"
|
||||
type="date"
|
||||
@@ -257,7 +257,7 @@ layout("/layouts/platform.html"){
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="出行结束日期">
|
||||
<el-form-item label="出行结束日期" prop="travelEndTime" :rules="requiredRules" required>
|
||||
<el-date-picker
|
||||
v-model="directRelativeForm.travelEndTime"
|
||||
type="date"
|
||||
@@ -276,34 +276,48 @@ layout("/layouts/platform.html"){
|
||||
<div class="tour-signup-actions">
|
||||
<el-button size="medium" type="primary" icon="el-icon-plus" :disabled="!signupForm.hasFamily" @click="addFamily">增加一条</el-button>
|
||||
</div>
|
||||
<el-table :data="familyData" border :size="tableSize" empty-text="暂无亲属信息">
|
||||
<el-form :model="{ rows: familyData }" ref="familyForm" label-width="0">
|
||||
<el-table class="tour-family-table" :data="familyData" border :size="tableSize" empty-text="暂无亲属信息">
|
||||
<el-table-column label="序号" type="index" width="70" align="center" header-align="center"></el-table-column>
|
||||
<el-table-column label="家属姓名" min-width="130" align="center" header-align="center">
|
||||
<template slot-scope="{row}">
|
||||
<template slot="header"><span style="color: #f56c6c">*</span> 家属姓名</template>
|
||||
<template slot-scope="{row, $index}">
|
||||
<el-form-item :prop="'rows.' + $index + '.familyName'" :rules="requiredRules">
|
||||
<el-input v-model="row.familyName" maxlength="100" placeholder="请输入"></el-input>
|
||||
</el-form-item>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="性别" width="110" align="center" header-align="center">
|
||||
<template slot-scope="{row}">
|
||||
<template slot="header"><span style="color: #f56c6c">*</span> 性别</template>
|
||||
<template slot-scope="{row, $index}">
|
||||
<el-form-item :prop="'rows.' + $index + '.gender'" :rules="requiredRules">
|
||||
<el-select v-model="row.gender" clearable placeholder="请选择">
|
||||
<el-option label="男" value="男"></el-option>
|
||||
<el-option label="女" value="女"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="身份证号码" min-width="180" align="center" header-align="center">
|
||||
<template slot-scope="{row}">
|
||||
<template slot-scope="{row, $index}">
|
||||
<el-form-item :prop="'rows.' + $index + '.idCard'" :rules="[{ required: familyContactRequired(row), validator: validateFamilyIdCard, trigger: ['blur', 'change'] }]">
|
||||
<el-input v-model="row.idCard" maxlength="18" :placeholder="familyContactRequired(row) ? '16岁及以上必填' : '选填'" @blur="normalizeFamilyIdCard(row)"></el-input>
|
||||
</el-form-item>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="手机号" min-width="150" align="center" header-align="center">
|
||||
<template slot-scope="{row}">
|
||||
<template slot-scope="{row, $index}">
|
||||
<el-form-item :prop="'rows.' + $index + '.mobile'" :rules="[{ required: familyContactRequired(row), message: '必填', trigger: ['blur', 'change'] }]">
|
||||
<el-input v-model="row.mobile" maxlength="30" :placeholder="familyContactRequired(row) ? '16岁及以上必填' : '选填'"></el-input>
|
||||
</el-form-item>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="年龄" width="110" align="center" header-align="center">
|
||||
<template slot-scope="{row}">
|
||||
<template slot="header"><span style="color: #f56c6c">*</span> 年龄</template>
|
||||
<template slot-scope="{row, $index}">
|
||||
<el-form-item :prop="'rows.' + $index + '.age'" :rules="requiredRules">
|
||||
<el-input-number v-model="row.age" :min="0" :max="120" :precision="0" controls-position="right" style="width: 100%"></el-input-number>
|
||||
</el-form-item>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column v-if="fillBedInfo" label="床型" min-width="120" align="center" header-align="center">
|
||||
@@ -336,10 +350,13 @@ layout("/layouts/platform.html"){
|
||||
</el-table-column>
|
||||
-->
|
||||
<el-table-column label="关系" width="120" align="center" header-align="center">
|
||||
<template slot-scope="{row}">
|
||||
<template slot="header"><span style="color: #f56c6c">*</span> 关系</template>
|
||||
<template slot-scope="{row, $index}">
|
||||
<el-form-item :prop="'rows.' + $index + '.relationship'" :rules="requiredRules">
|
||||
<el-select v-model="row.relationship" clearable placeholder="请选择">
|
||||
<el-option v-for="item in familyRelationshipOptions" :key="item.code" :label="item.name" :value="item.name"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="90" align="center" header-align="center" fixed="right">
|
||||
@@ -348,6 +365,8 @@ layout("/layouts/platform.html"){
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div v-if="familyValidationAttempted && familyData.length === 0" class="el-form-item__error" style="position: static">必填</div>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<span slot="footer" class="dialog-footer">
|
||||
@@ -389,6 +408,10 @@ layout("/layouts/platform.html"){
|
||||
</div>
|
||||
|
||||
<style>
|
||||
/* 覆盖全局表格 div 文字颜色,保留输入组件下方校验提示的红色。 */
|
||||
.tour-family-table.el-table td.el-table__cell .el-form-item__error {
|
||||
color: #f56c6c;
|
||||
}
|
||||
.tour-signup-title {
|
||||
border-left: 4px solid #0079c2;
|
||||
color: #0079c2;
|
||||
@@ -489,6 +512,12 @@ layout("/layouts/platform.html"){
|
||||
fillBedInfo: true,
|
||||
signupForm: {},
|
||||
familyData: [],
|
||||
familyValidationAttempted: false,
|
||||
requiredRules: [{ required: true, message: "必填", trigger: ["blur", "change"] }],
|
||||
mobileRules: [
|
||||
{ required: true, message: "必填", trigger: ["blur", "change"] },
|
||||
{ pattern: /^1[3-9]\d{9}$/, message: "请输入正确的11位手机号", trigger: ["blur", "change"] }
|
||||
],
|
||||
bedTypeOptions: [],
|
||||
familyRelationshipOptions: [],
|
||||
directRelativeOptions: [],
|
||||
@@ -791,6 +820,11 @@ layout("/layouts/platform.html"){
|
||||
this.signupForm.hasFamily = true
|
||||
}
|
||||
this.signupVisible = true
|
||||
this.$nextTick(() => {
|
||||
;[this.$refs.signupForm, this.$refs.directRelativeForm, this.$refs.familyForm].forEach(form => {
|
||||
if (form) form.clearValidate()
|
||||
})
|
||||
})
|
||||
} else {
|
||||
this.$message.warning(res.msg || "查询失败")
|
||||
}
|
||||
@@ -847,29 +881,22 @@ layout("/layouts/platform.html"){
|
||||
this.signupForm.hasFamily = false
|
||||
}
|
||||
},
|
||||
// 家属表格按行校验,缺失项显示在对应输入组件下方。
|
||||
validateFamilies() {
|
||||
if (!this.allowFamily || !this.signupForm.hasFamily) return true
|
||||
if (this.familyData.length === 0) {
|
||||
this.$message.warning("请添加亲属信息")
|
||||
return false
|
||||
this.familyValidationAttempted = true
|
||||
if (this.familyData.length === 0) return false
|
||||
return new Promise(resolve => this.$refs.familyForm.validate(valid => resolve(valid)))
|
||||
},
|
||||
// 未满16岁的家属允许不填身份证,已填写时仍检查格式。
|
||||
validateFamilyIdCard(rule, value, callback) {
|
||||
if (!value) {
|
||||
callback(rule.required ? new Error("必填") : undefined)
|
||||
} else if (!this.isValidIdCard(value)) {
|
||||
callback(new Error("请输入正确的身份证号码"))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
const invalidBase = this.familyData.some(item => !item.familyName || item.age === null || item.age === undefined
|
||||
|| !item.gender || !item.relationship)
|
||||
if (invalidBase) {
|
||||
this.$message.warning("请完善亲属姓名、年龄、性别和与本人关系")
|
||||
return false
|
||||
}
|
||||
const invalidContact = this.familyData.some(item => this.familyContactRequired(item) && (!item.idCard || !item.mobile))
|
||||
if (invalidContact) {
|
||||
this.$message.warning("年满16周岁的亲属必须填写身份证号码和手机号")
|
||||
return false
|
||||
}
|
||||
const invalidIdCard = this.familyData.some(item => item.idCard && !this.isValidIdCard(item.idCard))
|
||||
if (invalidIdCard) {
|
||||
this.$message.warning("请输入正确的身份证号码")
|
||||
return false
|
||||
}
|
||||
return true
|
||||
},
|
||||
familyContactRequired(family) {
|
||||
return family && family.age !== null && family.age !== undefined && Number(family.age) >= 16
|
||||
@@ -885,39 +912,17 @@ layout("/layouts/platform.html"){
|
||||
},
|
||||
validateDirectRelative() {
|
||||
if (!this.isDirectFamilyLine(this.signupForm)) return true
|
||||
if (!this.directRelativeForm.relativeName) {
|
||||
this.$message.warning("请输入亲属姓名")
|
||||
return false
|
||||
}
|
||||
if (!this.directRelativeForm.unitName) {
|
||||
this.$message.warning("请输入亲属所在单位")
|
||||
return false
|
||||
}
|
||||
if (!this.directRelativeForm.relationshipCode) {
|
||||
this.$message.warning("请选择亲属关系")
|
||||
return false
|
||||
}
|
||||
if (!this.directRelativeForm.lineName) {
|
||||
this.$message.warning("请输入直系亲属线路名称")
|
||||
return false
|
||||
}
|
||||
if (!this.directRelativeForm.travelStartTime) {
|
||||
this.$message.warning("请选择出行开始日期")
|
||||
return false
|
||||
}
|
||||
if (!this.directRelativeForm.travelEndTime) {
|
||||
this.$message.warning("请选择出行结束日期")
|
||||
return false
|
||||
}
|
||||
return true
|
||||
return new Promise(resolve => this.$refs.directRelativeForm.validate(valid => resolve(valid)))
|
||||
},
|
||||
submitSignup() {
|
||||
if (!this.signupForm.idCard || !this.signupForm.mobile) {
|
||||
this.$message.warning("请完善报名人身份证号码和手机号")
|
||||
return
|
||||
}
|
||||
if (!this.validateFamilies()) return
|
||||
if (!this.validateDirectRelative()) return
|
||||
async submitSignup() {
|
||||
if (this.signupLoading) return
|
||||
// 同时校验各区域,一次展示所有字段错误,通过后才提交报名。
|
||||
const results = await Promise.all([
|
||||
new Promise(resolve => this.$refs.signupForm.validate(valid => resolve(valid))),
|
||||
this.validateFamilies(),
|
||||
this.validateDirectRelative()
|
||||
])
|
||||
if (results.some(valid => !valid)) return
|
||||
const families = this.allowFamily && this.signupForm.hasFamily ? this.familyData : []
|
||||
const form = Object.assign({}, this.signupForm, {
|
||||
families: JSON.stringify(families),
|
||||
@@ -966,6 +971,7 @@ layout("/layouts/platform.html"){
|
||||
}).catch(() => {})
|
||||
},
|
||||
destroySignup() {
|
||||
this.familyValidationAttempted = false
|
||||
this.signupForm = {}
|
||||
this.familyData = []
|
||||
this.directRelativeForm = {}
|
||||
|
||||
@@ -138,14 +138,14 @@ layout("/layouts/platform.html"){
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="联系人手机" prop="contactPhone">
|
||||
<el-form-item label="联系人手机" prop="contactPhone" required>
|
||||
<el-input v-model="formData.contactPhone" maxlength="30" placeholder="请输入联系人手机"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="邮箱" prop="email">
|
||||
<el-form-item label="邮箱" prop="email" required>
|
||||
<el-input v-model="formData.email" maxlength="100" placeholder="请输入邮箱"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
@@ -221,8 +221,8 @@ layout("/layouts/platform.html"){
|
||||
agencyName: [{ required: true, message: "必填", trigger: ["blur", "change"] }],
|
||||
agencyCode: [{ required: true, message: "必填", trigger: ["blur", "change"] }],
|
||||
contactName: [{ required: true, message: "必填", trigger: ["blur", "change"] }],
|
||||
contactPhone: [{ validator: validateMobile, trigger: ["blur", "change"] }],
|
||||
email: [{ validator: validateEmail, trigger: ["blur", "change"] }]
|
||||
contactPhone: [{ required: true, validator: validateMobile, trigger: ["blur", "change"] }],
|
||||
email: [{ required: true, validator: validateEmail, trigger: ["blur", "change"] }]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -41,6 +41,30 @@ layout("/layouts/platform.html"){
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.qsv-online-answer-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 16px;
|
||||
padding-right: 16px;
|
||||
}
|
||||
|
||||
.qsv-online-quiz-timer {
|
||||
flex-shrink: 0;
|
||||
color: #e6a23c;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.qsv-online-description {
|
||||
line-height: 1.8;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
|
||||
.qsv-online-description img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.qsv-online-preview-title {
|
||||
margin: 0;
|
||||
font-size: 18px;
|
||||
@@ -90,6 +114,33 @@ layout("/layouts/platform.html"){
|
||||
min-width: 72px;
|
||||
}
|
||||
|
||||
.qsv-online-result-score {
|
||||
color: #409eff;
|
||||
font-size: 28px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.qsv-online-result-tags {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.qsv-online-result-option {
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.qsv-online-result-option.is-correct {
|
||||
color: #67c23a;
|
||||
}
|
||||
|
||||
.qsv-online-subject-result {
|
||||
margin-top: 12px;
|
||||
color: #f56c6c;
|
||||
}
|
||||
|
||||
.qsv-online-subject-result.is-correct {
|
||||
color: #67c23a;
|
||||
}
|
||||
|
||||
.qsv-online-option-fill {
|
||||
width: 520px;
|
||||
max-width: 100%;
|
||||
@@ -495,8 +546,22 @@ layout("/layouts/platform.html"){
|
||||
size="1145px"
|
||||
custom-class="qsv-online-drawer"
|
||||
append-to-body
|
||||
@closed="stopVoteCountdown">
|
||||
@close="stopAnswerTimers">
|
||||
<div slot="title" class="qsv-online-answer-header">
|
||||
<span>{{answerDialog.title}}</span>
|
||||
<span v-if="answerDialog.activity.category === 'QUIZ' && answerDialog.activity.timeLimit > 0 && !answerDialog.readonly" class="qsv-online-quiz-timer">
|
||||
<i class="el-icon-time"></i> 剩余时间:{{quizRemainingText}}
|
||||
</span>
|
||||
</div>
|
||||
<div class="qsv-online-preview-body" v-loading="answerDialog.loading">
|
||||
<div v-if="answerDialog.activity.description" class="qsv-online-subject">
|
||||
<div class="qsv-online-subject-title">说明</div>
|
||||
<div class="qsv-online-description" v-html="answerDialog.activity.description"></div>
|
||||
</div>
|
||||
<div v-if="showQuizResult" class="qsv-online-subject">
|
||||
<div class="qsv-online-subject-title">{{answerDialog.activity.title}}</div>
|
||||
<div class="qsv-online-result-score">总分:{{quizTotalScore}} 分</div>
|
||||
</div>
|
||||
<div v-if="isVoteActivity" class="qsv-online-vote">
|
||||
<div class="qsv-online-vote-header">
|
||||
<h2 class="qsv-online-vote-title">{{answerDialog.activity.title}}</h2>
|
||||
@@ -573,6 +638,11 @@ layout("/layouts/platform.html"){
|
||||
</div>
|
||||
<el-empty v-if="!isVoteActivity && visibleSubjects.length === 0 && !answerDialog.loading" description="暂无题目"></el-empty>
|
||||
<div v-if="!isVoteActivity" v-for="(subject, index) in visibleSubjects" :key="subject.id" class="qsv-online-subject">
|
||||
<div v-if="showQuizResult" class="qsv-online-result-tags">
|
||||
<el-tag v-if="subject.type === 'radio'" size="small">单选</el-tag>
|
||||
<el-tag v-else-if="subject.type === 'checkbox'" size="small">多选</el-tag>
|
||||
<el-tag v-if="subject.score !== undefined && subject.score !== null" size="small">{{subject.score}}分</el-tag>
|
||||
</div>
|
||||
<div class="qsv-online-subject-title">
|
||||
<span v-if="answerDialog.showIndex" class="qsv-online-subject-index">{{index + 1}}.</span>
|
||||
<span>{{subject.title}}</span>
|
||||
@@ -585,7 +655,7 @@ layout("/layouts/platform.html"){
|
||||
:value="getRadioValue(subject)"
|
||||
@input="setRadioValue(subject, $event)">
|
||||
<template v-for="option in subject.options">
|
||||
<el-radio :key="option.id" :label="option.id">{{option.text}}</el-radio>
|
||||
<el-radio :key="option.id" :label="option.id"><span :class="{ 'qsv-online-result-option': showQuizResult, 'is-correct': showQuizResult && option.isCorrect }">{{option.text}}<span v-if="showQuizResult && option.isCorrect">(正确答案)</span></span></el-radio>
|
||||
<el-input
|
||||
v-if="isOptionFillVisible(subject, option)"
|
||||
:key="option.id + '-fill'"
|
||||
@@ -604,7 +674,7 @@ layout("/layouts/platform.html"){
|
||||
:disabled="answerDialog.readonly"
|
||||
@change="onCheckboxChange(subject)">
|
||||
<template v-for="option in subject.options">
|
||||
<el-checkbox :key="option.id" :label="option.id">{{option.text}}</el-checkbox>
|
||||
<el-checkbox :key="option.id" :label="option.id"><span :class="{ 'qsv-online-result-option': showQuizResult, 'is-correct': showQuizResult && option.isCorrect }">{{option.text}}<span v-if="showQuizResult && option.isCorrect">(正确答案)</span></span></el-checkbox>
|
||||
<el-input
|
||||
v-if="isOptionFillVisible(subject, option)"
|
||||
:key="option.id + '-fill'"
|
||||
@@ -623,6 +693,10 @@ layout("/layouts/platform.html"){
|
||||
:readonly="answerDialog.readonly"
|
||||
v-model="subject.userFillContent"
|
||||
:placeholder="'请输入' + subject.title"></el-input>
|
||||
<div v-if="showQuizResult && getSubjectResult(subject)" class="qsv-online-subject-result" :class="{ 'is-correct': getSubjectResult(subject).isCorrect }">
|
||||
<i :class="getSubjectResult(subject).isCorrect ? 'el-icon-circle-check' : 'el-icon-circle-close'"></i>
|
||||
{{getSubjectResult(subject).isCorrect ? '回答正确' : '回答错误'}},得分:{{getSubjectResult(subject).score || 0}} 分
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="qsv-online-footer">
|
||||
@@ -709,6 +783,10 @@ layout("/layouts/platform.html"){
|
||||
minutes: 0,
|
||||
seconds: 0
|
||||
},
|
||||
quizTimer: null,
|
||||
quizStartedAt: 0,
|
||||
quizElapsedSeconds: 0,
|
||||
quizExpired: false,
|
||||
voteTimer: null,
|
||||
voteRankVisible: false,
|
||||
voteDetailVisible: false,
|
||||
@@ -717,6 +795,21 @@ layout("/layouts/platform.html"){
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
// 仅已完成的计分答题显示成绩和正确答案,普通调查与投票保持原有展示。
|
||||
showQuizResult() {
|
||||
return this.answerDialog.activity.category === "QUIZ" && !!this.answerDialog.answerRecord.isFinish
|
||||
},
|
||||
quizRemainingSeconds() {
|
||||
return Math.max(0, Number(this.answerDialog.activity.timeLimit || 0) * 60 - this.answerDialog.quizElapsedSeconds)
|
||||
},
|
||||
quizRemainingText() {
|
||||
const seconds = this.quizRemainingSeconds
|
||||
return Math.floor(seconds / 60) + '分' + String(seconds % 60).padStart(2, '0') + '秒'
|
||||
},
|
||||
quizTotalScore() {
|
||||
const answers = this.answerDialog.answerRecord.extJson || {}
|
||||
return Object.keys(answers).reduce((total, id) => total + Number(answers[id].score || 0), 0)
|
||||
},
|
||||
visibleSubjects() {
|
||||
return this.answerDialog.subjects.filter((subject) => {
|
||||
return this.isSubjectVisible(subject)
|
||||
@@ -862,6 +955,10 @@ layout("/layouts/platform.html"){
|
||||
this.$message.warning(unavailableMessage)
|
||||
return
|
||||
}
|
||||
this.stopAnswerTimers()
|
||||
this.answerDialog.quizStartedAt = 0
|
||||
this.answerDialog.quizElapsedSeconds = 0
|
||||
this.answerDialog.quizExpired = false
|
||||
this.answerDialog.visible = true
|
||||
this.answerDialog.loading = true
|
||||
this.answerDialog.readonly = row.actionType === "view"
|
||||
@@ -908,6 +1005,7 @@ layout("/layouts/platform.html"){
|
||||
this.answerDialog.answerRecord = res.data || {}
|
||||
this.answerDialog.readonly = !!this.answerDialog.answerRecord.isFinish
|
||||
this.initAnswer()
|
||||
this.startQuizTimer()
|
||||
}
|
||||
})
|
||||
},
|
||||
@@ -928,6 +1026,10 @@ layout("/layouts/platform.html"){
|
||||
this.clearHiddenSubjectAnswers()
|
||||
}
|
||||
},
|
||||
getSubjectResult(subject) {
|
||||
const answers = this.answerDialog.answerRecord.extJson || {}
|
||||
return answers[subject.id]
|
||||
},
|
||||
getRadioValue(subject) {
|
||||
return subject.userSelectOptionIds && subject.userSelectOptionIds.length > 0
|
||||
? subject.userSelectOptionIds[0]
|
||||
@@ -985,6 +1087,43 @@ layout("/layouts/platform.html"){
|
||||
}
|
||||
})
|
||||
},
|
||||
// 使用实际经过时间计时,避免切换浏览器标签后定时器节流导致倒计时变慢。
|
||||
startQuizTimer() {
|
||||
this.stopQuizTimer()
|
||||
if (!this.answerDialog.visible || this.answerDialog.readonly || this.answerDialog.activity.category !== "QUIZ") return
|
||||
this.answerDialog.quizStartedAt = Date.now()
|
||||
this.answerDialog.quizElapsedSeconds = 0
|
||||
this.answerDialog.quizExpired = false
|
||||
this.answerDialog.quizTimer = setInterval(() => this.updateQuizTimer(), 1000)
|
||||
},
|
||||
updateQuizTimer() {
|
||||
if (!this.answerDialog.quizStartedAt || this.answerDialog.readonly || !this.answerDialog.visible) return
|
||||
this.answerDialog.quizElapsedSeconds = Math.floor((Date.now() - this.answerDialog.quizStartedAt) / 1000)
|
||||
if (Number(this.answerDialog.activity.timeLimit) > 0 && this.quizRemainingSeconds === 0
|
||||
&& !this.answerDialog.quizExpired && !this.answerDialog.submitLoading) {
|
||||
this.answerDialog.quizExpired = true
|
||||
this.stopQuizTimer()
|
||||
// 与手机端一致:超时提示重新答题,不自动提交未完成的答卷。
|
||||
this.$alert("答题时间到,请重新进入答题", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
showClose: false,
|
||||
closeOnClickModal: false,
|
||||
closeOnPressEscape: false
|
||||
}).then(() => {
|
||||
this.answerDialog.visible = false
|
||||
})
|
||||
}
|
||||
},
|
||||
stopQuizTimer() {
|
||||
if (this.answerDialog.quizTimer) {
|
||||
clearInterval(this.answerDialog.quizTimer)
|
||||
this.answerDialog.quizTimer = null
|
||||
}
|
||||
},
|
||||
stopAnswerTimers() {
|
||||
this.stopQuizTimer()
|
||||
this.stopVoteCountdown()
|
||||
},
|
||||
startVoteCountdown() {
|
||||
this.stopVoteCountdown()
|
||||
this.updateVoteCountdown()
|
||||
@@ -1196,6 +1335,8 @@ layout("/layouts/platform.html"){
|
||||
return true
|
||||
},
|
||||
submitAnswer() {
|
||||
this.updateQuizTimer()
|
||||
if (this.answerDialog.readonly || this.answerDialog.quizExpired || this.answerDialog.submitLoading) return
|
||||
if (!this.validateAnswer()) {
|
||||
return
|
||||
}
|
||||
@@ -1204,11 +1345,14 @@ layout("/layouts/platform.html"){
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(() => {
|
||||
this.updateQuizTimer()
|
||||
if (!this.answerDialog.visible || this.answerDialog.readonly || this.answerDialog.quizExpired || this.answerDialog.submitLoading) return
|
||||
this.answerDialog.submitLoading = true
|
||||
$.post("/platform/qsv/online/submitAnswer", {
|
||||
answer: JSON.stringify({
|
||||
activityId: this.answerDialog.activity.id,
|
||||
answerRecordId: this.answerDialog.answerRecordId,
|
||||
answerTime: this.answerDialog.quizElapsedSeconds,
|
||||
subjects: this.submitSubjects.map((subject) => {
|
||||
return {
|
||||
id: subject.id,
|
||||
@@ -1221,7 +1365,14 @@ layout("/layouts/platform.html"){
|
||||
}).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.$message.success(res.msg)
|
||||
this.answerDialog.visible = false
|
||||
if (this.answerDialog.activity.category === "QUIZ") {
|
||||
// 提交后读取服务端判题结果,直接展示成绩并防止重复提交。
|
||||
this.answerDialog.readonly = true
|
||||
this.stopQuizTimer()
|
||||
this.loadAnswerRecord()
|
||||
} else {
|
||||
this.answerDialog.visible = false
|
||||
}
|
||||
this.pageData()
|
||||
} else {
|
||||
this.$message.error(res.msg)
|
||||
@@ -1237,7 +1388,7 @@ layout("/layouts/platform.html"){
|
||||
this.openAnswerFromUrl()
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.stopVoteCountdown()
|
||||
this.stopAnswerTimers()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -55,7 +55,7 @@ layout("/layouts/platform.html"){
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-descriptions-item>-->
|
||||
<el-descriptions-item label="证明人">
|
||||
<!-- <el-descriptions-item label="证明人">
|
||||
<el-form-item prop="certifierUserId" label="证明人">
|
||||
<el-select
|
||||
style="width: 100%"
|
||||
@@ -75,7 +75,7 @@ layout("/layouts/platform.html"){
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-descriptions-item>
|
||||
</el-descriptions-item> -->
|
||||
<el-descriptions-item label="慰问类型">
|
||||
<el-form-item prop="type" label="慰问类型">
|
||||
<el-select v-model="formData.type" @change="typeChange" style="width: 100%"
|
||||
@@ -112,14 +112,14 @@ layout("/layouts/platform.html"){
|
||||
</el-form-item>
|
||||
</el-descriptions-item>
|
||||
|
||||
<el-descriptions-item label="收款账户">
|
||||
<el-descriptions-item label="收款账户" v-if="!['A', 'D'].includes(formData.typeCode)">
|
||||
<el-form-item prop="bankCardNumber" label="收款账户">
|
||||
<el-input maxlength="20" v-model="formData.bankCardNumber" placeholder="请填写收款账户"
|
||||
<el-input maxlength="30" v-model="formData.bankCardNumber" placeholder="请填写银行卡号或对公账户号"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
</el-descriptions-item>
|
||||
|
||||
<el-descriptions-item label="户名">
|
||||
<el-descriptions-item label="户名" v-if="!['A', 'D'].includes(formData.typeCode)">
|
||||
<el-form-item prop="bankUserName" label="户名">
|
||||
<el-input maxlength="20" v-model="formData.bankUserName"
|
||||
placeholder="请填写户名"
|
||||
@@ -127,7 +127,7 @@ layout("/layouts/platform.html"){
|
||||
</el-form-item>
|
||||
</el-descriptions-item>
|
||||
|
||||
<el-descriptions-item label="开户行" >
|
||||
<el-descriptions-item label="开户行" v-if="!['A', 'D'].includes(formData.typeCode)">
|
||||
<el-form-item prop="bankOfDeposit" label="开户行">
|
||||
<el-input maxlength="20" v-model="formData.bankOfDeposit"
|
||||
placeholder="请填写开户行"
|
||||
@@ -173,10 +173,12 @@ layout("/layouts/platform.html"){
|
||||
</template>
|
||||
|
||||
|
||||
</el-descriptions>
|
||||
<el-descriptions :column="3" border>
|
||||
<el-descriptions-item label="申请事由" :span="3">
|
||||
<el-form-item prop="remark" label="申请事由">
|
||||
<el-input maxlength="500" v-model="formData.remark" placeholder="请填写申请事由"
|
||||
type="textarea" :autosize="{ minRows: 4, maxRows: 8}"></el-input>
|
||||
type="textarea" :rows="3" resize="none"></el-input>
|
||||
</el-form-item>
|
||||
</el-descriptions-item>
|
||||
|
||||
@@ -238,7 +240,10 @@ layout("/layouts/platform.html"){
|
||||
payUserId: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
||||
type: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
||||
way: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
||||
money: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
||||
money: [
|
||||
{ required: true, message: "请填写慰问金额", trigger: ["change", "blur"] },
|
||||
{ validator: (rule, value, callback) => callback(this.validateMoney(value) ? undefined : new Error("慰问金额须大于0且不超过10000元,最多两位小数")), trigger: ["change", "blur"] }
|
||||
],
|
||||
occurTime: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
||||
child: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
||||
hospital: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
||||
@@ -247,14 +252,20 @@ layout("/layouts/platform.html"){
|
||||
hospitalBy: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
||||
deadImmediateFamily: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
||||
remark: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
||||
files: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
||||
files: [{ required: true, type: "array", min: 1, max: 5, message: "请上传1至5个附件", trigger: ["change", "blur"] }],
|
||||
signature: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
||||
handlerUserId: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
||||
certifierUserId: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
||||
bankCardNumber: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
||||
// certifierUserId: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
||||
bankCardNumber: [
|
||||
{ required: true, message: "请填写银行卡号或对公账户号", trigger: ["change", "blur"] },
|
||||
{ pattern: /^[0-9]{6,30}$/, message: "收款账户须为6至30位数字(银行卡号或对公账户号)", trigger: ["change", "blur"] }
|
||||
],
|
||||
bankUserName: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
||||
bankOfDeposit: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
||||
thisYearHospitalizationNum: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
||||
thisYearHospitalizationNum: [
|
||||
{ required: true, message: "必填", trigger: ["change", "blur"] },
|
||||
{ type: "integer", min: 0, max: 10000, message: "住院次数须为0至10000的整数", trigger: ["change", "blur"] }
|
||||
],
|
||||
leaveHospitalTime: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
||||
hospitalizationTime: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
||||
},
|
||||
@@ -268,6 +279,9 @@ layout("/layouts/platform.html"){
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
validateMoney(value) {
|
||||
return /^(0|[1-9][0-9]*)(\.[0-9]{1,2})?$/.test(String(value)) && Number(value) > 0 && Number(value) <= 10000
|
||||
},
|
||||
createRemoteMethod(options) {
|
||||
return (keyword) => {
|
||||
this.selectQueryUser(keyword, options)
|
||||
|
||||
@@ -37,12 +37,12 @@ const basicForm = {
|
||||
<el-radio-button :label="false">不上传</el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-form-item>-->
|
||||
<!-- <el-form-item label="是否上传附件" prop="isUploadFile">-->
|
||||
<!-- <el-radio-group v-model="formData.isUploadFile">-->
|
||||
<!-- <el-radio-button :label="true">是</el-radio-button>-->
|
||||
<!-- <el-radio-button :label="false">否</el-radio-button>-->
|
||||
<!-- </el-radio-group>-->
|
||||
<!-- </el-form-item>-->
|
||||
<el-form-item label="是否上传附件" prop="isUploadFile">
|
||||
<el-radio-group v-model="formData.isUploadFile">
|
||||
<el-radio-button :label="true">是</el-radio-button>
|
||||
<el-radio-button :label="false">否</el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="上传附件说明" prop="uploadFileDesc" v-if="formData.isUploadFile">
|
||||
<el-input v-model="formData.uploadFileDesc" maxlength="50" clearable placeholder="请填写上传附件说明"></el-input>
|
||||
</el-form-item>
|
||||
|
||||
+64
-57
@@ -26,7 +26,7 @@ layout("/layouts/platform.html"){
|
||||
</el-form-item>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="受补助人">
|
||||
<el-form-item prop="userName">
|
||||
<el-form-item prop="userId">
|
||||
<template v-if="formData.mode == 2">
|
||||
<el-select :remote-method="queryRecipients"
|
||||
@change="userChange" clearable filterable
|
||||
@@ -51,7 +51,7 @@ layout("/layouts/platform.html"){
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="身份证号" :span="2">
|
||||
<el-form-item prop="idCard">
|
||||
<el-input maxlength="20" clearable placeholder="请填写身份证号"
|
||||
<el-input clearable placeholder="请填写身份证号"
|
||||
v-model="formData.idCard" maxlength="18"></el-input>
|
||||
</el-form-item>
|
||||
</el-descriptions-item>
|
||||
@@ -84,7 +84,7 @@ layout("/layouts/platform.html"){
|
||||
<el-descriptions-item label="手机号码">
|
||||
<el-form-item prop="mobile">
|
||||
<el-input maxlength="11" clearable placeholder="请填写手机号码"
|
||||
v-model="formData.mobile" maxlength="11"></el-input>
|
||||
v-model="formData.mobile"></el-input>
|
||||
</el-form-item>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="家庭年总收入(万元)">
|
||||
@@ -103,6 +103,7 @@ layout("/layouts/platform.html"){
|
||||
<el-input-number
|
||||
v-model="formData.homeNumber"
|
||||
:min="1"
|
||||
:precision="0"
|
||||
:step="1"
|
||||
style="width: 100%"
|
||||
placeholder="请填写家庭人数">
|
||||
@@ -113,7 +114,7 @@ layout("/layouts/platform.html"){
|
||||
<el-form-item prop="homeAddress">
|
||||
<el-input clearable
|
||||
style="width: 100%"
|
||||
v-model="formData.homeAddress"
|
||||
v-model="formData.homeAddress" maxlength="200"
|
||||
placeholder="请填写家庭住址">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
@@ -132,7 +133,7 @@ layout("/layouts/platform.html"){
|
||||
<!-- </el-descriptions-item>-->
|
||||
<el-descriptions-item label="银行卡号" >
|
||||
<el-form-item prop="bankCardNum">
|
||||
<el-input maxlength="20" clearable placeholder="请填写银行卡号"
|
||||
<el-input maxlength="19" clearable placeholder="请填写银行卡号"
|
||||
v-model="formData.bankCardNum"></el-input>
|
||||
</el-form-item>
|
||||
</el-descriptions-item>
|
||||
@@ -152,7 +153,7 @@ layout("/layouts/platform.html"){
|
||||
</el-descriptions-item>
|
||||
|
||||
<el-descriptions-item label="申请金额(元)">
|
||||
<el-form-item prop="applyMoney" :rules="[{required:true,type:'number',min:0.01,message:'请填写大于零的申请金额',trigger:['change','blur']}]">
|
||||
<el-form-item prop="applyMoney">
|
||||
<el-input-number v-model="formData.applyMoney" :precision="2" :min="0.01" placeholder="请输入申请金额"></el-input-number>
|
||||
</el-form-item>
|
||||
</el-descriptions-item>
|
||||
@@ -198,8 +199,8 @@ layout("/layouts/platform.html"){
|
||||
<template slot-scope="{row,$index}">
|
||||
<el-form-item label-width="0"
|
||||
:prop="'familyList.'+$index+'.relation'"
|
||||
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
|
||||
<el-input v-model="row.relation" placeholder="请填写与本人关系" clearable></el-input>
|
||||
:rules="textRules('与本人关系', 50)">
|
||||
<el-input v-model="row.relation" maxlength="50" placeholder="请填写与本人关系" clearable></el-input>
|
||||
</el-form-item>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@@ -207,8 +208,8 @@ layout("/layouts/platform.html"){
|
||||
<template slot-scope="{row,$index}">
|
||||
<el-form-item label-width="0"
|
||||
:prop="'familyList.'+$index+'.name'"
|
||||
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
|
||||
<el-input v-model="row.name" placeholder="请填写姓名" clearable></el-input>
|
||||
:rules="textRules('姓名', 100)">
|
||||
<el-input v-model="row.name" maxlength="100" placeholder="请填写姓名" clearable></el-input>
|
||||
</el-form-item>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@@ -216,9 +217,9 @@ layout("/layouts/platform.html"){
|
||||
<template slot-scope="{row,$index}">
|
||||
<el-form-item label-width="0"
|
||||
:prop="'familyList.'+$index+'.age'"
|
||||
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
|
||||
:rules="[{required:true,type:'integer',min:1,max:100,message:'年龄须为1至100的整数',trigger:['change','blur']}]">
|
||||
<el-input-number v-model="row.age" placeholder="年龄" :min="1"
|
||||
:max="100" :step="1" style="width: 100%" clearable></el-input-number>
|
||||
:max="100" :precision="0" :step="1" style="width: 100%" clearable></el-input-number>
|
||||
</el-form-item>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@@ -226,8 +227,8 @@ layout("/layouts/platform.html"){
|
||||
<template slot-scope="{row,$index}">
|
||||
<el-form-item label-width="0"
|
||||
:prop="'familyList.'+$index+'.homeUnit'"
|
||||
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
|
||||
<el-input v-model="row.homeUnit" placeholder="请填写工作单位" clearable></el-input>
|
||||
:rules="textRules('工作单位', 200)">
|
||||
<el-input v-model="row.homeUnit" maxlength="200" placeholder="请填写工作单位" clearable></el-input>
|
||||
</el-form-item>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@@ -235,9 +236,9 @@ layout("/layouts/platform.html"){
|
||||
<template slot-scope="{row,$index}">
|
||||
<el-form-item label-width="0"
|
||||
:prop="'familyList.'+$index+'.yearIncome'"
|
||||
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
|
||||
:rules="[{validator:validateIncome,required:true,trigger:['change','blur']}]">
|
||||
<el-input-number v-model="row.yearIncome" placeholder="年收入"
|
||||
:min="0" :step="1" style="width: 100%" clearable></el-input-number>
|
||||
:min="0" :precision="2" :step="1" style="width: 100%" clearable></el-input-number>
|
||||
</el-form-item>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@@ -245,8 +246,8 @@ layout("/layouts/platform.html"){
|
||||
<template slot-scope="{row,$index}">
|
||||
<el-form-item label-width="0"
|
||||
:prop="'familyList.'+$index+'.remarks'"
|
||||
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
|
||||
<el-input v-model="row.remarks" placeholder="请填写备注" clearable></el-input>
|
||||
:rules="textRules('备注', 500)">
|
||||
<el-input v-model="row.remarks" maxlength="500" placeholder="请填写备注" clearable></el-input>
|
||||
</el-form-item>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@@ -326,22 +327,37 @@ layout("/layouts/platform.html"){
|
||||
applyCount: '1',
|
||||
},
|
||||
formRules: {
|
||||
proxyUserName: [{required: true, message: '必填', trigger: ['blur', 'change']}],
|
||||
proxyLoginName: [{required: true, message: '必填', trigger: ['blur', 'change']}],
|
||||
sex: [{required: true, message: '请填写性别', trigger: ['blur', 'change']}],
|
||||
userName: [{required: true, message: '请填写受补助人', trigger: ['blur', 'change']}],
|
||||
unitName: [{required: true, message: '请填写所属单位', trigger: ['blur', 'change']}],
|
||||
proxyUserName: this.textRules('填写人姓名', 100),
|
||||
proxyLoginName: this.textRules('填写人工号', 100),
|
||||
mode: [{required: true, type: 'enum', enum: ['1', '2'], message: '请选择申请模式', trigger: ['blur', 'change']}],
|
||||
sex: [{required: true, type: 'enum', enum: ['男', '女'], message: '请选择性别', trigger: ['blur', 'change']}],
|
||||
userId: [{required: true, message: '请选择受补助人', trigger: ['blur', 'change']}],
|
||||
unitName: this.textRules('所属单位', 500),
|
||||
unionName: [{required: true, message: '请填写所属工会', trigger: ['blur', 'change']}],
|
||||
homeAddress: [{required: true, message: '请填写家庭住址', trigger: ['blur', 'change']}],
|
||||
mobile: [{required: true, message: '请填写手机号码', trigger: ['blur', 'change']}],
|
||||
idCard: [{required: true, message: '请填写身份证号', trigger: ['blur', 'change']}],
|
||||
bankCardNum: [{required: true, message: '请填写收款账户卡号', trigger: ['blur', 'change']}],
|
||||
homeAddress: this.textRules('家庭住址', 200),
|
||||
mobile: [
|
||||
{required: true, message: '请填写手机号码', trigger: ['blur', 'change']},
|
||||
{pattern: /^1[3-9]\d{9}$/, message: '请输入正确的11位手机号码', trigger: ['blur', 'change']}
|
||||
],
|
||||
idCard: [{validator: (rule, value, callback) => {
|
||||
const result = this.isValidIdCard(value || '')
|
||||
callback(result.status === 0 ? new Error(result.msg) : undefined)
|
||||
}, required: true, trigger: ['blur', 'change']}],
|
||||
bankCardNum: [{validator: (rule, value, callback) => {
|
||||
const result = this.validateCard(value || '')
|
||||
callback(result.status === 0 ? new Error(result.msg) : undefined)
|
||||
}, required: true, trigger: ['blur', 'change']}],
|
||||
bankUserName: [{required: true, message: '请填写户名', trigger: ['blur', 'change']}],
|
||||
bankOfDeposit: [{required: true, message: '请填写开户行', trigger: ['blur', 'change']}],
|
||||
position: [{required: true, message: '请填写职务', trigger: ['blur', 'change']}],
|
||||
officialCapacity: [{required: true, message: '请填写职称', trigger: ['blur', 'change']}],
|
||||
subsidyStandards: [{required: true, message: '请选择困难类型', trigger: ['blur', 'change']}],
|
||||
reason: [{required: true, message: '请填写申请原因', trigger: ['blur', 'change']}],
|
||||
bankOfDeposit: this.textRules('开户行', 30),
|
||||
position: this.textRules('职务', 20),
|
||||
officialCapacity: this.textRules('职称', 20),
|
||||
homeIncome: [{validator: this.validateIncome, required: true, trigger: ['blur', 'change']}],
|
||||
homeNumber: [{required: true, type: 'integer', min: 1, message: '家庭人数须为大于零的整数', trigger: ['blur', 'change']}],
|
||||
subsidy: this.textRules('补助类型', 500),
|
||||
subsidyStandards: this.textRules('困难类型', 500),
|
||||
applyMoney: [{validator: this.validateMoney, required: true, trigger: ['blur', 'change']}],
|
||||
reason: this.textRules('生活致困原因', 500),
|
||||
sign: [{required: true, whitespace: true, message: '请完成签字', trigger: ['blur', 'change']}],
|
||||
},
|
||||
|
||||
// 替他人申请相关
|
||||
@@ -349,8 +365,21 @@ layout("/layouts/platform.html"){
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
textRules(label, max) {
|
||||
return [{required: true, whitespace: true, max, message: '请填写' + label + ',且不超过' + max + '个字符', trigger: ['blur', 'change']}]
|
||||
},
|
||||
validateIncome(rule, value, callback) {
|
||||
const valid = typeof value === 'number' && Number.isFinite(value) && value >= 0 && /^\d+(\.\d{1,2})?$/.test(String(value))
|
||||
callback(valid ? undefined : new Error('收入须为不小于零的数字,最多保留两位小数'))
|
||||
},
|
||||
validateMoney(rule, value, callback) {
|
||||
const valid = typeof value === 'number' && Number.isFinite(value) && value > 0 && /^\d+(\.\d{1,2})?$/.test(String(value))
|
||||
callback(valid ? undefined : new Error('申请金额须大于零,最多保留两位小数'))
|
||||
},
|
||||
// 保存
|
||||
onSave() {
|
||||
async onSave() {
|
||||
const valid = await this.$refs.formRef.validate().catch(() => false)
|
||||
if (!valid) return
|
||||
this.$confirm("您确定保存吗?", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
@@ -367,24 +396,13 @@ layout("/layouts/platform.html"){
|
||||
|
||||
// 提交
|
||||
async onSubmit() {
|
||||
this.$refs.formRef.validate().then((valid) => {
|
||||
this.$refs.formRef.validate().catch(() => false).then((valid) => {
|
||||
if (valid) {
|
||||
this.$confirm("您确定要提交吗?", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(() => {
|
||||
const result = this.isValidIdCard(this.formData.idCard)
|
||||
if (result.status === 0) {
|
||||
this.$message.warning(result.msg)
|
||||
return
|
||||
}
|
||||
const bankRes = this.validateCard(this.formData.bankCardNum)
|
||||
if (bankRes.status === 0) {
|
||||
this.$message.warning(bankRes.msg)
|
||||
return;
|
||||
}
|
||||
|
||||
this.$axios.post('/platform/difficultHelp/apply/submit', {
|
||||
data: JSON.stringify(this.formData)
|
||||
}).then(res => {
|
||||
@@ -399,7 +417,7 @@ layout("/layouts/platform.html"){
|
||||
},
|
||||
|
||||
async onFinishTask() {
|
||||
this.$refs.formRef.validate().then((valid) => {
|
||||
this.$refs.formRef.validate().catch(() => false).then((valid) => {
|
||||
if (valid) {
|
||||
this.$confirm("您确定要提交吗?", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
@@ -407,17 +425,6 @@ layout("/layouts/platform.html"){
|
||||
type: "warning"
|
||||
}).then(() => {
|
||||
|
||||
const result = this.isValidIdCard(this.formData.idCard)
|
||||
if (result.status === 0) {
|
||||
this.$message.warning(result.msg)
|
||||
return
|
||||
}
|
||||
const bankRes = this.validateCard(this.formData.bankCardNum)
|
||||
if (bankRes.status === 0) {
|
||||
this.$message.warning(bankRes.msg)
|
||||
return;
|
||||
}
|
||||
|
||||
this.$axios.post('/platform/difficultHelp/apply/submitAgain', {
|
||||
data: JSON.stringify(this.formData),
|
||||
taskId: GetQueryString("taskId")
|
||||
|
||||
@@ -62,7 +62,7 @@ const filterUser = {
|
||||
</search-item>
|
||||
|
||||
<search-item label="所属单位">
|
||||
<el-select @change="unitChange" clearable filterable
|
||||
<el-select clearable filterable
|
||||
placeholder="请选择所属单位" style="width: 100%"
|
||||
v-model="pageForm.unitId">
|
||||
<el-option
|
||||
@@ -74,17 +74,6 @@ const filterUser = {
|
||||
</el-select>
|
||||
</search-item>
|
||||
|
||||
<search-item label="三级单位">
|
||||
<el-select clearable filterable placeholder="请先选择所属单位" style="width: 100%"
|
||||
v-model="pageForm.threeUnitId">
|
||||
<el-option
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.id"
|
||||
v-for="item in threeUnitOptions">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</search-item>
|
||||
|
||||
<search-item label="人员类型:">
|
||||
<dict-select clearable code="USER_PERSON_TYPE"
|
||||
@@ -94,13 +83,6 @@ const filterUser = {
|
||||
v-model="pageForm.personTypes"></dict-select>
|
||||
</search-item>
|
||||
|
||||
<search-item label="人员属性:">
|
||||
<dict-select clearable code="USER_ATTRIBUTE"
|
||||
multiple
|
||||
collapse-tags
|
||||
placeholder="请选择人员属性"
|
||||
v-model="pageForm.userAttributes"></dict-select>
|
||||
</search-item>
|
||||
|
||||
<search-item label="在职状态:">
|
||||
<dict-select clearable code="USER_STATE"
|
||||
@@ -169,14 +151,11 @@ const filterUser = {
|
||||
userStates: [],
|
||||
personTypes: [],
|
||||
preparedBys: [],
|
||||
userAttributes: [],
|
||||
unitId: null,
|
||||
threeUnitId: null
|
||||
unitId: null
|
||||
},
|
||||
sexOptions: ["男", "女"],
|
||||
unionOptions: [],
|
||||
unitOptions: [],
|
||||
threeUnitOptions: [],
|
||||
tableColumns: [
|
||||
{ prop: "loginname", label: "工号" },
|
||||
{ prop: "username", label: "姓名" },
|
||||
@@ -185,8 +164,7 @@ const filterUser = {
|
||||
{ prop: "personType", label: "人员类型", sortable: true },
|
||||
{ prop: "userState", label: "在职状态", sortable: true },
|
||||
{ prop: "unionName", label: "所属工会", sortable: true },
|
||||
{ prop: "unitName", label: "所属单位", sortable: true },
|
||||
{ prop: "threeUnitName", label: "三级单位", sortable: true }
|
||||
{ prop: "unitName", label: "所属单位", sortable: true }
|
||||
]
|
||||
}
|
||||
},
|
||||
@@ -208,35 +186,12 @@ const filterUser = {
|
||||
this.$set(this.pageForm, "birthMonths", [])
|
||||
this.$set(this.pageForm, "unionId", null)
|
||||
this.$set(this.pageForm, "unitId", null)
|
||||
this.$set(this.pageForm, "threeUnitId", null)
|
||||
this.threeUnitOptions = []
|
||||
this.$set(this.pageForm, "personTypes", [])
|
||||
this.$set(this.pageForm, "preparedBys", [])
|
||||
this.$set(this.pageForm, "userAttributes", [])
|
||||
this.$set(this.pageForm, "userStates", [])
|
||||
this.$set(this.pageForm, "isMember", null)
|
||||
},
|
||||
|
||||
// 所属单位改变后,仅加载该单位直属的三级单位,避免跨单位筛选。
|
||||
unitChange(unitId) {
|
||||
this.$set(this.pageForm, "threeUnitId", null)
|
||||
this.threeUnitOptions = []
|
||||
if (!unitId) {
|
||||
return
|
||||
}
|
||||
this.$axios.post("/platform/sys/unit/child", { pid: unitId })
|
||||
.then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.threeUnitOptions = res.data || []
|
||||
} else {
|
||||
this.$message.error(res.msg || "三级单位查询失败")
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
this.$message.error("三级单位查询失败,请稍后重试")
|
||||
})
|
||||
},
|
||||
|
||||
pageData() {
|
||||
this.tableLoading = true
|
||||
this.$axios
|
||||
|
||||
@@ -65,10 +65,6 @@ layout("/layouts/platform.html"){
|
||||
<dict-select v-model="pageForm.aidFundMemberUserType" placeholder="请选择人员分类" @change="doSearch"
|
||||
code="AIDFUND_MEMBER_USER_TYPE"></dict-select>
|
||||
</search-item>
|
||||
<search-item label="人员属性">
|
||||
<dict-select v-model="pageForm.userAttribute" placeholder="请选择人员属性" @change="doSearch"
|
||||
code="USER_ATTRIBUTE"></dict-select>
|
||||
</search-item>
|
||||
</search>
|
||||
</el-card>
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ const addUser = {
|
||||
</search-item>
|
||||
|
||||
<search-item label="所属单位">
|
||||
<el-select @change="unitChange" clearable
|
||||
<el-select clearable
|
||||
filterable
|
||||
placeholder="请选择所属单位" style="width: 100%"
|
||||
v-model="pageForm.unitId">
|
||||
@@ -76,17 +76,6 @@ const addUser = {
|
||||
</el-select>
|
||||
</search-item>
|
||||
|
||||
<search-item label="三级单位">
|
||||
<el-select clearable filterable placeholder="请先选择所属单位" style="width: 100%"
|
||||
v-model="pageForm.threeUnitId">
|
||||
<el-option
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.id"
|
||||
v-for="item in threeUnitOptions">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</search-item>
|
||||
|
||||
<search-item label="人员类型:">
|
||||
<dict-select clearable code="USER_PERSON_TYPE"
|
||||
@@ -96,13 +85,6 @@ const addUser = {
|
||||
v-model="pageForm.personTypes"></dict-select>
|
||||
</search-item>
|
||||
|
||||
<search-item label="人员属性:">
|
||||
<dict-select clearable code="USER_ATTRIBUTE"
|
||||
multiple
|
||||
collapse-tags
|
||||
placeholder="请选择人员属性"
|
||||
v-model="pageForm.userAttributes"></dict-select>
|
||||
</search-item>
|
||||
|
||||
<search-item label="在职状态:">
|
||||
<dict-select clearable code="USER_STATE"
|
||||
@@ -171,9 +153,7 @@ const addUser = {
|
||||
birthMonths: [],
|
||||
unionId: null,
|
||||
unitId: null,
|
||||
threeUnitId: null,
|
||||
personTypes: [],
|
||||
userAttributes: [],
|
||||
preparedBys: [],
|
||||
userStates: [],
|
||||
isMember: null
|
||||
@@ -181,7 +161,6 @@ const addUser = {
|
||||
sexOptions: ["男", "女"],
|
||||
unionOptions: [],
|
||||
unitOptions: [],
|
||||
threeUnitOptions: [],
|
||||
tableColumns: [
|
||||
{ prop: "loginname", label: "工号" },
|
||||
{ prop: "username", label: "姓名" },
|
||||
@@ -190,8 +169,7 @@ const addUser = {
|
||||
{ prop: "personType", label: "人员类型", sortable: true },
|
||||
{ prop: "userState", label: "在职状态", sortable: true },
|
||||
{ prop: "unionName", label: "所属工会", sortable: true },
|
||||
{ prop: "unitName", label: "所属单位", sortable: true },
|
||||
{ prop: "threeUnitName", label: "三级单位", sortable: true }
|
||||
{ prop: "unitName", label: "所属单位", sortable: true }
|
||||
]
|
||||
}
|
||||
},
|
||||
@@ -213,10 +191,7 @@ const addUser = {
|
||||
this.$set(this.pageForm, "birthMonths", [])
|
||||
this.$set(this.pageForm, "unionId", null)
|
||||
this.$set(this.pageForm, "unitId", null)
|
||||
this.$set(this.pageForm, "threeUnitId", null)
|
||||
this.$set(this, "threeUnitOptions", [])
|
||||
this.$set(this.pageForm, "personTypes", [])
|
||||
this.$set(this.pageForm, "userAttributes", [])
|
||||
this.$set(this.pageForm, "preparedBys", [])
|
||||
this.$set(this.pageForm, "userStates", [])
|
||||
this.$set(this.pageForm, "isMember", null)
|
||||
@@ -224,7 +199,6 @@ const addUser = {
|
||||
|
||||
async unionIdChange(val) {
|
||||
this.$set(this.pageForm, "unitId", null)
|
||||
this.unitChange(null)
|
||||
if (val) {
|
||||
this.$set(this, "unitOptions", await this.$businessTool.listUnit(val))
|
||||
} else {
|
||||
@@ -232,26 +206,6 @@ const addUser = {
|
||||
}
|
||||
},
|
||||
|
||||
// 所属单位改变后,仅加载该单位直属的三级单位,避免跨单位筛选。
|
||||
unitChange(unitId) {
|
||||
this.$set(this.pageForm, "threeUnitId", null)
|
||||
this.$set(this, "threeUnitOptions", [])
|
||||
if (!unitId) {
|
||||
return
|
||||
}
|
||||
this.$axios.post("/platform/sys/unit/child", { pid: unitId })
|
||||
.then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.$set(this, "threeUnitOptions", res.data || [])
|
||||
} else {
|
||||
this.$message.error(res.msg || "三级单位查询失败")
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
this.$message.error("三级单位查询失败,请稍后重试")
|
||||
})
|
||||
},
|
||||
|
||||
pageData() {
|
||||
this.tableLoading = true
|
||||
this.$axios
|
||||
|
||||
@@ -81,26 +81,12 @@ layout("/layouts/platform.html"){
|
||||
collapse-tags
|
||||
placeholder="请选择所属单位"
|
||||
style="width: 100%"
|
||||
@change="unitIdsChange"
|
||||
v-model="pageForm.unitIds"
|
||||
>
|
||||
<el-option :key="item.id" :label="item.name" :value="item.id" v-for="item in unitOptions"></el-option>
|
||||
</el-select>
|
||||
</search-item>
|
||||
|
||||
<search-item label="三级单位">
|
||||
<el-select
|
||||
clearable
|
||||
filterable
|
||||
multiple
|
||||
collapse-tags
|
||||
placeholder="请先选择所属单位"
|
||||
style="width: 100%"
|
||||
v-model="pageForm.threeUnitIds"
|
||||
>
|
||||
<el-option :key="item.id" :label="item.name" :value="item.id" v-for="item in threeUnitOptions"></el-option>
|
||||
</el-select>
|
||||
</search-item>
|
||||
|
||||
<search-item label="人员类型:">
|
||||
<dict-select
|
||||
@@ -128,10 +114,6 @@ layout("/layouts/platform.html"){
|
||||
<dict-select v-model="pageForm.aidFundMemberUserType" placeholder="请选择人员分类" @change="doSearch"
|
||||
code="AIDFUND_MEMBER_USER_TYPE"></dict-select>
|
||||
</search-item>
|
||||
<search-item label="人员属性">
|
||||
<dict-select v-model="pageForm.userAttributes" placeholder="请选择人员属性" @change="doSearch"
|
||||
code="USER_ATTRIBUTE" clearable multiple collapse-tags></dict-select>
|
||||
</search-item>
|
||||
|
||||
<!-- <search-item label="所选福利:">-->
|
||||
<!-- <el-select clearable placeholder="请选择所选福利" style="width: 100%" v-model="pageForm.optionId">-->
|
||||
@@ -283,7 +265,6 @@ layout("/layouts/platform.html"){
|
||||
},
|
||||
unionOptions: [],
|
||||
unitOptions: [],
|
||||
threeUnitOptions: [],
|
||||
sexOptions: ["男", "女"],
|
||||
projectSelectOptions: [],
|
||||
tableColumns: [
|
||||
@@ -295,7 +276,6 @@ layout("/layouts/platform.html"){
|
||||
{ prop: "userState", label: "在职状态", sortable: true },
|
||||
{ prop: "welfareUnionName", label: "所属工会", sortable: true },
|
||||
{ prop: "welfareUnitName", label: "所属单位", sortable: true },
|
||||
{ prop: "threeUnitName", label: "三级单位", sortable: true },
|
||||
{ prop: "remark", label: "备注", sortable: true }
|
||||
],
|
||||
|
||||
@@ -423,32 +403,6 @@ layout("/layouts/platform.html"){
|
||||
this.doSearch()
|
||||
})
|
||||
},
|
||||
// 根据已选所属单位查询直属三级单位,筛选项只保留当前所属单位范围内的数据。
|
||||
async unitIdsChange(unitIds) {
|
||||
this.$set(this.pageForm, "threeUnitIds", [])
|
||||
this.$set(this, "threeUnitOptions", [])
|
||||
if (!unitIds || unitIds.length === 0) {
|
||||
return
|
||||
}
|
||||
try {
|
||||
const responses = await Promise.all(unitIds.map((unitId) => this.$axios.post("/platform/sys/unit/child", { pid: unitId })))
|
||||
const failedResponse = responses.find((res) => res.code !== 0)
|
||||
if (failedResponse) {
|
||||
this.$message.error(failedResponse.msg || "三级单位查询失败")
|
||||
return
|
||||
}
|
||||
const optionMap = {}
|
||||
responses.forEach((res) => {
|
||||
const options = res.data || []
|
||||
options.forEach((item) => {
|
||||
optionMap[item.id] = item
|
||||
})
|
||||
})
|
||||
this.$set(this, "threeUnitOptions", Object.keys(optionMap).map((id) => optionMap[id]))
|
||||
} catch (e) {
|
||||
this.$message.error("三级单位查询失败,请稍后重试")
|
||||
}
|
||||
},
|
||||
pageData() {
|
||||
this.tableLoading = true
|
||||
this.$axios
|
||||
|
||||
@@ -16,6 +16,11 @@ layout("/layouts/platform_h5.html"){
|
||||
</div>
|
||||
|
||||
<div class="quiz-card-scroll" v-if="!answerRecord.isFinish">
|
||||
<van-collapse v-if="activity.description" v-model="descriptionPanels" class="quiz-description" @change="adaptDescriptionToMobile">
|
||||
<van-collapse-item title="说明" name="description" :value="descriptionPanels.length ? '收起' : '展开'">
|
||||
<div ref="descriptionContent" class="quiz-description-content" v-html="activity.description"></div>
|
||||
</van-collapse-item>
|
||||
</van-collapse>
|
||||
<div v-for="(subject, index) in subjects" :key="index" class="subject">
|
||||
<p>{{index+1}}、{{ subject.title }}</p>
|
||||
<div class="tag">
|
||||
@@ -65,6 +70,7 @@ layout("/layouts/platform_h5.html"){
|
||||
H5JumpTo: GetQueryString("H5JumpTo"),
|
||||
subjects: [],
|
||||
activity: {},
|
||||
descriptionPanels: [],
|
||||
isFinished: false,
|
||||
answerRecord: {},
|
||||
answerRecordId: null,
|
||||
@@ -100,6 +106,28 @@ layout("/layouts/platform_h5.html"){
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 按原有字号层次缩小大字,不覆盖富文本颜色、字重、对齐等样式。
|
||||
adaptDescriptionToMobile() {
|
||||
this.$nextTick(() => {
|
||||
const content = this.$refs.descriptionContent
|
||||
if (!content || !this.descriptionPanels.length || content.dataset.mobileAdapted) return
|
||||
// 先读取全部字号,避免父元素缩放后影响子元素的继承字号计算。
|
||||
const sizes = [content, ...content.querySelectorAll('*')].map(element => ({
|
||||
element,
|
||||
size: parseFloat(window.getComputedStyle(element).fontSize)
|
||||
}))
|
||||
const maxSize = sizes.reduce((max, item) => Math.max(max, item.size || 0), 0)
|
||||
if (maxSize > 22) {
|
||||
const ratio = 8 / (maxSize - 14)
|
||||
sizes.forEach(({ element, size }) => {
|
||||
if (!Number.isFinite(size)) return
|
||||
const mobileSize = size > 14 ? 14 + (size - 14) * ratio : size
|
||||
element.style.setProperty('font-size', mobileSize + 'px', 'important')
|
||||
})
|
||||
}
|
||||
content.dataset.mobileAdapted = 'true'
|
||||
})
|
||||
},
|
||||
getCategoryPageTitle(category, defaultTitle) {
|
||||
const titleMap = {
|
||||
QUIZ: "在线答题",
|
||||
@@ -412,6 +440,25 @@ layout("/layouts/platform_h5.html"){
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.quiz-description {
|
||||
margin-bottom: 14px;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.quiz-description-content {
|
||||
color: #303133;
|
||||
line-height: 1.8;
|
||||
overflow-wrap: break-word;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
|
||||
/deep/ .quiz-description-content img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.subject {
|
||||
background: #fff;
|
||||
padding: 15px;
|
||||
|
||||
@@ -276,8 +276,22 @@ layout("/layouts/platform_h5.html"){
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* 导航栏参与弹层布局,正文独立滚动,避免固定导航遮住首张卡片。 */
|
||||
.tour-record-popup {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
padding-top: env(safe-area-inset-top);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.tour-record-popup > .van-nav-bar {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.tour-popup-body {
|
||||
height: calc(100vh - 46px);
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
overflow-y: auto;
|
||||
padding: 10px 12px 76px;
|
||||
background: #f4f6f8;
|
||||
@@ -594,7 +608,7 @@ layout("/layouts/platform_h5.html"){
|
||||
}
|
||||
|
||||
.tour-popup-body {
|
||||
padding: 12px 12px 82px;
|
||||
padding: 12px 12px calc(82px + env(safe-area-inset-bottom));
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
|
||||
@@ -616,6 +630,12 @@ layout("/layouts/platform_h5.html"){
|
||||
box-shadow: 0 -6px 18px rgba(38, 66, 103, .08);
|
||||
}
|
||||
|
||||
.tour-bottom-bar .tour-cancel-button {
|
||||
border: 0;
|
||||
color: #65748a;
|
||||
background-color: #f0f2f5;
|
||||
}
|
||||
|
||||
/* 列表页结构与提案校工会预审核保持一致,业务字段及操作条件继续沿用疗休养逻辑。 */
|
||||
.tour-my-page .van-nav-bar {
|
||||
background-color: #fff;
|
||||
@@ -917,8 +937,8 @@ layout("/layouts/platform_h5.html"){
|
||||
</div>
|
||||
</van-popup>
|
||||
|
||||
<van-popup v-model="detailVisible" position="right" :style="{ width: '100%', height: '100%' }" :close-on-click-overlay="false">
|
||||
<van-nav-bar title="报名详情" left-text="返回" left-arrow @click-left="closeHistoryPopup('detail')" fixed placeholder></van-nav-bar>
|
||||
<van-popup v-model="detailVisible" class="tour-record-popup" position="right" :style="{ width: '100%', height: '100%' }" :close-on-click-overlay="false">
|
||||
<van-nav-bar title="报名详情" left-text="返回" left-arrow @click-left="closeHistoryPopup('detail')"></van-nav-bar>
|
||||
<div class="tour-popup-body">
|
||||
<div class="tour-section">
|
||||
<div class="tour-section-title">教职工信息</div>
|
||||
@@ -926,6 +946,7 @@ layout("/layouts/platform_h5.html"){
|
||||
<van-cell title="姓名" :value="detail.userName || ''"></van-cell>
|
||||
<van-cell title="性别" :value="detail.gender || ''"></van-cell>
|
||||
<van-cell title="身份证号" :value="detail.idCard || ''"></van-cell>
|
||||
<van-cell title="手机号" :value="detail.mobile || ''"></van-cell>
|
||||
<van-cell title="所在单位" :value="detail.unitName || ''"></van-cell>
|
||||
<van-cell title="所在工会" :value="detail.unionName || ''"></van-cell>
|
||||
</div>
|
||||
@@ -972,14 +993,15 @@ layout("/layouts/platform_h5.html"){
|
||||
</div>
|
||||
</van-popup>
|
||||
|
||||
<van-popup v-model="signupVisible" position="right" :style="{ width: '100%', height: '100%' }" :close-on-click-overlay="false" @closed="destroySignup">
|
||||
<van-nav-bar title="修改报名" left-text="返回" left-arrow @click-left="closeHistoryPopup('signup')" fixed placeholder></van-nav-bar>
|
||||
<van-popup v-model="signupVisible" class="tour-record-popup" position="right" :style="{ width: '100%', height: '100%' }" :close-on-click-overlay="false" @closed="destroySignup">
|
||||
<van-nav-bar title="修改报名" left-text="返回" left-arrow @click-left="closeHistoryPopup('signup')"></van-nav-bar>
|
||||
<div class="tour-popup-body">
|
||||
<div class="tour-section">
|
||||
<div class="tour-section-title">教职工信息</div>
|
||||
<van-field label="姓名" readonly v-model="signupForm.userName"></van-field>
|
||||
<van-field label="工号" readonly v-model="signupForm.jobNo"></van-field>
|
||||
<van-field label="身份证号" v-model="signupForm.idCard" maxlength="30" placeholder="请填写身份证号"></van-field>
|
||||
<van-field required label="身份证号" v-model="signupForm.idCard" maxlength="30" placeholder="请填写身份证号"></van-field>
|
||||
<van-field required label="手机号" v-model="signupForm.mobile" type="tel" maxlength="11" placeholder="请填写手机号"></van-field>
|
||||
<van-field label="所在工会" readonly v-model="signupForm.unionName"></van-field>
|
||||
</div>
|
||||
|
||||
@@ -1007,12 +1029,12 @@ layout("/layouts/platform_h5.html"){
|
||||
|
||||
<div v-if="isDirectFamilyLine(signupForm)" class="tour-section">
|
||||
<div class="tour-section-title">直系亲属线路</div>
|
||||
<van-field label="亲属姓名" v-model="directRelativeForm.relativeName" maxlength="100" placeholder="请输入亲属姓名"></van-field>
|
||||
<van-field label="所在单位" v-model="directRelativeForm.unitName" maxlength="100" placeholder="请输入所在单位"></van-field>
|
||||
<van-field readonly clickable is-link label="亲属关系" v-model="directRelativeForm.relationshipName" placeholder="请选择亲属关系" @click="openDirectRelativePicker"></van-field>
|
||||
<van-field label="线路名称" v-model="directRelativeForm.lineName" maxlength="100" placeholder="请输入线路名称"></van-field>
|
||||
<van-field label="出行开始" v-model="directRelativeForm.travelStartTime" type="date" placeholder="请选择出行开始日期"></van-field>
|
||||
<van-field label="出行结束" v-model="directRelativeForm.travelEndTime" type="date" placeholder="请选择出行结束日期"></van-field>
|
||||
<van-field required label="亲属姓名" v-model="directRelativeForm.relativeName" maxlength="100" placeholder="请输入亲属姓名"></van-field>
|
||||
<van-field required label="所在单位" v-model="directRelativeForm.unitName" maxlength="100" placeholder="请输入所在单位"></van-field>
|
||||
<van-field required readonly clickable is-link label="亲属关系" v-model="directRelativeForm.relationshipName" placeholder="请选择亲属关系" @click="openDirectRelativePicker"></van-field>
|
||||
<van-field required label="线路名称" v-model="directRelativeForm.lineName" maxlength="100" placeholder="请输入线路名称"></van-field>
|
||||
<van-field required label="出行开始" v-model="directRelativeForm.travelStartTime" type="date" placeholder="请选择出行开始日期"></van-field>
|
||||
<van-field required label="出行结束" v-model="directRelativeForm.travelEndTime" type="date" placeholder="请选择出行结束日期"></van-field>
|
||||
</div>
|
||||
|
||||
<div v-if="allowFamily && !isDirectFamilyLine(signupForm)" class="tour-section">
|
||||
@@ -1054,7 +1076,7 @@ layout("/layouts/platform_h5.html"){
|
||||
:title="familyTabTitle(family, familyIndex)">
|
||||
<div class="tour-family-form">
|
||||
<van-field required label="姓名" v-model="family.familyName" maxlength="100" placeholder="请填写姓名"></van-field>
|
||||
<van-field required label="年龄" v-model.number="family.age" type="digit" placeholder="请填写年龄"></van-field>
|
||||
<van-field required label="年龄" v-model.number="family.age" type="number" :formatter="formatFamilyAge" placeholder="请填写年龄"></van-field>
|
||||
<van-field required label="性别">
|
||||
<template #input>
|
||||
<van-radio-group v-model="family.gender" direction="horizontal">
|
||||
@@ -1065,7 +1087,7 @@ layout("/layouts/platform_h5.html"){
|
||||
</van-field>
|
||||
<van-field :required="familyContactRequired(family)" label="身份证号码" v-model="family.idCard" maxlength="18" placeholder="请填写身份证号码" @blur="normalizeFamilyIdCard(family)"></van-field>
|
||||
<van-field :required="familyContactRequired(family)" label="手机号" v-model="family.mobile" type="tel" maxlength="30" placeholder="请填写手机号"></van-field>
|
||||
<van-field required readonly clickable is-link label="与本人关系" v-model="family.relationship" placeholder="请选择关系" @click="openRelationshipPicker"></van-field>
|
||||
<van-field required readonly clickable is-link label="与本人关系" v-model="family.relationship" placeholder="请选择关系" @click="openRelationshipPicker(familyIndex)"></van-field>
|
||||
<van-field v-if="fillBedInfo" readonly clickable is-link label="床型" v-model="family.bedType" placeholder="请选择房型" @click="openBedPicker('family')"></van-field>
|
||||
<van-field v-if="fillBedInfo" label="床位" v-model="family.bedInfo" maxlength="100" placeholder="请输入床位数量"></van-field>
|
||||
<van-field v-if="fillBedInfo" label="意向拼床人" v-model="family.intendedRoommate" maxlength="100" placeholder="请输入意向拼床人"></van-field>
|
||||
@@ -1087,8 +1109,8 @@ layout("/layouts/platform_h5.html"){
|
||||
<div v-else class="tour-family-empty">暂无亲属,请按需添加</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tour-bottom-bar">
|
||||
<van-button v-if="signupForm.id" type="danger" plain block round :loading="cancelLoading" @click="cancelSignup">取消报名</van-button>
|
||||
<div class="tour-bottom-bar tour-h5-fixed-bar">
|
||||
<van-button v-if="signupForm.id" class="tour-cancel-button" type="default" block round :loading="cancelLoading" @click="cancelSignup">取消报名</van-button>
|
||||
<van-button type="info" block round :loading="signupLoading" @click="submitSignup">提交</van-button>
|
||||
</div>
|
||||
</van-popup>
|
||||
@@ -1442,6 +1464,7 @@ layout("/layouts/platform_h5.html"){
|
||||
userName: "",
|
||||
gender: "",
|
||||
idCard: "",
|
||||
mobile: "",
|
||||
unitId: "",
|
||||
unitName: "",
|
||||
unionId: "",
|
||||
@@ -1601,6 +1624,11 @@ layout("/layouts/platform_h5.html"){
|
||||
isBlankValue(value) {
|
||||
return value === undefined || value === null || !String(value).trim()
|
||||
},
|
||||
// 与 Web 端一致,亲属年龄限定为 0~120 岁整数,清空时保留必填状态。
|
||||
formatFamilyAge(value) {
|
||||
const age = parseInt(value, 10)
|
||||
return Number.isNaN(age) ? "" : String(Math.min(120, Math.max(0, age)))
|
||||
},
|
||||
// 年满16周岁的亲属才强制填写身份证号码和手机号。
|
||||
familyContactRequired(family) {
|
||||
return family && !this.isBlankValue(family.age) && Number(family.age) >= 16
|
||||
|
||||
@@ -307,9 +307,9 @@ layout("/layouts/platform_tour_signup_h5.html"){
|
||||
|
||||
<div v-if="isDirectFamilyLine(signupForm)" class="tour-apply-card">
|
||||
<div class="tour-apply-title">直系亲属线路</div>
|
||||
<van-field label="亲属姓名" v-model="directRelativeForm.relativeName" maxlength="100" placeholder="请输入亲属姓名"></van-field>
|
||||
<van-field label="所在单位" v-model="directRelativeForm.unitName" maxlength="100" placeholder="请输入所在单位"></van-field>
|
||||
<van-field
|
||||
<van-field required label="亲属姓名" v-model="directRelativeForm.relativeName" maxlength="100" placeholder="请输入亲属姓名"></van-field>
|
||||
<van-field required label="所在单位" v-model="directRelativeForm.unitName" maxlength="100" placeholder="请输入所在单位"></van-field>
|
||||
<van-field required
|
||||
label="亲属关系"
|
||||
readonly
|
||||
clickable
|
||||
@@ -318,9 +318,9 @@ layout("/layouts/platform_tour_signup_h5.html"){
|
||||
v-model="directRelativeForm.relationshipName"
|
||||
@click="openDirectRelativePicker">
|
||||
</van-field>
|
||||
<van-field label="线路名称" v-model="directRelativeForm.lineName" maxlength="100" placeholder="请输入线路名称"></van-field>
|
||||
<van-field label="出行开始" v-model="directRelativeForm.travelStartTime" type="date" placeholder="请选择出行开始日期"></van-field>
|
||||
<van-field label="出行结束" v-model="directRelativeForm.travelEndTime" type="date" placeholder="请选择出行结束日期"></van-field>
|
||||
<van-field required label="线路名称" v-model="directRelativeForm.lineName" maxlength="100" placeholder="请输入线路名称"></van-field>
|
||||
<van-field required label="出行开始" v-model="directRelativeForm.travelStartTime" type="date" placeholder="请选择出行开始日期"></van-field>
|
||||
<van-field required label="出行结束" v-model="directRelativeForm.travelEndTime" type="date" placeholder="请选择出行结束日期"></van-field>
|
||||
</div>
|
||||
|
||||
<div class="tour-apply-card">
|
||||
@@ -365,7 +365,7 @@ layout("/layouts/platform_tour_signup_h5.html"){
|
||||
:title="familyTabTitle(family, familyIndex)">
|
||||
<div class="tour-family-form">
|
||||
<van-field required label="姓名" v-model="family.familyName" maxlength="100" placeholder="请填写姓名"></van-field>
|
||||
<van-field required label="年龄" v-model.number="family.age" type="digit" placeholder="请填写年龄"></van-field>
|
||||
<van-field required label="年龄" v-model.number="family.age" type="number" :formatter="formatFamilyAge" placeholder="请填写年龄"></van-field>
|
||||
<van-field required label="性别">
|
||||
<template #input>
|
||||
<van-radio-group v-model="family.gender" direction="horizontal">
|
||||
@@ -753,6 +753,11 @@ layout("/layouts/platform_tour_signup_h5.html"){
|
||||
isBlankValue(value) {
|
||||
return value === undefined || value === null || !String(value).trim()
|
||||
},
|
||||
// 与 Web 端一致,亲属年龄限定为 0~120 岁整数,清空时保留必填状态。
|
||||
formatFamilyAge(value) {
|
||||
const age = parseInt(value, 10)
|
||||
return Number.isNaN(age) ? "" : String(Math.min(120, Math.max(0, age)))
|
||||
},
|
||||
// 年满16周岁的亲属才强制填写身份证号码和手机号。
|
||||
familyContactRequired(family) {
|
||||
return family && !this.isBlankValue(family.age) && Number(family.age) >= 16
|
||||
|
||||
@@ -255,7 +255,7 @@ layout("/layouts/platform_h5.html"){
|
||||
<van-empty description="暂无数据" v-else></van-empty>
|
||||
</van-action-sheet>-->
|
||||
|
||||
<van-field
|
||||
<!-- <van-field
|
||||
v-model="formData.certifierUserName"
|
||||
name="certifierUserName"
|
||||
label="证明人"
|
||||
@@ -288,7 +288,7 @@ layout("/layouts/platform_h5.html"){
|
||||
</template>
|
||||
</div>
|
||||
<van-empty description="暂无数据" v-else></van-empty>
|
||||
</van-action-sheet>
|
||||
</van-action-sheet> -->
|
||||
|
||||
<van-field
|
||||
v-model="formData.typeName"
|
||||
@@ -322,7 +322,7 @@ layout("/layouts/platform_h5.html"){
|
||||
name="money"
|
||||
label="慰问金额"
|
||||
required
|
||||
:rules="[{ required: true }]"
|
||||
:rules="[{ required: true, message: '请填写慰问金额' }, { validator: validateMoney, message: '慰问金额须大于0且不超过10000元,最多两位小数' }]"
|
||||
placeholder="选择慰问类型自动匹配金额"
|
||||
clickable
|
||||
type="number"
|
||||
@@ -353,17 +353,19 @@ layout("/layouts/platform_h5.html"){
|
||||
</van-popup>
|
||||
|
||||
<van-field
|
||||
v-if="!['A', 'D'].includes(formData.typeCode)"
|
||||
v-model="formData.bankCardNumber"
|
||||
label="收款账户"
|
||||
maxlength="20"
|
||||
maxlength="30"
|
||||
clearable
|
||||
name="bankCardNumber"
|
||||
placeholder="请填写收款账户"
|
||||
:rules="[{ required: true }]"
|
||||
placeholder="请填写银行卡号或对公账户号"
|
||||
:rules="[{ required: true, message: '请填写银行卡号或对公账户号' }, { pattern: /^[0-9]{6,30}$/, message: '收款账户须为6至30位数字(银行卡号或对公账户号)' }]"
|
||||
required
|
||||
></van-field>
|
||||
|
||||
<van-field
|
||||
v-if="!['A', 'D'].includes(formData.typeCode)"
|
||||
v-model="formData.bankUserName"
|
||||
label="户名"
|
||||
placeholder="请填写户名"
|
||||
@@ -373,9 +375,10 @@ layout("/layouts/platform_h5.html"){
|
||||
name="bankUserName"
|
||||
></van-field>
|
||||
<van-field
|
||||
v-if="!['A', 'D'].includes(formData.typeCode)"
|
||||
v-model="formData.bankOfDeposit"
|
||||
label="开户行"
|
||||
maxlength="30"
|
||||
maxlength="20"
|
||||
type="textarea"
|
||||
rows="4"
|
||||
autosize
|
||||
@@ -433,8 +436,8 @@ layout("/layouts/platform_h5.html"){
|
||||
></van-datetime-picker>
|
||||
</van-popup>
|
||||
|
||||
<van-field type="digit" label="当年第几次住院"
|
||||
:rules="[{ required: true }]"
|
||||
<van-field type="digit" label="当年第几次住院" name="thisYearHospitalizationNum"
|
||||
:rules="[{ required: true }, { validator: value => /^[0-9]+$/.test(String(value)) && Number(value) <= 10000, message: '住院次数须为0至10000的整数' }]"
|
||||
required
|
||||
placeholder="请输入当年第几次住院"
|
||||
v-model="formData.thisYearHospitalizationNum"></van-field>
|
||||
@@ -443,6 +446,7 @@ layout("/layouts/platform_h5.html"){
|
||||
<van-field
|
||||
v-model="formData.remark"
|
||||
name="remark"
|
||||
maxlength="500"
|
||||
label="申请事由"
|
||||
type="textarea"
|
||||
rows="4"
|
||||
@@ -460,15 +464,18 @@ layout("/layouts/platform_h5.html"){
|
||||
{{ '附件说明:' + chooseType.uploadFileDesc }}
|
||||
</div>
|
||||
<van-cell-group :border="false">
|
||||
<van-field class="direction-column-field" name="avatar" label="">
|
||||
<van-field class="direction-column-field" name="files" label="附件" required
|
||||
:rules="[{ validator: () => Array.isArray(formData.files) && formData.files.length > 0 && formData.files.length <= 5, message: '请上传1至5个附件' }]">
|
||||
<template #input>
|
||||
<h5-file-upload
|
||||
slot="input"
|
||||
:value.sync="formData.files"
|
||||
:upload_number="5"
|
||||
upload_text="上传附件"
|
||||
upload_result_category="array"
|
||||
complete_result
|
||||
></h5-file-upload>
|
||||
<div class="condolence-card__desc">最多上传 5 个文件</div>
|
||||
</template>
|
||||
</van-field>
|
||||
</van-cell-group>
|
||||
@@ -477,7 +484,8 @@ layout("/layouts/platform_h5.html"){
|
||||
<section class="form-section">
|
||||
<h2 class="condolence-card__title">签字确认</h2>
|
||||
<van-cell-group :border="false">
|
||||
<van-field class="direction-column-field" name="signature" label="">
|
||||
<van-field class="direction-column-field" name="signature" label="" :value="formData.signature"
|
||||
:rules="[{ required: true, message: '请填写签字' }]">
|
||||
<template #input>
|
||||
<h5-signature v-model="formData.signature" slot="input"></h5-signature>
|
||||
</template>
|
||||
@@ -532,6 +540,9 @@ layout("/layouts/platform_h5.html"){
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
validateMoney(value) {
|
||||
return /^(0|[1-9][0-9]*)(\.[0-9]{1,2})?$/.test(String(value)) && Number(value) > 0 && Number(value) <= 10000
|
||||
},
|
||||
// 选择出院时间
|
||||
showLeaveHospitalTimePickerClick() {
|
||||
if (this.formData.leaveHospitalTime) {
|
||||
|
||||
+1
-1
@@ -151,7 +151,7 @@ layout("/layouts/platform_h5.html"){
|
||||
<h2 class="condolence-info-card__title">
|
||||
审批签字<span class="condolence-audit-card__required">*</span>
|
||||
</h2>
|
||||
<van-field name="tf_sign" :value="formData.tf_sign" required :rules="[{required:true,message:'请完成审批签字'}]">
|
||||
<van-field name="tf_sign" :value="formData.tf_sign" :rules="[{required:true,message:'请完成审批签字'}]">
|
||||
<template #input><h5-signature v-model="formData.tf_sign" :key="formData.processTaskId"></h5-signature></template>
|
||||
</van-field>
|
||||
</van-form>
|
||||
|
||||
@@ -158,19 +158,44 @@
|
||||
}
|
||||
|
||||
.condolence-info-long-cell {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.condolence-info-card .condolence-attachments .empty-container {
|
||||
height: auto;
|
||||
justify-content: flex-start;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.condolence-info-card .condolence-attachments .empty-text {
|
||||
font-size: inherit;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
.condolence-info-opinion > :first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.condolence-info-opinion > :last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.condolence-signature-image,
|
||||
.condolence-approval-signature-image {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.condolence-info-long-cell .van-cell__title {
|
||||
width: auto;
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
height: 80px;
|
||||
}
|
||||
|
||||
.condolence-info-long-cell .van-cell__value {
|
||||
margin-top: 7px;
|
||||
.condolence-signature-image .van-image__img,
|
||||
.condolence-approval-signature-image {
|
||||
object-fit: contain;
|
||||
object-position: left center;
|
||||
}
|
||||
|
||||
.condolence-signature-image {
|
||||
display: block;
|
||||
.condolence-info-opinion img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
@@ -25,13 +25,13 @@ const condolenceInfo = {
|
||||
<van-cell title="申请人单位">{{ viewData.applyUnitName || '--' }}</van-cell>
|
||||
<van-cell title="申请人工会">{{ viewData.applyUnionName || '--' }}</van-cell>
|
||||
<van-cell title="慰问对象">{{ viewData.helpUserName || '--' }}</van-cell>
|
||||
<van-cell title="证明人">{{ viewData.certifierUserName || '--' }}</van-cell>
|
||||
<!-- <van-cell title="证明人">{{ viewData.certifierUserName || '--' }}</van-cell> -->
|
||||
<van-cell title="慰问类型">{{ viewData.typeName || '--' }}</van-cell>
|
||||
<van-cell title="慰问金额">{{ viewData.money || '--' }}</van-cell>
|
||||
<van-cell title="慰问时间">{{ viewData.occurTime || '--' }}</van-cell>
|
||||
<van-cell title="收款账户">{{ viewData.bankCardNumber || '--' }}</van-cell>
|
||||
<van-cell title="户名">{{ viewData.bankUserName || '--' }}</van-cell>
|
||||
<van-cell class="condolence-info-long-cell" title="开户行">
|
||||
<van-cell title="开户行">
|
||||
{{ viewData.bankOfDeposit || '暂无' }}
|
||||
</van-cell>
|
||||
<template v-if="['2'].includes(viewData.typeCode)">
|
||||
@@ -39,17 +39,18 @@ const condolenceInfo = {
|
||||
<van-cell title="出院时间">{{ viewData.leaveHospitalTime || '--' }}</van-cell>
|
||||
<van-cell title="当年第几次住院(次)">{{ viewData.thisYearHospitalizationNum || '--' }}</van-cell>
|
||||
</template>
|
||||
<van-cell class="condolence-info-long-cell" title="申请事由">
|
||||
<van-cell title="申请事由">
|
||||
{{ viewData.remark || '暂无' }}
|
||||
</van-cell>
|
||||
<van-cell class="condolence-info-long-cell" title="附件">
|
||||
<file-preview :files="viewData.files" complete_result></file-preview>
|
||||
<file-preview class="condolence-attachments" :files="viewData.files" complete_result></file-preview>
|
||||
</van-cell>
|
||||
<van-cell class="condolence-info-long-cell" title="签字">
|
||||
<van-image
|
||||
v-if="viewData.signature"
|
||||
:src="viewData.signature"
|
||||
class="condolence-signature-image"
|
||||
fit="contain"
|
||||
></van-image>
|
||||
<span v-else>暂无签字</span>
|
||||
</van-cell>
|
||||
@@ -86,10 +87,10 @@ const condolenceInfo = {
|
||||
></dict-tag>
|
||||
</van-cell>
|
||||
<van-cell v-if="task.taskFormData && task.taskFormData.sign" title="审批签字">
|
||||
<img :src="task.taskFormData.sign" style="max-width: 100%; height: 80px; object-fit: contain">
|
||||
<img :src="task.taskFormData.sign" class="condolence-approval-signature-image">
|
||||
</van-cell>
|
||||
<van-cell class="condolence-info-long-cell" title="办理意见">
|
||||
<div v-html="task.taskFormData && task.taskFormData.tf_opinion || '暂无'"></div>
|
||||
<van-cell title="办理意见">
|
||||
<div class="condolence-info-opinion" v-html="task.taskFormData && task.taskFormData.tf_opinion || '暂无'"></div>
|
||||
</van-cell>
|
||||
</van-cell-group>
|
||||
</section>
|
||||
|
||||
+18
-1
@@ -151,7 +151,7 @@ layout("/layouts/platform_h5.html"){
|
||||
<h2 class="condolence-info-card__title">
|
||||
审批签字<span class="condolence-audit-card__required">*</span>
|
||||
</h2>
|
||||
<van-field name="tf_sign" :value="formData.tf_sign" required :rules="[{required:true,message:'请完成审批签字'}]">
|
||||
<van-field name="tf_sign" :value="formData.tf_sign" :rules="[{required:true,message:'请完成审批签字'}]">
|
||||
<template #input><h5-signature v-model="formData.tf_sign" :key="formData.processTaskId"></h5-signature></template>
|
||||
</van-field>
|
||||
</van-form>
|
||||
@@ -223,6 +223,23 @@ layout("/layouts/platform_h5.html"){
|
||||
},
|
||||
onReady() {
|
||||
this.queryCondolenceType()
|
||||
this.openTodoTask()
|
||||
},
|
||||
openTodoTask() {
|
||||
const taskId = GetQueryString("taskId")
|
||||
const bizId = GetQueryString("bizId")
|
||||
if (!taskId || !bizId) return
|
||||
this.$axios.post("/flow/common/taskInfo", {taskId}).then((res) => {
|
||||
if (res.code !== 0 || !res.data) return
|
||||
const task = res.data
|
||||
if (task.taskName !== "cbd41337-3c87-4959-9027-809df5c7ef5e") return
|
||||
const row = {id: bizId, taskId: task.id, curTaskName: task.displayName}
|
||||
if (task.taskState === 10 && task.executable && GetQueryString("tab") === "todo") {
|
||||
this.onApproval(row)
|
||||
} else {
|
||||
this.onView(row)
|
||||
}
|
||||
})
|
||||
},
|
||||
onView(row) {
|
||||
this.$set(this, "showApprovalForm", false)
|
||||
|
||||
+1
-1
@@ -151,7 +151,7 @@ layout("/layouts/platform_h5.html"){
|
||||
<h2 class="condolence-info-card__title">
|
||||
审批签字<span class="condolence-audit-card__required">*</span>
|
||||
</h2>
|
||||
<van-field name="tf_sign" :value="formData.tf_sign" required :rules="[{required:true,message:'请完成审批签字'}]">
|
||||
<van-field name="tf_sign" :value="formData.tf_sign" :rules="[{required:true,message:'请完成审批签字'}]">
|
||||
<template #input><h5-signature v-model="formData.tf_sign" :key="formData.processTaskId"></h5-signature></template>
|
||||
</van-field>
|
||||
</van-form>
|
||||
|
||||
+1
-1
@@ -151,7 +151,7 @@ layout("/layouts/platform_h5.html"){
|
||||
<h2 class="condolence-info-card__title">
|
||||
审批签字<span class="condolence-audit-card__required">*</span>
|
||||
</h2>
|
||||
<van-field name="tf_sign" :value="formData.tf_sign" required :rules="[{required:true,message:'请完成审批签字'}]">
|
||||
<van-field name="tf_sign" :value="formData.tf_sign" :rules="[{required:true,message:'请完成审批签字'}]">
|
||||
<template #input><h5-signature v-model="formData.tf_sign" :key="formData.processTaskId"></h5-signature></template>
|
||||
</van-field>
|
||||
</van-form>
|
||||
|
||||
@@ -281,11 +281,13 @@ const todo = {
|
||||
// 处理任务
|
||||
onView(task) {
|
||||
const {taskId, taskKey, instanceId, businessNo, formKey, h5FormKey} = task;
|
||||
if (!h5FormKey) {
|
||||
const mobileFormKey = h5FormKey || (taskKey === "cbd41337-3c87-4959-9027-809df5c7ef5e"
|
||||
? "/platform/condolence/fourthApproval/h5" : "");
|
||||
if (!mobileFormKey) {
|
||||
this.$toast("当前流程暂不支持手机端审核,请前往PC端页面审核!");
|
||||
return;
|
||||
}
|
||||
this.$pjaxReplace(h5FormKey + "?taskId=" + taskId + "&bizId=" + businessNo + "&taskKey=" + taskKey + "&tab=" + this.activeTab)
|
||||
this.$pjaxReplace(mobileFormKey + "?taskId=" + taskId + "&bizId=" + businessNo + "&taskKey=" + taskKey + "&tab=" + this.activeTab)
|
||||
},
|
||||
|
||||
// 根据当前列表类型统一展示流程状态,发起列表保留流程实例的实际状态。
|
||||
|
||||
Reference in New Issue
Block a user