You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
637 lines
15 KiB
Vue
637 lines
15 KiB
Vue
<template>
|
|
<view class="page-container">
|
|
|
|
<view class="content">
|
|
<!-- 搜索区域 -->
|
|
<view class="search-section">
|
|
<view class="search-card">
|
|
<view class="search-row">
|
|
<tn-input v-model="searchKeyword" placeholder="请输入网格员姓名或负责区域" border height="80rpx"
|
|
class="search-input">
|
|
<template #prefix>
|
|
<uni-icons type="search" size="20" color="#999"></uni-icons>
|
|
</template>
|
|
</tn-input>
|
|
<tn-button type="primary" @click="handleSearch" :loading="loading" class="search-btn">
|
|
搜索
|
|
</tn-button>
|
|
<tn-button width="80px" height="32px" :plain="true" text-color="#0099ff" @click="backToIndex">
|
|
<uni-icons type="arrow-left" size="18" color="#0099ff"
|
|
style="margin-right: 5px;"></uni-icons>返回
|
|
</tn-button>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 网格员表格 -->
|
|
<view class="table-section">
|
|
<view class="section-card">
|
|
<view class="section-header">
|
|
<text class="section-title">网格员列表</text>
|
|
<text class="total-count">共 {{ gridMembers.length }} 人</text>
|
|
</view>
|
|
|
|
<uni-table ref="table" :loading="loading" border stripe emptyText="暂无网格员数据">
|
|
<uni-tr>
|
|
<uni-th width="120" align="center">姓名</uni-th>
|
|
<uni-th width="150" align="center">工号</uni-th>
|
|
<uni-th width="200" align="center">负责区域</uni-th>
|
|
<uni-th width="120" align="center">联系方式</uni-th>
|
|
<uni-th width="100" align="center">在岗状态</uni-th>
|
|
<uni-th width="120" align="center">操作</uni-th>
|
|
</uni-tr>
|
|
<uni-tr v-for="(member, index) in gridMembers" :key="member.id">
|
|
<uni-td align="center">
|
|
<view class="member-info">
|
|
<image :src="member.avatar || '/static/default-avatar.png'" class="avatar"></image>
|
|
<text class="member-name">{{ member.name }}</text>
|
|
</view>
|
|
</uni-td>
|
|
<uni-td align="center">{{ member.workNumber }}</uni-td>
|
|
<uni-td align="center">
|
|
<text class="area-text">{{ member.area }}</text>
|
|
</uni-td>
|
|
<uni-td align="center">
|
|
<view class="contact-info">
|
|
<text class="phone">{{ member.phone }}</text>
|
|
<text class="email" v-if="member.email">{{ member.email }}</text>
|
|
</view>
|
|
</uni-td>
|
|
<uni-td align="center">
|
|
<view class="status-badge" :class="getStatusClass(member.status)">
|
|
{{ getStatusText(member.status) }}
|
|
</view>
|
|
</uni-td>
|
|
<uni-td align="center">
|
|
<tn-button size="sm" type="primary" plain @click="viewMemberDetail(member)">
|
|
查看详情
|
|
</tn-button>
|
|
</uni-td>
|
|
</uni-tr>
|
|
</uni-table>
|
|
|
|
<!-- 分页 -->
|
|
<view class="pagination-section" v-if="total > pageSize">
|
|
<uni-pagination :total="total" :pageSize="pageSize" :current="currentPage"
|
|
@change="handlePageChange" show-icon />
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 网格员详情弹窗 -->
|
|
<uni-popup ref="detailPopup" type="center" background-color="#fff" class="detail-popup">
|
|
<view class="popup-content" v-if="currentMember">
|
|
<view class="popup-header">
|
|
<text class="popup-title">网格员详细信息</text>
|
|
<uni-icons type="close" size="20" color="#999" @click="closeDetailPopup"></uni-icons>
|
|
</view>
|
|
|
|
<view class="popup-body">
|
|
<!-- 基本信息 -->
|
|
<view class="detail-section">
|
|
<view class="detail-header">
|
|
<text class="detail-title">基本信息</text>
|
|
</view>
|
|
<view class="detail-grid">
|
|
<view class="detail-item">
|
|
<text class="item-label">姓名:</text>
|
|
<text class="item-value">{{ currentMember.name }}</text>
|
|
</view>
|
|
<view class="detail-item">
|
|
<text class="item-label">工号:</text>
|
|
<text class="item-value">{{ currentMember.workNumber }}</text>
|
|
</view>
|
|
<view class="detail-item">
|
|
<text class="item-label">性别:</text>
|
|
<text class="item-value">{{ currentMember.gender }}</text>
|
|
</view>
|
|
<view class="detail-item">
|
|
<text class="item-label">职务:</text>
|
|
<text class="item-value">{{ currentMember.position }}</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 联系信息 -->
|
|
<view class="detail-section">
|
|
<view class="detail-header">
|
|
<text class="detail-title">联系信息</text>
|
|
</view>
|
|
<view class="detail-grid">
|
|
<view class="detail-item">
|
|
<text class="item-label">手机号码:</text>
|
|
<text class="item-value">{{ currentMember.phone }}</text>
|
|
</view>
|
|
<view class="detail-item">
|
|
<text class="item-label">电子邮箱:</text>
|
|
<text class="item-value">{{ currentMember.email || '未填写' }}</text>
|
|
</view>
|
|
<view class="detail-item">
|
|
<text class="item-label">办公电话:</text>
|
|
<text class="item-value">{{ currentMember.officePhone || '未填写' }}</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 工作信息 -->
|
|
<view class="detail-section">
|
|
<view class="detail-header">
|
|
<text class="detail-title">工作信息</text>
|
|
</view>
|
|
<view class="detail-grid">
|
|
<view class="detail-item full-width">
|
|
<text class="item-label">负责区域:</text>
|
|
<text class="item-value">{{ currentMember.area }}</text>
|
|
</view>
|
|
<view class="detail-item">
|
|
<text class="item-label">在岗状态:</text>
|
|
<view class="status-badge" :class="getStatusClass(currentMember.status)">
|
|
{{ getStatusText(currentMember.status) }}
|
|
</view>
|
|
</view>
|
|
<view class="detail-item">
|
|
<text class="item-label">入职时间:</text>
|
|
<text class="item-value">{{ currentMember.joinDate }}</text>
|
|
</view>
|
|
<view class="detail-item full-width">
|
|
<text class="item-label">管辖企业数量:</text>
|
|
<text class="item-value">{{ currentMember.enterpriseCount }} 家</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 工作统计 -->
|
|
<view class="detail-section">
|
|
<view class="detail-header">
|
|
<text class="detail-title">工作统计</text>
|
|
</view>
|
|
<view class="stats-grid">
|
|
<view class="stat-item">
|
|
<text class="stat-number">{{ currentMember.monthlyTasks || 0 }}</text>
|
|
<text class="stat-label">本月任务</text>
|
|
</view>
|
|
<view class="stat-item">
|
|
<text class="stat-number">{{ currentMember.completedTasks || 0 }}</text>
|
|
<text class="stat-label">已完成</text>
|
|
</view>
|
|
<view class="stat-item">
|
|
<text class="stat-number">{{ currentMember.responseRate || '0%' }}</text>
|
|
<text class="stat-label">响应率</text>
|
|
</view>
|
|
<view class="stat-item">
|
|
<text class="stat-number">{{ currentMember.satisfaction || '0%' }}</text>
|
|
<text class="stat-label">满意度</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<view class="popup-footer">
|
|
<tn-button type="primary" @click="contactMember(currentMember)" class="action-btn">
|
|
<uni-icons type="phone" size="16" color="#fff"></uni-icons>
|
|
联系网格员
|
|
</tn-button>
|
|
<tn-button type="default" @click="assignTask(currentMember)" class="action-btn">
|
|
<uni-icons type="plus" size="16" color="#666"></uni-icons>
|
|
分配任务
|
|
</tn-button>
|
|
</view>
|
|
</view>
|
|
</uni-popup>
|
|
</view>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { ref, reactive, onMounted } from 'vue'
|
|
|
|
// 搜索相关
|
|
const searchKeyword = ref('')
|
|
const loading = ref(false)
|
|
|
|
// 分页相关
|
|
const currentPage = ref(1)
|
|
const pageSize = ref(10)
|
|
const total = ref(0)
|
|
|
|
// 弹窗引用
|
|
const detailPopup = ref()
|
|
|
|
// 网格员数据
|
|
const gridMembers = ref<any[]>([])
|
|
const currentMember = ref<any>(null)
|
|
|
|
// 状态映射
|
|
const statusMap = {
|
|
1: { text: '在岗', class: 'status-online' },
|
|
2: { text: '离岗', class: 'status-offline' },
|
|
3: { text: '忙碌', class: 'status-busy' },
|
|
4: { text: '休假', class: 'status-leave' }
|
|
}
|
|
|
|
// 初始化数据
|
|
const initGridMembers = () => {
|
|
// 模拟数据 - 实际项目中从API获取
|
|
gridMembers.value = [
|
|
{
|
|
id: 1,
|
|
name: '张三',
|
|
workNumber: 'GY2024001',
|
|
area: '某某区某某街道税务网格A区',
|
|
phone: '13800138001',
|
|
email: 'zhangsan@tax.gov.cn',
|
|
status: 1,
|
|
gender: '男',
|
|
position: '高级网格员',
|
|
officePhone: '020-12345678',
|
|
joinDate: '2022-03-15',
|
|
enterpriseCount: 45,
|
|
monthlyTasks: 23,
|
|
completedTasks: 18,
|
|
responseRate: '95%',
|
|
satisfaction: '92%'
|
|
},
|
|
{
|
|
id: 2,
|
|
name: '李四',
|
|
workNumber: 'GY2024002',
|
|
area: '某某区某某街道税务网格B区',
|
|
phone: '13800138002',
|
|
email: 'lisi@tax.gov.cn',
|
|
status: 2,
|
|
gender: '女',
|
|
position: '网格员',
|
|
officePhone: '020-12345679',
|
|
joinDate: '2023-01-10',
|
|
enterpriseCount: 38,
|
|
monthlyTasks: 19,
|
|
completedTasks: 15,
|
|
responseRate: '88%',
|
|
satisfaction: '90%'
|
|
},
|
|
{
|
|
id: 3,
|
|
name: '王五',
|
|
workNumber: 'GY2024003',
|
|
area: '某某区某某街道税务网格C区',
|
|
phone: '13800138003',
|
|
status: 3,
|
|
gender: '男',
|
|
position: '网格组长',
|
|
joinDate: '2021-08-20',
|
|
enterpriseCount: 52,
|
|
monthlyTasks: 28,
|
|
completedTasks: 25,
|
|
responseRate: '98%',
|
|
satisfaction: '96%'
|
|
},
|
|
{
|
|
id: 4,
|
|
name: '赵六',
|
|
workNumber: 'GY2024004',
|
|
area: '某某区某某街道税务网格D区',
|
|
phone: '13800138004',
|
|
email: 'zhaoliu@tax.gov.cn',
|
|
status: 4,
|
|
gender: '女',
|
|
position: '网格员',
|
|
joinDate: '2023-05-08',
|
|
enterpriseCount: 32,
|
|
monthlyTasks: 16,
|
|
completedTasks: 12,
|
|
responseRate: '85%',
|
|
satisfaction: '87%'
|
|
}
|
|
]
|
|
total.value = gridMembers.value.length
|
|
}
|
|
|
|
// 搜索处理
|
|
const handleSearch = () => {
|
|
loading.value = true
|
|
// 模拟搜索 - 实际项目中调用API
|
|
setTimeout(() => {
|
|
if (searchKeyword.value) {
|
|
const filtered = gridMembers.value.filter(member =>
|
|
member.name.includes(searchKeyword.value) ||
|
|
member.area.includes(searchKeyword.value)
|
|
)
|
|
gridMembers.value = filtered
|
|
total.value = filtered.length
|
|
} else {
|
|
initGridMembers()
|
|
}
|
|
loading.value = false
|
|
}, 500)
|
|
}
|
|
|
|
// 获取状态样式
|
|
const getStatusClass = (status : number) => {
|
|
return statusMap[status]?.class || 'status-offline'
|
|
}
|
|
|
|
// 获取状态文本
|
|
const getStatusText = (status : number) => {
|
|
return statusMap[status]?.text || '未知'
|
|
}
|
|
|
|
// 查看网格员详情
|
|
const viewMemberDetail = (member : any) => {
|
|
currentMember.value = member
|
|
detailPopup.value.open()
|
|
}
|
|
|
|
// 关闭详情弹窗
|
|
const closeDetailPopup = () => {
|
|
detailPopup.value.close()
|
|
}
|
|
|
|
// 联系网格员
|
|
const contactMember = (member : any) => {
|
|
uni.makePhoneCall({
|
|
phoneNumber: member.phone
|
|
})
|
|
}
|
|
|
|
// 分配任务
|
|
const assignTask = (member : any) => {
|
|
uni.showModal({
|
|
title: '分配任务',
|
|
content: `确定要给 ${member.name} 分配新任务吗?`,
|
|
success: (res) => {
|
|
if (res.confirm) {
|
|
uni.navigateTo({
|
|
url: `/pages/task/assign?memberId=${member.id}`
|
|
})
|
|
closeDetailPopup()
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
const backToIndex = () => {
|
|
uni.navigateTo({
|
|
url: '/pages/index/index'
|
|
})
|
|
}
|
|
|
|
// 分页变化
|
|
const handlePageChange = (e : any) => {
|
|
currentPage.value = e.current
|
|
// 实际项目中这里应该调用API获取对应页面的数据
|
|
}
|
|
|
|
onMounted(() => {
|
|
initGridMembers()
|
|
})
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.page-container {
|
|
min-height: 100vh;
|
|
background-color: #f5f7fa;
|
|
}
|
|
|
|
.content {
|
|
padding: 6vh 20px 0 20px;
|
|
}
|
|
|
|
// 搜索区域
|
|
.search-section {
|
|
margin-bottom: 30rpx;
|
|
|
|
.search-card {
|
|
background: #fff;
|
|
border-radius: 16rpx;
|
|
padding: 30rpx;
|
|
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.05);
|
|
|
|
.search-row {
|
|
display: flex;
|
|
gap: 20rpx;
|
|
align-items: center;
|
|
|
|
.search-input {
|
|
flex: 1;
|
|
}
|
|
|
|
.search-btn {
|
|
width: 200rpx;
|
|
height: 32px;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 表格区域
|
|
.table-section {
|
|
.section-card {
|
|
background: #fff;
|
|
border-radius: 16rpx;
|
|
padding: 30rpx;
|
|
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.05);
|
|
}
|
|
|
|
.section-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: 30rpx;
|
|
|
|
.section-title {
|
|
font-size: 32rpx;
|
|
font-weight: bold;
|
|
color: #333;
|
|
}
|
|
|
|
.total-count {
|
|
font-size: 24rpx;
|
|
color: #999;
|
|
}
|
|
}
|
|
}
|
|
|
|
// 网格员信息
|
|
.member-info {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
|
|
.avatar {
|
|
width: 60rpx;
|
|
height: 60rpx;
|
|
border-radius: 50%;
|
|
margin-right: 15rpx;
|
|
}
|
|
|
|
.member-name {
|
|
font-size: 28rpx;
|
|
color: #333;
|
|
}
|
|
}
|
|
|
|
.area-text {
|
|
font-size: 26rpx;
|
|
color: #666;
|
|
line-height: 1.4;
|
|
}
|
|
|
|
.contact-info {
|
|
.phone {
|
|
display: block;
|
|
font-size: 26rpx;
|
|
color: #333;
|
|
}
|
|
|
|
.email {
|
|
display: block;
|
|
font-size: 22rpx;
|
|
color: #999;
|
|
margin-top: 5rpx;
|
|
}
|
|
}
|
|
|
|
// 状态标签
|
|
.status-badge {
|
|
display: inline-block;
|
|
padding: 8rpx 16rpx;
|
|
border-radius: 20rpx;
|
|
font-size: 22rpx;
|
|
font-weight: 500;
|
|
|
|
&.status-online {
|
|
background: #f6ffed;
|
|
color: #52c41a;
|
|
border: 1rpx solid #b7eb8f;
|
|
}
|
|
|
|
&.status-offline {
|
|
background: #f5f5f5;
|
|
color: #999;
|
|
border: 1rpx solid #d9d9d9;
|
|
}
|
|
|
|
&.status-busy {
|
|
background: #fff2e8;
|
|
color: #fa541c;
|
|
border: 1rpx solid #ffbb96;
|
|
}
|
|
|
|
&.status-leave {
|
|
background: #e6f7ff;
|
|
color: #1890ff;
|
|
border: 1rpx solid #91d5ff;
|
|
}
|
|
}
|
|
|
|
// 分页
|
|
.pagination-section {
|
|
margin-top: 30rpx;
|
|
display: flex;
|
|
justify-content: center;
|
|
}
|
|
|
|
// 详情弹窗
|
|
.detail-popup {
|
|
.popup-content {
|
|
width: 700rpx;
|
|
max-height: 80vh;
|
|
border-radius: 20rpx;
|
|
overflow: hidden;
|
|
background: #fff;
|
|
}
|
|
|
|
.popup-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
padding: 30rpx;
|
|
border-bottom: 1rpx solid #f0f0f0;
|
|
|
|
.popup-title {
|
|
font-size: 32rpx;
|
|
font-weight: bold;
|
|
color: #333;
|
|
}
|
|
}
|
|
|
|
.popup-body {
|
|
padding: 30rpx;
|
|
max-height: 60vh;
|
|
overflow-y: auto;
|
|
}
|
|
|
|
.detail-section {
|
|
margin-bottom: 40rpx;
|
|
|
|
.detail-header {
|
|
margin-bottom: 20rpx;
|
|
padding-bottom: 15rpx;
|
|
border-bottom: 1rpx solid #f0f0f0;
|
|
|
|
.detail-title {
|
|
font-size: 28rpx;
|
|
font-weight: bold;
|
|
color: #333;
|
|
}
|
|
}
|
|
}
|
|
|
|
.detail-grid {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 20rpx;
|
|
|
|
.detail-item {
|
|
width: calc(50% - 10rpx);
|
|
|
|
&.full-width {
|
|
width: 100%;
|
|
}
|
|
|
|
.item-label {
|
|
font-size: 26rpx;
|
|
color: #666;
|
|
}
|
|
|
|
.item-value {
|
|
font-size: 26rpx;
|
|
color: #333;
|
|
font-weight: 500;
|
|
}
|
|
}
|
|
}
|
|
|
|
.stats-grid {
|
|
display: flex;
|
|
justify-content: space-around;
|
|
text-align: center;
|
|
|
|
.stat-item {
|
|
.stat-number {
|
|
display: block;
|
|
font-size: 32rpx;
|
|
font-weight: bold;
|
|
color: #1890ff;
|
|
margin-bottom: 8rpx;
|
|
}
|
|
|
|
.stat-label {
|
|
font-size: 22rpx;
|
|
color: #999;
|
|
}
|
|
}
|
|
}
|
|
|
|
.popup-footer {
|
|
display: flex;
|
|
gap: 20rpx;
|
|
padding: 30rpx;
|
|
border-top: 1rpx solid #f0f0f0;
|
|
|
|
.action-btn {
|
|
flex: 1;
|
|
}
|
|
}
|
|
}
|
|
</style> |