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

293 lines
6.7 KiB
Vue

<template>
<view class="naming-result">
<view class="naming-result-header">
<text class="naming-result-title">甄选吉名</text>
<view class="naming-result-reset" @click="$emit('reset')">
<text>重测</text>
</view>
</view>
<view class="naming-result-list">
<view v-for="item in results" :key="item.id" class="naming-result-item">
<view class="naming-result-item-bg"></view>
<view class="naming-result-item-actions">
<view class="naming-result-action-btn" @click.stop="checkDup(item.id)">查重</view>
<view
class="naming-result-action-btn naming-result-action-btn-heart"
:class="item.isFavorite ? 'naming-result-action-btn-heart-active' : ''"
@click.stop="toggleFav(item.id)"
></view>
</view>
<view class="naming-result-item-content" @click="handleItemClick(item)">
<text class="naming-result-item-name">{{ item.name }}</text>
<text class="naming-result-item-pinyin">{{ item.pinyin }}</text>
</view>
<view class="naming-result-item-tags" @click="handleItemClick(item)">
<text v-for="(t, i) in item.tags" :key="i" class="naming-result-tag">{{ t }}</text>
<text v-if="item.duplicateRate" class="naming-result-tag naming-result-tag-gold">
重名率: {{ item.duplicateRate }}
</text>
</view>
<view class="naming-result-item-divider"></view>
<view class="naming-result-item-details" @click="handleItemClick(item)">
<view class="naming-result-detail-row">
<text class="naming-result-detail-label naming-result-detail-label-primary">寓意</text>
<text class="naming-result-detail-text">{{ item.meaning }}</text>
</view>
<view class="naming-result-detail-row">
<text class="naming-result-detail-label">出处</text>
<text class="naming-result-detail-text naming-result-detail-text-small">{{ item.source }}</text>
</view>
</view>
</view>
</view>
</view>
</template>
<script setup lang="ts">
import { ref, watch } from "vue";
import { userApi } from "@/api";
declare const uni: any;
export interface GeneratedName {
id: string;
name: string;
pinyin: string;
meaning: string;
source: string;
tags: string[];
isFavorite?: boolean;
duplicateRate?: string;
score?: number;
zodiac?: string;
wuxing?: string;
constellation?: string;
}
const props = withDefaults(defineProps<{
data: GeneratedName[];
category?: 'personal' | 'company';
payBusinessId?: number;
payAmount?: number;
}>(), {
category: 'company',
payAmount: 9.9,
});
const emit = defineEmits<{
reset: [];
showDetail: [data: GeneratedName];
}>();
const results = ref<GeneratedName[]>([]);
watch(() => props.data, (newData: GeneratedName[]) => {
if (newData) {
results.value = newData.map((item: GeneratedName) => ({ ...item }));
}
}, { immediate: true });
const toggleFav = async (id: string) => {
const idx = results.value.findIndex((r: GeneratedName) => r.id === id);
if (idx < 0) return;
const solutionId = Number(id);
const prev = !!results.value[idx].isFavorite;
if (!prev) {
const res = await userApi.favoriteSolution({ solution_id: solutionId, category: props.category });
results.value[idx].isFavorite = true;
uni.showToast({ title: res?.msg || '收藏成功', icon: 'success' });
} else {
const res = await userApi.unfavoriteSolution({ solution_id: solutionId });
results.value[idx].isFavorite = false;
uni.showToast({ title: res?.msg || '已取消收藏', icon: 'success' });
}
};
const checkDup = (id: string) => {
const rates = ["低 (<100人)", "中 (~1000人)", "高 (>10000人)"];
const rate = rates[Math.floor(Math.random() * rates.length)];
results.value = results.value.map((r: GeneratedName) =>
r.id === id ? { ...r, duplicateRate: rate } : r
);
};
const handleItemClick = (item: GeneratedName) => {
emit("showDetail", item);
};
</script>
<style scoped>
.naming-result {
padding-bottom: 80rpx;
}
.naming-result-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 24rpx;
}
.naming-result-title {
font-size: 18px;
font-weight: 700;
color: #8b2323;
}
.naming-result-reset {
border: none;
background: transparent;
font-size: 12px;
color: #5a5a5a;
}
.naming-result-list {
display: flex;
flex-direction: column;
gap: 16rpx;
}
.naming-result-item {
background-color: #f9f7f2;
border-radius: 16rpx;
border: 1px solid #dcd3c9;
padding: 28rpx 24rpx 24rpx;
position: relative;
overflow: hidden;
}
.naming-result-item-bg {
position: absolute;
top: 0;
right: 0;
padding: 8rpx;
opacity: 0.08;
pointer-events: none;
}
.naming-result-item-actions {
position: absolute;
top: 12rpx;
right: 12rpx;
display: flex;
align-items: center;
gap: 8rpx;
z-index: 2;
}
.naming-result-action-btn {
border-radius: 999rpx;
border: 1px solid #dcd3c9;
background: rgba(255, 255, 255, 0.6);
font-size: 12px;
color: #5a5a5a;
padding:7rpx 12rpx;
}
.naming-result-action-btn-heart {
padding: 6rpx;
width: 15px;
height: 15px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
}
.naming-result-action-btn-heart-active {
color: #8b2323;
}
.naming-result-item-content {
padding-right: 80rpx;
}
.naming-result-item-name {
font-size: 22px;
font-weight: 700;
color: #2c2c2c;
margin-bottom: 4rpx;
display: block;
}
.naming-result-item-pinyin {
font-size: 12px;
color: #5a5a5a;
margin-bottom: 8rpx;
display: block;
}
.naming-result-item-tags {
display: flex;
flex-wrap: wrap;
gap: 8rpx;
margin-bottom: 8rpx;
}
.naming-result-tag {
font-size: 10px;
padding: 4rpx 8rpx;
border-radius: 6rpx;
border: 1px solid rgba(139, 35, 35, 0.2);
color: #8b2323;
background: rgba(139, 35, 35, 0.04);
}
.naming-result-tag-gold {
border-color: #d4af37;
color: #d4af37;
background: rgba(212, 175, 55, 0.08);
}
.naming-result-item-divider {
height: 1px;
margin: 12rpx 0;
background-color: #e5e5e5;
}
.naming-result-item-details {
display: flex;
flex-direction: column;
gap: 8rpx;
}
.naming-result-detail-row {
display: flex;
align-items: flex-start;
gap: 12rpx;
}
.naming-result-detail-label {
font-size: 10px;
padding: 4rpx 8rpx;
border-radius: 4rpx;
border: 1px solid #5a5a5a;
color: #5a5a5a;
margin-top: 4rpx;
white-space: nowrap;
}
.naming-result-detail-label-primary {
border-color: #8b2323;
color: #8b2323;
}
.naming-result-detail-text {
font-size: 14px;
color: #2c2c2c;
}
.naming-result-detail-text-small {
font-size: 12px;
color: #5a5a5a;
font-style: italic;
}
</style>