|
@@ -3,7 +3,6 @@
|
|
|
{% block title %}{{ '编辑' if member else '录入' }}成员 - 家谱管理系统{% endblock %}
|
|
{% block title %}{{ '编辑' if member else '录入' }}成员 - 家谱管理系统{% endblock %}
|
|
|
|
|
|
|
|
{% block extra_css %}
|
|
{% block extra_css %}
|
|
|
-<link href="https://cdn.jsdelivr.net/npm/tom-select@2.2.2/dist/css/tom-select.bootstrap5.min.css" rel="stylesheet">
|
|
|
|
|
<style>
|
|
<style>
|
|
|
.split-container { display: flex; height: calc(100vh - 100px); overflow: hidden; }
|
|
.split-container { display: flex; height: calc(100vh - 100px); overflow: hidden; }
|
|
|
.form-panel { flex: 1.2; padding: 20px; overflow-y: auto; border-right: 1px solid #dee2e6; }
|
|
.form-panel { flex: 1.2; padding: 20px; overflow-y: auto; border-right: 1px solid #dee2e6; }
|
|
@@ -126,6 +125,37 @@
|
|
|
<div class="invalid-feedback" id="ageFeedback"></div>
|
|
<div class="invalid-feedback" id="ageFeedback"></div>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
+ <div class="col-md-8">
|
|
|
|
|
+ <label class="form-label">世系世代</label>
|
|
|
|
|
+ <div id="lineage-generations-container" class="d-flex flex-wrap align-items-center gap-2">
|
|
|
|
|
+ {% if member and member.name_word_generation %}
|
|
|
|
|
+ {% set generations = member.name_word_generation.split(';') %}
|
|
|
|
|
+ {% for gen in generations %}
|
|
|
|
|
+ {% if gen.strip() %}
|
|
|
|
|
+ <span class="lineage-tag badge bg-primary bg-opacity-10 text-primary border border-primary border-opacity-25 px-3 py-2 rounded-pill d-inline-flex align-items-center" style="font-size: 0.85rem;">
|
|
|
|
|
+ {{ gen.strip() }}
|
|
|
|
|
+ <button type="button" class="btn-close ms-2 remove-lineage" style="font-size: 0.55rem; filter: none; opacity: 0.6;" aria-label="删除"></button>
|
|
|
|
|
+ <input type="hidden" name="lineage_generations[]" value="{{ gen.strip() }}">
|
|
|
|
|
+ </span>
|
|
|
|
|
+ {% endif %}
|
|
|
|
|
+ {% endfor %}
|
|
|
|
|
+ {% endif %}
|
|
|
|
|
+ <div id="lineage-input-form" class="d-none">
|
|
|
|
|
+ <div class="input-group input-group-sm" style="width: 220px;">
|
|
|
|
|
+ <input type="text" id="lineage-input" class="form-control" placeholder="如:衢州第二十九代" maxlength="20">
|
|
|
|
|
+ <button type="button" id="confirm-lineage" class="btn btn-success"><i class="bi bi-check-lg"></i></button>
|
|
|
|
|
+ <button type="button" id="cancel-lineage" class="btn btn-outline-secondary"><i class="bi bi-x-lg"></i></button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <button type="button" id="add-lineage" class="btn btn-outline-primary btn-sm rounded-pill px-3 py-1">
|
|
|
|
|
+ <i class="bi bi-plus-lg me-1"></i>添加
|
|
|
|
|
+ </button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="col-md-4">
|
|
|
|
|
+ <label class="form-label">堂内排行</label>
|
|
|
|
|
+ <input type="text" name="family_rank" class="form-control" value="{{ member.family_rank if member else '' }}">
|
|
|
|
|
+ </div>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
<div class="section-title">状态信息</div>
|
|
<div class="section-title">状态信息</div>
|
|
@@ -224,14 +254,6 @@
|
|
|
<label class="form-label">字辈</label>
|
|
<label class="form-label">字辈</label>
|
|
|
<input type="text" name="name_word" class="form-control" value="{{ member.name_word if member else '' }}">
|
|
<input type="text" name="name_word" class="form-control" value="{{ member.name_word if member else '' }}">
|
|
|
</div>
|
|
</div>
|
|
|
- <div class="col-md-4">
|
|
|
|
|
- <label class="form-label">堂内排行</label>
|
|
|
|
|
- <input type="text" name="family_rank" class="form-control" value="{{ member.family_rank if member else '' }}">
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="col-md-4">
|
|
|
|
|
- <label class="form-label">世系世代</label>
|
|
|
|
|
- <input type="text" name="name_word_generation" class="form-control" value="{{ member.name_word_generation if member else '' }}">
|
|
|
|
|
- </div>
|
|
|
|
|
<div class="col-md-6">
|
|
<div class="col-md-6">
|
|
|
<label class="form-label">名号/封号</label>
|
|
<label class="form-label">名号/封号</label>
|
|
|
<input type="text" name="name_title" class="form-control" value="{{ member.name_title if member else '' }}">
|
|
<input type="text" name="name_title" class="form-control" value="{{ member.name_title if member else '' }}">
|
|
@@ -396,7 +418,6 @@
|
|
|
{% endblock %}
|
|
{% endblock %}
|
|
|
|
|
|
|
|
{% block extra_js %}
|
|
{% block extra_js %}
|
|
|
-<script src="https://cdn.jsdelivr.net/npm/tom-select@2.2.2/dist/js/tom-select.complete.min.js"></script>
|
|
|
|
|
<script>
|
|
<script>
|
|
|
let tomSelectInstance = null;
|
|
let tomSelectInstance = null;
|
|
|
function toggleBirthdayUnknown() {
|
|
function toggleBirthdayUnknown() {
|
|
@@ -840,8 +861,13 @@
|
|
|
// --- End Local Match Update ---
|
|
// --- End Local Match Update ---
|
|
|
|
|
|
|
|
form.reset();
|
|
form.reset();
|
|
|
- // Clear hidden/custom fields if any manually
|
|
|
|
|
- form.querySelector('[name="name_word_generation"]').value = '';
|
|
|
|
|
|
|
+ // Clear lineage generation tags
|
|
|
|
|
+ document.querySelectorAll('#lineage-generations-container .lineage-tag').forEach(t => t.remove());
|
|
|
|
|
+ const lgInput = document.getElementById('lineage-input-form');
|
|
|
|
|
+ if (lgInput) lgInput.classList.add('d-none');
|
|
|
|
|
+ const lgAdd = document.getElementById('add-lineage');
|
|
|
|
|
+ if (lgAdd) lgAdd.classList.remove('d-none');
|
|
|
|
|
+
|
|
|
form.querySelector('[name="personal_achievements"]').value = '';
|
|
form.querySelector('[name="personal_achievements"]').value = '';
|
|
|
form.querySelector('[name="notes"]').value = '';
|
|
form.querySelector('[name="notes"]').value = '';
|
|
|
form.querySelector('[name="tags"]').value = '';
|
|
form.querySelector('[name="tags"]').value = '';
|
|
@@ -1843,6 +1869,82 @@
|
|
|
notesInput.addEventListener('input', window.checkSpouseInNotes);
|
|
notesInput.addEventListener('input', window.checkSpouseInNotes);
|
|
|
sexSelect.addEventListener('change', window.checkSpouseInNotes);
|
|
sexSelect.addEventListener('change', window.checkSpouseInNotes);
|
|
|
}
|
|
}
|
|
|
|
|
+</script>
|
|
|
|
|
+<script>
|
|
|
|
|
+ document.addEventListener('DOMContentLoaded', function() {
|
|
|
|
|
+ const container = document.getElementById('lineage-generations-container');
|
|
|
|
|
+ const addButton = document.getElementById('add-lineage');
|
|
|
|
|
+ const inputForm = document.getElementById('lineage-input-form');
|
|
|
|
|
+ const lineageInput = document.getElementById('lineage-input');
|
|
|
|
|
+ const confirmButton = document.getElementById('confirm-lineage');
|
|
|
|
|
+ const cancelButton = document.getElementById('cancel-lineage');
|
|
|
|
|
+
|
|
|
|
|
+ if (!container || !addButton || !inputForm || !lineageInput || !confirmButton || !cancelButton) return;
|
|
|
|
|
+
|
|
|
|
|
+ function addLineageTag(value) {
|
|
|
|
|
+ const tag = document.createElement('span');
|
|
|
|
|
+ tag.className = 'lineage-tag badge bg-primary bg-opacity-10 text-primary border border-primary border-opacity-25 px-3 py-2 rounded-pill d-inline-flex align-items-center';
|
|
|
|
|
+ tag.style.fontSize = '0.85rem';
|
|
|
|
|
+ tag.innerHTML = `${value}<button type="button" class="btn-close ms-2 remove-lineage" style="font-size:0.55rem;filter:none;opacity:0.6;" aria-label="删除"></button><input type="hidden" name="lineage_generations[]" value="${value}">`;
|
|
|
|
|
+ container.insertBefore(tag, inputForm);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ container.addEventListener('click', function(e) {
|
|
|
|
|
+ const removeBtn = e.target.closest('.remove-lineage');
|
|
|
|
|
+ if (removeBtn) {
|
|
|
|
|
+ e.preventDefault();
|
|
|
|
|
+ e.stopPropagation();
|
|
|
|
|
+ const tag = removeBtn.closest('.lineage-tag');
|
|
|
|
|
+ if (tag) tag.remove();
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
|
|
|
|
|
+ addButton.addEventListener('click', function(e) {
|
|
|
|
|
+ e.preventDefault();
|
|
|
|
|
+ e.stopPropagation();
|
|
|
|
|
+ inputForm.classList.remove('d-none');
|
|
|
|
|
+ addButton.classList.add('d-none');
|
|
|
|
|
+ lineageInput.value = '';
|
|
|
|
|
+ lineageInput.focus();
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ function confirmInput() {
|
|
|
|
|
+ const value = lineageInput.value.trim();
|
|
|
|
|
+ if (value) {
|
|
|
|
|
+ addLineageTag(value);
|
|
|
|
|
+ }
|
|
|
|
|
+ lineageInput.value = '';
|
|
|
|
|
+ inputForm.classList.add('d-none');
|
|
|
|
|
+ addButton.classList.remove('d-none');
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ confirmButton.addEventListener('click', function(e) {
|
|
|
|
|
+ e.preventDefault();
|
|
|
|
|
+ e.stopPropagation();
|
|
|
|
|
+ confirmInput();
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ lineageInput.addEventListener('keydown', function(e) {
|
|
|
|
|
+ if (e.key === 'Enter') {
|
|
|
|
|
+ e.preventDefault();
|
|
|
|
|
+ e.stopPropagation();
|
|
|
|
|
+ confirmInput();
|
|
|
|
|
+ }
|
|
|
|
|
+ if (e.key === 'Escape') {
|
|
|
|
|
+ e.preventDefault();
|
|
|
|
|
+ lineageInput.value = '';
|
|
|
|
|
+ inputForm.classList.add('d-none');
|
|
|
|
|
+ addButton.classList.remove('d-none');
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ cancelButton.addEventListener('click', function(e) {
|
|
|
|
|
+ e.preventDefault();
|
|
|
|
|
+ e.stopPropagation();
|
|
|
|
|
+ lineageInput.value = '';
|
|
|
|
|
+ inputForm.classList.add('d-none');
|
|
|
|
|
+ addButton.classList.remove('d-none');
|
|
|
|
|
+ });
|
|
|
|
|
+ });
|
|
|
</script>
|
|
</script>
|
|
|
{% endblock %}
|
|
{% endblock %}
|