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

574 lines
13 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!-- 物业人员页面 -->
<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>