通讯录页面布局

This commit is contained in:
2026-09-23 19:10:16 +08:00
parent bfec3f99b1
commit 74bdeb7a11
+116 -45
View File
@@ -6,29 +6,42 @@
</template> </template>
</fy-header> </fy-header>
<fy-scroll class="edge-scroll" dock @refresh="reload"> <fy-scroll class="edge-scroll" dock @refresh="reload">
<wd-search v-model="q" placeholder="搜索同事、部门或手机号" hide-cancel placeholder-left /> <view class="finder">
<view class="org" @click="goGroups"> <wd-icon name="search" size="28rpx" color="#9CA3AF" />
<view class="obox">👥</view> <input v-model="q" class="finder-input" placeholder="搜索同事、部门或手机号" placeholder-class="finder-ph" confirm-type="search" />
<view class="ometa"> <view v-if="q" class="finder-clear" @click="q = ''">
<text class="on">群聊</text> <wd-icon name="close-bold" size="22rpx" color="#9CA3AF" />
<text class="os">{{ groupCount }} 个群</text>
</view> </view>
<text class="arr"></text>
</view> </view>
<view class="org" @click="goSearch"> <view class="shortcuts">
<view class="obox">🏛</view> <view class="org" @click="goGroups">
<view class="ometa"> <view class="obox group">
<text class="on">全员架构</text> <wd-icon name="usergroup" size="36rpx" color="#1677FF" />
<text class="os"> {{ deptCount }} 个部门 · {{ peopleCount }} 位在职成员</text> </view>
<view class="ometa">
<text class="on">群聊</text>
<text class="os">{{ groupCount }} 个群</text>
</view>
<wd-icon name="arrow-right" size="28rpx" color="#D1D5DB" />
</view>
<view class="org" @click="goSearch">
<view class="obox orgn">
<wd-icon name="layers" size="36rpx" color="#16A34A" />
</view>
<view class="ometa">
<text class="on">全员架构</text>
<text class="os">{{ deptCount }} 个部门 · {{ peopleCount }} 位在职</text>
</view>
<wd-icon name="arrow-right" size="28rpx" color="#D1D5DB" />
</view> </view>
<text class="arr"></text>
</view> </view>
<view v-for="g in groups" :key="g.name" class="block"> <view v-for="g in groups" :key="g.name" class="block">
<view class="dept" @click="toggle(g.name)"> <view class="dept" @click="toggle(g.name)">
<text>{{ g.name }}</text> <text class="dept-name">{{ g.name }}</text>
<text class="cnt">({{ g.people.length }})</text> <text class="cnt">{{ g.people.length }}</text>
<wd-icon class="chev" :name="open[g.name] === false ? 'arrow-right' : 'arrow-down'" size="24rpx" color="#9CA3AF" />
</view> </view>
<view v-if="open[g.name] !== false" class="card"> <view v-if="open[g.name] !== false" class="card people">
<view v-for="p in g.people" :key="p.id" class="item" @click="openPerson(p)"> <view v-for="p in g.people" :key="p.id" class="item" @click="openPerson(p)">
<view class="av-wrap"> <view class="av-wrap">
<image v-if="p.avatar" class="av" :src="p.avatar" mode="aspectFill" /> <image v-if="p.avatar" class="av" :src="p.avatar" mode="aspectFill" />
@@ -37,16 +50,21 @@
</view> </view>
<view class="meta"> <view class="meta">
<text class="name">{{ p.name }}</text> <text class="name">{{ p.name }}</text>
<text class="sub">{{ p.online ? '在线' : '离线' }} · {{ p.title }}</text> <text class="sub">{{ p.title || (p.online ? '在线' : '离线') }}</text>
</view>
<view class="acts">
<view class="mini" @click.stop="chat(p)">
<wd-icon name="chat" size="34rpx" color="#1677FF" />
</view>
<view class="mini" @click.stop="call(p)">
<wd-icon name="phone" size="34rpx" color="#1677FF" />
</view>
</view> </view>
<text class="chip">{{ p.title }}</text>
<text class="mini" @click.stop="chat(p)">💬</text>
<text class="mini" @click.stop="call(p)"></text>
</view> </view>
</view> </view>
</view> </view>
<view v-if="!groups.length" class="empty">没有匹配的同事</view> <view v-if="!groups.length" class="empty">没有匹配的同事</view>
<text class="foot">仅显示当前所属企业成员 · 数据实时同步</text> <text class="foot">仅显示当前所属企业成员</text>
</fy-scroll> </fy-scroll>
</view> </view>
</template> </template>
@@ -132,28 +150,81 @@ export default {
</script> </script>
<style scoped> <style scoped>
.search { padding: 16rpx 24rpx; } .finder {
.search input { height: 80rpx; background: #fff; border-radius: 20rpx; padding: 0 28rpx; font-size: 28rpx; border: 1rpx solid rgba(17,24,39,0.06); } margin: 8rpx 24rpx 12rpx;
.org { margin: 0 24rpx 16rpx; background: #fff; border-radius: 16rpx; padding: 20rpx; display: flex; align-items: center; } height: 56rpx;
.obox { width: 64rpx; height: 64rpx; border-radius: 12rpx; background: #E8ECF2; display: flex; align-items: center; justify-content: center; } padding: 0 20rpx;
.ometa { flex: 1; margin-left: 16rpx; } border-radius: 12rpx;
.on { display: block; font-size: 28rpx; font-weight: 700; } background: #fff;
.os { font-size: 22rpx; color: #6B7280; } display: flex;
.arr { color: #D1D5DB; } align-items: center;
.block { margin: 8rpx 24rpx 24rpx; } color: #9CA3AF;
.dept { display: flex; align-items: center; padding: 16rpx 12rpx; font-size: 26rpx; font-weight: 600; background: #F3F6FB; border-radius: 12rpx 12rpx 0 0; } }
.cnt { color: #6B7280; font-weight: 400; font-size: 22rpx; margin-left: 8rpx; } .finder-input {
.item { display: flex; align-items: center; padding: 20rpx 20rpx; } flex: 1;
.av-wrap { position: relative; width: 72rpx; height: 72rpx; } height: 56rpx;
.av { width: 72rpx; height: 72rpx; border-radius: 50%; } margin-left: 8rpx;
.av.txt { background: #E8ECF2; color: #4B5563; display: flex; align-items: center; justify-content: center; font-weight: 600; } font-size: 26rpx;
.dot { position: absolute; right: 0; bottom: 0; width: 16rpx; height: 16rpx; border-radius: 50%; background: #006c49; border: 2rpx solid #fff; } line-height: 56rpx;
.meta { flex: 1; margin-left: 16rpx; min-width: 0; } color: #111827;
.name { display: block; font-size: 28rpx; font-weight: 600; } }
.sub { font-size: 22rpx; color: #6B7280; } .finder-ph { color: #9CA3AF; font-size: 26rpx; }
.chip { font-size: 20rpx; color: #1677FF; background: #E8F1FF; padding: 4rpx 12rpx; border-radius: 999rpx; margin-right: 8rpx; } .finder-clear {
.mini { width: 56rpx; text-align: center; font-size: 28rpx; color: #1677FF; } width: 40rpx;
.empty { text-align: center; color: #6B7280; padding: 80rpx; } height: 40rpx;
.foot { display: block; text-align: center; color: #6B7280; font-size: 22rpx; padding: 20rpx 0 40rpx; } display: flex;
.ico { padding: 8rpx 16rpx; color: #1677FF; font-size: 26rpx; } align-items: center;
justify-content: center;
}
.shortcuts {
margin: 0 24rpx 8rpx;
background: #fff;
border-radius: 20rpx;
border: 1rpx solid rgba(17, 24, 39, 0.06);
overflow: hidden;
}
.org {
padding: 22rpx 24rpx;
display: flex;
align-items: center;
}
.org + .org { border-top: 1rpx solid #F0F2F5; }
.obox {
width: 72rpx;
height: 72rpx;
border-radius: 18rpx;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.obox.group { background: #E8F1FF; }
.obox.orgn { background: #E8F8EF; }
.ometa { flex: 1; margin: 0 16rpx; min-width: 0; }
.on { display: block; font-size: 30rpx; font-weight: 600; color: #111827; }
.os { display: block; margin-top: 4rpx; font-size: 22rpx; color: #6B7280; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.block { margin: 20rpx 24rpx 0; }
.dept {
display: flex;
align-items: center;
padding: 8rpx 8rpx 12rpx;
}
.dept-name { font-size: 24rpx; font-weight: 600; color: #6B7280; }
.cnt { margin-left: 8rpx; font-size: 22rpx; color: #9CA3AF; }
.chev { margin-left: auto; }
.people { overflow: hidden; }
.item { display: flex; align-items: center; padding: 0 20rpx 0 24rpx; }
.item + .item .meta { border-top: 1rpx solid #F0F2F5; }
.av-wrap { position: relative; width: 80rpx; height: 80rpx; flex-shrink: 0; margin: 18rpx 0; }
.av { width: 80rpx; height: 80rpx; border-radius: 18rpx; }
.av.txt { background: #E8F1FF; color: #1677FF; display: flex; align-items: center; justify-content: center; font-weight: 600; font-size: 30rpx; }
.dot { position: absolute; right: -2rpx; bottom: -2rpx; width: 16rpx; height: 16rpx; border-radius: 50%; background: #16A34A; border: 3rpx solid #fff; }
.meta { flex: 1; margin-left: 20rpx; min-width: 0; padding: 22rpx 0; }
.name { display: block; font-size: 30rpx; font-weight: 600; color: #111827; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sub { display: block; margin-top: 4rpx; font-size: 22rpx; color: #6B7280; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.acts { display: flex; align-items: center; flex-shrink: 0; margin-left: 8rpx; }
.mini { width: 64rpx; height: 64rpx; display: flex; align-items: center; justify-content: center; }
.empty { text-align: center; color: #6B7280; padding: 120rpx 40rpx; font-size: 28rpx; }
.foot { display: block; text-align: center; color: #9CA3AF; font-size: 22rpx; padding: 28rpx 0 48rpx; }
.ico { padding: 8rpx 4rpx; color: #1677FF; font-size: 28rpx; font-weight: 600; }
</style> </style>