Просмотр исходного кода

Initial commit: 家谱小程序项目

林海 1 месяц назад
Родитель
Сommit
6a2198903a
4 измененных файлов с 142 добавлено и 94 удалено
  1. 1 1
      app.js
  2. 44 17
      pages/lineage/lineage.js
  3. 32 37
      pages/lineage/lineage.wxml
  4. 65 39
      pages/lineage/lineage.wxss

+ 1 - 1
app.js

@@ -3,7 +3,7 @@ App({
     userInfo: null,
     token: null,
     isLoggedIn: false,
-    baseUrl: 'http://192.168.124.37:5001/manager'
+    baseUrl: 'https://familial.yunzhixue.cn/manager'
   },
 
   onLaunch: function () {

+ 44 - 17
pages/lineage/lineage.js

@@ -8,9 +8,9 @@ Page({
     reversedGenerations: [],
     siblings: [],
     peers: [],
-    centerPeerIndex: 0,
-    scrollToCenterId: '',
+    peerScrollLeft: 0,
     children: [],
+    childrenScrollLeft: 0,
     loading: false,
     showDetail: false,
     detailMember: null
@@ -122,36 +122,62 @@ Page({
           console.log('[Lineage] siblings:', (d.siblings || []).length);
           console.log('[Lineage] children:', (d.children || []).length);
           console.log('[Lineage] center:', JSON.stringify(d.center));
-          const reversed = (d.generations || []).slice().reverse();
           const center = d.center || null;
           const siblings = d.siblings || [];
 
-          // 将 center 与兄弟合并,按 child_order 排序,null 默认为 1
+          // 计算 rpx→px 比率,用于 scroll-left
+          const sysInfo = wx.getSystemInfoSync();
+          const rpxRatio = sysInfo.windowWidth / 750;
+          // 卡片宽200rpx + 间距16rpx = 216rpx/卡
+          // padding两端各275rpx,当祖先在index=K时 scrollLeft=K*216*ratio
+          const cardUnit = 216 * rpxRatio;
+
+          // 每代:祖先 + 兄弟合并排序,计算 scrollLeft
+          const rawGenerations = (d.generations || []).slice().reverse();
+          const reversedGenerations = rawGenerations.map(gen => {
+            const allPeers = [
+              { ...gen.ancestor, isAncestor: true },
+              ...(gen.siblings || []).map(s => ({ ...s, isAncestor: false }))
+            ].sort((a, b) => {
+              const oa = a.child_order || 1;
+              const ob = b.child_order || 1;
+              return oa !== ob ? oa - ob : a.id - b.id;
+            });
+            const ancIdx = allPeers.findIndex(p => p.isAncestor);
+            return { ...gen, allPeers, scrollLeft: ancIdx * cardUnit };
+          });
+
+          // 查询人物行:center + 兄弟合并排序,计算 scrollLeft
           let peers = [];
-          let centerPeerIndex = 0;
+          let peerScrollLeft = 0;
           if (center) {
             const allPeers = [
               { ...center, isCenter: true },
               ...siblings.map(s => ({ ...s, isCenter: false }))
-            ];
-            allPeers.sort((a, b) => {
-              const oa = (a.child_order || 1);
-              const ob = (b.child_order || 1);
-              return oa !== ob ? oa - ob : (a.id - b.id);
+            ].sort((a, b) => {
+              const oa = a.child_order || 1;
+              const ob = b.child_order || 1;
+              return oa !== ob ? oa - ob : a.id - b.id;
             });
             peers = allPeers;
-            centerPeerIndex = allPeers.findIndex(p => p.isCenter);
+            const cIdx = allPeers.findIndex(p => p.isCenter);
+            peerScrollLeft = cIdx * cardUnit;
           }
 
+          // 子女行居中:将中间那个子女滚到屏幕中央
+          const childrenArr = d.children || [];
+          const midChildIdx = Math.floor(childrenArr.length / 2);
+          const childrenScrollLeft = midChildIdx * cardUnit;
+
           this.setData({
             center,
-            reversedGenerations: reversed,
+            reversedGenerations,
             siblings,
-            children: d.children || [],
+            children: childrenArr,
+            childrenScrollLeft,
             peers,
-            centerPeerIndex,
-            loading: false,
-            scrollToCenterId: 'peer-center'
+            peerScrollLeft,
+            loading: false
           });
         } else {
           console.error('[Lineage] 失败:', JSON.stringify(res.data));
@@ -176,8 +202,9 @@ Page({
       reversedGenerations: [],
       siblings: [],
       peers: [],
-      centerPeerIndex: 0,
+      peerScrollLeft: 0,
       children: [],
+      childrenScrollLeft: 0,
       loading: false
     });
   },

+ 32 - 37
pages/lineage/lineage.wxml

@@ -62,39 +62,32 @@
           <view class="gen-label">
             <text class="gen-label-text">{{helpers.getAncestorLabel(gen.depth)}}</text>
           </view>
-          <!-- 本代主节点 + 兄弟横向滚动 -->
-          <view class="row-cards">
-            <view
-              class="card ancestor-card"
-              bindtap="viewDetail"
-              data-member="{{gen.ancestor}}"
-            >
-              <view class="card-name-wrap">
-                <text class="card-name">{{gen.ancestor.name}}</text>
-                <text class="card-simplified" wx:if="{{gen.ancestor.simplified_name && gen.ancestor.simplified_name !== gen.ancestor.name}}">
-                  ({{gen.ancestor.simplified_name}})
-                </text>
-              </view>
-              <text class="card-gen">{{gen.ancestor.name_word_generation || ''}}</text>
-            </view>
-
-            <!-- 该代兄弟 -->
-            <scroll-view scroll-x class="sibling-scroll" wx:if="{{gen.siblings.length > 0}}">
-              <view class="sibling-list">
-                <view
-                  class="card sibling-card"
-                  wx:for="{{gen.siblings}}"
-                  wx:key="id"
-                  wx:for-item="sib"
-                  bindtap="viewDetail"
-                  data-member="{{sib}}"
-                >
-                  <text class="card-name card-name-sm">{{sib.name}}</text>
-                  <text class="card-gen">{{sib.name_word_generation || ''}}</text>
+          <!-- 本代:祖先 + 兄弟按 child_order 排序,scroll-left 精确居中 -->
+          <scroll-view
+            scroll-x
+            class="gen-peer-scroll"
+            scroll-left="{{gen.scrollLeft}}"
+          >
+            <view class="gen-peer-list">
+              <view
+                wx:for="{{gen.allPeers}}"
+                wx:key="id"
+                id="{{item.isAncestor ? 'anc-' + item.id : 'sib-' + item.id}}"
+                class="card {{item.isAncestor ? 'ancestor-card' : 'sibling-card'}}"
+                bindtap="viewDetail"
+                data-member="{{item}}"
+              >
+                <view class="order-badge" wx:if="{{item.child_order}}">
+                  <text class="order-badge-text">{{helpers.getChildOrderText(item.child_order)}}</text>
                 </view>
+                <view class="card-name-wrap">
+                  <text class="card-name {{item.isAncestor ? '' : 'card-name-sm'}}">{{item.name}}</text>
+                  <text class="card-simplified" wx:if="{{item.simplified_name && item.simplified_name !== item.name}}">({{item.simplified_name}})</text>
+                </view>
+                <text class="card-gen">{{item.name_word_generation || ''}}</text>
               </view>
-            </scroll-view>
-          </view>
+            </view>
+          </scroll-view>
         </view>
 
         <!-- 竖向连接线 -->
@@ -111,8 +104,7 @@
         <scroll-view
           scroll-x
           class="peer-scroll"
-          scroll-into-view="{{scrollToCenterId}}"
-          scroll-with-animation="{{true}}"
+          scroll-left="{{peerScrollLeft}}"
         >
           <view class="peer-list">
             <view
@@ -150,7 +142,7 @@
           <view class="children-label">
             <text class="children-label-text">子女</text>
           </view>
-          <scroll-view scroll-x class="children-scroll">
+          <scroll-view scroll-x class="children-scroll" scroll-left="{{childrenScrollLeft}}">
             <view class="children-list">
               <view
                 class="card child-card"
@@ -159,10 +151,13 @@
                 bindtap="viewDetail"
                 data-member="{{item}}"
               >
-                <view class="child-order-badge">
-                  <text class="child-order-text">{{helpers.getChildOrderText(item.child_order)}}</text>
+                <view class="order-badge">
+                  <text class="order-badge-text">{{helpers.getChildOrderText(item.child_order)}}</text>
+                </view>
+                <view class="card-name-wrap">
+                  <text class="card-name card-name-sm">{{item.name}}</text>
+                  <text class="card-simplified" wx:if="{{item.simplified_name && item.simplified_name !== item.name}}">({{item.simplified_name}})</text>
                 </view>
-                <text class="card-name card-name-sm">{{item.name}}</text>
                 <text class="card-gen">{{item.name_word_generation || ''}}</text>
                 <view class="has-children-dot" wx:if="{{item.has_children}}">▼</view>
               </view>

+ 65 - 39
pages/lineage/lineage.wxss

@@ -163,12 +163,12 @@
    世系树主体
 ════════════════════════════════ */
 .tree-scroll {
-  /* 减去搜索栏 + 自定义tabBar高度(约110rpx) */
-  height: calc(100vh - 140rpx - 110rpx);
+  /* 搜索栏约140rpx + 调试栏约50rpx + 自定义tabBar约130rpx */
+  height: calc(100vh - 320rpx);
 }
 
 .tree-body {
-  padding: 16rpx 0 60rpx;
+  padding: 16rpx 0 120rpx;
   display: flex;
   flex-direction: column;
   align-items: center;
@@ -218,9 +218,10 @@
   width: 100%;
   display: flex;
   align-items: flex-start;
-  justify-content: center;
   gap: 16rpx;
   overflow-x: auto;
+  padding: 0 24rpx;
+  box-sizing: border-box;
 }
 
 .center-row {
@@ -230,18 +231,24 @@
 /* ── 通用卡片 ── */
 .card {
   border-radius: 16rpx;
-  padding: 20rpx 24rpx;
+  padding: 16rpx 20rpx;
   display: flex;
   flex-direction: column;
-  gap: 8rpx;
+  gap: 6rpx;
   flex-shrink: 0;
+  width: 200rpx;
+  min-width: 200rpx;
+  max-width: 200rpx;
+  overflow: hidden;
+  box-sizing: border-box;
 }
 
 .card-name-wrap {
   display: flex;
   align-items: baseline;
-  gap: 8rpx;
-  flex-wrap: wrap;
+  gap: 6rpx;
+  flex-wrap: nowrap;
+  overflow: hidden;
 }
 
 .card-name {
@@ -251,6 +258,8 @@
   overflow: hidden;
   text-overflow: ellipsis;
   white-space: nowrap;
+  flex-shrink: 1;
+  min-width: 0;
 }
 
 .card-name-sm {
@@ -264,31 +273,40 @@
   text-overflow: ellipsis;
   white-space: nowrap;
   flex-shrink: 1;
+  min-width: 0;
 }
 
 .card-gen {
-  font-size: 21rpx;
+  font-size: 20rpx;
   color: rgba(255,255,255,0.55);
   line-height: 1.4;
   overflow: hidden;
-  display: -webkit-box;
-  -webkit-box-orient: vertical;
-  -webkit-line-clamp: 2;
-  white-space: normal;
+  text-overflow: ellipsis;
+  white-space: nowrap;
 }
 
 /* ── 祖先卡 ── */
 .ancestor-card {
   background: linear-gradient(135deg, #1e3a5f 0%, #2a5298 100%);
-  width: 220rpx;
-  min-width: 220rpx;
-  max-width: 220rpx;
   box-shadow: 0 4rpx 16rpx rgba(42, 82, 152, 0.4);
   border: 1rpx solid #2d5ea8;
-  overflow: hidden;
 }
 
-/* ── 兄弟卡 ── */
+/* ── 祖先行横向滚动(主卡 + 兄弟同行,scroll-into-view 使祖先居中) ── */
+.gen-peer-scroll {
+  width: 100%;
+  white-space: nowrap;
+}
+
+.gen-peer-list {
+  display: flex;
+  align-items: flex-start;
+  gap: 16rpx;
+  /* 两端留出约半屏宽度,让 scroll-into-view 能把目标卡片滚到屏幕中央 */
+  padding: 0 275rpx;
+}
+
+/* ── 兄弟卡(旧 sibling-scroll 保留兼容) ── */
 .sibling-scroll {
   flex: 1;
   white-space: nowrap;
@@ -300,6 +318,21 @@
   padding-right: 8rpx;
 }
 
+/* ── 统一排行徽标 ── */
+.order-badge {
+  background: rgba(255,255,255,0.18);
+  border-radius: 8rpx;
+  padding: 3rpx 12rpx;
+  align-self: flex-start;
+  margin-bottom: 6rpx;
+}
+
+.order-badge-text {
+  font-size: 20rpx;
+  color: rgba(255,255,255,0.92);
+  font-weight: bold;
+}
+
 /* ── 查询人物同辈横排(含center居中) ── */
 .peer-scroll {
   width: 100%;
@@ -310,7 +343,7 @@
   display: flex;
   align-items: flex-start;
   gap: 16rpx;
-  padding: 0 24rpx;
+  padding: 0 275rpx;
 }
 
 .peer-order-badge {
@@ -343,12 +376,8 @@
 
 .sibling-card {
   background: #1a3a5c;
-  width: 180rpx;
-  min-width: 180rpx;
-  max-width: 180rpx;
   border: 1rpx solid #2d5280;
   box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.2);
-  overflow: hidden;
 }
 
 .sibling-card .card-name {
@@ -359,15 +388,14 @@
   color: #4a6a8a;
 }
 
-/* ── 查询人物卡 ── */
+/* ── 查询人物卡(比普通卡略宽突出显示) ── */
 .center-card {
   background: linear-gradient(135deg, #b07d10 0%, #d4a017 100%);
   width: 220rpx;
   min-width: 220rpx;
   max-width: 220rpx;
   box-shadow: 0 4rpx 24rpx rgba(212, 160, 23, 0.5);
-  border: 1rpx solid #e0b030;
-  overflow: hidden;
+  border: 2rpx solid #e0b030;
 }
 
 .center-name {
@@ -376,24 +404,26 @@
   overflow: hidden;
   text-overflow: ellipsis;
   white-space: nowrap;
+  flex-shrink: 1;
+  min-width: 0;
 }
 
 .center-simplified {
-  color: rgba(255,255,255,0.8);
   font-size: 20rpx;
+  color: rgba(255,255,255,0.8);
   overflow: hidden;
   text-overflow: ellipsis;
   white-space: nowrap;
   flex-shrink: 1;
+  min-width: 0;
 }
 
 .center-gen {
+  font-size: 20rpx;
   color: rgba(255,255,255,0.75);
   overflow: hidden;
-  display: -webkit-box;
-  -webkit-box-orient: vertical;
-  -webkit-line-clamp: 2;
-  white-space: normal;
+  text-overflow: ellipsis;
+  white-space: nowrap;
 }
 
 /* ── 子女区域 ── */
@@ -411,17 +441,13 @@
 .children-list {
   display: flex;
   gap: 16rpx;
-  padding: 0 8rpx 8rpx;
-  justify-content: center;
+  padding: 0 275rpx 8rpx;
 }
 
 .child-card {
   background: linear-gradient(135deg, #1a3a2a 0%, #1e5c35 100%);
-  min-width: 160rpx;
-  max-width: 200rpx;
   border: 1rpx solid #2a7a45;
   box-shadow: 0 2rpx 10rpx rgba(30, 92, 53, 0.4);
-  position: relative;
 }
 
 .child-order-badge {
@@ -445,18 +471,18 @@
   margin-top: 4rpx;
 }
 
-/* ── 连接线 ── */
+/* ── 连接线(始终对齐屏幕中心) ── */
 .connector {
   display: flex;
   justify-content: center;
   width: 100%;
-  height: 40rpx;
+  height: 48rpx;
   align-items: center;
 }
 
 .connector-line {
   width: 3rpx;
-  height: 40rpx;
+  height: 48rpx;
   background: linear-gradient(to bottom, #2a5298, #4a6580);
   border-radius: 2rpx;
 }