v6:名册联系信息对齐 vCard + 头像与裁剪四项修正
- ① 头像上传失败(超限/非图片)不再挡保存,改为 flash 提示「已加进名册。头像没有保存:…」 ——这是「添加不了」的真根因(错误被塞进 errors.avatar 把整条新增打回) - ② 表单顺序:生日整块下移(身份证能读出生日时无需常改) - ③ 裁剪缩放语义反转:框在屏幕上的位置与大小不动、动它底下的图; 落库归一化矩形随倍率缩小(放大=同一块区域看得更清楚) - ④ 取消应用层 5MB 兆数上限;按像素动态上调 memory_limit(px*6+64M,封顶 768M); 头像输出恒为 512x512 - ⑤ 成员信息对齐 vCard:person_contacts 表(phone/email/address/url 可多行, value 加密落库)+ persons.org(工作单位)/title(职务职称);均可留空 Schema v5→v6:person_contacts 建表 + persons.org/title 加列
This commit is contained in:
+27
-19
@@ -168,28 +168,19 @@
|
||||
boxEl.style.height = h + 'px';
|
||||
}
|
||||
|
||||
/** 当前框的归一化矩形(相对**显示出来的图片**,与倍率无关) */
|
||||
function normOf() {
|
||||
if (!st || !st.dispW || !st.dispH) { return { x: 0, y: 0, w: 1, h: 1 }; }
|
||||
return {
|
||||
x: boxEl.offsetLeft / st.dispW,
|
||||
y: boxEl.offsetTop / st.dispH,
|
||||
w: boxEl.offsetWidth / st.dispW,
|
||||
h: boxEl.offsetHeight / st.dispH,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 改缩放。
|
||||
*
|
||||
* 关键:**框住的归一化区域保持不变**,只是把像素坐标整体重算 ——
|
||||
* 于是"放大"只让你看得更清楚、能框得更细,绝不会把已经选好的区域改掉。
|
||||
* 放大后把框滚回视野中间,不然用户会以为框不见了(框在滚动区外面)。
|
||||
* 关键:**框在屏幕上的位置和大小都不动**,动的是它底下那张图 ——
|
||||
* 放大=同一块区域看得更清楚;缩小=框进更多内容。
|
||||
* (2026-09-30 用户反馈:之前的做法是"归一化区域不变",结果框跟着图一起变大,
|
||||
* 缩放几下框就大得找不到了。)
|
||||
* 落库的归一化矩形由 place() 夹取后自动重算 —— 缩放改变选中的区域,这是本意。
|
||||
*/
|
||||
function setZoom(z) {
|
||||
if (!st) { return; }
|
||||
z = Math.max(1, Math.min(MAX_ZOOM, z));
|
||||
var before = normOf();
|
||||
var b = { x: boxEl.offsetLeft, y: boxEl.offsetTop, w: boxEl.offsetWidth, h: boxEl.offsetHeight };
|
||||
st.zoom = z;
|
||||
st.dispW = Math.max(1, Math.round(st.baseW * z));
|
||||
st.dispH = Math.max(1, Math.round(st.baseH * z));
|
||||
@@ -205,10 +196,8 @@
|
||||
var valEl = overlay.querySelector('.crop-zoom-val');
|
||||
if (valEl) { valEl.textContent = z.toFixed(1) + '×'; }
|
||||
|
||||
place(before.x * st.dispW, before.y * st.dispH,
|
||||
before.w * st.dispW, before.h * st.dispH);
|
||||
stage.scrollLeft = Math.max(0, boxEl.offsetLeft - (st.baseW - boxEl.offsetWidth) / 2);
|
||||
stage.scrollTop = Math.max(0, boxEl.offsetTop - (st.baseH - boxEl.offsetHeight) / 2);
|
||||
// 框保持屏显大小;位置也保持(place 只做越界夹取,缩小到 1× 时兜底用)
|
||||
place(b.x, b.y, b.w, b.h);
|
||||
}
|
||||
|
||||
function open(input, file) {
|
||||
@@ -417,6 +406,25 @@
|
||||
calc();
|
||||
})();
|
||||
|
||||
// ===== 补充联系方式:「再加一个」克隆出下一行 =====
|
||||
// 平行数组命名(ct_<kind>_label[] / ct_<kind>_value[])→ 克隆行就是合法的追加,
|
||||
// 服务端按下标 zip,不需要任何计数器字段。
|
||||
(function () {
|
||||
document.addEventListener('click', function (e) {
|
||||
var btn = e.target.closest ? e.target.closest('.ct-add') : null;
|
||||
if (!btn) { return; }
|
||||
var block = btn.closest('.ct-block');
|
||||
if (!block) { return; }
|
||||
var rows = block.querySelectorAll('[data-ct-row]');
|
||||
if (!rows.length) { return; }
|
||||
var clone = rows[rows.length - 1].cloneNode(true);
|
||||
Array.prototype.forEach.call(clone.querySelectorAll('input'), function (i) { i.value = ''; });
|
||||
rows[rows.length - 1].parentNode.insertBefore(clone, btn);
|
||||
var first = clone.querySelector('input');
|
||||
if (first) { first.focus(); }
|
||||
});
|
||||
})();
|
||||
|
||||
// ===== 名册:拖动卡片改顺序 / 拖到别的一栏改分组 =====
|
||||
//
|
||||
// 落库的是**整版布局**(每栏的有序 id 列表),一次提交写完 ——
|
||||
|
||||
Reference in New Issue
Block a user