增加字符串兼容性;去除国外开源地图软件代码;批次发布后仍可编辑;
This commit is contained in:
@@ -110,7 +110,17 @@ class TraceabilityService(
|
||||
value.entries.joinToString(";") { "${it.key}: ${formatJsonValue(it.value)}" }
|
||||
}
|
||||
}
|
||||
else -> value.toString().trim('"').ifBlank { "未填写" }
|
||||
else -> normalizeDisplayText(value.toString().trim('"'))
|
||||
}
|
||||
|
||||
private fun normalizeDisplayText(text: String): String {
|
||||
if (text.isBlank()) {
|
||||
return "未填写"
|
||||
}
|
||||
return text
|
||||
.replace("\\r\\n", "\n")
|
||||
.replace("\\n", "\n")
|
||||
.replace("\\t", "\t")
|
||||
}
|
||||
|
||||
private fun formatDateOnly(value: String): String {
|
||||
@@ -126,7 +136,7 @@ class TraceabilityService(
|
||||
val lng = coordinate["lng"]?.jsonPrimitive?.doubleOrNull
|
||||
val lat = coordinate["lat"]?.jsonPrimitive?.doubleOrNull
|
||||
return when {
|
||||
lng != null && lat != null -> "https://www.openstreetmap.org/?mlat=$lat&mlon=$lng#map=15/$lat/$lng"
|
||||
lng != null && lat != null -> "https://uri.amap.com/marker?position=$lng,$lat&name=坐标位置&src=traceability"
|
||||
else -> ""
|
||||
}
|
||||
}
|
||||
@@ -135,7 +145,7 @@ class TraceabilityService(
|
||||
val coordinate = value as? JsonObject ?: return ""
|
||||
val lng = coordinate["lng"]?.jsonPrimitive?.doubleOrNull ?: return ""
|
||||
val lat = coordinate["lat"]?.jsonPrimitive?.doubleOrNull ?: return ""
|
||||
return "https://www.openstreetmap.org/export/embed.html?bbox=${lng - 0.01}%2C${lat - 0.01}%2C${lng + 0.01}%2C${lat + 0.01}&layer=mapnik&marker=$lat%2C$lng"
|
||||
return "https://uri.amap.com/marker?position=$lng,$lat&name=坐标位置&src=traceability&callnative=0"
|
||||
}
|
||||
|
||||
private fun buildPageViewModel(
|
||||
|
||||
@@ -7,5 +7,5 @@ ktor:
|
||||
|
||||
traceability:
|
||||
# 访问主服务的地址
|
||||
# core-base-url: "http://127.0.0.1:8089" # 开发
|
||||
core-base-url: "https://ai.ronsunny.cn:8090/api" # 生产
|
||||
core-base-url: "http://127.0.0.1:8089" # 开发
|
||||
# core-base-url: "https://ai.ronsunny.cn:8090/api" # 生产
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>${page.batchName} - 溯源信息</title>
|
||||
<link rel="stylesheet" href="/static/traceability.css" />
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/ol@10.6.1/ol.css" />
|
||||
</head>
|
||||
<body style="--traceability-primary:${page.themeColor};">
|
||||
<div class="page-shell">
|
||||
@@ -78,9 +79,11 @@
|
||||
<img class="kv-image" src="${entry.value}" alt="${entry.label}" />
|
||||
</button>
|
||||
<#elseif entry.type == "coordinate" && entry.value?has_content && entry.value != "未填写">
|
||||
<#if entry.mapEmbedUrl?has_content>
|
||||
<iframe class="kv-map" src="${entry.mapEmbedUrl}" loading="lazy" referrerpolicy="no-referrer-when-downgrade" title="${entry.label}"></iframe>
|
||||
</#if>
|
||||
<div
|
||||
class="kv-map"
|
||||
data-coordinate="${entry.value?html}"
|
||||
data-label="${entry.label?html}"
|
||||
></div>
|
||||
<strong<#if entry.bold || entry.color?has_content> style="<#if entry.bold>font-weight:700;</#if><#if entry.color?has_content>color:${entry.color};</#if>"</#if>>${entry.value}</strong>
|
||||
<#else>
|
||||
<strong<#if entry.bold || entry.color?has_content> style="<#if entry.bold>font-weight:700;</#if><#if entry.color?has_content>color:${entry.color};</#if>"</#if>>${entry.value}</strong>
|
||||
@@ -115,9 +118,11 @@
|
||||
<img class="kv-image" src="${entry.value}" alt="${entry.label}" />
|
||||
</button>
|
||||
<#elseif entry.type == "coordinate" && entry.value?has_content && entry.value != "未填写">
|
||||
<#if entry.mapEmbedUrl?has_content>
|
||||
<iframe class="kv-map" src="${entry.mapEmbedUrl}" loading="lazy" referrerpolicy="no-referrer-when-downgrade" title="${entry.label}"></iframe>
|
||||
</#if>
|
||||
<div
|
||||
class="kv-map"
|
||||
data-coordinate="${entry.value?html}"
|
||||
data-label="${entry.label?html}"
|
||||
></div>
|
||||
<strong<#if entry.bold || entry.color?has_content> style="<#if entry.bold>font-weight:700;</#if><#if entry.color?has_content>color:${entry.color};</#if>"</#if>>${entry.value}</strong>
|
||||
<#else>
|
||||
<strong<#if entry.bold || entry.color?has_content> style="<#if entry.bold>font-weight:700;</#if><#if entry.color?has_content>color:${entry.color};</#if>"</#if>>${entry.value}</strong>
|
||||
@@ -190,6 +195,12 @@
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const openLayersScript = document.createElement('script');
|
||||
openLayersScript.src = 'https://cdn.jsdelivr.net/npm/ol@10.6.1/dist/ol.js';
|
||||
openLayersScript.defer = true;
|
||||
openLayersScript.onload = initCoordinateMaps;
|
||||
document.head.appendChild(openLayersScript);
|
||||
|
||||
const themeColor = '${page.themeColor}';
|
||||
function hexToRgb(hex) {
|
||||
const normalized = (hex || '').replace('#', '').trim();
|
||||
@@ -287,6 +298,73 @@
|
||||
});
|
||||
});
|
||||
|
||||
function parseCoordinateValue(raw) {
|
||||
if (!raw) return null;
|
||||
try {
|
||||
const parsed = JSON.parse(raw);
|
||||
const lng = Number(parsed.lng);
|
||||
const lat = Number(parsed.lat);
|
||||
if (Number.isFinite(lng) && Number.isFinite(lat)) {
|
||||
return { lng, lat };
|
||||
}
|
||||
} catch (error) {
|
||||
const parts = String(raw).split(',').map((item) => item.trim());
|
||||
if (parts.length >= 2) {
|
||||
const lng = Number(parts[0]);
|
||||
const lat = Number(parts[1]);
|
||||
if (Number.isFinite(lng) && Number.isFinite(lat)) {
|
||||
return { lng, lat };
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function initCoordinateMaps() {
|
||||
if (!window.ol) return;
|
||||
const mapNodes = document.querySelectorAll('.kv-map[data-coordinate]');
|
||||
mapNodes.forEach((node) => {
|
||||
if (node.dataset.initialized === 'true') return;
|
||||
const parsed = parseCoordinateValue(node.dataset.coordinate);
|
||||
if (!parsed) return;
|
||||
node.dataset.initialized = 'true';
|
||||
|
||||
const map = new ol.Map({
|
||||
target: node,
|
||||
layers: [
|
||||
new ol.layer.Tile({
|
||||
source: new ol.source.XYZ({
|
||||
url: 'https://webrd02.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=7&x={x}&y={y}&z={z}',
|
||||
crossOrigin: 'anonymous',
|
||||
}),
|
||||
}),
|
||||
],
|
||||
view: new ol.View({
|
||||
center: ol.proj.fromLonLat([parsed.lng, parsed.lat]),
|
||||
zoom: 13,
|
||||
}),
|
||||
controls: [],
|
||||
});
|
||||
|
||||
const marker = new ol.Feature({
|
||||
geometry: new ol.geom.Point(ol.proj.fromLonLat([parsed.lng, parsed.lat])),
|
||||
});
|
||||
const vectorLayer = new ol.layer.Vector({
|
||||
source: new ol.source.Vector({
|
||||
features: [marker],
|
||||
}),
|
||||
style: new ol.style.Style({
|
||||
image: new ol.style.Circle({
|
||||
radius: 7,
|
||||
fill: new ol.style.Fill({ color: primary }),
|
||||
stroke: new ol.style.Stroke({ color: '#ffffff', width: 2 }),
|
||||
}),
|
||||
}),
|
||||
});
|
||||
map.addLayer(vectorLayer);
|
||||
});
|
||||
}
|
||||
|
||||
if (window.location.search.includes('result=')) {
|
||||
const nextUrl = window.location.pathname + window.location.hash;
|
||||
window.history.replaceState({}, '', nextUrl);
|
||||
|
||||
Reference in New Issue
Block a user