staff/pagesB/permissions/staffList.vue

944 lines
22 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="container">
<!-- 自定义导航栏 -->
<wd-navbar :bordered="false"
custom-style="background: transparent !important; backdrop-filter: blur(10px) !important; -webkit-backdrop-filter: blur(20px) !important;"
safeAreaInsetTop fixed placeholder>
<template #left>
<view class="li-ml-15 li-mt-10 li-flex li-items-center">
<text v-if="hasMultiplePages" class="ri-arrow-left-s-line li-text-70"
@click="toPages({type:'nav'})"></text>
<text v-if="!hasMultiplePages" class="ri-home-5-line li-text-55 li-mb-8 li-mr-10"
@click="toPages({type:'home'})"></text>
<text class="li-text-42">员工权限</text>
</view>
</template>
<!-- #ifdef MP-WEIXIN -->
<template #right>
<view class="li-flex-center li-mr-200 li-pt-6" @click="handleAddStaff">
<text class="ri-add-line li-text-50"></text>
</view>
</template>
<!-- #endif -->
<!-- #ifndef MP-WEIXIN -->
<template #right>
<view class="li-flex-center li-mr-25 li-pt-6" @click="handleAddStaff">
<text class="ri-add-line li-text-55"></text>
</view>
</template>
<!-- #endif -->
</wd-navbar>
<!-- 导航栏背景 -->
<view class="nav-bg-layer"></view>
<!-- 页面背景 -->
<view class="page-bg"></view>
<view class="content">
<!-- 员工列表 -->
<view class="staff-list li-w-92% li-mx-auto li-mt-20" v-if="filteredStaffList.length > 0">
<view
v-for="staff in filteredStaffList"
:key="staff.id"
class="staff-card"
@tap="openPermissionSetting(staff)"
>
<view class="card-header">
<view class="staff-avatar" v-if="staff.avatar">
<image :src="staff.avatar" mode="aspectFill"></image>
</view>
<view class="staff-avatar default-avatar" v-else>
<text>{{staff.name.substring(0,1)}}</text>
</view>
<view class="staff-info">
<view class="staff-name">{{ staff.name }}</view>
<view class="staff-phone">
<text class="ri-phone-line phone-icon"></text>
<text>{{ staff.phone }}</text>
</view>
</view>
<view class="right-area">
<view class="perm-count" :class="{'has-perm': staff.permissions.length > 0}">
{{ staff.permissions.length }}
</view>
<text class="ri-arrow-right-s-line action-icon"></text>
</view>
</view>
<view class="card-content" v-if="staff.permissions.length > 0">
<!-- 权限标签 -->
<view class="perm-tags">
<view
v-for="(perm, index) in staff.permissions.slice(0, 2)"
:key="perm"
class="perm-tag"
:class="getPermissionClass(perm)"
>
<text :class="getPermissionIcon(perm)"></text>
<text>{{ getPermissionName(perm) }}</text>
</view>
<view class="perm-tag more" v-if="staff.permissions.length > 2">
<text>+{{ staff.permissions.length - 2 }}</text>
</view>
</view>
</view>
<view class="card-content" v-else>
<view class="no-perm-tag">
<text class="ri-lock-line"></text>
<text>暂无权限</text>
</view>
</view>
</view>
</view>
<!-- 空状态 -->
<view class="empty-state" v-else>
<wd-empty description="暂无员工数据">
<wd-button type="primary" @click="handleAddStaff">添加员工</wd-button>
</wd-empty>
</view>
<!-- 底部权限设置面板 -->
<wd-popup v-model="showPermissionPopup" position="bottom" custom-style="border-radius: 20rpx 20rpx 0 0;" @close="handlePopupClose" :safe-area-inset-bottom="true">
<permission-settings
:staff="currentStaff"
:permissions="allPermissions"
@save="savePermissions"
@cancel="closePermissionSheet"
/>
</wd-popup>
</view>
</view>
</template>
<script setup lang="ts">
import { ref, reactive, computed, nextTick } from 'vue';
import { useNavigation } from '@/hooks/useNavigation';
import { onLoad, onPullDownRefresh } from '@dcloudio/uni-app';
import PermissionSettings from '@/components/PermissionSettings.vue';
// 导航相关
const { toPages, hasMultiplePages, checkRouteStack } = useNavigation();
// 小区信息
const villageId = ref('');
const villageName = ref('阳光花园小区');
const villageAddress = ref('市政府北路123号');
// 搜索与筛选
const searchKeyword = ref('');
const currentFilter = ref('全部');
const filterOptions = ['全部', '配送权限', '维修权限'];
// 权限配置弹框搜索
const permissionSearchKeyword = ref('');
// 更多权限弹窗
const showMorePermissionsPopup = ref(false);
const currentStaffPermissions = ref([]);
// 弹窗管理
const showPermissionPopup = ref(false);
const currentStaff = ref(null);
const tempPermissions = reactive({});
// 员工列表数据 - 使用更多权限
const staffList = ref([
{
id: 1,
name: '张三',
phone: '13800138000',
avatar: '/static/swiper/1.png',
permissions: ['delivery', 'complaint'],
department: '配送部'
},
{
id: 2,
name: '李四',
phone: '13800138001',
avatar: '/static/swiper/1.png',
permissions: ['delivery', 'maintenance', 'inspection', 'facility', 'visitor'],
department: '综合部'
},
{
id: 3,
name: '王五',
phone: '13800138002',
avatar: '/static/swiper/1.png',
permissions: ['maintenance', 'inspection'],
department: '工程部'
},
{
id: 4,
name: '赵六',
phone: '13800138003',
avatar: '/static/swiper/1.png',
permissions: [],
department: '客服部'
}
]);
// 所有权限列表
const allPermissions = [
{ value: 'delivery', label: '配送权限', icon: 'ri-truck-line', description: '允许配送相关的订单处理', colorClass: 'delivery-color', isCommon: true },
{ value: 'maintenance', label: '维修权限', icon: 'ri-tools-line', description: '允许接受维修工单和处理', colorClass: 'maintenance-color', isCommon: true },
{ value: 'finance', label: '财务管理', icon: 'ri-money-cny-circle-line', description: '允许处理财务相关事务', colorClass: 'finance-color', isCommon: true },
{ value: 'resident', label: '住户管理', icon: 'ri-user-line', description: '允许管理小区住户信息', colorClass: 'general-color', isCommon: false },
{ value: 'security', label: '安防权限', icon: 'ri-shield-line', description: '允许管理小区安防系统', colorClass: 'general-color', isCommon: false },
{ value: 'admin', label: '管理员权限', icon: 'ri-admin-line', description: '系统管理员权限', colorClass: 'admin-color', isCommon: false },
{ value: 'parking', label: '车位管理', icon: 'ri-parking-line', description: '允许管理小区车位', colorClass: 'general-color', isCommon: false },
{ value: 'visitor', label: '访客管理', icon: 'ri-user-location-line', description: '允许管理小区访客', colorClass: 'general-color', isCommon: false },
{ value: 'complaint', label: '投诉处理', icon: 'ri-customer-service-line', description: '允许处理业主投诉', colorClass: 'general-color', isCommon: true },
{ value: 'facility', label: '设施管理', icon: 'ri-building-4-line', description: '允许管理小区公共设施', colorClass: 'general-color', isCommon: false },
{ value: 'notice', label: '通知发布', icon: 'ri-notification-line', description: '允许发布小区通知', colorClass: 'general-color', isCommon: false },
{ value: 'inspection', label: '巡检权限', icon: 'ri-survey-line', description: '允许进行小区巡检记录', colorClass: 'maintenance-color', isCommon: true },
];
// 筛选后的员工列表
const filteredStaffList = computed(() => {
let result = staffList.value;
// 按关键词筛选
if (searchKeyword.value) {
result = result.filter(staff =>
staff.name.includes(searchKeyword.value) ||
staff.phone.includes(searchKeyword.value)
);
}
// 按权限筛选
if (currentFilter.value !== '全部') {
// 查找对应的权限代码
const permCode = allPermissions.find(p => p.label === currentFilter.value)?.value;
if (permCode) {
result = result.filter(staff => staff.permissions.includes(permCode));
}
}
return result;
});
// 常用权限和其他权限
const commonPermissions = computed(() => {
return allPermissions.filter(perm => perm.isCommon);
});
const otherPermissions = computed(() => {
return allPermissions.filter(perm => !perm.isCommon);
});
/**
* 获取权限图标
* @param {string} permCode 权限代码
* @returns {string} 图标class
*/
const getPermissionIcon = (permCode) => {
const perm = allPermissions.find(p => p.value === permCode);
return perm ? perm.icon : 'ri-lock-line';
};
/**
* 获取权限名称
* @param {string} permCode 权限代码
* @returns {string} 权限名称
*/
const getPermissionName = (permCode) => {
const perm = allPermissions.find(p => p.value === permCode);
return perm ? perm.label : '未知权限';
};
/**
* 获取权限样式类
* @param {string} permCode 权限代码
* @returns {string} 样式类名
*/
const getPermissionClass = (permCode) => {
const perm = allPermissions.find(p => p.value === permCode);
return perm ? perm.colorClass : '';
};
/**
* 获取激活的权限数量
*/
const getActivePermissionsCount = () => {
return Object.values(tempPermissions).filter(v => v === true).length;
};
/**
* 显示更多权限弹窗
* @param {Object} staff 员工信息
*/
const showMorePermissions = (staff) => {
currentStaff.value = staff;
currentStaffPermissions.value = staff.permissions;
showMorePermissionsPopup.value = true;
};
/**
* 获取小区信息
*/
const getVillageInfo = () => {
// 实际项目中从服务器获取小区信息
console.log('获取小区ID为', villageId.value, '的信息');
};
/**
* 获取员工列表
*/
const getStaffList = () => {
// 实际项目中从服务器获取员工列表
console.log('获取小区ID为', villageId.value, '的员工列表');
};
/**
* 处理搜索
*/
const handleSearch = () => {
console.log('搜索关键词:', searchKeyword.value);
// 这里可以实现搜索逻辑
};
/**
* 设置筛选条件
* @param {string} filter 筛选条件
*/
const setFilter = (filter) => {
currentFilter.value = filter;
console.log('筛选条件:', filter);
// 这里可以实现筛选逻辑
};
/**
* 处理添加员工
*/
const handleAddStaff = () => {
uni.navigateTo({
url: '/pagesB/permissions/addStaff'
});
};
/**
* 处理权限设置
* @param {Object} staff 员工信息
*/
const handleSetPermission = (staff) => {
currentStaff.value = staff;
// 重置临时权限状态
allPermissions.forEach(perm => {
tempPermissions[perm.value] = staff.permissions.includes(perm.value);
});
showPermissionPopup.value = true;
};
/**
* 保存权限设置
*/
const savePermissions = () => {
if (!currentStaff.value) return;
// 显示加载中提示
uni.showLoading({
title: '保存中...',
mask: true
});
// API调用示例
// 这里只是示例实际项目中请替换为真实的API调用
const requestData = {
staffId: currentStaff.value.id,
permissions: currentStaff.value.permissions,
villageId: villageId.value
};
// 模拟API调用
setTimeout(() => {
// 实际项目中这里应该是真实的API调用例如:
/*
uni.request({
url: 'https://api.example.com/staff/permissions',
method: 'POST',
data: requestData,
success: (res) => {
if (res.data.code === 0) {
// 更新本地数据
updateLocalStaffPermissions();
// 关闭弹窗并显示成功提示
closePermissionSheet();
uni.showToast({
title: '权限设置成功',
icon: 'success'
});
} else {
uni.showToast({
title: res.data.message || '保存失败',
icon: 'none'
});
}
},
fail: (err) => {
uni.showToast({
title: '网络错误,请重试',
icon: 'none'
});
console.error('保存权限失败:', err);
},
complete: () => {
uni.hideLoading();
}
});
*/
// 更新本地数据
updateLocalStaffPermissions();
// 隐藏加载提示
uni.hideLoading();
// 关闭弹窗并显示成功提示
closePermissionSheet();
uni.showToast({
title: '权限设置成功',
icon: 'success'
});
}, 800);
};
/**
* 更新本地员工权限数据
*/
const updateLocalStaffPermissions = () => {
const index = staffList.value.findIndex(item => item.id === currentStaff.value.id);
if (index !== -1) {
staffList.value[index] = {
...staffList.value[index],
permissions: [...currentStaff.value.permissions]
};
}
};
// 权限操作列表
const permissionActions = [
{ name: '配送权限', value: 'delivery', icon: 'ri-truck-line' },
{ name: '维修权限', value: 'maintenance', icon: 'ri-tools-line' },
{ name: '财务管理', value: 'finance', icon: 'ri-money-cny-circle-line' },
{ name: '住户管理', value: 'resident', icon: 'ri-user-line' },
{ name: '安防权限', value: 'security', icon: 'ri-shield-line' },
{ name: '管理员权限', value: 'admin', icon: 'ri-admin-line' },
{ name: '投诉处理', value: 'complaint', icon: 'ri-customer-service-line' },
{ name: '巡检权限', value: 'inspection', icon: 'ri-survey-line' },
];
// 切换权限筛选器
const handleFilterChange = (filter) => {
currentFilter.value = filter;
};
// 重置筛选
const resetFilter = () => {
currentFilter.value = '全部';
searchKeyword.value = '';
};
// 清除搜索关键词
const clearSearchKeyword = () => {
searchKeyword.value = '';
};
// 打开权限设置
const openPermissionSetting = (staff) => {
// 设置当前员工
currentStaff.value = {
...staff,
// 创建一个权限数组的副本,避免直接修改原始数据
permissions: [...staff.permissions]
};
// 显示弹窗
showPermissionPopup.value = true;
};
// 关闭权限设置面板
const closePermissionSheet = () => {
showPermissionPopup.value = false;
};
// 切换权限状态
const togglePermission = (permission) => {
if (!currentStaff.value) return;
const index = currentStaff.value.permissions.indexOf(permission);
if (index > -1) {
// 移除已有权限
currentStaff.value.permissions.splice(index, 1);
} else {
// 添加新权限
currentStaff.value.permissions.push(permission);
}
};
// 检查权限是否已启用
const hasPermission = (permission) => {
if (!currentStaff.value) return false;
return currentStaff.value.permissions.includes(permission);
};
// 页面加载
onLoad((options) => {
if (options.villageId) {
villageId.value = options.villageId;
// 获取小区信息和员工列表
getVillageInfo();
getStaffList();
}
checkRouteStack();
});
// 下拉刷新
onPullDownRefresh(() => {
getStaffList();
setTimeout(() => {
uni.stopPullDownRefresh();
}, 1000);
});
// 处理wd-popup组件的close事件
const handlePopupClose = () => {
// 处理逻辑
};
</script>
<style lang="scss" scoped>
/* 主容器 */
.container {
min-height: 100vh;
background-color: transparent;
position: relative;
font-family: -apple-system, BlinkMacSystemFont, Helvetica Neue, Helvetica, Segoe UI, Arial, Roboto, PingFang SC, sans-serif;
padding-bottom: env(safe-area-inset-bottom);
}
/* 导航栏背景 */
.nav-bg-layer {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: calc(var(--status-bar-height) + 88rpx);
background: linear-gradient(180deg, rgba(255, 255, 255, 0.95) 0%, rgba(255, 255, 255, 0.9) 100%);
z-index: -1;
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
}
/* 页面背景 */
.page-bg {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(135deg, #f8fafd 0%, #eef2f9 100%);
z-index: -2;
&::before {
content: '';
position: absolute;
top: 0;
right: 0;
width: 100%;
height: 30%;
background: linear-gradient(135deg, rgba(76, 132, 255, 0.03), rgba(76, 132, 255, 0));
z-index: -1;
}
&::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 40%;
background: linear-gradient(315deg, rgba(76, 132, 255, 0.02), rgba(76, 132, 255, 0));
z-index: -1;
}
}
/* 添加按钮 */
.add-btn {
width: 60rpx;
height: 60rpx;
border-radius: 50%;
background-color: #4080FF;
color: #FFFFFF;
display: flex;
align-items: center;
justify-content: center;
font-size: 40rpx;
box-shadow: 0 4rpx 8rpx rgba(64, 128, 255, 0.3);
}
/* 内容区域 */
.content {
position: relative;
z-index: 2;
padding-bottom: 30rpx;
/* #ifdef MP-WEIXIN */
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
/* #endif */
/* #ifdef APP-PLUS || H5 */
padding-bottom: 50rpx;
/* #endif */
}
/* 小区卡片 */
.village-card {
margin: 0 30rpx 30rpx;
background-color: #fff;
border-radius: 24rpx;
overflow: hidden;
box-shadow: 0 10rpx 30rpx rgba(31, 35, 172, 0.05);
}
.card-header {
padding: 36rpx 40rpx;
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1rpx solid rgba(0, 0, 0, 0.03);
position: relative;
overflow: hidden;
&::before {
content: '';
position: absolute;
top: 0;
right: 0;
width: 200rpx;
height: 200rpx;
background: radial-gradient(circle at top right, rgba(255, 255, 255, 0.8), rgba(255, 255, 255, 0));
z-index: 1;
}
.village-name {
font-size: 36rpx;
font-weight: 600;
color: #333;
position: relative;
z-index: 2;
}
.badge-container {
position: relative;
z-index: 2;
.badge {
display: inline-flex;
align-items: center;
padding: 6rpx 20rpx;
background-color: rgba(76, 132, 255, 0.1);
border-radius: 30rpx;
color: #4C84FF;
.badge-num {
font-size: 28rpx;
font-weight: bold;
margin-right: 6rpx;
}
.badge-text {
font-size: 24rpx;
}
}
}
}
.card-content {
padding: 25rpx 40rpx;
.village-address {
display: flex;
align-items: center;
font-size: 28rpx;
color: #666;
.address-icon {
color: #999;
margin-right: 10rpx;
font-size: 32rpx;
}
.address-text {
color: #666;
}
}
}
/* 搜索容器 */
.search-wrapper {
position: relative;
z-index: 3;
margin-bottom: 30rpx;
&::before {
content: '';
position: absolute;
top: 50%;
left: -15%;
width: 120rpx;
height: 120rpx;
border-radius: 50%;
background: linear-gradient(135deg, rgba(76, 132, 255, 0.1), rgba(76, 132, 255, 0));
z-index: -1;
transform: translateY(-50%);
}
&::after {
content: '';
position: absolute;
top: -20rpx;
right: -5%;
width: 80rpx;
height: 80rpx;
border-radius: 50%;
background: linear-gradient(135deg, rgba(66, 211, 170, 0.06), rgba(66, 211, 170, 0));
z-index: -1;
}
}
/* 筛选容器 */
.filter-container {
margin: 0 0 20rpx;
position: relative;
z-index: 2;
}
/* 筛选标签 */
.filter-tabs {
white-space: nowrap;
padding: 0 30rpx 10rpx;
.filter-tab {
display: inline-block;
padding: 15rpx 32rpx;
margin-right: 15rpx;
background-color: #fff;
border-radius: 50rpx;
font-size: 28rpx;
color: #666;
box-shadow: 0 6rpx 12rpx rgba(76, 132, 255, 0.06);
transition: all 0.3s;
position: relative;
overflow: hidden;
&:before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(135deg, rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0));
z-index: -1;
}
&.active {
background-color: #4080FF;
color: #fff;
font-weight: 500;
box-shadow: 0 8rpx 16rpx rgba(64, 128, 255, 0.3);
&:before {
background: linear-gradient(135deg, rgba(255, 255, 255, 0.3), rgba(255, 255, 255, 0));
}
}
}
}
/* 员工列表 */
.staff-list {
padding: 0 30rpx;
}
/* 员工卡片 */
.staff-card {
padding: 24rpx;
background-color: #fff;
border-radius: 16rpx;
margin-bottom: 16rpx;
position: relative;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.03);
transition: all 0.3s;
// border-left: 3rpx solid #0070F0;
&:active {
transform: translateY(1rpx);
background-color: #fafafa;
}
.card-header {
display: flex;
align-items: center;
position: relative;
.staff-avatar {
width: 64rpx;
height: 64rpx;
border-radius: 50%;
overflow: hidden;
margin-right: 16rpx;
flex-shrink: 0;
background-color: #f2f8ff;
image {
width: 100%;
height: 100%;
}
&.default-avatar {
background-color: #0070F0;
color: #fff;
display: flex;
align-items: center;
justify-content: center;
font-size: 26rpx;
font-weight: bold;
}
}
.staff-info {
flex: 1;
.staff-name {
font-size: 28rpx;
font-weight: 600;
color: #333;
margin-bottom: 4rpx;
}
.staff-phone {
font-size: 24rpx;
color: #999;
display: flex;
align-items: center;
.phone-icon {
font-size: 22rpx;
color: #999;
margin-right: 4rpx;
}
}
}
.right-area {
display: flex;
align-items: center;
.action-icon {
font-size: 32rpx;
color: #ddd;
margin-left: 10rpx;
}
}
}
.card-content {
margin-top: 12rpx;
}
}
/* 权限标签 */
.perm-tags {
display: flex;
flex-wrap: wrap;
margin-top: 2rpx;
.perm-tag {
height: 38rpx;
line-height: 38rpx;
display: inline-flex;
align-items: center;
padding: 0 10rpx;
background-color: #f0f7ff;
color: #0070F0;
font-size: 24rpx;
border-radius: 4rpx;
margin-right: 10rpx;
margin-bottom: 0;
text {
&:first-child {
margin-right: 4rpx;
font-size: 22rpx;
}
}
&.more {
background-color: #f0f0f0;
color: #999;
}
&.delivery-color {
background-color: #f0f7ff;
color: #0070F0;
}
&.maintenance-color {
background-color: #f0f7ff;
color: #0070F0;
}
&.finance-color {
background-color: #f0f7ff;
color: #0070F0;
}
&.admin-color {
background-color: #f0f7ff;
color: #0070F0;
}
&.general-color {
background-color: #f0f7ff;
color: #0070F0;
}
}
}
.no-perm-tag {
font-size: 24rpx;
color: #999;
display: flex;
align-items: center;
.ri-lock-line {
margin-right: 4rpx;
}
}
/* 空状态 */
.empty-state {
padding: 100rpx 0;
}
.perm-count {
min-width: 32rpx;
height: 32rpx;
padding: 0 6rpx;
border-radius: 16rpx;
background-color: #0070F0;
color: #fff;
font-size: 22rpx;
display: flex;
align-items: center;
justify-content: center;
}
</style>