diff --git a/src/apis/project/type.ts b/src/apis/project/type.ts index c15d7e8..cbdb186 100644 --- a/src/apis/project/type.ts +++ b/src/apis/project/type.ts @@ -156,14 +156,14 @@ export interface ProjectDetailResp extends ProjectCard { export interface TeamMemberResp { id: string | number name: string - position: string + roleType: string phone?: string email?: string avatar?: string joinDate?: string performance?: number remark?: string - status?: 'available' | 'busy' | 'offline' + status?: 'ACTIVE' | 'SUSPENDED' | 'INACTIVE' } /** 后端返回的团队成员数据结构 */ @@ -182,7 +182,7 @@ export interface BackendTeamMemberResp { phone: string | null email: string | null position: string - status: 'ACTIVE' | 'BUSY' | 'OFFLINE' + status: 'ACTIVE' | 'SUSPENDED' | 'INACTIVE' skills: string joinDate: string remark: string @@ -201,11 +201,11 @@ export interface BackendTeamMemberResp { export interface TeamMemberQuery extends PageQuery { projectId: string | number name?: string // 姓名搜索 - position?: string // 岗位筛选 + position?: string // 项目岗位筛选 status?: string // 状态筛选 joinDateStart?: string // 入职日期开始 joinDateEnd?: string // 入职日期结束 - sortBy?: 'name' | 'position' | 'joinDate' | 'status' // 排序字段 + sortBy?: 'name' | 'roleType' | 'joinDate' | 'status' // 排序字段 sortOrder?: 'asc' | 'desc' // 排序方向 } @@ -213,33 +213,33 @@ export interface TeamMemberQuery extends PageQuery { export interface TeamMemberExportQuery { projectId: string | number name?: string // 姓名搜索 - position?: string // 岗位筛选 + position?: string // 项目岗位筛选 status?: string // 状态筛选 joinDateStart?: string // 入职日期开始 joinDateEnd?: string // 入职日期结束 - sortBy?: 'name' | 'position' | 'joinDate' | 'status' // 排序字段 + sortBy?: 'name' | 'roleType' | 'joinDate' | 'status' // 排序字段 sortOrder?: 'asc' | 'desc' // 排序方向 } /** 创建团队成员表单 */ export interface CreateTeamMemberForm { projectId: string | number + roleType: string // 项目岗位 name: string phone: string email?: string - position: string - status?: 'available' | 'busy' | 'offline' + status?: 'ACTIVE' | 'SUSPENDED' | 'INACTIVE' joinDate?: string remark?: string } /** 更新团队成员表单 */ export interface UpdateTeamMemberForm { + roleType?: string // 项目岗位 name?: string phone?: string email?: string - position?: string - status?: 'available' | 'busy' | 'offline' + status?: 'ACTIVE' | 'SUSPENDED' | 'INACTIVE' joinDate?: string remark?: string } @@ -250,7 +250,7 @@ export interface UpdateTeamMemberForm { export interface BatchOperationForm { ids: (string | number)[] operation: 'delete' | 'updateStatus' - status?: 'available' | 'busy' | 'offline' + status?: 'ACTIVE' | 'SUSPENDED' | 'INACTIVE' } /** 导入结果响应 */ diff --git a/src/views/project-management/personnel-dispatch/construction-personnel.vue b/src/views/project-management/personnel-dispatch/construction-personnel.vue index 7bf428c..7deaaf4 100644 --- a/src/views/project-management/personnel-dispatch/construction-personnel.vue +++ b/src/views/project-management/personnel-dispatch/construction-personnel.vue @@ -41,6 +41,20 @@
+ +
+ + 当前应用了搜索筛选条件 + + 清除所有筛选 + +
+ - + @@ -73,6 +89,7 @@ placeholder="请选择状态" style="width: 120px" allow-clear + @change="handleSearch" > - + 搜索 @@ -99,24 +121,49 @@
+ + + + + + + @@ -132,9 +179,31 @@ @@ -160,10 +229,10 @@
- - + + @@ -293,24 +362,26 @@ import { const route = useRoute() const projectId = route.query.projectId as string -// 选项数据常量 -const POSITION_OPTIONS = [ - { label: '项目经理', value: '项目经理' }, - { label: '技术负责人', value: '技术负责人' }, - { label: '安全员', value: '安全员' }, - { label: '质量员', value: '质量员' }, - { label: '施工员', value: '施工员' }, - { label: '材料员', value: '材料员' }, - { label: '资料员', value: '资料员' }, - { label: '实习生', value: '实习生' }, - { label: '技术工人', value: '技术工人' }, - { label: '普通工人', value: '普通工人' } +// 选项数据常量 - 项目岗位选项 + +const ROLE_TYPE_OPTIONS = [ + { label: '项目经理', value: 'PROJECT_MANAGER' }, + { label: '项目负责人', value: 'TEAM_LEADER' }, + { label: '技术负责人', value: 'TECH_LEADER' }, + { label: '安全员', value: 'SAFETY_OFFICER' }, + { label: '质量员', value: 'QUALITY_OFFICER' }, + { label: '施工员', value: 'CONSTRUCTOR' }, + { label: '材料员', value: 'MATERIAL_MANAGER' }, + { label: '资料员', value: 'DOCUMENT_MANAGER' }, + { label: '实习生', value: 'INTERN' }, + { label: '技术工人', value: 'TECH_WORKER' }, + { label: '普通工人', value: 'WORKER' } ] const STATUS_OPTIONS = [ - { label: '可用', value: 'available' }, - { label: '忙碌', value: 'busy' }, - { label: '离线', value: 'offline' } + { label: '可用', value: 'ACTIVE' }, + { label: '忙碌', value: 'SUSPENDED' }, + { label: '离线', value: 'INACTIVE' } ] // 响应式数据 @@ -328,11 +399,11 @@ const pagination = reactive({ // 搜索表单 const searchForm = reactive<{ name: string - position: string + roleType: string status: string }>({ name: '', - position: '', + roleType: '', status: '' }) @@ -341,7 +412,7 @@ const tableColumns = [ { title: '姓名', dataIndex: 'name', width: 100, fixed: 'left' }, { title: '联系电话', dataIndex: 'phone', width: 120 }, { title: '邮箱', dataIndex: 'email', width: 150 }, - { title: '项目岗位', dataIndex: 'position', width: 120 }, + { title: '项目岗位', dataIndex: 'roleType', width: 120, slotName: 'roleType' }, { title: '状态', dataIndex: 'status', width: 100, slotName: 'status' }, { title: '入职日期', dataIndex: 'joinDate', width: 120 }, { title: '备注', dataIndex: 'remark', width: 200, slotName: 'remark' }, @@ -359,9 +430,9 @@ const memberForm = reactive({ projectId: projectId, name: '', phone: '', + roleType: '', // 项目岗位 + status: 'ACTIVE', email: '', - position: '', - status: 'available', joinDate: '', remark: '' }) @@ -370,12 +441,12 @@ const statusForm = reactive<{ id: string | number name: string currentStatus: string - newStatus: 'available' | 'busy' | 'offline' + newStatus: 'ACTIVE' | 'SUSPENDED' | 'INACTIVE' }>({ id: '', name: '', currentStatus: '', - newStatus: 'available' + newStatus: 'ACTIVE' }) const fileList = ref([]) @@ -392,56 +463,80 @@ const loadData = async () => { try { console.log('正在加载项目团队成员数据,项目ID:', projectId) - // 构建查询参数 + // 构建查询参数,字段名要与后端接口匹配 const queryParams: TeamMemberQuery = { projectId: projectId, page: pagination.current, pageSize: pagination.pageSize, name: searchForm.name || undefined, - position: searchForm.position || undefined, + position: searchForm.roleType || undefined, // 后端使用position字段 status: searchForm.status || undefined } + console.log('查询参数:', queryParams) + const response = await getProjectTeamMembers(queryParams) - console.log('API响应数据:', response.data) + console.log('API响应数据:', response) - // 确保response.data是数组 - const rawData = Array.isArray(response.data) ? response.data : [response.data] + // 处理后端返回的数据 + let mappedData: TeamMemberResp[] = [] + let total = 0 - console.log('处理后的原始数据:', rawData) - - // 处理后端返回的数据,将后端字段映射到前端期望的字段 - const mappedData = rawData.map((item: BackendTeamMemberResp) => { - const mappedItem: TeamMemberResp = { + if (response.data) { + // 如果后端返回的是分页数据 + if (response.data.list && Array.isArray(response.data.list)) { + mappedData = response.data.list.map((item: BackendTeamMemberResp) => { + return { id: item.memberId, name: item.name || '', phone: item.phone || '', email: item.email || '', - position: item.position || '', - status: (item.status === 'ACTIVE' ? 'available' : item.status === 'BUSY' ? 'busy' : 'offline') as 'available' | 'busy' | 'offline', + roleType: item.roleType || item.position || '', // 优先使用roleType,fallback到position + status: (item.status === 'ACTIVE' ? 'ACTIVE' : item.status === 'SUSPENDED' ? 'SUSPENDED' : 'INACTIVE') as 'ACTIVE' | 'SUSPENDED' | 'INACTIVE', joinDate: item.joinDate || '', remark: item.remark || '', avatar: item.userAvatar || '' } - console.log('映射后的数据项:', mappedItem) - return mappedItem - }) + }) + total = response.data.total || mappedData.length + } + // 如果后端直接返回数组 + else if (Array.isArray(response.data)) { + mappedData = response.data.map((item: BackendTeamMemberResp) => { + return { + id: item.memberId, + name: item.name || '', + phone: item.phone || '', + email: item.email || '', + roleType: item.roleType || item.position || '', + status: (item.status === 'ACTIVE' ? 'ACTIVE' : item.status === 'SUSPENDED' ? 'SUSPENDED' : 'INACTIVE') as 'ACTIVE' | 'SUSPENDED' | 'INACTIVE', + joinDate: item.joinDate || '', + remark: item.remark || '', + avatar: item.userAvatar || '' + } + }) + total = mappedData.length + } + } dataList.value = mappedData - pagination.total = mappedData.length + pagination.total = total console.log('团队成员数据加载完成,显示数据:', dataList.value.length, '条,总计:', pagination.total, '条') } catch (error) { console.error('团队成员数据加载失败:', error) Message.error('团队成员数据加载失败') + dataList.value = [] + pagination.total = 0 } finally { loading.value = false } } const handleSearch = async () => { + console.log('执行搜索,搜索条件:', searchForm) pagination.current = 1 await loadData() } @@ -450,19 +545,22 @@ const handleReset = () => { console.log('重置搜索表单') Object.assign(searchForm, { name: '', - position: '', + roleType: '', status: '' }) pagination.current = 1 + // 重置后自动加载数据 loadData() } const onPageChange = (page: number) => { + console.log('页码变化:', page) pagination.current = page loadData() } const onPageSizeChange = (pageSize: number) => { + console.log('每页大小变化:', pageSize) pagination.pageSize = pageSize pagination.current = 1 loadData() @@ -481,9 +579,9 @@ const openEditModal = (record: TeamMemberResp) => { projectId: projectId, name: record.name, phone: record.phone || '', + roleType: record.roleType || '', + status: record.status || 'ACTIVE', email: record.email || '', - position: record.position, - status: record.status || 'available', joinDate: record.joinDate || '', remark: record.remark || '' }) @@ -491,7 +589,7 @@ const openEditModal = (record: TeamMemberResp) => { } const saveMember = async () => { - if (!memberForm.name || !memberForm.phone || !memberForm.position) { + if (!memberForm.name || !memberForm.phone || !memberForm.roleType) { Message.error('请填写必填项') return } @@ -502,9 +600,9 @@ const saveMember = async () => { const updateData: UpdateTeamMemberForm = { name: memberForm.name, phone: memberForm.phone, - email: memberForm.email, - position: memberForm.position, + roleType: memberForm.roleType, status: memberForm.status, + email: memberForm.email, joinDate: memberForm.joinDate, remark: memberForm.remark } @@ -516,9 +614,9 @@ const saveMember = async () => { projectId: projectId, name: memberForm.name, phone: memberForm.phone, - email: memberForm.email, - position: memberForm.position, + roleType: memberForm.roleType, status: memberForm.status, + email: memberForm.email, joinDate: memberForm.joinDate, remark: memberForm.remark } @@ -545,9 +643,9 @@ const resetMemberForm = () => { projectId: projectId, name: '', phone: '', + roleType: '', + status: 'ACTIVE', email: '', - position: '', - status: 'available', joinDate: '', remark: '' }) @@ -557,8 +655,8 @@ const openStatusModal = (record: TeamMemberResp) => { Object.assign(statusForm, { id: record.id, name: record.name, - currentStatus: record.status || 'available', - newStatus: record.status || 'available' + currentStatus: record.status || 'ACTIVE', + newStatus: record.status || 'ACTIVE' }) statusModalVisible.value = true } @@ -566,7 +664,7 @@ const openStatusModal = (record: TeamMemberResp) => { const saveStatus = async () => { try { await updateTeamMember(statusForm.id, { - status: statusForm.newStatus as 'available' | 'busy' | 'offline' + status: statusForm.newStatus as 'ACTIVE' | 'SUSPENDED' | 'INACTIVE' }) Message.success('状态更新成功') statusModalVisible.value = false @@ -655,7 +753,7 @@ const exportData = async () => { const queryParams: TeamMemberExportQuery = { projectId: projectId, name: searchForm.name || undefined, - position: searchForm.position || undefined, + position: searchForm.roleType || undefined, status: searchForm.status || undefined } @@ -677,24 +775,34 @@ const exportData = async () => { } // 工具方法 +const getRoleTypeText = (roleType: string) => { + const option = ROLE_TYPE_OPTIONS.find(opt => opt.value === roleType) + return option ? option.label : roleType +} + const getStatusColor = (status: string) => { const colorMap: Record = { - available: 'green', - busy: 'orange', - offline: 'gray' + ACTIVE: 'success', + SUSPENDED: 'warning', + INACTIVE: 'danger' } - return colorMap[status] || 'gray' + return colorMap[status] || 'danger' } const getStatusText = (status: string) => { const textMap: Record = { - available: '可用', - busy: '忙碌', - offline: '离线' + ACTIVE: '可用', + SUSPENDED: '忙碌', + INACTIVE: '离线' } return textMap[status] || '未知' } +// 计算属性:判断是否有激活的搜索条件 +const hasActiveFilters = computed(() => { + return searchForm.name || searchForm.roleType || searchForm.status +}) + // 生命周期 onMounted(() => { console.log('团队成员管理页面加载,项目ID:', projectId) @@ -735,54 +843,138 @@ onMounted(() => { // 确保表格容器可以滚动 :deep(.arco-table-container) { overflow-x: auto; - overflow-y: visible; + overflow-y: auto; +} + +// 确保表格内容可以正常滚动 +:deep(.arco-table-body) { + overflow-y: auto !important; +} + +:deep(.arco-table-tbody) { + overflow-y: auto !important; +} + +// 确保分页器不会影响滚动 +:deep(.arco-pagination) { + margin-top: 16px; +} + +// 操作链接样式 +.action-link { + display: inline-flex; + align-items: center; + gap: 4px; + padding: 6px 12px; + border-radius: 6px; + font-weight: 500; + transition: all 0.3s ease; + text-decoration: none; + + &:hover { + transform: translateY(-1px); + text-decoration: none; + } + + &.edit-link { + color: #1677ff; + + &:hover { + background: rgba(22, 119, 255, 0.1); + color: #0958d9; + } + } + + &.status-link { + color: #52c41a; + + &:hover { + background: rgba(82, 196, 26, 0.1); + color: #389e0d; + } + } + + &.delete-link { + color: #ff4d4f; + + &:hover { + background: rgba(255, 77, 79, 0.1); + color: #d9363e; + } + } } .page-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 24px; - padding: 20px; - background: white; - border-radius: 8px; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06); + padding: 24px; + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + border-radius: 16px; + box-shadow: 0 8px 32px rgba(102, 126, 234, 0.3); + position: relative; + overflow: hidden; + + &::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: url('data:image/svg+xml,'); + opacity: 0.3; + } .header-left { display: flex; align-items: center; - gap: 16px; + gap: 20px; + position: relative; + z-index: 1; .back-btn { border: none; - background: #f7f8fa; - color: #4e5969; + background: rgba(255, 255, 255, 0.2); + color: white; + backdrop-filter: blur(10px); + border-radius: 8px; + padding: 8px 16px; + transition: all 0.3s ease; &:hover { - background: #e5e6eb; - color: #1d2129; + background: rgba(255, 255, 255, 0.3); + transform: translateX(-2px); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2); } } .header-title { display: flex; align-items: center; - gap: 8px; + gap: 12px; .title-icon { - font-size: 24px; - color: #667eea; + font-size: 28px; + color: white; + filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.2)); } h1 { margin: 0; - font-size: 20px; - font-weight: 600; - color: #1d2129; + font-size: 24px; + font-weight: 700; + color: white; + text-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); } .project-info { font-size: 14px; - color: #969fa8; + color: rgba(255, 255, 255, 0.9); + background: rgba(255, 255, 255, 0.2); + padding: 6px 12px; + border-radius: 20px; + backdrop-filter: blur(10px); } } } @@ -790,6 +982,19 @@ onMounted(() => { .header-actions { display: flex; gap: 12px; + position: relative; + z-index: 1; + + .arco-btn { + border-radius: 8px; + font-weight: 600; + transition: all 0.3s ease; + + &:hover { + transform: translateY(-2px); + box-shadow: 0 6px 20px rgba(0, 0, 0, 0.2); + } + } } } @@ -797,56 +1002,148 @@ onMounted(() => { margin-bottom: 16px; .search-card { - background: white; - border-radius: 8px; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06); + background: linear-gradient(135deg, #f8f9ff 0%, #f0f2ff 100%); + border-radius: 16px; + box-shadow: 0 4px 20px rgba(102, 126, 234, 0.1); + border: 1px solid rgba(102, 126, 234, 0.1); :deep(.arco-card-body) { - padding: 20px; + padding: 24px; + } + + // 搜索状态提示样式 + .search-status { + display: flex; + align-items: center; + margin-bottom: 16px; + padding: 12px 16px; + background: rgba(102, 126, 234, 0.1); + border-radius: 8px; + border-left: 4px solid #667eea; + font-size: 14px; + color: #4e5969; + + .arco-btn { + padding: 2px 8px; + height: auto; + line-height: 1.4; + + &:hover { + background: rgba(102, 126, 234, 0.2); + } + } } :deep(.arco-form-item) { margin-bottom: 0; - margin-right: 16px; + margin-right: 20px; } :deep(.arco-form-item-label) { - font-weight: 500; + font-weight: 600; color: #4e5969; + font-size: 14px; } :deep(.arco-input), :deep(.arco-select) { width: 100%; + border-radius: 8px; + border: 1px solid rgba(102, 126, 234, 0.2); + transition: all 0.3s ease; + + &:hover { + border-color: rgba(102, 126, 234, 0.4); + box-shadow: 0 2px 8px rgba(102, 126, 234, 0.1); + } + + &:focus { + border-color: #667eea; + box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1); + } + } + + :deep(.arco-btn) { + border-radius: 8px; + font-weight: 600; + transition: all 0.3s ease; + + &:hover { + transform: translateY(-1px); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); + } + + &:disabled { + opacity: 0.6; + cursor: not-allowed; + + &:hover { + transform: none; + box-shadow: none; + } + } } } } -// 表格区域样式 -:deep(.gi-table) { - background: white; - border-radius: 8px; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06); - margin-bottom: 24px; - max-height: calc(100vh - 300px); - overflow: hidden; +// 搜索结果统计样式 +.search-results-info { + margin-bottom: 16px; - .arco-table-container { - overflow-x: auto; - overflow-y: auto; - max-height: calc(100vh - 350px); - } - - .arco-table { - overflow: visible; - } - - .arco-table-body { - overflow-y: auto; + .results-card { + background: linear-gradient(135deg, #f8f9ff 0%, #f0f2ff 100%); + border-radius: 12px; + box-shadow: 0 2px 12px rgba(102, 126, 234, 0.1); + border: 1px solid rgba(102, 126, 234, 0.1); + + :deep(.arco-card-body) { + padding: 16px 20px; + } + + .results-summary { + display: flex; + align-items: center; + font-size: 14px; + color: #4e5969; + + strong { + color: #667eea; + font-weight: 600; + } + } } } - +// 空状态样式 +.empty-state { + text-align: center; + padding: 60px 20px; + color: #c9cdd4; + + .empty-text { + h3 { + margin: 0 0 12px 0; + font-size: 18px; + font-weight: 600; + color: #4e5969; + } + + p { + margin: 8px 0; + font-size: 14px; + line-height: 1.6; + + .arco-link { + color: #667eea; + font-weight: 500; + + &:hover { + color: #4c5fd9; + } + } + } + } +} .remark-content { max-width: 180px; @@ -854,11 +1151,101 @@ onMounted(() => { text-overflow: ellipsis; white-space: nowrap; color: #4e5969; + background: rgba(102, 126, 234, 0.05); + padding: 8px 12px; + border-radius: 8px; + border-left: 3px solid #667eea; + font-size: 13px; + line-height: 1.4; + transition: all 0.3s ease; + + &:hover { + background: rgba(102, 126, 234, 0.1); + transform: translateX(2px); + white-space: normal; + max-width: 250px; + z-index: 10; + position: relative; + box-shadow: 0 4px 16px rgba(102, 126, 234, 0.2); + } } .no-remark { color: #c9cdd4; font-style: italic; + background: rgba(201, 205, 212, 0.1); + padding: 8px 12px; + border-radius: 8px; + border: 1px dashed #c9cdd4; + text-align: center; + font-size: 13px; +} + +.role-type-text { + display: inline-block; + padding: 6px 12px; + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + color: white; + font-weight: 600; + font-size: 12px; + border-radius: 20px; + text-align: center; + min-width: 80px; + box-shadow: 0 2px 8px rgba(102, 126, 234, 0.3); + text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); + transition: all 0.3s ease; + + &:hover { + transform: scale(1.05); + box-shadow: 0 4px 16px rgba(102, 126, 234, 0.4); + } +} + +// 状态标签样式 +.status-tag { + display: inline-block; + padding: 6px 12px; + border-radius: 20px; + font-weight: 600; + font-size: 12px; + text-align: center; + min-width: 60px; + transition: all 0.3s ease; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); + + &:hover { + transform: scale(1.05); + } + + &.status-ACTIVE { + background: linear-gradient(135deg, #52c41a 0%, #73d13d 100%); + color: white; + box-shadow: 0 2px 8px rgba(82, 196, 26, 0.3); + + &:hover { + box-shadow: 0 4px 16px rgba(82, 196, 26, 0.4); + } + } + + &.status-SUSPENDED { + background: linear-gradient(135deg, #faad14 0%, #ffc53d 100%); + color: white; + box-shadow: 0 2px 8px rgba(250, 173, 20, 0.3); + + &:hover { + box-shadow: 0 4px 16px rgba(250, 173, 20, 0.4); + } + } + + &.status-INACTIVE { + background: linear-gradient(135deg, #ff4d4f 0%, #ff7875 100%); + color: white; + box-shadow: 0 2px 8px rgba(255, 77, 79, 0.3); + + &:hover { + box-shadow: 0 4px 16px rgba(255, 77, 79, 0.4); + } + } } .member-form { @@ -926,21 +1313,23 @@ onMounted(() => { // 页面滚动修复 .construction-personnel-page { - height: 100vh; - overflow: hidden; + height: auto; + min-height: 100vh; + overflow: visible; display: flex; flex-direction: column; :deep(.gi-page-layout) { - height: 100%; - overflow: hidden; + height: auto; + min-height: 100vh; + overflow: visible; display: flex; flex-direction: column; } :deep(.gi-page-layout-content) { flex: 1; - overflow: hidden; + overflow: visible; display: flex; flex-direction: column; } @@ -978,4 +1367,153 @@ onMounted(() => { } } } + +// 全局动画效果 +@keyframes fadeInUp { + from { + opacity: 0; + transform: translateY(20px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes slideInLeft { + from { + opacity: 0; + transform: translateX(-20px); + } + to { + opacity: 1; + transform: translateX(0); + } +} + +// 页面加载动画 +.construction-personnel-page { + animation: fadeInUp 0.6s ease-out; +} + +.page-header { + animation: slideInLeft 0.8s ease-out; +} + +.search-section { + animation: fadeInUp 0.8s ease-out 0.2s both; +} + +:deep(.gi-table) { + animation: fadeInUp 0.8s ease-out 0.4s both; +} + +// 表格行进入动画 +:deep(.arco-table-tbody .arco-table-tr) { + animation: fadeInUp 0.6s ease-out; + animation-fill-mode: both; + + @for $i from 1 through 20 { + &:nth-child(#{$i}) { + animation-delay: #{0.1 * $i}s; + } + } +} + +// 悬停效果增强 +:deep(.arco-table-tbody .arco-table-tr:hover) { + .role-type-text { + transform: scale(1.05); + } + + .action-link { + transform: translateY(-2px); + } +} + +// 状态标签悬停效果 +:deep(.arco-tag) { + transition: all 0.3s ease; + + &:hover { + transform: scale(1.05); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); + } +} + +// 表格区域样式 +:deep(.gi-table) { + background: white; + border-radius: 12px; + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08); + margin-bottom: 24px; + overflow: hidden; + + .arco-table-container { + overflow-x: auto; + overflow-y: auto; + } + + .arco-table { + overflow: visible; + } + + .arco-table-body { + overflow-y: auto; + } + + // 表格头部样式 + .arco-table-thead { + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + + .arco-table-th { + background: transparent !important; + border-bottom: 2px solid rgba(255, 255, 255, 0.2); + + .arco-table-th-item-title { + color: white !important; + font-weight: 600; + font-size: 14px; + text-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + } + } + } + + // 表格行样式 + .arco-table-tbody { + .arco-table-tr { + transition: all 0.3s ease; + + &:hover { + background: linear-gradient(135deg, #f8f9ff 0%, #f0f2ff 100%); + transform: translateY(-1px); + box-shadow: 0 4px 12px rgba(102, 126, 234, 0.1); + } + + .arco-table-td { + border-bottom: 1px solid #f0f0f0; + padding: 16px 12px; + vertical-align: middle; + } + } + + // 斑马纹效果 + .arco-table-tr:nth-child(even) { + background: #fafbfc; + + &:hover { + background: linear-gradient(135deg, #f8f9ff 0%, #f0f2ff 100%); + } + } + } + + // 固定列样式 + .arco-table-fixed-left, + .arco-table-fixed-right { + .arco-table-td { + background: white; + box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); + } + } +} \ No newline at end of file diff --git a/src/views/project-management/personnel-dispatch/index.vue b/src/views/project-management/personnel-dispatch/index.vue index 8c9770e..dc86c4d 100644 --- a/src/views/project-management/personnel-dispatch/index.vue +++ b/src/views/project-management/personnel-dispatch/index.vue @@ -265,7 +265,7 @@
{{ member.position || '未设置岗位' }}
- {{ member.status === 'available' ? '在线' : '离线' }} + {{ member.status === 'ACTIVE' ? '在线' : '离线' }} 入职: {{ member.joinDate || '未设置' }}
@@ -468,7 +468,7 @@ const mapProjectRespToProjectCard = (projectResp: any): any => { position: member.roleTypeDesc || member.jobCodeDesc || '未设置岗位', phone: member.phone || '', // 后端数据中的电话字段 email: member.email || '', // 后端数据中的邮箱字段 - status: member.status === 'ACTIVE' ? 'available' : 'offline', + status: member.status === 'ACTIVE' ? 'ACTIVE' : 'INACTIVE', skills: [], // 后端数据中没有技能字段 joinDate: member.joinDate || '未设置', remark: member.remark || member.jobDesc || '', @@ -1326,13 +1326,13 @@ onMounted(async () => { text-transform: uppercase; letter-spacing: 0.5px; - &.available { + &.ACTIVE { background: linear-gradient(135deg, #e6f7ff 0%, #bae7ff 100%); color: #1890ff; border: 1px solid #91d5ff; } - &.offline { + &.INACTIVE { background: linear-gradient(135deg, #f5f5f5 0%, #e8e8e8 100%); color: #8c8c8c; border: 1px solid #d9d9d9;