feat: complete huihui square avatar workflows

This commit is contained in:
stefanfeng
2026-07-24 14:04:21 +08:00
parent 2ef58a44b8
commit e3bda469bb
68 changed files with 8062 additions and 132 deletions
@@ -0,0 +1,142 @@
<template>
<div class="contacts-page">
<!-- 顶部导航 -->
<header class="page-header">
<div class="header-left">
<button class="back-btn" @click="goBack">‹</button>
<h1 class="page-title">分身人脉</h1>
</div>
<button class="add-btn" @click="addContact">+</button>
</header>
<!-- 搜索 -->
<section class="search-section">
<div class="search-box">
<span class="search-icon">🔍</span>
<input v-model="keyword" class="search-input" placeholder="搜索人脉" />
</div>
</section>
<!-- 人脉列表 -->
<section class="contacts-section">
<div class="contact-list" v-if="filteredContacts.length > 0">
<div class="contact-item" v-for="c in filteredContacts" :key="c.id">
<div class="contact-avatar">{{ c.emoji }}</div>
<div class="contact-info">
<div class="contact-name-row">
<span class="contact-name">{{ c.name }}</span>
<span class="relation-tag" :class="c.relation">{{ relationText(c.relation) }}</span>
</div>
<span class="contact-last">最近互动:{{ c.last }}</span>
</div>
<button class="chat-btn" @click="openChat(c)">💬</button>
</div>
</div>
<div class="empty-state" v-else>
<span class="empty-icon">🤝</span>
<p class="empty-text">还没有人脉,点击右上角添加</p>
</div>
</section>
<p class="toast" v-if="toast">{{ toast }}</p>
</div>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue'
import { useRouter } from 'vue-router'
const router = useRouter()
const keyword = ref('')
const toast = ref('')
interface Contact { id: string; emoji: string; name: string; relation: string; last: string }
const contacts = ref<Contact[]>([
{ id: '1', emoji: '👩', name: '林小满', relation: 'friend', last: '今天 14:20' },
{ id: '2', emoji: '🧑', name: '陈工', relation: 'colleague', last: '昨天 09:10' },
{ id: '3', emoji: '👨', name: '王总', relation: 'client', last: '3 天前' },
{ id: '4', emoji: '🧑', name: 'Anna', relation: 'friend', last: '上周' }
])
const filteredContacts = computed(() =>
contacts.value.filter(c => c.name.includes(keyword.value))
)
const relationText = (r: string) => ({
friend: '好友', colleague: '同事', client: '客户'
}[r] || '好友')
const goBack = () => router.back()
const addContact = () => {
const sample = ['👤', '🧑', '👩', '🧑']
const names = ['新朋友', '合作伙伴', '张同学', '李经理']
const relations = ['friend', 'colleague', 'client']
const idx = contacts.value.length
contacts.value.unshift({
id: String(Date.now()),
emoji: sample[idx % sample.length],
name: names[idx % names.length],
relation: relations[idx % relations.length],
last: '刚刚添加'
})
toast.value = '已添加示例人脉'
setTimeout(() => (toast.value = ''), 2000)
}
const openChat = (c: Contact) => {
toast.value = `打开与 ${c.name} 的对话(示例)`
setTimeout(() => (toast.value = ''), 2000)
}
</script>
<style scoped>
.contacts-page { min-height: 100vh; background: #F8F9FA; padding-bottom: 40px; }
.page-header {
display: flex; align-items: center; justify-content: space-between;
padding: 16px 20px; background: linear-gradient(135deg, #F97316 0%, #FB923C 100%); color: white;
}
.header-left { display: flex; align-items: center; gap: 12px; }
.back-btn { background: none; border: none; color: white; font-size: 24px; cursor: pointer; padding: 4px; }
.page-title { font-size: 18px; font-weight: 600; margin: 0; }
.add-btn { background: rgba(255,255,255,0.2); border: none; color: white; font-size: 22px; width: 36px; height: 36px; border-radius: 50%; cursor: pointer; }
.search-section { padding: 16px 20px; }
.search-box { display: flex; align-items: center; gap: 8px; background: white; border-radius: 12px; padding: 10px 14px; box-shadow: 0 2px 8px rgba(0,0,0,0.05); }
.search-icon { font-size: 16px; }
.search-input { flex: 1; border: none; outline: none; font-size: 14px; color: #18191C; background: transparent; }
.contacts-section { padding: 0 20px; }
.contact-list { display: flex; flex-direction: column; gap: 10px; }
.contact-item {
display: flex; align-items: center; gap: 12px; padding: 14px 16px;
background: white; border-radius: 12px; box-shadow: 0 2px 8px rgba(0,0,0,0.05);
}
.contact-avatar {
width: 44px; height: 44px; border-radius: 50%; background: #FFF0E6;
display: flex; align-items: center; justify-content: center; font-size: 22px; flex-shrink: 0;
}
.contact-info { flex: 1; min-width: 0; }
.contact-name-row { display: flex; align-items: center; gap: 8px; margin-bottom: 4px; }
.contact-name { font-size: 15px; font-weight: 600; color: #18191C; }
.relation-tag { padding: 2px 8px; border-radius: 10px; font-size: 11px; font-weight: 500; }
.relation-tag.friend { background: #ECFDF5; color: #22C55E; }
.relation-tag.colleague { background: #EFF6FF; color: #3B82F6; }
.relation-tag.client { background: #FFF0E6; color: #F97316; }
.contact-last { font-size: 12px; color: #9398AE; }
.chat-btn {
width: 38px; height: 38px; border-radius: 50%; border: none; background: #FFF0E6;
font-size: 18px; cursor: pointer; flex-shrink: 0; transition: transform 0.2s;
}
.chat-btn:hover { transform: scale(1.08); }
.empty-state {
display: flex; flex-direction: column; align-items: center; justify-content: center;
padding: 40px 20px; background: white; border-radius: 12px; box-shadow: 0 2px 8px rgba(0,0,0,0.05);
}
.empty-icon { font-size: 48px; margin-bottom: 12px; }
.empty-text { font-size: 14px; color: #9398AE; margin: 0; }
.toast { text-align: center; font-size: 13px; color: #F97316; margin: 16px 20px 0; }
</style>