feat: migrate app routes and business modules

This commit is contained in:
2026-08-12 18:22:59 +08:00
parent 555aa00043
commit cc706378c2
247 changed files with 28623 additions and 14988 deletions
+286
View File
@@ -0,0 +1,286 @@
<template>
<view
class="genealogy-card"
:class="{ 'genealogy-card--current': selected }"
role="button"
:aria-label="accessibleLabel"
hover-class="genealogy-card--pressed"
@click="$emit('select', genealogy)"
>
<image
class="row-frame"
src="/static/assets/modules/genealogy/transparent/list-slip-frame.png"
mode="scaleToFill"
/>
<view class="surname-seal">
<image
class="surname-seal-frame"
src="/static/assets/modules/genealogy/transparent/row-seal-frame.png"
mode="scaleToFill"
/>
<view class="surname-seal-copy">
<text class="seal-title">家谱</text>
</view>
</view>
<view class="card-main">
<view class="card-title-row">
<text class="card-name">{{ genealogy.name }}</text>
<image
class="card-chevron"
src="/static/assets/foundation/transparent/chevron-right.png"
mode="aspectFit"
/>
</view>
<view class="card-detail-row">
<view class="card-meta-item card-meta-item--location">
<image
class="card-meta-icon"
src="/static/assets/foundation/transparent/meta-location.png"
mode="aspectFit"
/>
<text class="card-meta">{{ genealogy.location }}</text>
</view>
<view class="card-meta-item card-meta-item--members">
<image
class="card-meta-icon"
src="/static/assets/foundation/transparent/meta-member.png"
mode="aspectFit"
/>
<text class="card-meta">{{ genealogy.memberCount }} 位成员</text>
</view>
<view class="card-trailing">
<text class="card-role app-single-line">{{ role }}</text>
<text v-if="genealogy.updatedAt" class="card-updated app-single-line"
>更新于 {{ genealogy.updatedAt }}</text
>
</view>
</view>
</view>
</view>
</template>
<script setup>
import { computed } from "vue";
const props = defineProps({
genealogy: { type: Object, required: true },
role: { type: String, required: true },
selected: { type: Boolean, default: false },
});
defineEmits(["select"]);
const accessibleLabel = computed(
() =>
`${props.genealogy.name}${props.role}${props.selected ? ',当前家谱' : ''}${props.genealogy.location}${props.genealogy.memberCount} 位成员`,
);
</script>
<style scoped lang="scss">
.genealogy-card {
--card-padding-x: 24rpx;
--card-padding-y: 20rpx;
display: grid;
grid-template-columns: 68rpx minmax(0, 1fr);
min-height: 204rpx;
align-items: center;
column-gap: 20rpx;
padding: 20rpx 24rpx;
box-sizing: border-box;
background: transparent;
}
.genealogy-card--current {
background: transparent;
}
.genealogy-card--pressed {
opacity: 0.72;
}
.row-frame {
grid-area: 1 / 1 / 2 / -1;
z-index: 1;
width: calc(100% + var(--card-padding-x) + var(--card-padding-x));
height: calc(100% + var(--card-padding-y) + var(--card-padding-y));
margin: calc(-1 * var(--card-padding-y)) calc(-1 * var(--card-padding-x));
pointer-events: none;
}
.surname-seal {
display: grid;
grid-column: 1;
grid-row: 1;
z-index: 2;
width: 68rpx;
height: 106rpx;
place-items: center;
color: #fff5df;
}
.surname-seal-frame {
z-index: 0;
width: 100%;
height: 100%;
}
.surname-seal-frame,
.surname-seal-copy {
grid-area: 1 / 1;
}
.surname-seal-copy {
z-index: 1;
display: flex;
height: 78rpx;
align-items: center;
justify-content: center;
}
.seal-title {
color: #fff5df;
font-family: "STKaiti", "KaiTi", serif;
font-size: clamp(17px, 30rpx, 22px);
font-weight: 700;
letter-spacing: 2rpx;
line-height: 1;
writing-mode: vertical-rl;
}
.genealogy-card:not(.genealogy-card--current) .surname-seal-frame {
opacity: 0.32;
}
.genealogy-card:not(.genealogy-card--current) .seal-title {
color: $ink-muted;
}
.card-main {
grid-column: 2;
grid-row: 1;
z-index: 2;
display: flex;
min-width: 0;
flex: 1;
flex-direction: column;
}
.card-title-row {
display: flex;
min-width: 0;
align-items: center;
justify-content: space-between;
gap: 12rpx;
}
.card-name {
min-width: 0;
flex: 1;
color: $ink;
font-family: "STKaiti", "KaiTi", serif;
font-size: clamp(18px, 34rpx, 23px);
font-weight: 700;
line-height: 1.25;
overflow: hidden;
overflow-wrap: anywhere;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
}
.card-detail-row {
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
min-width: 0;
align-items: center;
column-gap: 16rpx;
row-gap: 4rpx;
margin-top: 10rpx;
}
.card-meta-item {
display: flex;
min-width: 0;
align-items: center;
}
.card-meta-item--location {
grid-column: 1 / -1;
}
.card-meta-item--members {
grid-column: 1;
}
.card-meta-icon {
width: 38rpx;
height: 38rpx;
flex: 0 0 auto;
margin-right: 6rpx;
opacity: 1;
filter: saturate(1.35) brightness(0.82) contrast(1.15);
}
.card-meta {
min-width: 0;
color: #62584c;
font-size: clamp(15px, 24rpx, 18px);
font-weight: 500;
overflow-wrap: anywhere;
}
.card-trailing {
grid-column: 2;
display: flex;
min-width: 0;
align-items: flex-end;
justify-content: center;
row-gap: 4rpx;
flex-direction: column;
}
.card-updated {
display: flex;
align-items: center;
justify-content: flex-end;
margin-top: 0;
margin-left: 0;
color: #62584c;
font-size: clamp(14px, 22rpx, 17px);
font-weight: 500;
line-height: 1.35;
white-space: nowrap;
overflow-wrap: anywhere;
}
.card-role {
min-width: 0;
padding: 3rpx 10rpx 4rpx;
border: 1rpx solid rgba(181, 138, 75, 0.56);
border-radius: 999rpx;
color: #7f4f16;
font-size: clamp(14px, 23rpx, 17px);
font-weight: 600;
line-height: 1.25;
white-space: nowrap;
}
.card-chevron {
width: 30rpx;
height: 30rpx;
margin-left: 8rpx;
}
@media screen and (max-width: 340px) {
.genealogy-card {
--card-padding-x: 18rpx;
grid-template-columns: 62rpx minmax(0, 1fr);
column-gap: 16rpx;
min-height: 176rpx;
padding-right: 18rpx;
padding-left: 18rpx;
}
.surname-seal {
width: 62rpx;
height: 96rpx;
}
.card-name {
font-size: clamp(17px, 32rpx, 22px);
}
.card-meta {
font-size: clamp(14px, 22rpx, 17px);
}
.card-updated {
display: none;
}
.card-chevron {
width: 28rpx;
height: 28rpx;
margin-left: 8rpx;
}
}
</style>