fjrcloud-community-app/pages/sub/staff/index.vue

574 lines
13 KiB
Vue
Raw Normal View History

<!-- 物业人员页面 -->
<template>
<s-layout title="物业人员" :bgStyle="{ backgroundColor:'#F8EDE8' }" navbar="inner" color="#333333">
<view class="staff-page">
<!-- 渐变背景装饰 -->
<view class="gradient-bg"></view>
<!-- 固定头部统计卡片+分类Tab -->
<view class="page-header">
<!-- 统计卡片 -->
<view class="stats-card">
<!-- 背景图 -->
<image class="stats-bg" src="/static/img/wy-icon3.png" mode="aspectFill" />
<!-- 右上角标签 -->
<view class="corner-badge">物业人员</view>
<!-- 左侧内容区 -->
<view class="card-left">
<!-- 小区名称 -->
<view class="card-top">
<image class="building-icon" src="/static/img/wy-icon2.png" mode="aspectFit" />
<text class="building-name">{{ statsInfo.buildingName }}</text>
</view>
<!-- 总人数 -->
<view class="total-row">
<text class="total-label">总人数</text>
<text class="total-count">{{ statsInfo.total }}<text class="total-unit"></text></text>
</view>
<!-- 分类统计 -->
<view class="category-row">
<view
class="category-item"
v-for="(cat, index) in statsInfo.categories"
:key="index"
>
<text class="cat-name">{{ cat.name }}</text>
<text class="cat-count">{{ cat.count }}</text>
</view>
</view>
</view>
<!-- 右侧叠加背景图 -->
<image class="right-bg" src="/static/img/wy-icon1.png" mode="aspectFit" />
<!-- 右侧区域 -->
<view class="card-right"></view>
</view>
<!-- 人员信息标题 -->
<view class="section-title">人员信息</view>
<!-- 分类Tab栏 -->
<scroll-view class="tab-scroll" scroll-x :show-scrollbar="false">
<view class="tab-bar">
<view
class="tab-item"
:class="{ active: currentTab === tab.key }"
v-for="(tab, index) in tabList"
:key="index"
@tap="currentTab = tab.key"
>
<text class="tab-text">{{ tab.label }}</text>
</view>
</view>
</scroll-view>
</view>
<!-- 人员列表 - 独立滚动区域 -->
<scroll-view class="staff-scroll" scroll-y :style="{ height: scrollHeight + 'px' }">
<view class="staff-list">
<!-- 员工卡片 -->
<view
class="staff-item"
v-for="(item, index) in filteredStaffList"
:key="index"
>
<!-- 头像 -->
<image class="staff-avatar" :src="item.avatar" mode="aspectFill" />
<!-- 信息区 -->
<view class="staff-info">
<!-- 姓名+职业 -->
<view class="name-row">
<text class="name-label">姓名</text>
<text class="name-text">{{ item.name }}</text>
<text class="job-label">职业</text>
<text class="job-text">{{ item.job }}</text>
</view>
<!-- 电话 -->
<view class="phone-row">
<text class="phone-label">电话</text>
<text class="phone-text" @tap="callPhone(item.phone)">{{ item.phone }}</text>
</view>
<!-- 职责描述 -->
<view class="duty-row">
<text class="duty-label">职责</text>
<text class="duty-text">{{ item.duty }}</text>
</view>
</view>
</view>
<!-- 空状态 -->
<view class="empty-state" v-if="filteredStaffList.length === 0">
<text class="empty-text">暂无相关人员</text>
</view>
</view>
</scroll-view>
</view>
</s-layout>
</template>
<script setup>
import { ref, computed, onMounted, nextTick, getCurrentInstance } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
// 当前选中的分类Tab
const currentTab = ref('security');
// 列表滚动高度
const scrollHeight = ref(0);
// Tab列表
const tabList = ref([
{ key: 'security', label: '安保类' },
{ key: 'cleaning', label: '保洁类' },
{ key: 'engineering', label: '工程类' },
{ key: 'admin', label: '行政管理类' },
{ key: 'finance', label: '财务类' }
]);
// 统计信息
const statsInfo = ref({
buildingName: '融侨馨苑',
total: 48,
categories: [
{ name: '安保', count: 10 },
{ name: '保洁', count: 10 },
{ name: '维修', count: 10 },
{ name: '楼管', count: 10 },
{ name: '经理', count: 2 },
{ name: '客服', count: 10 }
]
});
// 人员列表数据
const staffList = ref([
{
id: 1,
category: 'security',
name: '吴仁贵',
job: '安保主管',
phone: '184****5263',
duty: '人员调配与排班、根据项目需求制定安保人员排班计划确保24小时无缝覆盖。',
avatar: '/static/img/guest.png'
},
{
id: 2,
category: 'security',
name: '李梓发',
job: '保安',
phone: '187****1005',
duty: '定期巡查项目重点区域,检查安全设施(监控、消防器材、门禁系统)是否完好',
avatar: '/static/img/login_img.png'
},
{
id: 3,
category: 'security',
name: '冯启彬',
job: '保安',
phone: '187****1005',
duty: '定期巡查项目重点区域,检查安全设施(监控、消防器材、门禁系统)是否完好',
avatar: '/static/img/guest.png'
}
]);
// 根据当前Tab筛选列表
const filteredStaffList = computed(() => {
return staffList.value.filter(item => item.category === currentTab.value);
});
// 页面加载
onLoad(() => {
loadStaffData();
});
// 渲染完成后计算scroll-view高度
onMounted(() => {
const instance = getCurrentInstance();
nextTick(() => {
const sysInfo = uni.getSystemInfoSync();
uni.createSelectorQuery()
.in(instance)
.select('.page-header')
.boundingClientRect((rect) => {
if (rect) {
// scroll-view高度 = 屏幕可用高度 - 头部高度 - 头部距顶部距离
scrollHeight.value = sysInfo.windowHeight - rect.height - rect.top;
}
})
.exec();
});
});
// 加载人员数据TODO: 对接API
function loadStaffData() {
// TODO: 调用API获取物业人员列表
}
// 拨打电话
function callPhone(phone) {
uni.makePhoneCall({
phoneNumber: phone.replace(/\*/g, '') // 去掉脱敏星号
});
}
</script>
<style lang="scss" scoped>
/* ==================== 页面容器 ==================== */
.staff-page {
position: relative;
min-height: 100vh;
}
/* ==================== 渐变背景 ==================== */
.gradient-bg {
position: absolute;
top: -176rpx;
left: 0;
right: 0;
height: calc(100% + 176rpx);
background: linear-gradient(180deg, #F8EDE8 0%, #FFFFFF 30%);
z-index: -1;
}
/* ==================== 固定头部区域 ==================== */
.page-header {
padding-bottom: 16rpx;
}
/* ==================== 统计卡片 ==================== */
.stats-card {
margin: 24rpx 32rpx 24rpx;
padding: 28rpx 0 24rpx 32rpx;
border-radius: 24rpx;
display: flex;
align-items: flex-start;
justify-content: space-between;
position: relative;
overflow: hidden;
min-height: 320rpx;
/* 背景图 */
.stats-bg {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 0;
}
/* 右侧叠加背景图 */
.right-bg {
position: absolute;
top: 50%;
right: 24rpx;
transform: translateY(-50%);
width: 160rpx;
height: 180rpx;
z-index: 1;
}
/* 右上角标签 */
.corner-badge {
position: absolute;
top: 0;
right: 30rpx;
color: #FFFFFF;
font-size: 28rpx;
font-weight: 500;
padding: 12rpx 28rpx;
border-radius: 0 24rpx 0 24rpx;
z-index: 2;
}
/* 左侧内容区 */
.card-left {
flex: 1;
min-width: 0;
position: relative;
z-index: 1;
}
/* 卡片顶部:小区名 */
.card-top {
display: flex;
align-items: center;
margin-bottom: 20rpx;
.building-icon {
width: 40rpx;
height: 40rpx;
margin-right: 12rpx;
flex-shrink: 0;
}
.building-name {
font-size: 32rpx;
font-weight: 600;
color: #333333;
}
}
/* 总人数行 - 纵向排列 */
.total-row {
display: flex;
flex-direction: column;
margin-bottom: 20rpx;
.total-label {
font-size: 26rpx;
color: #666666;
margin-bottom: 8rpx;
}
.total-count {
font-size: 52rpx;
font-weight: 700;
color: #FA7E49; /* 橙色主题 */
.total-unit {
font-size: 30rpx;
font-weight: 400;
color: #FA7E49;
margin-left: 4rpx;
}
}
}
/* 分类统计行 */
.category-row {
display: flex;
justify-content: space-around;
gap: 32rpx;
.category-item {
display: flex;
flex-direction: column;
align-items: center;
.cat-name {
font-size: 24rpx;
color: #666666;
margin-bottom: 10rpx;
}
.cat-count {
font-size: 32rpx;
font-weight: 600;
color: #333333;
}
}
}
/* 右侧区域 */
.card-right {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding-right: 24rpx;
padding-left: 16rpx;
position: relative;
z-index: 1;
}
}
/* ==================== 分类Tab栏 ==================== */
.tab-scroll {
white-space: nowrap;
margin: 0 0 8rpx;
}
.tab-bar {
display: inline-flex;
padding: 0 32rpx;
.tab-item {
padding: 20rpx 0;
margin-right: 40rpx;
position: relative;
flex-shrink: 0; /* 防止Tab项被压缩 */
&:last-child {
margin-right: 0;
}
.tab-text {
font-size: 28rpx;
color: #999999;
transition: all 0.2s;
}
/* 选中状态 */
&.active {
.tab-text {
color: #FA7E49; /* 橙色主题 */
font-weight: 600;
}
/* 底部橙色指示条 */
&::after {
content: '';
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 48rpx;
height: 4rpx;
background: #FA7E49;
border-radius: 2rpx;
}
}
}
}
/* ==================== 人员信息标题 ==================== */
.section-title {
padding: 16rpx 32rpx 20rpx;
font-size: 32rpx;
font-weight: 600;
color: #333333;
}
/* ==================== 人员列表滚动区域 ==================== */
.staff-scroll {
width: 100%;
}
/* ==================== 人员列表内容 ==================== */
.staff-list {
padding: 0 32rpx 160rpx;
}
/* ==================== 单个员工卡片 ==================== */
.staff-item {
display: flex;
padding: 28rpx 0;
position: relative;
/* 分割线 */
&::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 1rpx;
background-color: #F0F0F0;
}
/* 头像 */
.staff-avatar {
width: 96rpx;
height: 96rpx;
border-radius: 50%;
flex-shrink: 0;
background-color: #F0F0F0;
}
/* 信息区域 */
.staff-info {
flex: 1;
margin-left: 24rpx;
/* 姓名+职业行 */
.name-row {
display: flex;
align-items: center;
margin-bottom: 12rpx;
.name-label,
.job-label {
font-size: 26rpx;
color: #999999;
}
.name-text,
.job-text {
font-size: 28rpx;
color: #333333;
font-weight: 500;
margin-right: 24rpx;
}
.name-text{
margin-right:100rpx;
}
}
/* 电话行 */
.phone-row {
display: flex;
align-items: center;
margin-bottom: 12rpx;
.phone-label {
font-size: 26rpx;
color: #999999;
}
.phone-text {
font-size: 28rpx;
color: #333333;
margin-right: 16rpx;
}
/* 拨打按钮 */
.call-btn {
width: 44rpx;
height: 44rpx;
border-radius: 50%;
background-color: #FA7E49;
display: flex;
align-items: center;
justify-content: center;
.call-icon {
font-size: 24rpx;
color: #FFFFFF;
}
}
}
/* 职责描述行 - 标签与内容同行换行 */
.duty-row {
display: flex;
align-items: flex-start;
.duty-label {
font-size: 26rpx;
color: #999999;
flex-shrink: 0;
}
.duty-text {
flex: 1;
font-size: 26rpx;
color: #666666;
line-height: 1.6;
word-break: break-all;
}
}
}
}
/* ==================== 空状态 ==================== */
.empty-state {
display: flex;
align-items: center;
justify-content: center;
padding: 200rpx 0;
.empty-text {
font-size: 28rpx;
color: #999999;
}
}
</style>