Files
----/前端源码/uni-app/components/screens/NamingSolutionsList.vue

392 lines
11 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="solutions-screen">
<view class="solutions-bg"></view>
<view class="status-bar-placeholder"></view>
<view class="solutions-header">
<view class="solutions-back-btn" @click="$emit('back')">
<text class="solutions-back-icon"></text>
</view>
<view class="solutions-header-center">
<text class="solutions-title">起名方案列表</text>
</view>
<view class="solutions-header-placeholder"></view>
</view>
<scroll-view scroll-y class="solutions-scroll">
<view class="solutions-content">
<view v-if="!solutions.length" class="solutions-empty">
<text class="solutions-empty-icon"></text>
<text class="solutions-empty-text">暂无方案</text>
</view>
<view
v-for="(it, idx) in solutions"
:key="String(it?.id || it?.solution_id || idx)"
class="solutions-item"
:style="{ animationDelay: (idx * 0.04) + 's' }"
@click="open(it)"
>
<view class="solutions-item-main">
<view class="solutions-item-header">
<view>
<text class="solutions-item-name">{{ titleOf(it) }}</text>
<text class="solutions-item-pinyin">{{ pinyinOf(it) }}</text>
</view>
<view class="solutions-item-actions">
<view class="solutions-item-view-btn" @click.stop="open(it)">
<text class="solutions-item-view-icon"></text>
<text class="solutions-item-view-text">查看</text>
</view>
<view class="solutions-item-badge">
<text class="solutions-item-badge-text">{{ idx + 1 }}</text>
</view>
</view>
</view>
<view class="solutions-item-meta">
<text class="solutions-tag">{{ tagAOf(it) }}</text>
<text class="solutions-tag">{{ tagBOf(it) }}</text>
</view>
<view class="solutions-item-meta-sub">
<text v-if="scoreOf(it)" class="solutions-chip">评分 {{ scoreOf(it) }}</text>
</view>
<view v-if="poetryOf(it)" class="solutions-item-poetry">
<text class="solutions-item-poetry-label">出处</text>
<text class="solutions-item-poetry-text">{{ poetryOf(it) }}</text>
</view>
</view>
</view>
</view>
</scroll-view>
</view>
</template>
<script setup lang="ts">
import { computed } from "vue";
import { namingApi } from "@/api/naming";
import { parseMaybeJson } from "@/utils/poll-test-solution-detail";
declare const uni: any;
const props = defineProps<{
reportId: number;
solutions: any[];
category?: string;
serviceType?: string;
}>();
const emit = defineEmits<{
back: [];
showDetail: [data: any, category?: string, serviceType?: string];
}>();
const solutions = computed(() => (Array.isArray(props.solutions) ? props.solutions : []));
const titleOf = (it: any) => {
const name = String(it?.name || it?.solution_name || it?.title || it?.label || "").trim();
if (name) return name;
const fallback = String(it?.given_name || it?.full_name || it?.company_name || "").trim();
return fallback || "方案";
};
const pinyinOf = (it: any) => String(it?.pinyin || it?.name_pinyin || "").trim() || "Pīn Yīn";
const tagAOf = (it: any) => String(it?.wuxing || it?.wuxing_tag || it?.element_tag || "五行均衡");
const tagBOf = (it: any) => String(it?.style || it?.style_tag || it?.feature_tag || "温文尔雅");
const poetryOf = (it: any) => String(it?.poetry_source || it?.poetry || it?.source || "").trim();
const scoreOf = (it: any) => {
const v = it?.total_score ?? it?.score;
if (v === null || v === undefined || v === "") return "";
return String(v);
};
const open = async (it: any) => {
const id = it?.id || it?.solution_id;
if (!id) {
uni.showToast({ title: "方案ID不存在", icon: "none" });
return;
}
try {
uni.showLoading({ title: "加载中..." });
const detailRaw: any = await namingApi.getSolutionDetail(id);
uni.hideLoading();
const parsed = parseMaybeJson(detailRaw);
if (!parsed || typeof parsed !== "object") {
uni.showToast({ title: "详情数据格式异常", icon: "none" });
return;
}
emit("showDetail", parsed, props.category, String(props.serviceType || ""));
} catch (e: any) {
uni.hideLoading();
uni.showToast({ title: e?.msg || e?.message || "加载失败", icon: "none" });
}
};
</script>
<style scoped>
.solutions-screen{
min-height: 100%;
position: relative;
overflow: hidden;
}
.solutions-bg{
position: fixed;
inset: 0;
background:
/* 纸张底色 */
radial-gradient(1200px 900px at 30% 20%, rgba(255,255,255,.92), rgba(245,241,232,.88) 45%, rgba(235,229,214,.92) 100%),
/* 纸纹颗粒 */
radial-gradient(2px 2px at 12% 18%, rgba(0,0,0,.06), transparent 55%),
radial-gradient(2px 2px at 48% 62%, rgba(0,0,0,.05), transparent 55%),
radial-gradient(2px 2px at 78% 34%, rgba(0,0,0,.04), transparent 55%),
radial-gradient(2px 2px at 32% 84%, rgba(0,0,0,.04), transparent 55%),
/* 墨韵晕染 */
radial-gradient(900px 520px at 12% 8%, rgba(25,28,33,.10), transparent 60%),
radial-gradient(760px 520px at 92% 22%, rgba(120,75,40,.08), transparent 62%),
radial-gradient(900px 640px at 40% 92%, rgba(90,35,35,.08), transparent 62%),
linear-gradient(180deg, #f6f2e8 0%, #efe7d6 60%, #f6f2e8 100%);
z-index: -1;
}
.status-bar-placeholder{
height: 24px;
}
.solutions-header{
display:flex;
align-items:center;
justify-content:space-between;
padding: 10px 14px 12px;
}
.solutions-back-btn{
width: 36px;
height: 36px;
border-radius: 12px;
border: 1px solid rgba(120,90,40,.26);
background: linear-gradient(180deg, rgba(255,255,255,.70), rgba(244,236,220,.65));
box-shadow: 0 6px 16px rgba(40,30,20,.10);
display:flex;
align-items:center;
justify-content:center;
}
.solutions-back-icon{
font-size: 22px;
color: rgba(82,60,28,.92);
line-height: 1;
}
.solutions-header-center{
display:flex;
flex-direction:column;
align-items:center;
gap: 3px;
}
.solutions-title{
font-size: 17px;
font-weight: 900;
color: rgba(28,24,20,.92);
letter-spacing: .08em;
font-family: "STSong","Songti SC","SimSun","STSong","Noto Serif SC",serif;
}
.solutions-subtitle{
font-size: 11px;
color: rgba(70,58,44,.72);
font-family: "STSong","Songti SC","SimSun","STSong","Noto Serif SC",serif;
}
.solutions-header-placeholder{
width: 36px;
height: 36px;
}
.solutions-scroll{
height: calc(100vh - 24px - 58px);
}
.solutions-content{
padding: 2px 14px 24px;
box-sizing:border-box;
}
.solutions-empty{
padding: 26px 10px;
border-radius: 18px;
border: 1px solid rgba(120,90,40,.18);
background: linear-gradient(180deg, rgba(255,255,255,.76), rgba(247,239,224,.66));
box-shadow: 0 10px 26px rgba(40,30,20,.10);
text-align:center;
}
.solutions-empty-icon{
display:block;
font-size: 18px;
color: rgba(132,98,52,.85);
margin-bottom: 6px;
}
.solutions-empty-text{
font-size: 13px;
color: rgba(50,40,28,.78);
font-family: "STSong","Songti SC","SimSun","STSong","Noto Serif SC",serif;
}
.solutions-item{
position: relative;
display:flex;
align-items:stretch;
justify-content:space-between;
border-radius: 18px;
border: 1px solid rgba(178,120,120,.45);
background:
linear-gradient(180deg, rgba(255,255,255,.84), rgba(249,243,232,.78));
overflow:hidden;
padding: 14px 14px 13px 14px;
margin-bottom: 14px;
animation: solFadeUp .22s ease both;
box-shadow:
0 14px 30px rgba(40,30,20,.14),
inset 0 1px 0 rgba(255,255,255,.55);
}
.solutions-item-main{
flex: 1;
}
.solutions-item-header{
display:flex;
align-items:flex-start;
justify-content:space-between;
gap: 10px;
}
.solutions-item-name{
font-size: 18px;
font-weight: 900;
color: #20252e;
letter-spacing: .04em;
font-family: "STSong","Songti SC","SimSun","STSong","Noto Serif SC",serif;
display: block;
}
.solutions-item-pinyin{
display: block;
margin-top: 4px;
font-size: 12px;
color: rgba(32,37,46,.72);
letter-spacing: .08em;
}
.solutions-item-badge{
width: 24px;
height: 24px;
border-radius: 999px;
border: 1px solid rgba(202,166,96,.62);
background:
linear-gradient(180deg, rgba(255,245,220,.90), rgba(248,229,184,.82));
display:flex;
align-items:center;
justify-content:center;
flex: 0 0 24px;
}
.solutions-item-badge-text{
font-size: 11px;
font-weight: 900;
color: rgba(128,96,42,.92);
}
.solutions-item-actions{
display: flex;
align-items: center;
gap: 8px;
}
.solutions-item-view-btn{
height: 26px;
padding: 0 10px;
border-radius: 999px;
border: 1px solid rgba(188,170,136,.78);
background: rgba(255,255,255,.70);
display:flex;
align-items:center;
gap: 4px;
box-shadow: 0 2px 6px rgba(40,30,20,.08);
}
.solutions-item-view-icon{
font-size: 12px;
color: rgba(55,60,68,.75);
}
.solutions-item-view-text{
font-size: 12px;
font-weight: 700;
color: rgba(55,60,68,.85);
}
.solutions-item-meta{
display:flex;
gap: 8px;
margin-top: 8px;
flex-wrap: wrap;
}
.solutions-tag{
font-size: 11px;
padding: 3px 8px;
border-radius: 7px;
border: 1px solid rgba(188,114,114,.52);
color: rgba(130,58,58,.90);
background: rgba(255,250,248,.78);
font-family: "STSong","Songti SC","SimSun","STSong","Noto Serif SC",serif;
}
.solutions-item-meta-sub{
display:flex;
gap: 8px;
margin-top: 9px;
flex-wrap: wrap;
}
.solutions-chip{
font-size: 10px;
padding: 3px 8px;
border-radius: 999px;
border: 1px solid rgba(196,168,106,.42);
color: rgba(128,96,42,.88);
background: rgba(250,239,211,.65);
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
}
.solutions-item-poetry{
margin-top: 8px;
display:flex;
align-items:flex-start;
gap: 8px;
}
.solutions-item-poetry-label{
flex: 0 0 auto;
font-size: 11px;
line-height: 1.5;
color: rgba(130,58,58,.90);
border: 1px solid rgba(188,114,114,.50);
border-radius: 6px;
padding: 1px 6px;
background: rgba(255,250,248,.78);
}
.solutions-item-poetry-text{
flex: 1;
font-size: 12px;
line-height: 1.6;
color: rgba(40,34,26,.82);
font-family: "STSong","Songti SC","SimSun","STSong","Noto Serif SC",serif;
}
@keyframes solFadeUp{
from{opacity:0;transform:translateY(6px)}
to{opacity:1;transform:translateY(0)}
}
/* 细节:内侧金线与“卷轴边” */
.solutions-item::before{
content:"";
position:absolute;
inset: 9px 9px 9px 9px;
border-radius: 12px;
border: 1px solid rgba(188,170,136,.28);
pointer-events:none;
}
.solutions-item::after{
content:"";
position:absolute;
top:-40px;
right:-60px;
width: 160px;
height: 160px;
background: radial-gradient(closest-side, rgba(188,114,114,.08), transparent 70%);
transform: rotate(18deg);
pointer-events:none;
}
/* 轻微按压反馈 */
.solutions-item:active{
transform: translateY(1px);
box-shadow:
0 10px 22px rgba(40,30,20,.12),
inset 0 1px 0 rgba(255,255,255,.55);
}
</style>