Ver Fonte

commit 优化

Hai Lin há 3 dias atrás
pai
commit
7f622652ca
3 ficheiros alterados com 132 adições e 15 exclusões
  1. 2 2
      app.py
  2. 114 12
      templates/add_member.html
  3. 16 1
      templates/member_detail.html

+ 2 - 2
app.py

@@ -781,7 +781,7 @@ def add_member():
                 'former_name': request.form.get('former_name'),
                 'childhood_name': request.form.get('childhood_name'),
                 'name_word': request.form.get('name_word'),
-                'name_word_generation': request.form.get('name_word_generation'),
+                'name_word_generation': ';'.join([g.strip() for g in request.form.getlist('lineage_generations[]') if g.strip()]),
                 'name_title': request.form.get('name_title'),
                 'sex': request.form['sex'],
                 'birthday': birthday_ts,
@@ -937,7 +937,7 @@ def edit_member(member_id):
                 'former_name': request.form.get('former_name'),
                 'childhood_name': request.form.get('childhood_name'),
                 'name_word': request.form.get('name_word'),
-                'name_word_generation': request.form.get('name_word_generation'),
+                'name_word_generation': ';'.join([g.strip() for g in request.form.getlist('lineage_generations[]') if g.strip()]),
                 'name_title': request.form.get('name_title'),
                 'sex': request.form['sex'],
                 'birthday': birthday_ts,

+ 114 - 12
templates/add_member.html

@@ -3,7 +3,6 @@
 {% block title %}{{ '编辑' if member else '录入' }}成员 - 家谱管理系统{% endblock %}
 
 {% 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>
     .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; }
@@ -126,6 +125,37 @@
                                 <div class="invalid-feedback" id="ageFeedback"></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 class="section-title">状态信息</div>
@@ -224,14 +254,6 @@
                                     <label class="form-label">字辈</label>
                                     <input type="text" name="name_word" class="form-control" value="{{ member.name_word if member else '' }}">
                                 </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">
                                     <label class="form-label">名号/封号</label>
                                     <input type="text" name="name_title" class="form-control" value="{{ member.name_title if member else '' }}">
@@ -396,7 +418,6 @@
 {% endblock %}
 
 {% block extra_js %}
-<script src="https://cdn.jsdelivr.net/npm/tom-select@2.2.2/dist/js/tom-select.complete.min.js"></script>
 <script>
     let tomSelectInstance = null;
     function toggleBirthdayUnknown() {
@@ -840,8 +861,13 @@
                     // --- End Local Match Update ---
 
                     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="notes"]').value = '';
                     form.querySelector('[name="tags"]').value = '';
@@ -1843,6 +1869,82 @@
         notesInput.addEventListener('input', 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>
 {% endblock %}

+ 16 - 1
templates/member_detail.html

@@ -186,7 +186,22 @@
                     </div>
                     <div class="col-md-6">
                         <span class="info-label">世系世代:</span>
-                        <span class="info-value">{{ member.name_word_generation or '-' }}</span>
+                        <span class="info-value">
+                            {% if member.name_word_generation %}
+                                {% set generations = member.name_word_generation.split(';') %}
+                                <span class="d-inline-flex flex-wrap gap-1 align-items-center">
+                                {% for gen in generations %}
+                                    {% if gen.strip() %}
+                                    <span class="badge rounded-pill px-3 py-1" style="background: linear-gradient(135deg, #e8f0fe, #d2e3fc); color: #1a56db; font-weight: 500; font-size: 0.8rem; letter-spacing: 0.5px; border: 1px solid rgba(26,86,219,0.15);">
+                                        <i class="bi bi-diagram-3 me-1" style="font-size: 0.7rem;"></i>{{ gen.strip() }}
+                                    </span>
+                                    {% endif %}
+                                {% endfor %}
+                                </span>
+                            {% else %}
+                                -
+                            {% endif %}
+                        </span>
                     </div>
                     <div class="col-md-6">
                         <span class="info-label">名号/封号:</span>