混凝土运输管理微信小程序、替班
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

462 lines
9.5 KiB

<template>
<view class="content">
<navbar title="员工管理" leftClick @leftClick="$utils.navigateBack" />
<view class="header">
<view class="title">员工管理</view>
<view class="subtitle">管理企业员工信息和权限</view>
</view>
<!-- 搜索栏 -->
<view class="search-bar">
<view class="search-input">
<uv-icon name="search" size="20" color="#999"></uv-icon>
<input v-model="searchKeyword" placeholder="搜索员工姓名或手机号" @input="onSearch" />
</view>
<view class="add-btn" @click="addStaff">
<uv-icon name="plus" size="20" color="#fff"></uv-icon>
<text>添加</text>
</view>
</view>
<!-- 统计信息 -->
<view class="stats-container">
<view class="stats-item">
<view class="stats-number">{{ totalStaff }}</view>
<view class="stats-label">总员工数</view>
</view>
<view class="stats-item">
<view class="stats-number">{{ activeStaff }}</view>
<view class="stats-label">在职员工</view>
</view>
<view class="stats-item">
<view class="stats-number">{{ onlineStaff }}</view>
<view class="stats-label">在线员工</view>
</view>
</view>
<!-- 员工列表 -->
<view class="staff-list">
<view v-if="filteredStaffList.length === 0" class="empty-state">
<view class="empty-icon">👥</view>
<view class="empty-text">暂无员工信息</view>
</view>
<view v-for="(item, index) in filteredStaffList" :key="index" class="staff-item">
<view class="staff-avatar">
<image :src="item.avatar" mode="aspectFill"></image>
<view class="online-status" :class="{online: item.isOnline}"></view>
</view>
<view class="staff-info">
<view class="staff-header">
<view class="name">{{ item.name }}</view>
<view class="role-badge" :class="item.role">{{ getRoleText(item.role) }}</view>
</view>
<view class="staff-details">
<text>手机:{{ item.phone }}</text>
<text>部门:{{ item.department }}</text>
<text>入职时间:{{ item.joinDate }}</text>
</view>
<view class="staff-stats">
<view class="stat-item">
<text class="stat-label">本月订单:</text>
<text class="stat-value">{{ item.monthlyOrders }}</text>
</view>
<view class="stat-item">
<text class="stat-label">评分:</text>
<text class="stat-value">{{ item.rating }}分</text>
</view>
</view>
</view>
<view class="staff-actions">
<view class="action-btn" @click="viewStaff(item)">
<uv-icon name="eye" size="16" color="#007AFF"></uv-icon>
</view>
<view class="action-btn" @click="editStaff(item)">
<uv-icon name="edit-pen" size="16" color="#ff9500"></uv-icon>
</view>
<view class="action-btn" @click="deleteStaff(item)">
<uv-icon name="trash" size="16" color="#ff3b30"></uv-icon>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
import navbar from '@/components/base/navbar.vue'
export default {
name: 'StaffManage',
components: {
navbar
},
data() {
return {
searchKeyword: '',
totalStaff: 15,
activeStaff: 12,
onlineStaff: 8,
staffList: [
{
id: 1,
name: '张师傅',
phone: '13800138001',
avatar: '/static/re/logo.png',
role: 'driver',
department: '运输部',
joinDate: '2023-06-15',
isOnline: true,
monthlyOrders: 28,
rating: 4.8
},
{
id: 2,
name: '李师傅',
phone: '13800138002',
avatar: '/static/re/logo.png',
role: 'driver',
department: '运输部',
joinDate: '2023-08-20',
isOnline: false,
monthlyOrders: 22,
rating: 4.6
},
{
id: 3,
name: '王主管',
phone: '13800138003',
avatar: '/static/re/logo.png',
role: 'supervisor',
department: '调度部',
joinDate: '2023-03-10',
isOnline: true,
monthlyOrders: 45,
rating: 4.9
},
{
id: 4,
name: '赵师傅',
phone: '13800138004',
avatar: '/static/re/logo.png',
role: 'driver',
department: '运输部',
joinDate: '2023-09-05',
isOnline: true,
monthlyOrders: 31,
rating: 4.7
},
{
id: 5,
name: '陈操作员',
phone: '13800138005',
avatar: '/static/re/logo.png',
role: 'operator',
department: '操作部',
joinDate: '2023-11-12',
isOnline: false,
monthlyOrders: 18,
rating: 4.5
}
]
}
},
computed: {
filteredStaffList() {
if (!this.searchKeyword) {
return this.staffList;
}
return this.staffList.filter(staff =>
staff.name.includes(this.searchKeyword) ||
staff.phone.includes(this.searchKeyword)
);
}
},
onLoad() {
uni.setNavigationBarTitle({
title: '员工管理'
});
},
methods: {
onSearch() {
// 搜索逻辑已在computed中实现
},
getRoleText(role) {
switch(role) {
case 'driver': return '司机';
case 'supervisor': return '主管';
case 'operator': return '操作员';
default: return '员工';
}
},
addStaff() {
uni.navigateTo({
url: '/pages_order/staff/addStaff'
});
},
viewStaff(staff) {
uni.navigateTo({
url: `/pages_order/staff/staffDetail?id=${staff.id}`
});
},
editStaff(staff) {
uni.navigateTo({
url: `/pages_order/staff/editStaff?id=${staff.id}`
});
},
deleteStaff(staff) {
uni.showModal({
title: '确认删除',
content: `确定要删除员工${staff.name}吗?此操作不可恢复。`,
success: (res) => {
if (res.confirm) {
const index = this.staffList.findIndex(item => item.id === staff.id);
if (index > -1) {
this.staffList.splice(index, 1);
this.totalStaff--;
this.activeStaff--;
if (staff.isOnline) {
this.onlineStaff--;
}
uni.showToast({
title: '删除成功',
icon: 'success'
});
}
}
}
});
}
}
}
</script>
<style scoped lang="scss">
.content {
padding: 20rpx;
min-height: 100vh;
background-color: #f5f5f5;
}
.header {
background-color: #fff;
padding: 30rpx;
border-radius: 10rpx;
margin-bottom: 20rpx;
text-align: center;
.title {
font-size: 36rpx;
font-weight: bold;
color: #333;
margin-bottom: 10rpx;
}
.subtitle {
font-size: 28rpx;
color: #666;
}
}
.search-bar {
display: flex;
gap: 20rpx;
margin-bottom: 20rpx;
.search-input {
flex: 1;
display: flex;
align-items: center;
padding: 20rpx;
background-color: #fff;
border-radius: 25rpx;
gap: 15rpx;
input {
flex: 1;
font-size: 28rpx;
border: none;
outline: none;
}
}
.add-btn {
display: flex;
align-items: center;
gap: 8rpx;
padding: 20rpx 30rpx;
background-color: #007AFF;
color: #fff;
border-radius: 25rpx;
font-size: 28rpx;
}
}
.stats-container {
display: flex;
background-color: #fff;
border-radius: 10rpx;
margin-bottom: 20rpx;
padding: 30rpx 0;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
.stats-item {
flex: 1;
text-align: center;
.stats-number {
font-size: 48rpx;
font-weight: bold;
color: #007AFF;
margin-bottom: 10rpx;
}
.stats-label {
font-size: 24rpx;
color: #666;
}
}
}
.staff-list {
.empty-state {
text-align: center;
padding: 100rpx 0;
background-color: #fff;
border-radius: 10rpx;
.empty-icon {
font-size: 120rpx;
margin-bottom: 20rpx;
}
.empty-text {
font-size: 28rpx;
color: #999;
}
}
.staff-item {
display: flex;
background-color: #fff;
border-radius: 10rpx;
padding: 30rpx;
margin-bottom: 20rpx;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
.staff-avatar {
position: relative;
width: 120rpx;
height: 120rpx;
margin-right: 20rpx;
image {
width: 100%;
height: 100%;
border-radius: 60rpx;
}
.online-status {
position: absolute;
bottom: 5rpx;
right: 5rpx;
width: 24rpx;
height: 24rpx;
border-radius: 12rpx;
background-color: #ccc;
border: 3rpx solid #fff;
&.online {
background-color: #34c759;
}
}
}
.staff-info {
flex: 1;
.staff-header {
display: flex;
align-items: center;
margin-bottom: 15rpx;
gap: 15rpx;
.name {
font-size: 32rpx;
font-weight: bold;
color: #333;
}
.role-badge {
padding: 6rpx 12rpx;
border-radius: 15rpx;
font-size: 22rpx;
color: #fff;
&.driver {
background-color: #007AFF;
}
&.supervisor {
background-color: #ff9500;
}
&.operator {
background-color: #34c759;
}
}
}
.staff-details {
font-size: 26rpx;
color: #666;
line-height: 1.4;
margin-bottom: 15rpx;
text {
display: block;
margin-bottom: 5rpx;
}
}
.staff-stats {
display: flex;
gap: 30rpx;
.stat-item {
font-size: 24rpx;
.stat-label {
color: #666;
}
.stat-value {
color: #007AFF;
font-weight: bold;
}
}
}
}
.staff-actions {
display: flex;
flex-direction: column;
gap: 15rpx;
.action-btn {
width: 60rpx;
height: 60rpx;
display: flex;
align-items: center;
justify-content: center;
background-color: #f8f8f8;
border-radius: 30rpx;
}
}
}
}
</style>