Merge pull request '【修改】文字考点,' (#7) from hyc into master
Reviewed-on: #7
This commit is contained in:
@@ -143,7 +143,11 @@ public class MonitorServiceImpl implements MonitorService {
|
||||
String key = "userCache:" + stuMonitorPaperVo.getTaskId() + ":" + stuMonitorPaperVo.getStuId();
|
||||
MonitorDO info = JsonUtils.parseObject(stringRedisTemplate.opsForValue().get(key), MonitorDO.class);
|
||||
if (info == null) {
|
||||
return 0L;
|
||||
info=monitorMapper.selectOne(
|
||||
new QueryWrapper<MonitorDO>()
|
||||
.eq("task_id", stuMonitorPaperVo.getTaskId())
|
||||
.eq("stu_id", stuMonitorPaperVo.getStuId())
|
||||
);
|
||||
}
|
||||
//获取属性 判断 专业/课程点位
|
||||
Long loginTenantId = SecurityFrameworkUtils.getLoginTenantId();
|
||||
@@ -266,7 +270,7 @@ public class MonitorServiceImpl implements MonitorService {
|
||||
info.setTemporaryId(stuMonitorPaperVo.getTemporaryId());
|
||||
info.setIp(stuMonitorPaperVo.getIp());
|
||||
if (info.getRemainingTime() == null) {
|
||||
stringRedisTemplate.opsForValue().set("userCache:" + stuMonitorPaperVo.getTaskId() + ":" + stuMonitorPaperVo.getStuId(), JsonUtils.toJsonString(info));
|
||||
stringRedisTemplate.opsForValue().set(key, JsonUtils.toJsonString(info));
|
||||
monitorMapper.updateById(info);
|
||||
return 24 * 60 * 60L; // (1天)
|
||||
} else {
|
||||
@@ -320,6 +324,7 @@ public class MonitorServiceImpl implements MonitorService {
|
||||
info.setEndTime(end.format(fmt));
|
||||
// 判分后更新记录
|
||||
monitorMapper.updateById(info);
|
||||
stringRedisTemplate.opsForValue().set(key, JsonUtils.toJsonString(info));
|
||||
return finalRemaining;
|
||||
} else {
|
||||
return 0;
|
||||
@@ -334,7 +339,7 @@ public class MonitorServiceImpl implements MonitorService {
|
||||
LocalDateTime target = now.plusSeconds((long) examTime.toLocalTime().toSecondOfDay());
|
||||
// 没有考场更新结束时间
|
||||
info.setEndTime(target.format(fmt));
|
||||
stringRedisTemplate.opsForValue().set("userCache:" + stuMonitorPaperVo.getTaskId() + ":" + stuMonitorPaperVo.getStuId(), JsonUtils.toJsonString(info));
|
||||
stringRedisTemplate.opsForValue().set(key, JsonUtils.toJsonString(info));
|
||||
monitorMapper.updateById(info);
|
||||
return (long) examTime.toLocalTime().toSecondOfDay();
|
||||
}
|
||||
|
@@ -810,7 +810,7 @@ public class ExamQuestionServiceImpl implements IExamQuestionService {
|
||||
// 批量插入
|
||||
examQuestionMapper.insertExamPsKeywordList(psKeywords);
|
||||
}
|
||||
examQuestionMapper.updateBatch(examQuestion);
|
||||
examQuestionMapper.updateById(examQuestion);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -139,7 +139,7 @@
|
||||
<select id="getSchoolNameTotal" resultType="java.lang.Long">
|
||||
SELECT count(*)
|
||||
FROM system_tenant
|
||||
WHERE id != 1 AND deleted = 0
|
||||
WHERE deleted = 0
|
||||
<if test="name != null and name != ''">
|
||||
AND name LIKE CONCAT('%', #{name}, '%')
|
||||
</if>
|
||||
|
@@ -121,6 +121,8 @@
|
||||
<select id="selectExamSpecialtyBySpId" parameterType="Long" resultMap="ExamSpecialtyResult">
|
||||
<include refid="selectExamSpecialtyVo"/>
|
||||
where sp_id = #{spId}
|
||||
and status = 0
|
||||
and deleted = 0
|
||||
</select>
|
||||
|
||||
<select id="selectExamSpecialtyBySpNameOne" parameterType="String" resultType="ExamSpecialty">
|
||||
@@ -147,6 +149,8 @@
|
||||
SELECT sp_id AS id, sp_name AS name, ancestors, parent_id, status, create_time
|
||||
from exam_specialty
|
||||
where parent_id = #{parentId}
|
||||
and status = 0
|
||||
and deleted = 0
|
||||
</select>
|
||||
<select id="getRoleById" resultType="java.lang.String">
|
||||
select roles
|
||||
|
@@ -141,12 +141,20 @@ public class DocxMaster {
|
||||
Object[] arguments = {paragraph, stylePart, wordMLPackage, ndp};
|
||||
String value = (String) methodWithArgs.invoke(obj, arguments);
|
||||
if (value!=null){
|
||||
// 写入结果
|
||||
judgementWordsVOS = setJudgementWord(
|
||||
judgementWordsVOS,
|
||||
docxFunction + "@" + value,
|
||||
firstName + examName + value
|
||||
);
|
||||
if ("getParagraphListLvlText".equals(function)||("getParagraphListAbstractNumId").equals(function)||("getParagraphListLvlFuHao").equals(function)){
|
||||
judgementWordsVOS = setJudgementWord(
|
||||
judgementWordsVOS,
|
||||
docxFunction + "@" + value,
|
||||
firstName + examName + "【是否正确】"
|
||||
);
|
||||
}else {
|
||||
// 写入结果
|
||||
judgementWordsVOS = setJudgementWord(
|
||||
judgementWordsVOS,
|
||||
docxFunction + "@" + value,
|
||||
firstName + examName + value
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -78,7 +78,7 @@ public class Drawing {
|
||||
String width = String.format("%.2fcm", widthCm);
|
||||
return width;
|
||||
}
|
||||
|
||||
//
|
||||
//布局 锁定横纵比
|
||||
public static String getLayoutLock(List<JudgementWordsVO> judgementWordsVOS, Anchor anchor, int betoLong, WordprocessingMLPackage wordMLPackage) {
|
||||
boolean lock = anchor.getCNvGraphicFramePr().getGraphicFrameLocks().isNoChangeAspect();
|
||||
@@ -134,6 +134,15 @@ public class Drawing {
|
||||
}
|
||||
return "未知";
|
||||
}
|
||||
// 位置 → 水平 → 绝对位置
|
||||
public static String getLayoutHorizontalAbsolute(List<JudgementWordsVO> judgementWordsVOS, Anchor anchor, int betoLong, WordprocessingMLPackage wordMLPackage) {
|
||||
if (anchor == null || anchor.getPositionH() == null) return "未知";
|
||||
|
||||
long offsetEmu = anchor.getPositionH().getPosOffset(); // EMU单位
|
||||
double offsetCm = offsetEmu / 360000.0;
|
||||
|
||||
return String.format("相对于右侧%.2fcm", offsetCm);
|
||||
}
|
||||
|
||||
// 位置 → 水平 → 相对于
|
||||
public static String getLayoutHorizontalRelativeTo(List<JudgementWordsVO> judgementWordsVOS, Anchor anchor, int betoLong, WordprocessingMLPackage wordMLPackage) {
|
||||
@@ -172,7 +181,15 @@ public class Drawing {
|
||||
}
|
||||
return "未知";
|
||||
}
|
||||
// 位置 → 垂直 → 绝对位置
|
||||
public static String getLayoutVerticalAbsolute(List<JudgementWordsVO> judgementWordsVOS, Anchor anchor, int betoLong, WordprocessingMLPackage wordMLPackage) {
|
||||
if (anchor == null || anchor.getPositionV() == null) return "未知";
|
||||
|
||||
long offsetEmu = anchor.getPositionV().getPosOffset(); // EMU单位
|
||||
double offsetCm = offsetEmu / 360000.0;
|
||||
|
||||
return String.format("相对于下侧%.2fcm", offsetCm);
|
||||
}
|
||||
// 位置 → 垂直 → 相对于
|
||||
public static String getLayoutVerticalRelativeTo(List<JudgementWordsVO> judgementWordsVOS, Anchor anchor, int betoLong, WordprocessingMLPackage wordMLPackage) {
|
||||
if (anchor == null || anchor.getPositionV() == null) return "未知";
|
||||
|
@@ -166,7 +166,14 @@ public class DrawingInline {
|
||||
return "未知";
|
||||
}
|
||||
}
|
||||
|
||||
// 位置 → 水平 → 绝对位置
|
||||
public static String getLayoutHorizontalAbsolute(List<JudgementWordsVO> judgementWordsVOS, Inline anchor, int betoLong, WordprocessingMLPackage wordMLPackage) {
|
||||
return "无";
|
||||
}
|
||||
// 位置 → 垂直 → 绝对位置
|
||||
public static String getLayoutVerticalAbsolute(List<JudgementWordsVO> judgementWordsVOS, Inline anchor, int betoLong, WordprocessingMLPackage wordMLPackage) {
|
||||
return "无";
|
||||
}
|
||||
// 位置 → 水平 → 相对于
|
||||
public static String getLayoutHorizontalRelativeTo(List<JudgementWordsVO> judgementWordsVOS, Inline anchor, int betoLong, WordprocessingMLPackage wordMLPackage) {
|
||||
if (anchor == null) return "未知";
|
||||
|
@@ -102,45 +102,71 @@ public class Paragraphs {
|
||||
}
|
||||
/// 段落格式(缩进) 首行缩进 磅
|
||||
public static String getParagraphIndFirstLine(P paragraph, StyleDefinitionsPart stylePart, WordprocessingMLPackage wordMLPackage, NumberingDefinitionsPart ndp) {
|
||||
if (paragraph == null) return "无";
|
||||
|
||||
PPr pPr = paragraph.getPPr();
|
||||
PPrBase.Ind ind = pPr.getInd();
|
||||
if (ind != null) {
|
||||
if (ind.getFirstLine() != null) {
|
||||
return ind.getFirstLine().intValue() + " 磅";
|
||||
}
|
||||
}
|
||||
if (pPr != null && pPr.getPStyle() != null && stylePart != null) {
|
||||
Double firstLine = null;
|
||||
|
||||
if (pPr != null && pPr.getInd() != null && pPr.getInd().getFirstLine() != null) {
|
||||
firstLine = pPr.getInd().getFirstLine().doubleValue();
|
||||
} else if (pPr != null && pPr.getPStyle() != null && stylePart != null) {
|
||||
String styleId = pPr.getPStyle().getVal();
|
||||
Style style = stylePart.getStyleById(styleId);
|
||||
if (style != null && style.getPPr() != null && style.getPPr().getInd() != null) {
|
||||
PPrBase.Ind indStyle = style.getPPr().getInd();
|
||||
if (indStyle.getFirstLine() != null) {
|
||||
return indStyle.getFirstLine().intValue() + " 磅";
|
||||
}
|
||||
if (style != null && style.getPPr() != null && style.getPPr().getInd() != null &&
|
||||
style.getPPr().getInd().getFirstLine() != null) {
|
||||
firstLine = style.getPPr().getInd().getFirstLine().doubleValue();
|
||||
}
|
||||
}
|
||||
return "";
|
||||
if (firstLine == null) return "无";
|
||||
|
||||
// 1 字符 ≈ 200 twip(即 10 磅)
|
||||
double chars = firstLine / 240.0;
|
||||
|
||||
// 四舍五入到 0.5
|
||||
double rounded = Math.round(chars * 2) / 2.0;
|
||||
|
||||
// 如果是整数,去掉小数点
|
||||
if (rounded == (int) rounded) {
|
||||
return (int) rounded + " 字符";
|
||||
} else {
|
||||
return rounded + " 字符";
|
||||
}
|
||||
}
|
||||
/// 段落格式(缩进) 悬挂缩进 磅
|
||||
public static String getParagraphIndHanging(P paragraph, StyleDefinitionsPart stylePart, WordprocessingMLPackage wordMLPackage, NumberingDefinitionsPart ndp) {
|
||||
if (paragraph == null) return "无";
|
||||
|
||||
PPr pPr = paragraph.getPPr();
|
||||
PPrBase.Ind ind = pPr.getInd();
|
||||
if (ind != null) {
|
||||
if (ind.getHanging() != null) {
|
||||
return ind.getHanging().intValue() + " 磅";
|
||||
}
|
||||
Double hanging = null;
|
||||
|
||||
// 1️⃣ 直接在段落中取
|
||||
if (pPr != null && pPr.getInd() != null && pPr.getInd().getHanging() != null) {
|
||||
hanging = pPr.getInd().getHanging().doubleValue();
|
||||
}
|
||||
if (pPr != null && pPr.getPStyle() != null && stylePart != null) {
|
||||
// 2️⃣ 样式中取
|
||||
else if (pPr != null && pPr.getPStyle() != null && stylePart != null) {
|
||||
String styleId = pPr.getPStyle().getVal();
|
||||
Style style = stylePart.getStyleById(styleId);
|
||||
if (style != null && style.getPPr() != null && style.getPPr().getInd() != null) {
|
||||
PPrBase.Ind indStyle = style.getPPr().getInd();
|
||||
if (indStyle.getHanging() != null) {
|
||||
return indStyle.getHanging().intValue() + " 磅";
|
||||
}
|
||||
if (style != null && style.getPPr() != null && style.getPPr().getInd() != null &&
|
||||
style.getPPr().getInd().getHanging() != null) {
|
||||
hanging = style.getPPr().getInd().getHanging().doubleValue();
|
||||
}
|
||||
}
|
||||
return "";
|
||||
|
||||
if (hanging == null) return "无";
|
||||
|
||||
// 1 字符 ≈ 200 twip(10 磅)
|
||||
double chars = hanging / 240.0;
|
||||
|
||||
// 四舍五入到 0.5
|
||||
double rounded = Math.round(chars * 2) / 2.0;
|
||||
|
||||
// 输出为整数或 .5 字符
|
||||
if (rounded == (int) rounded) {
|
||||
return (int) rounded + " 字符";
|
||||
} else {
|
||||
return rounded + " 字符";
|
||||
}
|
||||
}
|
||||
|
||||
/// 段落格式(间距) 段前行
|
||||
@@ -165,39 +191,75 @@ public class Paragraphs {
|
||||
}
|
||||
/// 段落格式(间距) 段前磅
|
||||
public static String getParagraphSpacingBefore(P paragraph, StyleDefinitionsPart stylePart, WordprocessingMLPackage wordMLPackage, NumberingDefinitionsPart ndp) {
|
||||
if (paragraph == null) return "无";
|
||||
|
||||
PPr pPr = paragraph.getPPr();
|
||||
if (pPr != null && pPr.getSpacing() != null) {
|
||||
if(pPr.getSpacing().getBefore()!=null){
|
||||
return String.valueOf(pPr.getSpacing().getBefore().intValue() / 20)+"磅";
|
||||
}
|
||||
Double before = null;
|
||||
|
||||
// 1️⃣ 段落自身定义
|
||||
if (pPr != null && pPr.getSpacing() != null && pPr.getSpacing().getBefore() != null) {
|
||||
before = pPr.getSpacing().getBefore().doubleValue();
|
||||
}
|
||||
if (pPr != null && pPr.getPStyle() != null && stylePart != null) {
|
||||
// 2️⃣ 从样式定义中继承
|
||||
else if (pPr != null && pPr.getPStyle() != null && stylePart != null) {
|
||||
String styleId = pPr.getPStyle().getVal();
|
||||
Style style = stylePart.getStyleById(styleId);
|
||||
if (style != null && style.getPPr() != null && style.getPPr().getSpacing() != null) {
|
||||
PPrBase.Spacing spacing = style.getPPr().getSpacing();
|
||||
return String.valueOf(style.getPPr().getSpacing().getBefore().intValue() / 20)+"磅";
|
||||
if (style != null && style.getPPr() != null && style.getPPr().getSpacing() != null &&
|
||||
style.getPPr().getSpacing().getBefore() != null) {
|
||||
before = style.getPPr().getSpacing().getBefore().doubleValue();
|
||||
}
|
||||
}
|
||||
return "";
|
||||
|
||||
if (before == null) return "";
|
||||
|
||||
// 转换为磅(1磅 = 20twip)
|
||||
double point = before / 20.0;
|
||||
|
||||
// 四舍五入到 0.5
|
||||
double rounded = Math.round(point * 2) / 2.0;
|
||||
|
||||
// 输出格式
|
||||
if (rounded == (int) rounded) {
|
||||
return (int) rounded + " 磅";
|
||||
} else {
|
||||
return rounded + " 磅";
|
||||
}
|
||||
}
|
||||
/// 段落格式(间距) 段后磅
|
||||
public static String getParagraphSpacingAfter(P paragraph, StyleDefinitionsPart stylePart, WordprocessingMLPackage wordMLPackage, NumberingDefinitionsPart ndp) {
|
||||
if (paragraph == null) return "无";
|
||||
|
||||
PPr pPr = paragraph.getPPr();
|
||||
if (pPr != null && pPr.getSpacing() != null) {
|
||||
if(pPr.getSpacing().getAfter()!=null){
|
||||
return String.valueOf(pPr.getSpacing().getAfter().intValue() / 20)+"磅";
|
||||
}
|
||||
Double after = null;
|
||||
|
||||
// 1️⃣ 段落自身定义
|
||||
if (pPr != null && pPr.getSpacing() != null && pPr.getSpacing().getAfter() != null) {
|
||||
after = pPr.getSpacing().getAfter().doubleValue();
|
||||
}
|
||||
if (pPr != null && pPr.getPStyle() != null && stylePart != null) {
|
||||
// 2️⃣ 样式定义
|
||||
else if (pPr != null && pPr.getPStyle() != null && stylePart != null) {
|
||||
String styleId = pPr.getPStyle().getVal();
|
||||
Style style = stylePart.getStyleById(styleId);
|
||||
if (style != null && style.getPPr() != null && style.getPPr().getSpacing() != null) {
|
||||
PPrBase.Spacing spacing = style.getPPr().getSpacing();
|
||||
return String.valueOf(style.getPPr().getSpacing().getAfter().intValue() / 20)+"磅";
|
||||
if (style != null && style.getPPr() != null && style.getPPr().getSpacing() != null &&
|
||||
style.getPPr().getSpacing().getAfter() != null) {
|
||||
after = style.getPPr().getSpacing().getAfter().doubleValue();
|
||||
}
|
||||
}
|
||||
return "";
|
||||
|
||||
if (after == null) return "";
|
||||
|
||||
// 转换为磅(1 磅 = 20 twip)
|
||||
double point = after / 20.0;
|
||||
|
||||
// 四舍五入到 0.5 磅
|
||||
double rounded = Math.round(point * 2) / 2.0;
|
||||
|
||||
// 输出格式:整数不带小数,半磅保留 .5
|
||||
if (rounded == (int) rounded) {
|
||||
return (int) rounded + " 磅";
|
||||
} else {
|
||||
return rounded + " 磅";
|
||||
}
|
||||
}
|
||||
|
||||
/// 段落格式(间距) 段后行
|
||||
@@ -510,6 +572,57 @@ public class Paragraphs {
|
||||
}
|
||||
return "无";
|
||||
}
|
||||
/// 段落 编号列表 编号序号
|
||||
public static String getParagraphListLvlNumber(P paragraph, StyleDefinitionsPart stylePart, WordprocessingMLPackage wordMLPackage, NumberingDefinitionsPart ndp) {
|
||||
PPr pPr = paragraph.getPPr();
|
||||
if (pPr == null || pPr.getNumPr() == null) return "无";
|
||||
|
||||
BigInteger numId = pPr.getNumPr().getNumId() != null ? pPr.getNumPr().getNumId().getVal() : null;
|
||||
BigInteger ilvl = pPr.getNumPr().getIlvl() != null ? pPr.getNumPr().getIlvl().getVal() : null;
|
||||
if (numId == null || ilvl == null || ndp == null) return "无";
|
||||
|
||||
// 获取文档所有段落
|
||||
List<Object> paragraphs = wordMLPackage.getMainDocumentPart().getContent();
|
||||
int count = 0;
|
||||
for (Object obj : paragraphs) {
|
||||
if (!(obj instanceof P)) continue;
|
||||
P p = (P) obj;
|
||||
if (p == paragraph) break; // 到当前段落停止计数
|
||||
PPr pp = p.getPPr();
|
||||
if (pp != null && pp.getNumPr() != null) {
|
||||
BigInteger nid = pp.getNumPr().getNumId() != null ? pp.getNumPr().getNumId().getVal() : null;
|
||||
BigInteger lvl = pp.getNumPr().getIlvl() != null ? pp.getNumPr().getIlvl().getVal() : null;
|
||||
if (numId.equals(nid) && ilvl.equals(lvl)) count++;
|
||||
}
|
||||
}
|
||||
|
||||
// 获取 Lvl 对象
|
||||
Numbering.Num num = ndp.getJaxbElement().getNum().stream()
|
||||
.filter(n -> n.getNumId().equals(numId))
|
||||
.findFirst().orElse(null);
|
||||
if (num == null) return "无";
|
||||
|
||||
BigInteger abstractNumId = num.getAbstractNumId().getVal();
|
||||
Numbering.AbstractNum absNum = Convert.getAbstractNumById(ndp, abstractNumId);
|
||||
if (absNum == null) return "无";
|
||||
|
||||
Lvl lvl = absNum.getLvl().stream()
|
||||
.filter(l -> l.getIlvl().equals(ilvl))
|
||||
.findFirst().orElse(null);
|
||||
if (lvl == null) return "无";
|
||||
|
||||
// 获取编号模板和起始值
|
||||
String lvlText = lvl.getLvlText() != null ? lvl.getLvlText().getVal() : "%1.";
|
||||
BigInteger start = lvl.getStart() != null ? lvl.getStart().getVal() : BigInteger.ONE;
|
||||
|
||||
// 实际编号
|
||||
int actualNumber = start.intValue() + count;
|
||||
|
||||
// 替换模板中的 %1、%2… 注意 ilvl 从 0 开始
|
||||
String result = lvlText.replace("%" + (ilvl.intValue() + 1), String.valueOf(actualNumber));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 段落边框 样式(带汉化)
|
||||
public static String getParagraphBorderStyle(P paragraph, StyleDefinitionsPart stylePart,
|
||||
|
@@ -1,15 +1,15 @@
|
||||
package pc.exam.pp.module.judgement.utils.wps_word.docx4j.section;
|
||||
|
||||
import jakarta.xml.bind.JAXBContext;
|
||||
import jakarta.xml.bind.JAXBElement;
|
||||
import jakarta.xml.bind.Marshaller;
|
||||
import jakarta.xml.bind.JAXBException;
|
||||
import org.docx4j.TextUtils;
|
||||
import org.docx4j.XmlUtils;
|
||||
import org.docx4j.dml.Graphic;
|
||||
import org.docx4j.dml.GraphicData;
|
||||
import org.docx4j.dml.wordprocessingDrawing.Anchor;
|
||||
import org.docx4j.dml.wordprocessingDrawing.Inline;
|
||||
import org.docx4j.mce.AlternateContent;
|
||||
import org.docx4j.model.structure.DocumentModel;
|
||||
import org.docx4j.model.fields.FieldUpdater;
|
||||
import org.docx4j.model.structure.HeaderFooterPolicy;
|
||||
import org.docx4j.model.structure.PageDimensions;
|
||||
import org.docx4j.model.structure.SectionWrapper;
|
||||
@@ -17,29 +17,27 @@ import org.docx4j.openpackaging.exceptions.Docx4JException;
|
||||
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
|
||||
import org.docx4j.openpackaging.parts.Part;
|
||||
import org.docx4j.openpackaging.parts.WordprocessingML.*;
|
||||
import org.docx4j.vml.CTFill;
|
||||
import org.docx4j.vml.CTTextbox;
|
||||
import org.docx4j.wml.*;
|
||||
import org.docx4j.wml.CTBackground;
|
||||
import org.docx4j.wml.CTBorder;
|
||||
import org.docx4j.wml.CTColumn;
|
||||
import org.docx4j.wml.CTColumns;
|
||||
import org.docx4j.wml.CTDocGrid;
|
||||
import org.docx4j.wml.CTShd;
|
||||
import org.docx4j.wml.STPageOrientation;
|
||||
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
import org.xml.sax.SAXException;
|
||||
import pc.exam.pp.module.judgement.utils.wps_word.utils.ColorUtils;
|
||||
|
||||
import javax.xml.namespace.QName;
|
||||
import javax.xml.xpath.XPath;
|
||||
import javax.xml.xpath.XPathConstants;
|
||||
import javax.xml.xpath.XPathExpression;
|
||||
import javax.xml.xpath.XPathFactory;
|
||||
import java.io.StringWriter;
|
||||
import java.lang.reflect.Field;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
@@ -78,7 +76,9 @@ public class SectionPage {
|
||||
long topTwips = pgMar.getTop().longValue(); // twips
|
||||
double topPt = topTwips / 20.0; // 转换为磅
|
||||
double topCm = topPt * 0.0352778; // 转换为厘米
|
||||
return String.format("%.1f磅(%.2f厘米)", topPt, topCm);
|
||||
// return String.format("%.1f磅(%.2f厘米)", topPt, topCm);
|
||||
return String.format("%.2f厘米", topCm);
|
||||
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@@ -95,7 +95,8 @@ public class SectionPage {
|
||||
long bottomTwips = pgMar.getBottom().longValue(); // twips
|
||||
double bottomPt = bottomTwips / 20.0; // 磅
|
||||
double bottomCm = bottomPt * 0.0352778; // 厘米
|
||||
return String.format("%.1f磅(%.2f厘米)", bottomPt, bottomCm);
|
||||
// return String.format("%.1f磅(%.2f厘米)", bottomPt, bottomCm);
|
||||
return String.format("%.2f厘米", bottomCm);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@@ -112,7 +113,8 @@ public class SectionPage {
|
||||
long leftTwips = pgMar.getLeft().longValue(); // twips
|
||||
double leftPt = leftTwips / 20.0; // 转换为磅
|
||||
double leftCm = leftPt * 0.0352778; // 转换为厘米
|
||||
return String.format("%.1f磅(%.2f厘米)", leftPt, leftCm);
|
||||
// return String.format("%.1f磅(%.2f厘米)", leftPt, leftCm);
|
||||
return String.format("%.2f厘米", leftCm);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@@ -129,7 +131,8 @@ public class SectionPage {
|
||||
long rightTwips = pgMar.getRight().longValue(); // twips
|
||||
double rightPt = rightTwips / 20.0; // 转换为磅
|
||||
double rightCm = rightPt * 0.0352778; // 转换为厘米
|
||||
return String.format("%.1f磅(%.2f厘米)", rightPt, rightCm);
|
||||
return String.format("%.2f厘米", rightCm);
|
||||
// return String.format("%.1f磅(%.2f厘米)", rightPt, rightCm);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@@ -146,7 +149,8 @@ public class SectionPage {
|
||||
long gutterTwips = pgMar.getGutter().longValue(); // twips
|
||||
double gutterPt = gutterTwips / 20.0; // 转换为磅
|
||||
double gutterCm = gutterPt * 0.0352778; // 转换为厘米
|
||||
return String.format("%.1f磅(%.2f厘米)", gutterPt, gutterCm);
|
||||
// return String.format("%.1f磅(%.2f厘米)", gutterPt, gutterCm);
|
||||
return String.format("%.2f厘米", gutterCm);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@@ -1170,33 +1174,130 @@ public class SectionPage {
|
||||
}
|
||||
|
||||
|
||||
// 页脚(元素) 包含页码 返回 是/否
|
||||
// 页脚(元素) 页码
|
||||
public static String getHeaderContainsPageNumber(
|
||||
P paragraph,
|
||||
HeaderFooterPolicy hfp,
|
||||
WordprocessingMLPackage wordMLPackage,
|
||||
List<SectionWrapper> sections) {
|
||||
List<SectionWrapper> sections) throws IOException, SAXException, Docx4JException, JAXBException {
|
||||
if (hfp == null) return "无页码";
|
||||
|
||||
if (hfp == null) return "否";
|
||||
|
||||
// 获取页脚对象列表
|
||||
// 更新字段,保证获取显示值
|
||||
FieldUpdater updater = new FieldUpdater(wordMLPackage);
|
||||
updater.update(true);
|
||||
FooterPart[] footerParts = new FooterPart[]{
|
||||
hfp.getFirstFooter(),
|
||||
hfp.getEvenFooter(),
|
||||
hfp.getDefaultFooter()
|
||||
};
|
||||
|
||||
Set<String> chineseNumbers = Set.of("一","二","三","四","五","六","七","八","九","十");
|
||||
Set<String> capitalChineseNumbers = Set.of("壹","贰","叁","肆","伍","陆","柒","捌","玖","拾");
|
||||
|
||||
for (FooterPart fp : footerParts) {
|
||||
if (fp == null) continue;
|
||||
|
||||
String xml = XmlUtils.marshaltoString(fp.getJaxbElement(), true, true);
|
||||
System.out.println("Footer XML:\n" + xml);
|
||||
// 判断是否包含页码域 (PAGE 或 NUMPAGES)
|
||||
if (xml.contains("PAGE") || xml.contains("NUMPAGES")) {
|
||||
return "是";
|
||||
org.w3c.dom.Document doc = XmlUtils.getNewDocumentBuilder()
|
||||
.parse(new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8)));
|
||||
|
||||
NodeList pNodes = doc.getElementsByTagNameNS(
|
||||
"http://schemas.openxmlformats.org/wordprocessingml/2006/main", "p");
|
||||
|
||||
for (int i = 0; i < pNodes.getLength(); i++) {
|
||||
org.w3c.dom.Element pElem = (org.w3c.dom.Element) pNodes.item(i);
|
||||
|
||||
// 检查 PAGE / NUMPAGES
|
||||
NodeList instrNodes = pElem.getElementsByTagNameNS(
|
||||
"http://schemas.openxmlformats.org/wordprocessingml/2006/main", "instrText");
|
||||
boolean hasPAGE = false, hasNUMPAGES = false;
|
||||
for (int j = 0; j < instrNodes.getLength(); j++) {
|
||||
String instr = instrNodes.item(j).getTextContent();
|
||||
if (instr.contains("PAGE")) hasPAGE = true;
|
||||
if (instr.contains("NUMPAGES")) hasNUMPAGES = true;
|
||||
}
|
||||
|
||||
// 拼接 run 内文本 + 字段文本
|
||||
NodeList rNodes = pElem.getElementsByTagNameNS(
|
||||
"http://schemas.openxmlformats.org/wordprocessingml/2006/main", "r");
|
||||
|
||||
StringBuilder textBuilder = new StringBuilder();
|
||||
for (int j = 0; j < rNodes.getLength(); j++) {
|
||||
Element rElem = (Element) rNodes.item(j);
|
||||
|
||||
NodeList tNodes = rElem.getElementsByTagNameNS(
|
||||
"http://schemas.openxmlformats.org/wordprocessingml/2006/main", "t");
|
||||
for (int k = 0; k < tNodes.getLength(); k++) {
|
||||
textBuilder.append(tNodes.item(k).getTextContent());
|
||||
}
|
||||
|
||||
NodeList instrNodesR = rElem.getElementsByTagNameNS(
|
||||
"http://schemas.openxmlformats.org/wordprocessingml/2006/main", "instrText");
|
||||
for (int k = 0; k < instrNodesR.getLength(); k++) {
|
||||
textBuilder.append(instrNodesR.item(k).getTextContent());
|
||||
}
|
||||
}
|
||||
|
||||
String text = textBuilder.toString().trim();
|
||||
System.out.println("页脚文本内容: " + text);
|
||||
if (text.isEmpty()) continue;
|
||||
|
||||
boolean containsChineseNum = chineseNumbers.stream().anyMatch(text::contains);
|
||||
boolean containsDigit = text.matches(".*\\d+.*");
|
||||
// -------------------- 核心逻辑 --------------------
|
||||
// 数字斜杠序列
|
||||
if (text.matches(".*\\d+\\s*/\\s*(?:\\d+|PAGE|NUMPAGES).*")) {
|
||||
return "1 / x";
|
||||
}
|
||||
if (containsChineseNum && hasPAGE && hasNUMPAGES) {
|
||||
return "第一页 共x页"; // WPS 中文 + PAGE + NUMPAGES
|
||||
}
|
||||
|
||||
if (containsDigit && hasPAGE && hasNUMPAGES) {
|
||||
return "第1页 共x页"; // 普通数字 + PAGE + NUMPAGES
|
||||
}
|
||||
|
||||
if (containsChineseNum && hasPAGE && !hasNUMPAGES) {
|
||||
return "第一页"; // WPS 中文单页
|
||||
}
|
||||
// ✅ 关键部分:支持短横线页码形式
|
||||
if (text.matches(".*[-–]\\s*\\d+\\s*[-–].*")) {
|
||||
return "-1-, -2-, -3- ..."; // 短横线包裹数字
|
||||
}
|
||||
if (text.matches(".*[—]\\s*\\d+\\s*[—].*")) {
|
||||
return "— 1 —, — 2 —, — 3 — ..."; // 数字横杠序列
|
||||
}
|
||||
// 半角数字序列
|
||||
if (text.matches("\\d+\\s*PAGE.*\\d+\\s*PAGE.*")) {
|
||||
return "1, 2, 3 ..."; // 数字序列
|
||||
}
|
||||
|
||||
// 全角数字序列
|
||||
if (text.matches(".*[0-9]+\\s*PAGE.*[0-9]+\\s*PAGE.*")) {
|
||||
return "1,2,3 ...";
|
||||
}
|
||||
if (containsDigit && hasPAGE && !hasNUMPAGES) {
|
||||
return "第1页"; // 普通数字单页
|
||||
}
|
||||
|
||||
if (text.matches("[IVXLCDM]+.*")) {
|
||||
return "I, II, III ..."; // 罗马数字
|
||||
}
|
||||
|
||||
if (text.matches("[A-Z]+\\d*.*")) {
|
||||
return "A, B, C ..."; // 大写字母
|
||||
}
|
||||
|
||||
if (text.matches("[a-z]+\\d*.*")) {
|
||||
return "a, b, c ..."; // 小写字母
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return "否";
|
||||
return "无页码";
|
||||
}
|
||||
|
||||
|
||||
@@ -1204,9 +1305,6 @@ public class SectionPage {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// public static void readTextWatermark(
|
||||
// P paragraph,
|
||||
// HeaderFooterPolicy hfp,
|
||||
|
Reference in New Issue
Block a user