|
@@ -79,6 +79,20 @@
|
|
|
.filter-controls input[type=range] { width: 80px; }
|
|
.filter-controls input[type=range] { width: 80px; }
|
|
|
.page-nav { margin-bottom: 10px; display: flex; gap: 10px; align-items: center; }
|
|
.page-nav { margin-bottom: 10px; display: flex; gap: 10px; align-items: center; }
|
|
|
.section-title { border-left: 4px solid #0d6efd; padding-left: 10px; margin: 25px 0 15px; font-weight: bold; color: #333; }
|
|
.section-title { border-left: 4px solid #0d6efd; padding-left: 10px; margin: 25px 0 15px; font-weight: bold; color: #333; }
|
|
|
|
|
+
|
|
|
|
|
+ .father-lineage-hint {
|
|
|
|
|
+ background-color: #f8f9fa;
|
|
|
|
|
+ border-left: 4px solid #17a2b8;
|
|
|
|
|
+ padding: 8px 12px;
|
|
|
|
|
+ border-radius: 4px;
|
|
|
|
|
+ font-size: 14px;
|
|
|
|
|
+ margin-top: 8px;
|
|
|
|
|
+ margin-bottom: 12px;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .father-lineage-hint .text-info {
|
|
|
|
|
+ color: #17a2b8;
|
|
|
|
|
+ }
|
|
|
</style>
|
|
</style>
|
|
|
{% endblock %}
|
|
{% endblock %}
|
|
|
|
|
|
|
@@ -1263,29 +1277,77 @@
|
|
|
if (person.matches.father && person.matches.father.length > 0) {
|
|
if (person.matches.father && person.matches.father.length > 0) {
|
|
|
// Pick the first one for now (could show UI to choose if multiple)
|
|
// Pick the first one for now (could show UI to choose if multiple)
|
|
|
const father = person.matches.father[0];
|
|
const father = person.matches.father[0];
|
|
|
- const relSelect = form.querySelector('[name="related_mid"]');
|
|
|
|
|
const relTypeSelect = form.querySelector('[name="relation_type"]');
|
|
const relTypeSelect = form.querySelector('[name="relation_type"]');
|
|
|
|
|
|
|
|
- if (relSelect && relTypeSelect) {
|
|
|
|
|
- if (typeof tomSelectInstance !== 'undefined' && tomSelectInstance) {
|
|
|
|
|
- tomSelectInstance.setValue(father.id);
|
|
|
|
|
- } else {
|
|
|
|
|
- relSelect.value = father.id;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ if (relTypeSelect) {
|
|
|
|
|
+ // Set the related member
|
|
|
|
|
+ document.getElementById('related-member-display').value = father.name;
|
|
|
|
|
+ document.getElementById('related_mid').value = father.id;
|
|
|
|
|
+
|
|
|
|
|
+ // Set relation type to father
|
|
|
relTypeSelect.value = '1'; // 父子
|
|
relTypeSelect.value = '1'; // 父子
|
|
|
- // Trigger change event if needed by other logic (not needed here yet)
|
|
|
|
|
|
|
+
|
|
|
|
|
+ // Trigger the lineage generation reference display
|
|
|
|
|
+ const relatedMid = document.getElementById('related_mid').value;
|
|
|
|
|
+ if (relTypeSelect.value == 1 && relatedMid) {
|
|
|
|
|
+ fetch(`/manager/api/member/${relatedMid}`)
|
|
|
|
|
+ .then(response => response.json())
|
|
|
|
|
+ .then(data => {
|
|
|
|
|
+ if (data.member && data.member.name_word_generation) {
|
|
|
|
|
+ // 显示父亲的世系世代
|
|
|
|
|
+ const lineageContainer = document.getElementById('lineage-generations-container');
|
|
|
|
|
+ const fatherLineageDiv = document.getElementById('father-lineage');
|
|
|
|
|
+
|
|
|
|
|
+ if (!fatherLineageDiv) {
|
|
|
|
|
+ const newDiv = document.createElement('div');
|
|
|
|
|
+ newDiv.id = 'father-lineage';
|
|
|
|
|
+ newDiv.className = 'father-lineage-hint';
|
|
|
|
|
+ newDiv.innerHTML = `
|
|
|
|
|
+ <div class="d-flex align-items-center">
|
|
|
|
|
+ <i class="bi bi-info-circle me-2 text-info"></i>
|
|
|
|
|
+ <div>
|
|
|
|
|
+ <strong class="text-info">父亲世系世代参考:</strong>
|
|
|
|
|
+ <span>${data.member.name_word_generation}</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ `;
|
|
|
|
|
+ // Find the add button container
|
|
|
|
|
+ const addButtonContainer = document.querySelector('#lineage-generations-container .d-flex.justify-content-between.align-items-center');
|
|
|
|
|
+ if (addButtonContainer) {
|
|
|
|
|
+ // Insert after the add button container
|
|
|
|
|
+ addButtonContainer.parentNode.insertBefore(newDiv, addButtonContainer.nextSibling);
|
|
|
|
|
+ } else if (lineageContainer.firstChild) {
|
|
|
|
|
+ // Insert after the first child
|
|
|
|
|
+ lineageContainer.insertBefore(newDiv, lineageContainer.firstChild.nextSibling);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // Append to container
|
|
|
|
|
+ lineageContainer.appendChild(newDiv);
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ fatherLineageDiv.innerHTML = `
|
|
|
|
|
+ <div class="d-flex align-items-center">
|
|
|
|
|
+ <i class="bi bi-info-circle me-2 text-info"></i>
|
|
|
|
|
+ <div>
|
|
|
|
|
+ <strong class="text-info">父亲世系世代参考:</strong>
|
|
|
|
|
+ <span>${data.member.name_word_generation}</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ `;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
} else if (person.matches.spouse && person.matches.spouse.length > 0) {
|
|
} else if (person.matches.spouse && person.matches.spouse.length > 0) {
|
|
|
const spouse = person.matches.spouse[0];
|
|
const spouse = person.matches.spouse[0];
|
|
|
- const relSelect = form.querySelector('[name="related_mid"]');
|
|
|
|
|
const relTypeSelect = form.querySelector('[name="relation_type"]');
|
|
const relTypeSelect = form.querySelector('[name="relation_type"]');
|
|
|
|
|
|
|
|
- if (relSelect && relTypeSelect) {
|
|
|
|
|
- if (typeof tomSelectInstance !== 'undefined' && tomSelectInstance) {
|
|
|
|
|
- tomSelectInstance.setValue(spouse.id);
|
|
|
|
|
- } else {
|
|
|
|
|
- relSelect.value = spouse.id;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ if (relTypeSelect) {
|
|
|
|
|
+ // Set the related member
|
|
|
|
|
+ document.getElementById('related-member-display').value = spouse.name;
|
|
|
|
|
+ document.getElementById('related_mid').value = spouse.id;
|
|
|
|
|
+
|
|
|
|
|
+ // Set relation type to spouse
|
|
|
relTypeSelect.value = '10'; // 夫妻
|
|
relTypeSelect.value = '10'; // 夫妻
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -1863,50 +1925,135 @@
|
|
|
window.checkSpouseInNotes = function() {
|
|
window.checkSpouseInNotes = function() {
|
|
|
if (!notesInput || !sexSelect) return;
|
|
if (!notesInput || !sexSelect) return;
|
|
|
|
|
|
|
|
- // Only trigger if female
|
|
|
|
|
|
|
+ const val = notesInput.value;
|
|
|
|
|
+
|
|
|
|
|
+ // Check for father information
|
|
|
|
|
+ const fatherMatch = val.match(/父亲[::\s]*([^\s;;,,。]+)/);
|
|
|
|
|
+ if (fatherMatch && fatherMatch[1]) {
|
|
|
|
|
+ const fatherName = fatherMatch[1].trim();
|
|
|
|
|
+ const relationTypeSelect = document.querySelector('select[name="relation_type"]');
|
|
|
|
|
+
|
|
|
|
|
+ if (relationTypeSelect) {
|
|
|
|
|
+ // Find the father in the members list
|
|
|
|
|
+ fetch(`/manager/api/members?search=${encodeURIComponent(fatherName)}`)
|
|
|
|
|
+ .then(response => response.json())
|
|
|
|
|
+ .then(data => {
|
|
|
|
|
+ if (data.members && data.members.length > 0) {
|
|
|
|
|
+ // Find the best match
|
|
|
|
|
+ let bestMatch = null;
|
|
|
|
|
+ for (const member of data.members) {
|
|
|
|
|
+ const optName = member.name;
|
|
|
|
|
+ const normalizedOpt = optName.replace(/公$/, '').replace(/^留/, '');
|
|
|
|
|
+ const normalizedFather = fatherName.replace(/公$/, '').replace(/^留/, '');
|
|
|
|
|
+
|
|
|
|
|
+ if (optName === fatherName || normalizedOpt === normalizedFather ||
|
|
|
|
|
+ (normalizedOpt && normalizedFather && (normalizedOpt.includes(normalizedFather) || normalizedFather.includes(normalizedOpt)))) {
|
|
|
|
|
+ bestMatch = member;
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (bestMatch) {
|
|
|
|
|
+ // Set the related member
|
|
|
|
|
+ document.getElementById('related-member-display').value = bestMatch.name;
|
|
|
|
|
+ document.getElementById('related_mid').value = bestMatch.id;
|
|
|
|
|
+
|
|
|
|
|
+ // Set relation type to father
|
|
|
|
|
+ relationTypeSelect.value = '1';
|
|
|
|
|
+
|
|
|
|
|
+ // Trigger the lineage generation reference display
|
|
|
|
|
+ const relatedMid = document.getElementById('related_mid').value;
|
|
|
|
|
+ if (relationTypeSelect.value == 1 && relatedMid) {
|
|
|
|
|
+ fetch(`/manager/api/member/${relatedMid}`)
|
|
|
|
|
+ .then(response => response.json())
|
|
|
|
|
+ .then(data => {
|
|
|
|
|
+ if (data.member && data.member.name_word_generation) {
|
|
|
|
|
+ // 显示父亲的世系世代
|
|
|
|
|
+ const lineageContainer = document.getElementById('lineage-generations-container');
|
|
|
|
|
+ const fatherLineageDiv = document.getElementById('father-lineage');
|
|
|
|
|
+
|
|
|
|
|
+ if (!fatherLineageDiv) {
|
|
|
|
|
+ const newDiv = document.createElement('div');
|
|
|
|
|
+ newDiv.id = 'father-lineage';
|
|
|
|
|
+ newDiv.className = 'father-lineage-hint';
|
|
|
|
|
+ newDiv.innerHTML = `
|
|
|
|
|
+ <div class="d-flex align-items-center">
|
|
|
|
|
+ <i class="bi bi-info-circle me-2 text-info"></i>
|
|
|
|
|
+ <div>
|
|
|
|
|
+ <strong class="text-info">父亲世系世代参考:</strong>
|
|
|
|
|
+ <span>${data.member.name_word_generation}</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ `;
|
|
|
|
|
+ // Find the add button container
|
|
|
|
|
+ const addButtonContainer = document.querySelector('#lineage-generations-container .d-flex.justify-content-between.align-items-center');
|
|
|
|
|
+ if (addButtonContainer) {
|
|
|
|
|
+ // Insert after the add button container
|
|
|
|
|
+ addButtonContainer.parentNode.insertBefore(newDiv, addButtonContainer.nextSibling);
|
|
|
|
|
+ } else if (lineageContainer.firstChild) {
|
|
|
|
|
+ // Insert after the first child
|
|
|
|
|
+ lineageContainer.insertBefore(newDiv, lineageContainer.firstChild.nextSibling);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // Append to container
|
|
|
|
|
+ lineageContainer.appendChild(newDiv);
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ fatherLineageDiv.innerHTML = `
|
|
|
|
|
+ <div class="d-flex align-items-center">
|
|
|
|
|
+ <i class="bi bi-info-circle me-2 text-info"></i>
|
|
|
|
|
+ <div>
|
|
|
|
|
+ <strong class="text-info">父亲世系世代参考:</strong>
|
|
|
|
|
+ <span>${data.member.name_word_generation}</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ `;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Only check for spouse if female
|
|
|
if (sexSelect.value === '2') {
|
|
if (sexSelect.value === '2') {
|
|
|
- const val = notesInput.value;
|
|
|
|
|
- // Match cases like "配偶:张三", "配偶:张三", "配偶 张三", "配偶张三"
|
|
|
|
|
- // We use a robust regex to get the word after 配偶
|
|
|
|
|
- const match = val.match(/配偶[::\s]*([^\s;;,,。]+)/);
|
|
|
|
|
- if (match && match[1]) {
|
|
|
|
|
- const spouseName = match[1].trim();
|
|
|
|
|
- const normalizedSpouse = spouseName.replace(/公$/, '').replace(/^留/, '');
|
|
|
|
|
- const relatedSelect = document.querySelector('select[name="related_mid"]');
|
|
|
|
|
|
|
+ const spouseMatch = val.match(/配偶[::\s]*([^\s;;,,。]+)/);
|
|
|
|
|
+ if (spouseMatch && spouseMatch[1]) {
|
|
|
|
|
+ const spouseName = spouseMatch[1].trim();
|
|
|
const relationTypeSelect = document.querySelector('select[name="relation_type"]');
|
|
const relationTypeSelect = document.querySelector('select[name="relation_type"]');
|
|
|
|
|
|
|
|
- if (relatedSelect && relationTypeSelect) {
|
|
|
|
|
- for (let i = 0; i < relatedSelect.options.length; i++) {
|
|
|
|
|
- const opt = relatedSelect.options[i];
|
|
|
|
|
- if (!opt.value) continue;
|
|
|
|
|
-
|
|
|
|
|
- const optText = opt.text.trim();
|
|
|
|
|
- // Extract name before " (ID:" robustly
|
|
|
|
|
- const optName = optText.replace(/\s*\(ID:.*$/, '').trim();
|
|
|
|
|
- const normalizedOpt = optName.replace(/公$/, '').replace(/^留/, '');
|
|
|
|
|
-
|
|
|
|
|
- // Match exact or without '公' suffix and without '留' prefix
|
|
|
|
|
- if (optName === spouseName || normalizedOpt === normalizedSpouse ||
|
|
|
|
|
- (normalizedOpt && normalizedSpouse && (normalizedOpt.includes(normalizedSpouse) || normalizedSpouse.includes(normalizedOpt)))) {
|
|
|
|
|
- // If not already selected, select it and set relation to Spouse
|
|
|
|
|
- if (relatedSelect.value !== opt.value) {
|
|
|
|
|
- if (typeof tomSelectInstance !== 'undefined' && tomSelectInstance) {
|
|
|
|
|
- tomSelectInstance.setValue(opt.value);
|
|
|
|
|
- } else {
|
|
|
|
|
- relatedSelect.value = opt.value;
|
|
|
|
|
|
|
+ if (relationTypeSelect) {
|
|
|
|
|
+ // Find the spouse in the members list
|
|
|
|
|
+ fetch(`/manager/api/members?search=${encodeURIComponent(spouseName)}`)
|
|
|
|
|
+ .then(response => response.json())
|
|
|
|
|
+ .then(data => {
|
|
|
|
|
+ if (data.members && data.members.length > 0) {
|
|
|
|
|
+ // Find the best match
|
|
|
|
|
+ let bestMatch = null;
|
|
|
|
|
+ for (const member of data.members) {
|
|
|
|
|
+ const optName = member.name;
|
|
|
|
|
+ const normalizedOpt = optName.replace(/公$/, '').replace(/^留/, '');
|
|
|
|
|
+ const normalizedSpouse = spouseName.replace(/公$/, '').replace(/^留/, '');
|
|
|
|
|
+
|
|
|
|
|
+ if (optName === spouseName || normalizedOpt === normalizedSpouse ||
|
|
|
|
|
+ (normalizedOpt && normalizedSpouse && (normalizedOpt.includes(normalizedSpouse) || normalizedSpouse.includes(normalizedOpt)))) {
|
|
|
|
|
+ bestMatch = member;
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
- relationTypeSelect.value = '10'; // 10 is Spouse
|
|
|
|
|
|
|
|
|
|
- // Optional visual feedback to user
|
|
|
|
|
- notesInput.style.transition = "background-color 0.3s";
|
|
|
|
|
- notesInput.style.backgroundColor = "#e8f5e9";
|
|
|
|
|
- setTimeout(() => notesInput.style.backgroundColor = "", 1000);
|
|
|
|
|
-
|
|
|
|
|
- console.log("Auto-linked spouse: ", optName);
|
|
|
|
|
|
|
+ if (bestMatch) {
|
|
|
|
|
+ // Set the related member
|
|
|
|
|
+ document.getElementById('related-member-display').value = bestMatch.name;
|
|
|
|
|
+ document.getElementById('related_mid').value = bestMatch.id;
|
|
|
|
|
+
|
|
|
|
|
+ // Set relation type to spouse
|
|
|
|
|
+ relationTypeSelect.value = '10';
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
- break;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ });
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -1996,20 +2143,50 @@
|
|
|
|
|
|
|
|
// 加载成员数据
|
|
// 加载成员数据
|
|
|
function loadMembers(page = 1, search = '') {
|
|
function loadMembers(page = 1, search = '') {
|
|
|
|
|
+ console.log('Loading members...', { page, search });
|
|
|
fetch(`/manager/api/members?page=${page}&search=${encodeURIComponent(search)}`)
|
|
fetch(`/manager/api/members?page=${page}&search=${encodeURIComponent(search)}`)
|
|
|
- .then(response => response.json())
|
|
|
|
|
|
|
+ .then(response => {
|
|
|
|
|
+ console.log('Response status:', response.status);
|
|
|
|
|
+ return response.json();
|
|
|
|
|
+ })
|
|
|
.then(data => {
|
|
.then(data => {
|
|
|
- membersData = data.members;
|
|
|
|
|
- totalMembers = data.total;
|
|
|
|
|
- totalPages = Math.ceil(totalMembers / 10);
|
|
|
|
|
- currentPage = page;
|
|
|
|
|
-
|
|
|
|
|
- // 更新成员列表
|
|
|
|
|
- updateMemberList();
|
|
|
|
|
- // 更新分页
|
|
|
|
|
- updatePagination();
|
|
|
|
|
- // 更新总数
|
|
|
|
|
- document.getElementById('total-members').textContent = totalMembers;
|
|
|
|
|
|
|
+ console.log('Response data:', data);
|
|
|
|
|
+ // Check if it's an error response
|
|
|
|
|
+ if (data.message && data.success === false) {
|
|
|
|
|
+ console.error('API error:', data.message);
|
|
|
|
|
+ // If unauthorized, redirect to login
|
|
|
|
|
+ if (data.message === 'Unauthorized') {
|
|
|
|
|
+ window.location.href = '/manager/login';
|
|
|
|
|
+ }
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ // Handle success response - check if members and total exist
|
|
|
|
|
+ if (data.members !== undefined && data.total !== undefined) {
|
|
|
|
|
+ membersData = data.members;
|
|
|
|
|
+ totalMembers = data.total;
|
|
|
|
|
+ totalPages = Math.ceil(totalMembers / 10);
|
|
|
|
|
+ currentPage = page;
|
|
|
|
|
+
|
|
|
|
|
+ // 更新成员列表
|
|
|
|
|
+ updateMemberList();
|
|
|
|
|
+ // 更新分页
|
|
|
|
|
+ updatePagination();
|
|
|
|
|
+ // 更新总数
|
|
|
|
|
+ document.getElementById('total-members').textContent = totalMembers;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ console.error('Invalid response structure:', data);
|
|
|
|
|
+ // Set default values
|
|
|
|
|
+ membersData = [];
|
|
|
|
|
+ totalMembers = 0;
|
|
|
|
|
+ totalPages = 1;
|
|
|
|
|
+ currentPage = 1;
|
|
|
|
|
+ updateMemberList();
|
|
|
|
|
+ updatePagination();
|
|
|
|
|
+ document.getElementById('total-members').textContent = 0;
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+ .catch(error => {
|
|
|
|
|
+ console.error('Error loading members:', error);
|
|
|
});
|
|
});
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -2023,17 +2200,19 @@
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- membersData.forEach(member => {
|
|
|
|
|
|
|
+ membersData.forEach(function(member) {
|
|
|
const item = document.createElement('div');
|
|
const item = document.createElement('div');
|
|
|
item.className = 'list-group-item list-group-item-action';
|
|
item.className = 'list-group-item list-group-item-action';
|
|
|
- item.onclick = () => selectMember(member);
|
|
|
|
|
|
|
+ item.onclick = function() {
|
|
|
|
|
+ selectMemberById(member.id);
|
|
|
|
|
+ };
|
|
|
item.innerHTML = `
|
|
item.innerHTML = `
|
|
|
<div class="d-flex justify-content-between align-items-center">
|
|
<div class="d-flex justify-content-between align-items-center">
|
|
|
<div>
|
|
<div>
|
|
|
<h6 class="mb-0">${member.name}</h6>
|
|
<h6 class="mb-0">${member.name}</h6>
|
|
|
<small class="text-muted">ID: ${member.id} | ${member.sex === 1 ? '男' : '女'}</small>
|
|
<small class="text-muted">ID: ${member.id} | ${member.sex === 1 ? '男' : '女'}</small>
|
|
|
</div>
|
|
</div>
|
|
|
- <button type="button" class="btn btn-sm btn-outline-primary" onclick="event.stopPropagation(); selectMember(member);">
|
|
|
|
|
|
|
+ <button type="button" class="btn btn-sm btn-outline-primary" onclick="event.stopPropagation(); selectMemberById(${member.id});">
|
|
|
选择
|
|
选择
|
|
|
</button>
|
|
</button>
|
|
|
</div>
|
|
</div>
|
|
@@ -2057,7 +2236,7 @@
|
|
|
for (let i = 1; i <= totalPages; i++) {
|
|
for (let i = 1; i <= totalPages; i++) {
|
|
|
const li = document.createElement('li');
|
|
const li = document.createElement('li');
|
|
|
li.className = `page-item ${i === currentPage ? 'active' : ''}`;
|
|
li.className = `page-item ${i === currentPage ? 'active' : ''}`;
|
|
|
- li.innerHTML = `<a class="page-link" href="#" onclick="changePage(${i})"><onclick="changePage(${i})">${i}</a>`;
|
|
|
|
|
|
|
+ li.innerHTML = `<a class="page-link" href="#" onclick="changePage(${i})">${i}</a>`;
|
|
|
pagination.appendChild(li);
|
|
pagination.appendChild(li);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -2100,23 +2279,34 @@
|
|
|
if (!fatherLineageDiv) {
|
|
if (!fatherLineageDiv) {
|
|
|
const newDiv = document.createElement('div');
|
|
const newDiv = document.createElement('div');
|
|
|
newDiv.id = 'father-lineage';
|
|
newDiv.id = 'father-lineage';
|
|
|
- newDiv.className = 'alert alert-info alert-sm mb-3 p-2';
|
|
|
|
|
|
|
+ newDiv.className = 'father-lineage-hint';
|
|
|
newDiv.innerHTML = `
|
|
newDiv.innerHTML = `
|
|
|
<div class="d-flex align-items-center">
|
|
<div class="d-flex align-items-center">
|
|
|
- <i class="bi bi-info-circle me-2"></i>
|
|
|
|
|
|
|
+ <i class="bi bi-info-circle me-2 text-info"></i>
|
|
|
<div>
|
|
<div>
|
|
|
- <strong>父亲世系世代参考:</strong>
|
|
|
|
|
|
|
+ <strong class="text-info">父亲世系世代参考:</strong>
|
|
|
<span>${data.member.name_word_generation}</span>
|
|
<span>${data.member.name_word_generation}</span>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
`;
|
|
`;
|
|
|
- lineageContainer.insertBefore(newDiv, lineageContainer.firstChild);
|
|
|
|
|
|
|
+ // Find the add button container
|
|
|
|
|
+ const addButtonContainer = document.querySelector('#lineage-generations-container .d-flex.justify-content-between.align-items-center');
|
|
|
|
|
+ if (addButtonContainer) {
|
|
|
|
|
+ // Insert after the add button container
|
|
|
|
|
+ addButtonContainer.parentNode.insertBefore(newDiv, addButtonContainer.nextSibling);
|
|
|
|
|
+ } else if (lineageContainer.firstChild) {
|
|
|
|
|
+ // Insert after the first child
|
|
|
|
|
+ lineageContainer.insertBefore(newDiv, lineageContainer.firstChild.nextSibling);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // Append to container
|
|
|
|
|
+ lineageContainer.appendChild(newDiv);
|
|
|
|
|
+ }
|
|
|
} else {
|
|
} else {
|
|
|
fatherLineageDiv.innerHTML = `
|
|
fatherLineageDiv.innerHTML = `
|
|
|
<div class="d-flex align-items-center">
|
|
<div class="d-flex align-items-center">
|
|
|
- <i class="bi bi-info-circle me-2"></i>
|
|
|
|
|
|
|
+ <i class="bi bi-info-circle me-2 text-info"></i>
|
|
|
<div>
|
|
<div>
|
|
|
- <strong>父亲世系世代参考:</strong>
|
|
|
|
|
|
|
+ <strong class="text-info">父亲世系世代参考:</strong>
|
|
|
<span>${data.member.name_word_generation}</span>
|
|
<span>${data.member.name_word_generation}</span>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
@@ -2130,6 +2320,24 @@
|
|
|
const modal = bootstrap.Modal.getInstance(document.getElementById('memberSelectModal'));
|
|
const modal = bootstrap.Modal.getInstance(document.getElementById('memberSelectModal'));
|
|
|
modal.hide();
|
|
modal.hide();
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ // 通过ID选择成员
|
|
|
|
|
+ function selectMemberById(memberId) {
|
|
|
|
|
+ // 先在当前加载的成员中查找
|
|
|
|
|
+ const member = membersData.find(m => m.id === memberId);
|
|
|
|
|
+ if (member) {
|
|
|
|
|
+ selectMember(member);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 如果没找到,从API获取
|
|
|
|
|
+ fetch(`/manager/api/member/${memberId}`)
|
|
|
|
|
+ .then(response => response.json())
|
|
|
|
|
+ .then(data => {
|
|
|
|
|
+ if (data.member) {
|
|
|
|
|
+ selectMember(data.member);
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
// 监听关系类型变化
|
|
// 监听关系类型变化
|
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
@@ -2150,23 +2358,34 @@
|
|
|
if (!fatherLineageDiv) {
|
|
if (!fatherLineageDiv) {
|
|
|
const newDiv = document.createElement('div');
|
|
const newDiv = document.createElement('div');
|
|
|
newDiv.id = 'father-lineage';
|
|
newDiv.id = 'father-lineage';
|
|
|
- newDiv.className = 'alert alert-info alert-sm mb-3 p-2';
|
|
|
|
|
|
|
+ newDiv.className = 'father-lineage-hint';
|
|
|
newDiv.innerHTML = `
|
|
newDiv.innerHTML = `
|
|
|
<div class="d-flex align-items-center">
|
|
<div class="d-flex align-items-center">
|
|
|
- <i class="bi bi-info-circle me-2"></i>
|
|
|
|
|
|
|
+ <i class="bi bi-info-circle me-2 text-info"></i>
|
|
|
<div>
|
|
<div>
|
|
|
- <strong>父亲世系世代参考:</strong>
|
|
|
|
|
|
|
+ <strong class="text-info">父亲世系世代参考:</strong>
|
|
|
<span>${data.member.name_word_generation}</span>
|
|
<span>${data.member.name_word_generation}</span>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
`;
|
|
`;
|
|
|
- lineageContainer.insertBefore(newDiv, lineageContainer.firstChild);
|
|
|
|
|
|
|
+ // Find the add button container
|
|
|
|
|
+ const addButtonContainer = document.querySelector('#lineage-generations-container .d-flex.justify-content-between.align-items-center');
|
|
|
|
|
+ if (addButtonContainer) {
|
|
|
|
|
+ // Insert after the add button container
|
|
|
|
|
+ addButtonContainer.parentNode.insertBefore(newDiv, addButtonContainer.nextSibling);
|
|
|
|
|
+ } else if (lineageContainer.firstChild) {
|
|
|
|
|
+ // Insert after the first child
|
|
|
|
|
+ lineageContainer.insertBefore(newDiv, lineageContainer.firstChild.nextSibling);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // Append to container
|
|
|
|
|
+ lineageContainer.appendChild(newDiv);
|
|
|
|
|
+ }
|
|
|
} else {
|
|
} else {
|
|
|
fatherLineageDiv.innerHTML = `
|
|
fatherLineageDiv.innerHTML = `
|
|
|
<div class="d-flex align-items-center">
|
|
<div class="d-flex align-items-center">
|
|
|
- <i class="bi bi-info-circle me-2"></i>
|
|
|
|
|
|
|
+ <i class="bi bi-info-circle me-2 text-info"></i>
|
|
|
<div>
|
|
<div>
|
|
|
- <strong>父亲世系世代参考:</strong>
|
|
|
|
|
|
|
+ <strong class="text-info">父亲世系世代参考:</strong>
|
|
|
<span>${data.member.name_word_generation}</span>
|
|
<span>${data.member.name_word_generation}</span>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|