diff --git a/assets/style.css b/assets/style.css index 3b8deec..ac9258e 100644 --- a/assets/style.css +++ b/assets/style.css @@ -817,6 +817,15 @@ input[type="date"]::-webkit-calendar-picker-indicator { cursor: pointer; padding } .photo-del:hover { background: var(--danger); } +/* 批 11:表单缩略图旁的「✂ 裁剪」按钮 —— 上传后不再自动弹裁剪框,点它才弹 */ +.photo-card > .photo-crop-btn { + position: absolute; top: 6px; left: 6px; + border: 0; border-radius: 6px; padding: 3px 9px; + font-size: 12px; line-height: 1.4; cursor: pointer; + background: rgba(20, 24, 34, .62); color: #fff; +} +.photo-card > .photo-crop-btn:hover { background: rgba(20, 24, 34, .85); } + /* 详情页上的小照片墙 */ .photo-more { display: flex; flex-direction: column; align-items: center; justify-content: center; diff --git a/templates/activities/show.php b/templates/activities/show.php index d400c4d..68d2559 100644 --- a/templates/activities/show.php +++ b/templates/activities/show.php @@ -30,6 +30,165 @@ + (int)$rn['id'], + 'title' => (string)($rn['title'] ?: '(无标题节点)'), + 'icon' => (string)($rn['node_type_icon'] ?: '📍'), + 'img' => $imgId > 0 ? media_att($imgId) : '', + 'url' => url('nodes/show', ['id' => (int)$rn['id']]), + 'sname' => $sname, // 出发地名:没有坐标时交给高德地理编码兜底 + 'ename' => $ename, // 到达地名:同上 + 'start' => $hasS ? ['lng' => (float)$s['lng'], 'lat' => (float)$s['lat']] : null, + 'end' => $hasE ? ['lng' => (float)$e['lng'], 'lat' => (float)$e['lat']] : null, + ]; +} +?> + +
+

🗺️ 行程路线

+
+

+ 按时间顺序连出的执行节点路线(节点间虚线衔接),圆标在每段行程的中间,点它可打开对应节点。 + 红点 = 到达地。只有地名没坐标的地点会自动向高德查询定位,太偏僻的地名可能查不到。 +

+
+ + +

📋 计划 ()

@@ -54,129 +213,6 @@
- (int)$rn['id'], - 'title' => (string)($rn['title'] ?: '(无标题节点)'), - 'icon' => (string)($rn['node_type_icon'] ?: '📍'), - 'img' => $imgId > 0 ? media_att($imgId) : '', - 'url' => url('nodes/show', ['id' => (int)$rn['id']]), - 'start' => $hasS ? ['lng' => (float)$s['lng'], 'lat' => (float)$s['lat']] : null, - 'end' => $hasE ? ['lng' => (float)$e['lng'], 'lat' => (float)$e['lat']] : null, - ]; -} -?> - -
-

🗺️ 行程路线

-
-

- 按时间顺序连出的执行节点路线(节点间虚线衔接),点标记可打开对应节点。 - 线上圆标 = 节点出发地,红点 = 到达地。 -

-
- - ×' : '') + (it.cropped ? '已裁剪' : '') + + (it.croppable && modal + ? '' + : '') + '
' + '' + esc(it.name) + '' + '' + esc(fmtSize(bytesOf(it))) + '' @@ -757,7 +762,6 @@ $tripField = [ if (!arr.length) return; var errors = []; - var addedCroppable = false; arr.forEach(function (f) { if (picked.length >= MAX_FILES) { errors.push(f.name + ':一次最多 ' + MAX_FILES + ' 个'); @@ -779,7 +783,6 @@ $tripField = [ var image = isImageFile(f); var url = image ? URL.createObjectURL(f) : ''; var croppable = image && canvasSafe(f); - if (croppable) addedCroppable = true; picked.push({ uid: ++seq, file: f, @@ -799,11 +802,8 @@ $tripField = [ render(); if (errors.length) { setStatus(errors.join(';'), true); return; } - // 新选进来的图片里有能裁的 → 自动开始逐张裁剪;不想裁就一路点「确定」或直接「取消」 - if (addedCroppable && modal && typeof window.Cropper !== 'undefined') { - cropStopped = false; - advanceCrop(); - } + /* 批 11:选图后**不再自动弹出**裁剪框 —— 每张缩略图旁有「✂ 裁剪」按钮, + 想裁哪张点哪张;想批量处理就用上面的「逐张裁剪」。 */ } function removeAt(idx) { @@ -816,7 +816,15 @@ $tripField = [ } preview.addEventListener('click', function (ev) { - var btn = ev.target.closest ? ev.target.closest('button[data-idx]') : null; + if (!ev.target.closest) return; + /* 「✂ 裁剪」:只打开这一张的裁剪框,确定/取消都不自动跳下一张 */ + var cropBtn = ev.target.closest('button[data-crop]'); + if (cropBtn) { + var ci = parseInt(cropBtn.getAttribute('data-crop'), 10); + if (picked[ci]) openCrop(picked[ci].uid, false); + return; + } + var btn = ev.target.closest('button[data-idx]'); if (!btn) return; removeAt(parseInt(btn.getAttribute('data-idx'), 10)); }); @@ -856,13 +864,13 @@ $tripField = [ if (cropStopped) return; for (var i = 0; i < picked.length; i++) { if (picked[i].croppable && !picked[i].reviewed) { - openCrop(picked[i].uid); + openCrop(picked[i].uid, true); return; } } } - function openCrop(uid) { + function openCrop(uid, chained) { var it = find(uid); if (!it || !it.croppable) return; if (typeof window.Cropper === 'undefined') { @@ -871,8 +879,10 @@ $tripField = [ return; } cropUid = uid; + cropChain = !!chained; var pending = picked.filter(function (x) { return x.croppable && !x.reviewed; }).length; - cropTitle.textContent = '裁剪:' + it.name + (pending > 1 ? '(还有 ' + (pending - 1) + ' 张待处理)' : ''); + cropTitle.textContent = '裁剪:' + it.name + + (chained && pending > 1 ? '(还有 ' + (pending - 1) + ' 张待处理)' : ''); // 每次都换一个新的 img 节点,避免 Cropper 复用旧实例时状态残留 var fresh = document.createElement('img'); @@ -986,7 +996,7 @@ $tripField = [ it.reviewed = true; closeCrop(); render(); - advanceCrop(); // 还有没处理过的图就继续弹下一张 + if (cropChain) advanceCrop(); // 只有「逐张裁剪」流程才自动弹下一张 } if (cropAll) {