验收20%

This commit is contained in:
2026-07-16 07:42:07 +08:00
parent 0dec90ffdd
commit cb25317412
108 changed files with 6477 additions and 1308 deletions
+246 -70
View File
@@ -1,116 +1,292 @@
<!-- 页面编号G-06用途公开家谱检索统一承载初始加载结果与无结果状态 -->
<!-- 页面编号G-06用途搜索家谱邀请码加入双模式定位目标家谱 -->
<template>
<view class="search-page">
<!-- 底图只提供完整纸纹不以 CSS 补色或绘制装饰 -->
<image class="search-page__paper" src="/static/assets/foundation/opaque/page-paper.jpg" mode="aspectFill" />
<image class="search-page__paper" src="/static/assets/foundation/opaque/page-paper.jpg" mode="scaleToFill" />
<image class="search-page__footer" src="/static/assets/foundation/transparent/footer-mountain-bamboo.png" mode="widthFix" />
<view class="search-page__header"><PageHeader title="查找家谱" /></view>
<view class="search-page__header"><PageHeader title="加入家谱" /></view>
<view class="search-page__content">
<!-- 选定题签稿题签位图只提供材质品牌谱印和标题保留为真实应用元素 -->
<view class="search-title-strip">
<image class="search-title-strip__skin" src="/static/assets/modules/genealogy/opaque/g06-search-title-strip.png" mode="scaleToFill" />
<image class="search-title-strip__seal" src="/static/assets/foundation/transparent/brand-seal.png" mode="aspectFit" />
<text class="search-title-strip__text">公开家谱检索</text>
<text class="search-title-strip__text">加入家谱</text>
</view>
<view class="search-controls">
<view class="search-field">
<image class="search-field__skin" src="/static/assets/modules/genealogy/opaque/g06-search-input-wide.png" mode="scaleToFill" />
<input v-model="keyword" class="search-input" placeholder="输入姓氏、谱名或地区" placeholder-class="search-input__placeholder" @confirm="search" />
</view>
<view class="search-action" @click="search">
<image class="search-action__skin" src="/static/assets/modules/genealogy/opaque/g06-search-button.png" mode="scaleToFill" />
<text class="search-action__label">搜索</text>
</view>
</view>
<image class="search-divider" src="/static/assets/modules/genealogy/transparent/section-divider.png" mode="scaleToFill" />
<!-- 同一路由内以数据状态切换避免为结果或空结果新增占位页面 -->
<view v-if="searchState === 'loading'" class="search-status search-loading">
<text>正在整理可申请加入的家谱</text>
</view>
<view v-else-if="searchState === 'initial'" class="search-status search-initial">
<text class="search-status__lead">从姓氏谱名或祖居地开始</text>
<text class="search-status__copy">找到合适的家谱后可申请加入并查阅</text>
<image class="search-status__hall" src="/static/assets/foundation/transparent/root-header-hall.png" mode="aspectFit" />
</view>
<view v-else-if="searchState === 'results'" class="search-results">
<view class="search-results__head"><text>检索到 {{ results.length }} 部可申请的家谱</text><text>点选后填写申请</text></view>
<GenealogyCard v-for="item in results" :key="item.id" :genealogy="item" role="可申请" @select="openApply" />
</view>
<view v-else class="search-status search-empty">
<image class="search-status__cloud" src="/static/assets/modules/genealogy/transparent/create-cloud.png" mode="aspectFit" />
<text class="search-status__lead">暂未找到公开家谱</text>
<text class="search-status__copy">可换一个姓氏谱名或祖居地再试</text>
<view class="mode-tabs">
<view class="mode-tab" :class="{ 'mode-tab--active': mode === 'search' }" @click="switchMode('search')">搜索家谱</view>
<view class="mode-tab" :class="{ 'mode-tab--active': mode === 'invite' }" @click="switchMode('invite')">邀请码加入</view>
</view>
<template v-if="mode === 'search'">
<view class="search-controls">
<view class="search-field">
<image class="search-field__skin" src="/static/assets/modules/genealogy/opaque/g06-search-input-wide.png" mode="scaleToFill" />
<input v-model.trim="keyword" class="search-input" placeholder="姓氏、谱名、地区或堂号" placeholder-class="search-input__placeholder" @confirm="search" />
<view v-if="keyword" class="search-clear" @click="clearSearch">清空</view>
</view>
<view class="search-action" @click="search">
<image class="search-action__skin" src="/static/assets/modules/genealogy/opaque/g06-search-button.png" mode="scaleToFill" />
<text class="search-action__label">搜索</text>
</view>
</view>
<view class="filter-row">
<text class="filter-label">地区</text>
<view v-for="area in areas" :key="area" class="filter-chip" :class="{ 'filter-chip--active': selectedArea === area }" @click="selectedArea = area">{{ area }}</view>
</view>
<image class="search-divider" src="/static/assets/modules/genealogy/transparent/section-divider.png" mode="scaleToFill" />
<view v-if="searchState === 'loading'" class="search-status search-loading">
<text class="search-status__lead">正在检索公开家谱</text>
<text class="search-status__copy">请稍候正在整理匹配结果</text>
</view>
<view v-else-if="searchState === 'initial'" class="search-status search-initial">
<text class="search-status__lead">先确认家族是否已有家谱</text>
<text class="search-status__copy">可按姓氏谱名地区或堂号查找避免重复创建</text>
<image class="search-status__hall" src="/static/assets/foundation/transparent/root-header-hall.png" mode="aspectFit" />
</view>
<view v-else-if="searchState === 'results'" class="search-results">
<view class="search-results__head"><text>检索到 {{ results.length }} 部家谱</text><text>请核对支系与管理信息</text></view>
<view v-for="item in results" :key="item.id" class="result-card genealogy-card" @click="openPreview(item)">
<image class="result-card__skin" src="/static/assets/modules/genealogy/transparent/list-slip-frame.png" mode="scaleToFill" />
<view class="result-card__content">
<view class="result-card__head">
<view>
<text class="result-card__name">{{ item.name }}</text>
<text class="result-card__identity">{{ item.surname }} · {{ item.hall }}</text>
</view>
<text class="result-card__relation" :class="`result-card__relation--${item.relation}`">{{ item.actionLabel }}</text>
</view>
<view class="result-card__facts">
<text>地区{{ item.location }}</text>
<text>所属上级谱{{ item.parentName }}</text>
<text>当前支系{{ item.branchName }}</text>
<text>管理信息{{ item.manager }} · {{ item.certification }}</text>
<text>{{ item.memberCount }} 位成员 · 更新于 {{ item.updatedAt }}</text>
</view>
<view class="result-card__action" @click.stop="handleResultAction(item)">{{ item.actionLabel }}</view>
</view>
</view>
</view>
<view v-else-if="searchState === 'empty'" class="search-status search-empty">
<image class="search-status__cloud" src="/static/assets/modules/genealogy/transparent/create-cloud.png" mode="aspectFit" />
<text class="search-status__lead">暂未找到匹配家谱</text>
<text class="search-status__copy">可调整地区或关键词后重试也可使用邀请码加入</text>
</view>
<view v-else class="search-status search-error">
<text class="search-status__lead">检索暂时失败</text>
<text class="search-status__copy">当前仅展示失败样式请稍后重新搜索</text>
<view class="status-retry" @click="search">重新搜索</view>
</view>
</template>
<template v-else>
<view class="invite-block">
<text class="invite-title">输入家谱邀请码</text>
<text class="invite-copy">邀请码用于定位指定家谱加入前仍需确认真实姓名和关系</text>
<view class="invite-controls">
<view class="invite-field">
<image class="search-field__skin" src="/static/assets/modules/genealogy/opaque/g06-search-input-wide.png" mode="scaleToFill" />
<input v-model.trim="inviteCode" class="invite-input" maxlength="12" placeholder="请输入邀请码" placeholder-class="search-input__placeholder" />
</view>
<view class="search-action" @click="verifyInvite">
<image class="search-action__skin" src="/static/assets/modules/genealogy/opaque/g06-search-button.png" mode="scaleToFill" />
<text class="search-action__label">验证</text>
</view>
</view>
<text class="invite-demo">样式验证可输入 JP2026</text>
</view>
<image class="search-divider" src="/static/assets/modules/genealogy/transparent/section-divider.png" mode="scaleToFill" />
<view v-if="inviteState === 'initial'" class="search-status invite-initial">
<text class="search-status__lead">通过邀请码直接定位家谱</text>
<text class="search-status__copy">验证有效后会显示目标家谱确认关系后可直接加入</text>
</view>
<view v-else-if="inviteState === 'invalid'" class="search-status invite-invalid">
<text class="search-status__lead">邀请码无效或已过期</text>
<text class="search-status__copy">请核对邀请码或向家谱管理员重新获取</text>
</view>
<view v-else class="invite-result">
<text class="invite-result__label">已定位目标家谱</text>
<view class="result-card genealogy-card">
<image class="result-card__skin" src="/static/assets/modules/genealogy/transparent/list-slip-frame.png" mode="scaleToFill" />
<view class="result-card__content">
<text class="result-card__name">{{ inviteTarget.name }}</text>
<view class="result-card__facts">
<text>{{ inviteTarget.surname }} · {{ inviteTarget.hall }} · {{ inviteTarget.location }}</text>
<text>所属上级谱{{ inviteTarget.parentName }}</text>
<text>当前支系{{ inviteTarget.branchName }}</text>
<text>{{ inviteTarget.manager }} · {{ inviteTarget.certification }}</text>
</view>
<view class="result-card__action" @click="confirmInvite">确认关系并加入</view>
</view>
</view>
<text class="invite-result__note">提交后直接加入无需等待审核</text>
</view>
</template>
</view>
</view>
</template>
<script setup>
import { onMounted, ref } from 'vue'
import { computed, ref } from 'vue'
import { onLoad, onUnload, onShow } from '@dcloudio/uni-app'
import PageHeader from '@/components/PageHeader.vue'
import GenealogyCard from '@/components/GenealogyCard.vue'
import { appApi } from '@/utils/api.js'
const mode = ref('search')
const keyword = ref('')
const allResults = ref([])
const results = ref([])
const selectedArea = ref('全部')
const searchState = ref('initial')
const inviteCode = ref('')
const inviteState = ref('initial')
const results = ref([])
let searchTimer = null
onMounted(async () => {
searchState.value = 'loading'
allResults.value = await appApi.getPublicGenealogies()
searchState.value = 'initial'
})
const areas = ['全部', '河南', '山东']
const resultFixtures = [
{ id: 2001, surname: '汤', name: '汤氏南阳宗谱', hall: '敦睦堂', location: '河南·南阳', parentName: '汤氏中华总谱', branchName: '南阳主支', manager: '管理员 汤文礼', certification: '资料已认证', memberCount: 428, updatedAt: '2026-07-12', relation: 'available', actionLabel: '申请加入' },
{ id: 2002, surname: '汤', name: '汤氏洛阳家谱', hall: '承志堂', location: '河南·洛阳', parentName: '汤氏中华总谱', branchName: '洛阳二支', manager: '管理员 汤文远', certification: '资料已认证', memberCount: 158, updatedAt: '2026-07-10', relation: 'joined', actionLabel: '已加入' },
{ id: 2003, surname: '汤', name: '汤氏济宁宗谱', hall: '敬宗堂', location: '山东·济宁', parentName: '汤氏鲁西总谱', branchName: '济宁主支', manager: '管理员 汤正明', certification: '管理员已实名', memberCount: 286, updatedAt: '2026-07-08', relation: 'pending', actionLabel: '审核中' },
{ id: 2004, surname: '汤', name: '汤氏清河家谱', hall: '思源堂', location: '山东·临清', parentName: '汤氏鲁西总谱', branchName: '清河支系', manager: '管理员 汤志成', certification: '资料已认证', memberCount: 96, updatedAt: '2026-07-05', relation: 'rejected', actionLabel: '修改后重新申请' },
{ id: 2005, surname: '汤', name: '汤氏汝南支谱', hall: '崇本堂', location: '河南·驻马店', parentName: '汤氏中原总谱', branchName: '汝南三支', manager: '管理员 汤国安', certification: '管理员已实名', memberCount: 72, updatedAt: '2026-07-02', relation: 'removed', actionLabel: '重新申请' },
{ id: 2006, surname: '汤', name: '汤氏新安家谱', hall: '继善堂', location: '河南·三门峡', parentName: '无上级谱', branchName: '新安主支', manager: '创建者 当前用户', certification: '资料待完善', memberCount: 34, updatedAt: '2026-06-28', relation: 'owned', actionLabel: '我创建的' }
]
const search = () => {
const value = keyword.value.trim()
results.value = value
? allResults.value.filter((item) => `${item.name}${item.surname}${item.location}`.includes(value))
: allResults.value
searchState.value = results.value.length ? 'results' : 'empty'
const inviteTarget = computed(() => resultFixtures[0])
const syncModeFromRoute = () => {
let requestedMode = 'search'
if (typeof location !== 'undefined') {
requestedMode = new URLSearchParams(location.hash.split('?')[1] || '').get('mode') || 'search'
} else {
const pages = getCurrentPages()
requestedMode = pages[pages.length - 1]?.options?.mode || 'search'
}
mode.value = requestedMode === 'invite' ? 'invite' : 'search'
}
const openApply = (genealogy) => uni.navigateTo({ url: `/pages/genealogy/g08-join-application?genealogyId=${genealogy.id}` })
onLoad(syncModeFromRoute)
onShow(syncModeFromRoute)
onUnload(() => { if (searchTimer) clearTimeout(searchTimer) })
const switchMode = (nextMode) => {
mode.value = nextMode
searchState.value = 'initial'
inviteState.value = 'initial'
}
const search = () => {
if (searchTimer) clearTimeout(searchTimer)
searchState.value = 'loading'
searchTimer = setTimeout(() => {
const value = keyword.value.trim()
if (value === '失败') {
searchState.value = 'error'
return
}
results.value = resultFixtures.filter((item) => {
const matchesKeyword = !value || `${item.name}${item.surname}${item.location}${item.hall}`.includes(value)
const matchesArea = selectedArea.value === '全部' || item.location.includes(selectedArea.value)
return matchesKeyword && matchesArea
})
searchState.value = results.value.length ? 'results' : 'empty'
searchTimer = null
}, 260)
}
const clearSearch = () => {
keyword.value = ''
results.value = []
searchState.value = 'initial'
}
const openPreview = (item) => {
if (item.relation === 'available') {
uni.navigateTo({ url: `/pages/genealogy/g05-genealogy-overview?mode=public&genealogyId=${item.id}` })
}
}
const handleResultAction = (item) => {
if (item.relation === 'available') return uni.navigateTo({ url: `/pages/genealogy/g08-join-application?source=search&genealogyId=${item.id}` })
if (item.relation === 'pending') return uni.navigateTo({ url: '/pages/genealogy/g09-my-applications?status=pending' })
if (item.relation === 'rejected' || item.relation === 'removed') return uni.navigateTo({ url: `/pages/genealogy/g08-join-application?source=search&previous=${item.relation}&genealogyId=${item.id}` })
return uni.reLaunch({ url: `/pages/genealogy/g01-my-genealogies?genealogyId=${item.id}` })
}
const verifyInvite = () => {
inviteState.value = inviteCode.value.toUpperCase() === 'JP2026' ? 'valid' : 'invalid'
}
const confirmInvite = () => uni.navigateTo({ url: `/pages/genealogy/g08-join-application?source=invite&genealogyId=${inviteTarget.value.id}` })
</script>
<style scoped lang="scss">
/* G06 的完整检索位图与叠放控件样式必须作为同一 SFC 样式模块刷新。 */
.search-page { position: relative; min-height: 100vh; overflow: hidden; background: $paper; }
.search-page { position: relative; min-height: 100vh; overflow-x: hidden; background: $paper; }
.search-page__paper { position: absolute; inset: 0; z-index: 0; width: 100%; height: 100%; opacity: .98; pointer-events: none; }
.search-page__footer { position: absolute; right: 0; bottom: 0; left: 0; z-index: 1; width: 100%; opacity: .15; pointer-events: none; }
.search-page__footer { position: fixed; right: 0; bottom: 0; left: 0; z-index: 1; width: 100%; opacity: .15; pointer-events: none; }
.search-page__header { position: relative; z-index: 2; }
.search-page__content { position: relative; z-index: 3; min-height: calc(100vh - 104rpx); padding: 30rpx 24rpx calc(58rpx + env(safe-area-inset-bottom)); box-sizing: border-box; }
.search-title-strip { position: relative; width: 100%; height: 138rpx; }
.search-title-strip__skin { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }
.search-title-strip__seal { position: absolute; top: 27rpx; left: 52rpx; z-index: 1; width: 72rpx; height: 84rpx; }
.search-title-strip__text { position: absolute; top: 0; right: 170rpx; bottom: 0; left: 156rpx; z-index: 1; display: flex; align-items: center; justify-content: center; color: #f5d596; font-family: 'STKaiti', 'KaiTi', serif; font-size: 39rpx; font-weight: 700; letter-spacing: 5rpx; }
.search-controls { display: flex; align-items: center; gap: 20rpx; margin-top: 48rpx; }
.search-title-strip__text { position: absolute; inset: 0 170rpx 0 156rpx; z-index: 1; display: flex; align-items: center; justify-content: center; color: #f5d596; font-family: 'STKaiti', 'KaiTi', serif; font-size: 39rpx; font-weight: 700; letter-spacing: 5rpx; }
.mode-tabs { display: flex; width: 500rpx; margin: 30rpx auto 0; border-bottom: 1rpx solid rgba(181, 138, 75, .45); }
.mode-tab { position: relative; display: flex; flex: 1; align-items: center; justify-content: center; min-height: 70rpx; color: $ink-muted; font-family: 'STKaiti', 'KaiTi', serif; font-size: 28rpx; }
.mode-tab--active { color: $brand-red; font-weight: 700; }
.mode-tab--active::after { position: absolute; right: 42rpx; bottom: -2rpx; left: 42rpx; height: 4rpx; background: $brand-red; content: ''; }
.search-controls { display: flex; align-items: center; gap: 20rpx; margin-top: 32rpx; }
.invite-controls { display: flex; align-items: center; gap: 20rpx; margin-top: 32rpx; }
.search-field { position: relative; width: 430rpx; height: 95rpx; }
.search-field__skin, .search-action__skin { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }
.search-input { position: relative; z-index: 1; width: 100%; height: 100%; padding: 0 30rpx; box-sizing: border-box; color: $ink; font-size: 26rpx; }
.search-field__skin,
.search-action__skin { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }
.search-input { position: relative; z-index: 1; width: 100%; height: 100%; padding: 0 82rpx 0 30rpx; box-sizing: border-box; color: $ink; font-size: 25rpx; }
.search-input__placeholder { color: #ab9c83; }
.search-clear { position: absolute; z-index: 2; top: 0; right: 20rpx; display: flex; height: 100%; align-items: center; color: $brand-red; font-size: 21rpx; }
.search-action { position: relative; display: flex; width: 200rpx; height: 88rpx; align-items: center; justify-content: center; }
.search-action__label { position: relative; z-index: 1; color: #fff4dc; font-family: 'STKaiti', 'KaiTi', serif; font-size: 31rpx; font-weight: 700; letter-spacing: 7rpx; }
.search-divider { display: block; width: 100%; height: 30rpx; margin: 40rpx 0 34rpx; }
.search-status { display: flex; min-height: 190rpx; flex-direction: column; align-items: center; justify-content: center; padding: 10rpx 28rpx 24rpx; box-sizing: border-box; text-align: center; }
.search-action__label { position: relative; z-index: 1; color: #fff4dc; font-family: 'STKaiti', 'KaiTi', serif; font-size: 31rpx; font-weight: 700; letter-spacing: 5rpx; }
.filter-row { display: flex; align-items: center; gap: 12rpx; margin: 16rpx 14rpx 0; }
.filter-label { color: $ink-muted; font-size: 22rpx; }
.filter-chip { display: flex; min-width: 82rpx; min-height: 52rpx; align-items: center; justify-content: center; color: $ink-muted; font-size: 22rpx; }
.filter-chip--active { color: $brand-red; font-weight: 700; }
.search-divider { display: block; width: 100%; height: 30rpx; margin: 24rpx 0 24rpx; }
.search-status { display: flex; min-height: 240rpx; flex-direction: column; align-items: center; justify-content: center; padding: 16rpx 28rpx 24rpx; box-sizing: border-box; text-align: center; }
.search-status__cloud { width: 92rpx; height: 46rpx; margin-bottom: 4rpx; opacity: .78; }
.search-status__lead { color: $ink; font-family: 'STKaiti', 'KaiTi', serif; font-size: 29rpx; font-weight: 700; letter-spacing: 2rpx; }
.search-status__copy { margin-top: 12rpx; color: $ink-muted; font-size: 22rpx; }
.search-status__hall { width: 330rpx; height: 132rpx; margin-top: 330rpx; opacity: .22; filter: grayscale(1); }
.search-loading { min-height: 168rpx; color: $ink-muted; font-size: 24rpx; }
.search-results { display: flex; flex-direction: column; gap: 18rpx; margin-top: 6rpx; }
.search-results__head { display: flex; align-items: center; justify-content: space-between; padding: 0 16rpx; color: $ink-muted; font-size: 22rpx; }
.search-status__lead { color: $ink; font-family: 'STKaiti', 'KaiTi', serif; font-size: 30rpx; font-weight: 700; letter-spacing: 2rpx; }
.search-status__copy { margin-top: 12rpx; color: $ink-muted; font-size: 22rpx; line-height: 36rpx; }
.search-status__hall { width: 330rpx; height: 132rpx; margin-top: 210rpx; opacity: .22; filter: grayscale(1); }
.status-retry { display: flex; min-height: 70rpx; align-items: center; margin-top: 18rpx; color: $brand-red; font-size: 24rpx; }
.search-results { display: flex; flex-direction: column; gap: 16rpx; margin-top: 4rpx; }
.search-results__head { display: flex; align-items: center; justify-content: space-between; padding: 0 16rpx; color: $ink-muted; font-size: 21rpx; }
.search-results__head text:first-child { color: $ink; font-family: 'STKaiti', 'KaiTi', serif; font-size: 27rpx; font-weight: 700; }
.result-card { position: relative; min-height: 314rpx; box-sizing: border-box; padding: 28rpx 30rpx; overflow: hidden; }
.result-card__skin { position: absolute; inset: 0; width: 100%; height: 100%; }
.result-card__content { position: relative; z-index: 1; }
.result-card__head { display: flex; align-items: flex-start; justify-content: space-between; }
.result-card__name,
.result-card__identity { display: block; }
.result-card__name { color: $ink; font-family: 'STKaiti', 'KaiTi', serif; font-size: 33rpx; font-weight: 700; }
.result-card__identity { margin-top: 5rpx; color: $ink-muted; font-size: 22rpx; }
.result-card__relation { flex: 0 0 auto; max-width: 190rpx; margin-left: 12rpx; color: #9a641f; font-size: 21rpx; text-align: right; }
.result-card__relation--rejected,
.result-card__relation--removed { color: $brand-red; }
.result-card__facts { display: grid; grid-template-columns: 1fr 1fr; gap: 8rpx 18rpx; margin-top: 16rpx; color: $ink-muted; font-size: 23rpx; line-height: 32rpx; }
.result-card__facts text:nth-child(4),
.result-card__facts text:nth-child(5) { grid-column: 1 / -1; }
.result-card__action { display: flex; min-height: 58rpx; align-items: center; justify-content: center; margin-top: 14rpx; color: $brand-red; font-family: 'STKaiti', 'KaiTi', serif; font-size: 27rpx; font-weight: 700; }
.invite-block { padding: 24rpx 18rpx 0; }
.invite-title { display: block; color: $ink; font-family: 'STKaiti', 'KaiTi', serif; font-size: 31rpx; font-weight: 700; }
.invite-copy { display: block; margin-top: 10rpx; color: $ink-muted; font-size: 22rpx; line-height: 35rpx; }
.invite-field { position: relative; flex: 1; height: 95rpx; }
.invite-input { position: relative; z-index: 1; width: 100%; height: 100%; padding: 0 30rpx; box-sizing: border-box; color: $ink; font-size: 25rpx; letter-spacing: 3rpx; }
.invite-demo { display: block; margin-top: 8rpx; color: #9b876f; font-size: 19rpx; }
.invite-result__label { display: block; margin: 0 12rpx 12rpx; color: $ink; font-family: 'STKaiti', 'KaiTi', serif; font-size: 27rpx; font-weight: 700; }
.invite-result__note { display: block; margin-top: 12rpx; color: $brand-red; font-size: 22rpx; text-align: center; }
@media screen and (max-width: 340px) {
.search-page__content { padding-right: 20rpx; padding-left: 20rpx; }
.search-title-strip__seal { left: 44rpx; }
.search-title-strip__text { right: 148rpx; left: 138rpx; font-size: 37rpx; }
.search-field { width: 430rpx; }
.search-action { width: 200rpx; height: 88rpx; }
.result-card { padding-right: 24rpx; padding-left: 24rpx; }
.result-card__facts { grid-template-columns: 1fr; }
.result-card__facts text { grid-column: 1 !important; }
}
</style>