节点表单内支持快捷新建参与人成员(批 29)
This commit is contained in:
@@ -1321,6 +1321,15 @@ video.video-thumb.video-thumb-mini {
|
|||||||
.member-pick-avatar {
|
.member-pick-avatar {
|
||||||
width: 22px; height: 22px; border-radius: 50%; object-fit: cover; display: block;
|
width: 22px; height: 22px; border-radius: 50%; object-fit: cover; display: block;
|
||||||
}
|
}
|
||||||
|
/* 快捷新建成员(批 29):参与人勾选区下的一行「名字输入 + 新建」 */
|
||||||
|
.member-quickadd {
|
||||||
|
display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
|
||||||
|
margin-top: 12px; padding-top: 12px; border-top: 1px dashed var(--border);
|
||||||
|
}
|
||||||
|
.member-quickadd input[type="text"] { flex: 1 1 200px; min-width: 0; }
|
||||||
|
.member-quickadd-msg { font-size: 12.5px; }
|
||||||
|
.member-quickadd-msg.is-ok { color: var(--ok, #1a7f37); }
|
||||||
|
.member-quickadd-msg.is-err { color: var(--danger, #c62828); }
|
||||||
/* 联想选中后回填的详细地址(让人看见记下来的是什么) */
|
/* 联想选中后回填的详细地址(让人看见记下来的是什么) */
|
||||||
.loc-detail { margin-top: 6px; font-size: 12.5px; word-break: break-all; }
|
.loc-detail { margin-top: 6px; font-size: 12.5px; word-break: break-all; }
|
||||||
|
|
||||||
|
|||||||
@@ -145,6 +145,7 @@ $map = [
|
|||||||
'users/index' => [UserController::class, 'index'],
|
'users/index' => [UserController::class, 'index'],
|
||||||
'users/create' => [UserController::class, 'create'],
|
'users/create' => [UserController::class, 'create'],
|
||||||
'users/store' => [UserController::class, 'store'],
|
'users/store' => [UserController::class, 'store'],
|
||||||
|
'users/quickCreate' => [UserController::class, 'quickCreate'],
|
||||||
'users/edit' => [UserController::class, 'edit'],
|
'users/edit' => [UserController::class, 'edit'],
|
||||||
'users/update' => [UserController::class, 'update'],
|
'users/update' => [UserController::class, 'update'],
|
||||||
'users/destroy' => [UserController::class, 'destroy'],
|
'users/destroy' => [UserController::class, 'destroy'],
|
||||||
|
|||||||
@@ -100,6 +100,46 @@ class UserController
|
|||||||
redirect('users/index');
|
redirect('users/index');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 节点表单内「快捷新建成员」(批 29):只填名字,建一个 guest 成员,JSON 应答。
|
||||||
|
* 手机号 / 密码 / 头像都不收 —— 需要时去「成员管理」完善。AJAX 专用,不做页面跳转。
|
||||||
|
*/
|
||||||
|
public function quickCreate(): void
|
||||||
|
{
|
||||||
|
$this->requireAdmin();
|
||||||
|
csrf_check();
|
||||||
|
|
||||||
|
header('Content-Type: application/json; charset=utf-8');
|
||||||
|
|
||||||
|
$db = Database::get();
|
||||||
|
$familyId = Auth::familyId();
|
||||||
|
$name = trim((string)($_POST['name'] ?? ''));
|
||||||
|
|
||||||
|
$fail = static function (int $code, string $error): void {
|
||||||
|
http_response_code($code);
|
||||||
|
echo json_encode(['ok' => false, 'error' => $error], JSON_UNESCAPED_UNICODE);
|
||||||
|
exit;
|
||||||
|
};
|
||||||
|
if ($name === '') {
|
||||||
|
$fail(422, '名字不能为空');
|
||||||
|
}
|
||||||
|
if (mb_strlen($name) > 50) {
|
||||||
|
$fail(422, '名字太长(最多 50 字)');
|
||||||
|
}
|
||||||
|
$chk = $db->prepare('SELECT id FROM users WHERE family_id = ? AND name = ? LIMIT 1');
|
||||||
|
$chk->execute([$familyId, $name]);
|
||||||
|
if ($chk->fetch()) {
|
||||||
|
$fail(409, '已有同名成员(直接勾选即可)');
|
||||||
|
}
|
||||||
|
|
||||||
|
$stmt = $db->prepare('INSERT INTO users (family_id, name) VALUES (?, ?)');
|
||||||
|
$stmt->execute([$familyId, $name]);
|
||||||
|
|
||||||
|
echo json_encode(['ok' => true, 'id' => (int)$db->lastInsertId(), 'name' => $name],
|
||||||
|
JSON_UNESCAPED_UNICODE);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
public function edit(): void
|
public function edit(): void
|
||||||
{
|
{
|
||||||
$id = (int)($_GET['id'] ?? 0);
|
$id = (int)($_GET['id'] ?? 0);
|
||||||
|
|||||||
@@ -257,6 +257,18 @@ $tripField = [
|
|||||||
</div>
|
</div>
|
||||||
<p class="form-hint">勾选后保存即生效;已选的人重新勾选不会清掉之前记的签到 / 心情。</p>
|
<p class="form-hint">勾选后保存即生效;已选的人重新勾选不会清掉之前记的签到 / 心情。</p>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php /* 快捷新建成员(批 29):只填名字建一个 guest 成员并自动勾上,不离开表单。
|
||||||
|
想补手机号/头像/角色,去「成员管理」完善。 */ ?>
|
||||||
|
<?php if (\App\Auth::isAdmin()): ?>
|
||||||
|
<div class="member-quickadd" id="member-quickadd"
|
||||||
|
data-url="<?= e(url('users/quickCreate')) ?>" data-csrf="<?= e(csrf_token()) ?>">
|
||||||
|
<input type="text" id="new-member-name" maxlength="50"
|
||||||
|
placeholder="没找到?输入名字直接新建成员" autocomplete="off">
|
||||||
|
<button type="button" class="btn" id="new-member-add">+ 新建并勾选</button>
|
||||||
|
<span class="member-quickadd-msg" id="new-member-msg" aria-live="polite"></span>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
<?php
|
<?php
|
||||||
@@ -1223,6 +1235,72 @@ $tripField = [
|
|||||||
restoreDraft(saved);
|
restoreDraft(saved);
|
||||||
setStatus('已恢复上次没保存成功的内容(照片需要重新选择)。', false);
|
setStatus('已恢复上次没保存成功的内容(照片需要重新选择)。', false);
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
// ===== 快捷新建成员(批 29):AJAX 建 guest 成员 → 插入已勾选的参与人 =====
|
||||||
|
(function initQuickAdd() {
|
||||||
|
var box = document.getElementById('member-quickadd');
|
||||||
|
if (!box) return;
|
||||||
|
var input = document.getElementById('new-member-name');
|
||||||
|
var btn = document.getElementById('new-member-add');
|
||||||
|
var msg = document.getElementById('new-member-msg');
|
||||||
|
var list = document.querySelector('#member-field .member-pick');
|
||||||
|
if (!input || !btn || !msg || !list) return;
|
||||||
|
|
||||||
|
function say(text, ok) {
|
||||||
|
msg.textContent = text;
|
||||||
|
msg.classList.toggle('is-ok', !!ok);
|
||||||
|
msg.classList.toggle('is-err', !ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
function addOption(name, id) {
|
||||||
|
var label = document.createElement('label');
|
||||||
|
label.className = 'member-pick-item';
|
||||||
|
var cb = document.createElement('input');
|
||||||
|
cb.type = 'checkbox';
|
||||||
|
cb.name = 'members[]';
|
||||||
|
cb.value = String(id);
|
||||||
|
cb.checked = true;
|
||||||
|
label.appendChild(cb);
|
||||||
|
var span = document.createElement('span');
|
||||||
|
span.className = 'member-pick-name';
|
||||||
|
span.textContent = name;
|
||||||
|
label.appendChild(span);
|
||||||
|
list.appendChild(label);
|
||||||
|
}
|
||||||
|
|
||||||
|
function submit() {
|
||||||
|
var name = input.value.replace(/\s+/g, ' ').trim();
|
||||||
|
if (!name) { say('先输入名字', false); input.focus(); return; }
|
||||||
|
btn.disabled = true;
|
||||||
|
say('创建中…', true);
|
||||||
|
var fd = new FormData();
|
||||||
|
fd.append('name', name);
|
||||||
|
fd.append('_csrf', box.dataset.csrf || '');
|
||||||
|
fetch(box.dataset.url, { method: 'POST', body: fd, credentials: 'same-origin' })
|
||||||
|
.then(function (r) {
|
||||||
|
return r.json().then(function (j) { return { status: r.status, j: j }; });
|
||||||
|
})
|
||||||
|
.then(function (res) {
|
||||||
|
if (res.j && res.j.ok) {
|
||||||
|
addOption(res.j.name, res.j.id);
|
||||||
|
input.value = '';
|
||||||
|
say('已创建「' + res.j.name + '」并勾选', true);
|
||||||
|
} else {
|
||||||
|
say((res.j && res.j.error) || ('创建失败(' + res.status + ')'), false);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(function () { say('网络错误,请重试', false); })
|
||||||
|
.finally(function () {
|
||||||
|
btn.disabled = false;
|
||||||
|
input.focus();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
btn.addEventListener('click', submit);
|
||||||
|
input.addEventListener('keydown', function (ev) {
|
||||||
|
if (ev.key === 'Enter') { ev.preventDefault(); submit(); }
|
||||||
|
});
|
||||||
|
})();
|
||||||
})();
|
})();
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Reference in New Issue
Block a user