更新人员组织查看工作组功能
This commit is contained in:
parent
de3c826d4e
commit
4ea535b82f
|
@ -117,6 +117,86 @@ export interface ProjectKanbanStats {
|
||||||
teamLeaderCount: string
|
teamLeaderCount: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ==================== 工作组相关类型 ====================
|
||||||
|
|
||||||
|
/** 工作组类型 */
|
||||||
|
export interface WorkGroup {
|
||||||
|
id: string
|
||||||
|
name: string
|
||||||
|
description: string
|
||||||
|
projectId: string
|
||||||
|
status: 'ACTIVE' | 'INACTIVE' | 'COMPLETED'
|
||||||
|
workTypeGroups: WorkTypeGroup[]
|
||||||
|
memberCount: number
|
||||||
|
requiredCount: number
|
||||||
|
members?: WorkGroupMember[]
|
||||||
|
createTime: string
|
||||||
|
updateTime?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 工种分组类型 */
|
||||||
|
export interface WorkTypeGroup {
|
||||||
|
id?: string
|
||||||
|
name: string
|
||||||
|
requiredCount: number
|
||||||
|
priority: 'HIGH' | 'MEDIUM' | 'LOW'
|
||||||
|
assignedCount?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 工作组成员类型 */
|
||||||
|
export interface WorkGroupMember {
|
||||||
|
id: string
|
||||||
|
name: string
|
||||||
|
role: string
|
||||||
|
avatar?: string
|
||||||
|
phone?: string
|
||||||
|
email?: string
|
||||||
|
workTypes?: string[]
|
||||||
|
joinTime?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 工作组查询参数 */
|
||||||
|
export interface WorkGroupQuery {
|
||||||
|
projectId?: string
|
||||||
|
name?: string
|
||||||
|
status?: string
|
||||||
|
workType?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 工作组分页查询参数 */
|
||||||
|
export interface WorkGroupPageQuery extends WorkGroupQuery, PageQuery {}
|
||||||
|
|
||||||
|
/** 创建工作组请求参数 */
|
||||||
|
export interface CreateWorkGroupReq {
|
||||||
|
name: string
|
||||||
|
description?: string
|
||||||
|
projectId: string
|
||||||
|
workTypeGroups: WorkTypeGroup[]
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 更新工作组请求参数 */
|
||||||
|
export interface UpdateWorkGroupReq {
|
||||||
|
id: string
|
||||||
|
name?: string
|
||||||
|
description?: string
|
||||||
|
status?: string
|
||||||
|
workTypeGroups?: WorkTypeGroup[]
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 分配工人到工作组请求参数 */
|
||||||
|
export interface AssignWorkerReq {
|
||||||
|
workGroupId: string
|
||||||
|
workerIds: string[]
|
||||||
|
workTypeName: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 从工作组移除工人请求参数 */
|
||||||
|
export interface RemoveWorkerReq {
|
||||||
|
workGroupId: string
|
||||||
|
workerId: string
|
||||||
|
workTypeName: string
|
||||||
|
}
|
||||||
|
|
||||||
/** 项目看板数据 */
|
/** 项目看板数据 */
|
||||||
export interface ProjectKanbanData {
|
export interface ProjectKanbanData {
|
||||||
inProgressProjects: ProjectCard[]
|
inProgressProjects: ProjectCard[]
|
||||||
|
@ -472,3 +552,88 @@ export interface PageRes<T> {
|
||||||
page: number
|
page: number
|
||||||
pageSize: number
|
pageSize: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ==================== 工作组相关类型 ====================
|
||||||
|
|
||||||
|
/** 工作组类型 */
|
||||||
|
export interface WorkGroup {
|
||||||
|
id: string
|
||||||
|
name: string
|
||||||
|
description: string
|
||||||
|
projectId: string
|
||||||
|
status: 'ACTIVE' | 'INACTIVE' | 'COMPLETED'
|
||||||
|
workTypeGroups: WorkTypeGroup[]
|
||||||
|
memberCount: number
|
||||||
|
requiredCount: number
|
||||||
|
members?: WorkGroupMember[]
|
||||||
|
createTime: string
|
||||||
|
updateTime?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 工种分组类型 */
|
||||||
|
export interface WorkTypeGroup {
|
||||||
|
id?: string
|
||||||
|
name: string
|
||||||
|
requiredCount: number
|
||||||
|
priority: 'HIGH' | 'MEDIUM' | 'LOW'
|
||||||
|
assignedCount?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 工作组成员类型 */
|
||||||
|
export interface WorkGroupMember {
|
||||||
|
id: string
|
||||||
|
name: string
|
||||||
|
role: string
|
||||||
|
avatar?: string
|
||||||
|
phone?: string
|
||||||
|
email?: string
|
||||||
|
workTypes?: string[]
|
||||||
|
joinTime?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 工作组查询参数 */
|
||||||
|
export interface WorkGroupQuery {
|
||||||
|
projectId?: string
|
||||||
|
name?: string
|
||||||
|
status?: string
|
||||||
|
workType?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 工作组分页查询参数 */
|
||||||
|
export interface WorkGroupPageQuery extends WorkGroupQuery, PageQuery {}
|
||||||
|
|
||||||
|
/** 创建工作组请求参数 */
|
||||||
|
export interface CreateWorkGroupReq {
|
||||||
|
name: string
|
||||||
|
description?: string
|
||||||
|
projectId: string
|
||||||
|
workTypeGroups: WorkTypeGroup[]
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 更新工作组请求参数 */
|
||||||
|
export interface UpdateWorkGroupReq {
|
||||||
|
id: string
|
||||||
|
name?: string
|
||||||
|
description?: string
|
||||||
|
status?: string
|
||||||
|
workTypeGroups?: WorkTypeGroup[]
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 分配工人到工作组请求参数 */
|
||||||
|
export interface AssignWorkerReq {
|
||||||
|
workGroupId: string
|
||||||
|
workerIds: string[]
|
||||||
|
workTypeName: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 从工作组移除工人请求参数 */
|
||||||
|
export interface RemoveWorkerReq {
|
||||||
|
workGroupId: string
|
||||||
|
workerId: string
|
||||||
|
workTypeName: string
|
||||||
|
}
|
||||||
|
|
||||||
|
// 扩展项目类型,包含工作组信息
|
||||||
|
export interface ProjectWithWorkGroups extends ProjectResp {
|
||||||
|
workGroups?: WorkGroup[]
|
||||||
|
}
|
|
@ -0,0 +1,81 @@
|
||||||
|
import request from '@/utils/http'
|
||||||
|
import type {
|
||||||
|
WorkGroup,
|
||||||
|
WorkTypeGroup,
|
||||||
|
WorkGroupPageQuery,
|
||||||
|
CreateWorkGroupReq,
|
||||||
|
UpdateWorkGroupReq,
|
||||||
|
AssignWorkerReq,
|
||||||
|
RemoveWorkerReq,
|
||||||
|
PageRes
|
||||||
|
} from './type'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取工作组列表
|
||||||
|
*/
|
||||||
|
export function getWorkGroupList(params: WorkGroupPageQuery) {
|
||||||
|
return request.get<PageRes<WorkGroup>>('/api/work-groups', params)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据项目ID获取工作组列表
|
||||||
|
*/
|
||||||
|
export function getWorkGroupsByProject(projectId: string) {
|
||||||
|
return request.get<WorkGroup[]>(`/api/projects/${projectId}/work-groups`)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取工作组详情
|
||||||
|
*/
|
||||||
|
export function getWorkGroupDetail(id: string) {
|
||||||
|
return request.get<WorkGroup>(`/api/work-groups/${id}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建工作组
|
||||||
|
*/
|
||||||
|
export function createWorkGroup(data: CreateWorkGroupReq) {
|
||||||
|
return request.post<WorkGroup>('/api/work-groups', data)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新工作组
|
||||||
|
*/
|
||||||
|
export function updateWorkGroup(id: string, data: UpdateWorkGroupReq) {
|
||||||
|
return request.put<WorkGroup>(`/api/work-groups/${id}`, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除工作组
|
||||||
|
*/
|
||||||
|
export function deleteWorkGroup(id: string) {
|
||||||
|
return request.del(`/api/work-groups/${id}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分配工人到工作组
|
||||||
|
*/
|
||||||
|
export function assignWorkerToGroup(data: AssignWorkerReq) {
|
||||||
|
return request.post('/api/work-groups/assign-worker', data)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从工作组移除工人
|
||||||
|
*/
|
||||||
|
export function removeWorkerFromGroup(data: RemoveWorkerReq) {
|
||||||
|
return request.post('/api/work-groups/remove-worker', data)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新工作组状态
|
||||||
|
*/
|
||||||
|
export function updateWorkGroupStatus(id: string, status: string) {
|
||||||
|
return request.patch<WorkGroup>(`/api/work-groups/${id}/status`, { status })
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取工作组统计信息
|
||||||
|
*/
|
||||||
|
export function getWorkGroupStats(projectId?: string) {
|
||||||
|
return request.get('/api/work-groups/stats', { projectId })
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<GiPageLayout :body-style="{ overflow: 'auto' }">
|
<GiPageLayout>
|
||||||
<div class="personnel-organization-container">
|
<div class="personnel-organization-container">
|
||||||
<!-- 流程导航 -->
|
<!-- 流程导航 -->
|
||||||
<div class="process-flow">
|
<div class="process-flow">
|
||||||
|
@ -60,11 +60,40 @@
|
||||||
<p class="project-farm">{{ project.farmName }}</p>
|
<p class="project-farm">{{ project.farmName }}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 显示项目下的工作组信息 -->
|
||||||
|
<div class="project-work-groups" v-if="project.workGroups && project.workGroups.length > 0">
|
||||||
|
<div class="work-groups-header">
|
||||||
|
<icon-user-group />
|
||||||
|
<span>工作组 ({{ project.workGroups.length }})</span>
|
||||||
|
</div>
|
||||||
|
<div class="work-groups-list">
|
||||||
|
<div
|
||||||
|
v-for="workGroup in project.workGroups.slice(0, 3)"
|
||||||
|
:key="workGroup.id"
|
||||||
|
class="work-group-preview"
|
||||||
|
>
|
||||||
|
<span class="work-group-name">{{ workGroup.name }}</span>
|
||||||
|
<span class="work-group-count">{{ workGroup.memberCount }}/{{ workGroup.requiredCount }}</span>
|
||||||
|
</div>
|
||||||
|
<div v-if="project.workGroups.length > 3" class="more-work-groups">
|
||||||
|
+{{ project.workGroups.length - 3 }} 个工作组
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="project-actions">
|
<div class="project-actions">
|
||||||
<a-button type="primary" @click.stop="enterWorkGroupCreation(project)">
|
<a-button type="primary" @click.stop="enterWorkGroupCreation(project)">
|
||||||
<template #icon><icon-arrow-right /></template>
|
<template #icon><icon-arrow-right /></template>
|
||||||
进入工作组创建
|
进入工作组创建
|
||||||
</a-button>
|
</a-button>
|
||||||
|
<a-button
|
||||||
|
v-if="project.workGroups && project.workGroups.length > 0"
|
||||||
|
@click.stop="viewProjectWorkGroups(project)"
|
||||||
|
style="margin-top: 8px;"
|
||||||
|
>
|
||||||
|
<template #icon><icon-eye /></template>
|
||||||
|
查看工作组详情
|
||||||
|
</a-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -412,6 +441,67 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</a-modal>
|
</a-modal>
|
||||||
|
|
||||||
|
<!-- 工作组详情弹窗 -->
|
||||||
|
<a-modal
|
||||||
|
v-model:visible="workGroupDetailModalVisible"
|
||||||
|
title="工作组详情"
|
||||||
|
width="800px"
|
||||||
|
:footer="false"
|
||||||
|
>
|
||||||
|
<div class="work-group-detail">
|
||||||
|
<div class="project-info-section">
|
||||||
|
<h3>{{ selectedProjectForDetail?.projectName }}</h3>
|
||||||
|
<p class="project-code">项目编号: {{ selectedProjectForDetail?.projectCode }}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="work-groups-section">
|
||||||
|
<h4>工作组列表</h4>
|
||||||
|
<div class="work-groups-detail-list">
|
||||||
|
<div
|
||||||
|
v-for="workGroup in selectedProjectForDetail?.workGroups"
|
||||||
|
:key="workGroup.id"
|
||||||
|
class="work-group-detail-item"
|
||||||
|
>
|
||||||
|
<div class="work-group-detail-header">
|
||||||
|
<h5>{{ workGroup.name }}</h5>
|
||||||
|
<div class="work-group-detail-stats">
|
||||||
|
<span class="member-count">{{ workGroup.memberCount }}/{{ workGroup.requiredCount }}</span>
|
||||||
|
<a-tag :color="getWorkGroupStatusColor(workGroup.status)" size="small">
|
||||||
|
{{ getWorkGroupStatusText(workGroup.status) }}
|
||||||
|
</a-tag>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="work-group-detail-members" v-if="workGroup.members && workGroup.members.length > 0">
|
||||||
|
<div class="members-header">
|
||||||
|
<span>成员列表:</span>
|
||||||
|
</div>
|
||||||
|
<div class="members-grid">
|
||||||
|
<div
|
||||||
|
v-for="member in workGroup.members"
|
||||||
|
:key="member.id"
|
||||||
|
class="member-detail-item"
|
||||||
|
>
|
||||||
|
<a-avatar :src="member.avatar" :size="32">
|
||||||
|
{{ member.name.charAt(0) }}
|
||||||
|
</a-avatar>
|
||||||
|
<div class="member-detail-info">
|
||||||
|
<span class="member-name">{{ member.name }}</span>
|
||||||
|
<span class="member-role">{{ member.role }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="work-group-detail-description" v-if="workGroup.description">
|
||||||
|
<p><strong>描述:</strong>{{ workGroup.description }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a-modal>
|
||||||
</div>
|
</div>
|
||||||
</GiPageLayout>
|
</GiPageLayout>
|
||||||
</template>
|
</template>
|
||||||
|
@ -436,13 +526,57 @@ import {
|
||||||
IconCheck,
|
IconCheck,
|
||||||
IconFilter,
|
IconFilter,
|
||||||
IconClose,
|
IconClose,
|
||||||
IconSave
|
IconSave,
|
||||||
|
IconEye
|
||||||
} from '@arco-design/web-vue/es/icon'
|
} from '@arco-design/web-vue/es/icon'
|
||||||
import type {
|
import type {
|
||||||
ProjectResp,
|
ProjectResp,
|
||||||
ConstructorResp,
|
ConstructorResp,
|
||||||
CertificationResp
|
CertificationResp,
|
||||||
|
WorkGroup,
|
||||||
|
WorkTypeGroup,
|
||||||
|
WorkGroupMember,
|
||||||
|
ProjectWithWorkGroups
|
||||||
} from '@/apis/project/type'
|
} from '@/apis/project/type'
|
||||||
|
import {
|
||||||
|
getWorkGroupsByProject,
|
||||||
|
createWorkGroup as createWorkGroupAPI,
|
||||||
|
assignWorkerToGroup,
|
||||||
|
removeWorkerFromGroup
|
||||||
|
} from '@/apis/project/workGroup'
|
||||||
|
|
||||||
|
// 移除重复的类型定义,使用导入的类型
|
||||||
|
// interface WorkGroup {
|
||||||
|
// id: string
|
||||||
|
// name: string
|
||||||
|
// description: string
|
||||||
|
// projectId: string
|
||||||
|
// status: 'ACTIVE' | 'INACTIVE' | 'COMPLETED'
|
||||||
|
// workTypeGroups: WorkTypeGroup[]
|
||||||
|
// memberCount: number
|
||||||
|
// requiredCount: number
|
||||||
|
// members?: WorkGroupMember[]
|
||||||
|
// createTime: string
|
||||||
|
// }
|
||||||
|
|
||||||
|
// interface WorkTypeGroup {
|
||||||
|
// name: string
|
||||||
|
// requiredCount: number
|
||||||
|
// priority: 'HIGH' | 'MEDIUM' | 'LOW'
|
||||||
|
// }
|
||||||
|
|
||||||
|
// interface WorkGroupMember {
|
||||||
|
// id: string
|
||||||
|
// name: string
|
||||||
|
// role: string
|
||||||
|
// avatar?: string
|
||||||
|
// phone?: string
|
||||||
|
// }
|
||||||
|
|
||||||
|
// 扩展项目类型,包含工作组信息
|
||||||
|
// interface ProjectWithWorkGroups extends ProjectResp {
|
||||||
|
// workGroups?: WorkGroup[]
|
||||||
|
// }
|
||||||
|
|
||||||
defineOptions({ name: 'PersonnelOrganization' })
|
defineOptions({ name: 'PersonnelOrganization' })
|
||||||
|
|
||||||
|
@ -450,11 +584,13 @@ defineOptions({ name: 'PersonnelOrganization' })
|
||||||
const currentStep = ref(1)
|
const currentStep = ref(1)
|
||||||
|
|
||||||
// 项目数据
|
// 项目数据
|
||||||
const projectList = ref<ProjectResp[]>([])
|
const projectList = ref<ProjectWithWorkGroups[]>([])
|
||||||
const selectedProject = ref<ProjectResp | null>(null)
|
const selectedProject = ref<ProjectWithWorkGroups | null>(null)
|
||||||
|
const selectedProjectForDetail = ref<ProjectWithWorkGroups | null>(null)
|
||||||
|
|
||||||
// 工作组表单
|
// 工作组表单
|
||||||
const workGroupForm = reactive({
|
const workGroupForm = reactive({
|
||||||
|
id: '', // 添加工作组ID字段
|
||||||
name: '',
|
name: '',
|
||||||
description: '',
|
description: '',
|
||||||
projectId: '',
|
projectId: '',
|
||||||
|
@ -483,6 +619,7 @@ const workerAssignments = ref<Record<string, ConstructorResp[]>>({})
|
||||||
// 弹窗状态
|
// 弹窗状态
|
||||||
const certificateModalVisible = ref(false)
|
const certificateModalVisible = ref(false)
|
||||||
const selectedWorkerCertificates = ref<CertificationResp[]>([])
|
const selectedWorkerCertificates = ref<CertificationResp[]>([])
|
||||||
|
const workGroupDetailModalVisible = ref(false)
|
||||||
|
|
||||||
// 拖拽状态
|
// 拖拽状态
|
||||||
const draggedWorker = ref<ConstructorResp | null>(null)
|
const draggedWorker = ref<ConstructorResp | null>(null)
|
||||||
|
@ -499,7 +636,7 @@ const getGroupMembers = (groupName: string) => {
|
||||||
// 方法
|
// 方法
|
||||||
const loadProjectList = async () => {
|
const loadProjectList = async () => {
|
||||||
try {
|
try {
|
||||||
// 使用模拟数据
|
// 使用模拟数据,包含工作组信息
|
||||||
projectList.value = [
|
projectList.value = [
|
||||||
{
|
{
|
||||||
projectId: '1',
|
projectId: '1',
|
||||||
|
@ -507,7 +644,44 @@ const loadProjectList = async () => {
|
||||||
projectName: '风电场A区建设项目',
|
projectName: '风电场A区建设项目',
|
||||||
farmName: '风电场A区',
|
farmName: '风电场A区',
|
||||||
status: 1,
|
status: 1,
|
||||||
statusLabel: '进行中'
|
statusLabel: '进行中',
|
||||||
|
workGroups: [
|
||||||
|
{
|
||||||
|
id: 'wg1',
|
||||||
|
name: '高空作业组',
|
||||||
|
description: '负责塔上登高作业',
|
||||||
|
projectId: '1',
|
||||||
|
status: 'ACTIVE',
|
||||||
|
workTypeGroups: [
|
||||||
|
{ name: '塔上登高作业', requiredCount: 5, priority: 'HIGH' }
|
||||||
|
],
|
||||||
|
memberCount: 3,
|
||||||
|
requiredCount: 5,
|
||||||
|
members: [
|
||||||
|
{ id: 'm1', name: '张登高', role: '组长', avatar: '' },
|
||||||
|
{ id: 'm2', name: '李高空', role: '组员', avatar: '' },
|
||||||
|
{ id: 'm3', name: '王高空', role: '组员', avatar: '' }
|
||||||
|
],
|
||||||
|
createTime: '2024-01-15'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'wg2',
|
||||||
|
name: '地勤保障组',
|
||||||
|
description: '负责地面保障工作',
|
||||||
|
projectId: '1',
|
||||||
|
status: 'ACTIVE',
|
||||||
|
workTypeGroups: [
|
||||||
|
{ name: '地勤人员', requiredCount: 3, priority: 'MEDIUM' }
|
||||||
|
],
|
||||||
|
memberCount: 2,
|
||||||
|
requiredCount: 3,
|
||||||
|
members: [
|
||||||
|
{ id: 'm4', name: '赵地勤', role: '组长', avatar: '' },
|
||||||
|
{ id: 'm5', name: '孙地勤', role: '组员', avatar: '' }
|
||||||
|
],
|
||||||
|
createTime: '2024-01-16'
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
projectId: '2',
|
projectId: '2',
|
||||||
|
@ -515,7 +689,29 @@ const loadProjectList = async () => {
|
||||||
projectName: '风电场B区维护项目',
|
projectName: '风电场B区维护项目',
|
||||||
farmName: '风电场B区',
|
farmName: '风电场B区',
|
||||||
status: 2,
|
status: 2,
|
||||||
statusLabel: '已完成'
|
statusLabel: '已完成',
|
||||||
|
workGroups: [
|
||||||
|
{
|
||||||
|
id: 'wg3',
|
||||||
|
name: '维护保养组',
|
||||||
|
description: '负责设备维护保养',
|
||||||
|
projectId: '2',
|
||||||
|
status: 'COMPLETED',
|
||||||
|
workTypeGroups: [
|
||||||
|
{ name: '机械工程师', requiredCount: 2, priority: 'HIGH' },
|
||||||
|
{ name: '电气工程师', requiredCount: 2, priority: 'HIGH' }
|
||||||
|
],
|
||||||
|
memberCount: 4,
|
||||||
|
requiredCount: 4,
|
||||||
|
members: [
|
||||||
|
{ id: 'm6', name: '周机械', role: '机械工程师', avatar: '' },
|
||||||
|
{ id: 'm7', name: '吴电气', role: '电气工程师', avatar: '' },
|
||||||
|
{ id: 'm8', name: '郑机械', role: '机械工程师', avatar: '' },
|
||||||
|
{ id: 'm9', name: '王电气', role: '电气工程师', avatar: '' }
|
||||||
|
],
|
||||||
|
createTime: '2024-01-10'
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
projectId: '3',
|
projectId: '3',
|
||||||
|
@ -523,9 +719,21 @@ const loadProjectList = async () => {
|
||||||
projectName: '风电场C区升级项目',
|
projectName: '风电场C区升级项目',
|
||||||
farmName: '风电场C区',
|
farmName: '风电场C区',
|
||||||
status: 0,
|
status: 0,
|
||||||
statusLabel: '准备中'
|
statusLabel: '准备中',
|
||||||
|
workGroups: []
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
// 为每个项目加载工作组信息
|
||||||
|
for (const project of projectList.value) {
|
||||||
|
try {
|
||||||
|
const workGroups = await getWorkGroupsByProject(project.projectId)
|
||||||
|
project.workGroups = workGroups
|
||||||
|
} catch (error) {
|
||||||
|
console.warn(`加载项目 ${project.projectName} 的工作组失败:`, error)
|
||||||
|
// 保持模拟数据作为后备
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
Message.error('加载项目列表失败')
|
Message.error('加载项目列表失败')
|
||||||
}
|
}
|
||||||
|
@ -662,11 +870,11 @@ const loadWorkers = async () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const selectProject = (project: ProjectResp) => {
|
const selectProject = (project: ProjectWithWorkGroups) => {
|
||||||
selectedProject.value = project
|
selectedProject.value = project
|
||||||
}
|
}
|
||||||
|
|
||||||
const enterWorkGroupCreation = (project: ProjectResp) => {
|
const enterWorkGroupCreation = (project: ProjectWithWorkGroups) => {
|
||||||
selectedProject.value = project
|
selectedProject.value = project
|
||||||
workGroupForm.projectId = project.projectId
|
workGroupForm.projectId = project.projectId
|
||||||
currentStep.value = 2
|
currentStep.value = 2
|
||||||
|
@ -696,7 +904,7 @@ const goBackToStep2 = () => {
|
||||||
currentStep.value = 2
|
currentStep.value = 2
|
||||||
}
|
}
|
||||||
|
|
||||||
const createWorkGroup = () => {
|
const createWorkGroup = async () => {
|
||||||
if (!workGroupForm.name || !workGroupForm.projectId) {
|
if (!workGroupForm.name || !workGroupForm.projectId) {
|
||||||
Message.warning('请填写工作组名称和关联项目')
|
Message.warning('请填写工作组名称和关联项目')
|
||||||
return
|
return
|
||||||
|
@ -708,11 +916,38 @@ const createWorkGroup = () => {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 调用API创建工作组
|
||||||
|
const newWorkGroup = await createWorkGroupAPI({
|
||||||
|
name: workGroupForm.name,
|
||||||
|
description: workGroupForm.description,
|
||||||
|
projectId: workGroupForm.projectId,
|
||||||
|
workTypeGroups: workGroupForm.workTypeGroups
|
||||||
|
})
|
||||||
|
|
||||||
|
Message.success('工作组创建成功')
|
||||||
|
|
||||||
|
// 保存新创建的工作组ID
|
||||||
|
workGroupForm.id = newWorkGroup.id
|
||||||
|
|
||||||
|
// 更新项目的工作组列表
|
||||||
|
if (selectedProject.value) {
|
||||||
|
if (!selectedProject.value.workGroups) {
|
||||||
|
selectedProject.value.workGroups = []
|
||||||
|
}
|
||||||
|
selectedProject.value.workGroups.push(newWorkGroup)
|
||||||
|
}
|
||||||
|
|
||||||
currentStep.value = 3
|
currentStep.value = 3
|
||||||
loadWorkers()
|
loadWorkers()
|
||||||
|
} catch (error) {
|
||||||
|
Message.error('创建工作组失败')
|
||||||
|
console.error('创建工作组错误:', error)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const resetWorkGroupForm = () => {
|
const resetWorkGroupForm = () => {
|
||||||
|
workGroupForm.id = '' // 重置工作组ID
|
||||||
workGroupForm.name = ''
|
workGroupForm.name = ''
|
||||||
workGroupForm.description = ''
|
workGroupForm.description = ''
|
||||||
workGroupForm.projectId = ''
|
workGroupForm.projectId = ''
|
||||||
|
@ -802,11 +1037,29 @@ const handleDrop = (event: DragEvent, group: any) => {
|
||||||
Message.success(`已将 ${draggedWorker.value.name} 分配到 ${groupName}`)
|
Message.success(`已将 ${draggedWorker.value.name} 分配到 ${groupName}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
const removeFromGroup = (member: ConstructorResp, groupName: string) => {
|
const removeFromGroup = async (member: ConstructorResp, groupName: string) => {
|
||||||
|
try {
|
||||||
|
if (!workGroupForm.id) {
|
||||||
|
Message.error('工作组ID不存在')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
await removeWorkerFromGroup({
|
||||||
|
workGroupId: workGroupForm.id,
|
||||||
|
workerId: member.id,
|
||||||
|
workTypeName: groupName
|
||||||
|
})
|
||||||
|
|
||||||
|
// 从本地分配数据中移除
|
||||||
const index = workerAssignments.value[groupName].findIndex(m => m.id === member.id)
|
const index = workerAssignments.value[groupName].findIndex(m => m.id === member.id)
|
||||||
if (index > -1) {
|
if (index > -1) {
|
||||||
workerAssignments.value[groupName].splice(index, 1)
|
workerAssignments.value[groupName].splice(index, 1)
|
||||||
|
}
|
||||||
|
|
||||||
Message.success(`已从 ${groupName} 移除 ${member.name}`)
|
Message.success(`已从 ${groupName} 移除 ${member.name}`)
|
||||||
|
} catch (error) {
|
||||||
|
Message.error('移除工人失败')
|
||||||
|
console.error('移除工人错误:', error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -832,13 +1085,50 @@ const saveAssignment = async () => {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!workGroupForm.id) {
|
||||||
|
Message.error('工作组ID不存在')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 调用API保存分配结果
|
||||||
|
const assignmentPromises = []
|
||||||
|
|
||||||
|
for (const [workTypeName, workers] of Object.entries(workerAssignments.value)) {
|
||||||
|
if (workers.length > 0) {
|
||||||
|
const workerIds = workers.map(w => w.id)
|
||||||
|
assignmentPromises.push(
|
||||||
|
assignWorkerToGroup({
|
||||||
|
workGroupId: workGroupForm.id,
|
||||||
|
workerIds,
|
||||||
|
workTypeName
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await Promise.all(assignmentPromises)
|
||||||
Message.success('分配保存成功')
|
Message.success('分配保存成功')
|
||||||
// 这里可以调用API保存分配结果
|
|
||||||
|
// 刷新项目的工作组信息
|
||||||
|
if (selectedProject.value) {
|
||||||
|
try {
|
||||||
|
const workGroups = await getWorkGroupsByProject(selectedProject.value.projectId)
|
||||||
|
selectedProject.value.workGroups = workGroups
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('刷新工作组信息失败:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
Message.error('保存分配失败')
|
Message.error('保存分配失败')
|
||||||
|
console.error('保存分配错误:', error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const viewProjectWorkGroups = (project: ProjectWithWorkGroups) => {
|
||||||
|
selectedProjectForDetail.value = project
|
||||||
|
workGroupDetailModalVisible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
// 工具方法
|
// 工具方法
|
||||||
const getStatusColor = (status: number) => {
|
const getStatusColor = (status: number) => {
|
||||||
const statusMap: Record<number, string> = {
|
const statusMap: Record<number, string> = {
|
||||||
|
@ -885,6 +1175,24 @@ const getCertificateStatusText = (status: string) => {
|
||||||
return statusMap[status] || status
|
return statusMap[status] || status
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getWorkGroupStatusColor = (status: string) => {
|
||||||
|
const statusMap: Record<string, string> = {
|
||||||
|
'ACTIVE': 'green',
|
||||||
|
'INACTIVE': 'red',
|
||||||
|
'COMPLETED': 'gray'
|
||||||
|
}
|
||||||
|
return statusMap[status] || 'gray'
|
||||||
|
}
|
||||||
|
|
||||||
|
const getWorkGroupStatusText = (status: string) => {
|
||||||
|
const statusMap: Record<string, string> = {
|
||||||
|
'ACTIVE': '进行中',
|
||||||
|
'INACTIVE': '已暂停',
|
||||||
|
'COMPLETED': '已完成'
|
||||||
|
}
|
||||||
|
return statusMap[status] || status
|
||||||
|
}
|
||||||
|
|
||||||
// 生命周期
|
// 生命周期
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await loadProjectList()
|
await loadProjectList()
|
||||||
|
@ -896,16 +1204,7 @@ onMounted(async () => {
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
|
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
overflow-y: auto;
|
overflow-y: auto; // 添加垂直滚动
|
||||||
height: auto;
|
|
||||||
position: relative;
|
|
||||||
z-index: 1;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 确保页面可以滚动
|
|
||||||
:deep(.gi-page-layout__body) {
|
|
||||||
overflow: auto !important;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 流程导航样式
|
// 流程导航样式
|
||||||
|
@ -918,6 +1217,7 @@ onMounted(async () => {
|
||||||
background: white;
|
background: white;
|
||||||
border-radius: 16px;
|
border-radius: 16px;
|
||||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
|
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
|
||||||
|
flex-shrink: 0; // 防止压缩
|
||||||
}
|
}
|
||||||
|
|
||||||
.flow-step {
|
.flow-step {
|
||||||
|
@ -958,8 +1258,7 @@ onMounted(async () => {
|
||||||
.step-content {
|
.step-content {
|
||||||
max-width: 1200px;
|
max-width: 1200px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
overflow-y: auto;
|
margin-bottom: 30px; // 添加底部间距
|
||||||
height: auto;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 项目选择卡片
|
// 项目选择卡片
|
||||||
|
@ -1047,8 +1346,49 @@ onMounted(async () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.project-work-groups {
|
||||||
|
margin-top: 20px;
|
||||||
|
padding-top: 16px;
|
||||||
|
border-top: 1px solid #e9ecef;
|
||||||
|
|
||||||
|
.work-groups-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #1d2129;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.work-groups-list {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.work-group-preview {
|
||||||
|
background: #f8f9fa;
|
||||||
|
border: 1px solid #e9ecef;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 8px 12px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #1d2129;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.more-work-groups {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #86909c;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.project-actions {
|
.project-actions {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
margin-top: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 工作组创建表单
|
// 工作组创建表单
|
||||||
|
@ -1103,16 +1443,14 @@ onMounted(async () => {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 280px 1fr 320px;
|
grid-template-columns: 280px 1fr 320px;
|
||||||
gap: 24px;
|
gap: 24px;
|
||||||
min-height: calc(100vh - 200px);
|
min-height: 600px; // 设置最小高度而不是固定高度
|
||||||
height: auto;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.filter-sidebar,
|
.filter-sidebar,
|
||||||
.work-groups-sidebar {
|
.work-groups-sidebar {
|
||||||
.filter-card,
|
.filter-card,
|
||||||
.work-groups-card {
|
.work-groups-card {
|
||||||
min-height: 100%;
|
height: 100%;
|
||||||
height: auto;
|
|
||||||
border-radius: 16px;
|
border-radius: 16px;
|
||||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
|
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
|
||||||
|
|
||||||
|
@ -1134,8 +1472,7 @@ onMounted(async () => {
|
||||||
|
|
||||||
.worker-table-section {
|
.worker-table-section {
|
||||||
.worker-table-card {
|
.worker-table-card {
|
||||||
min-height: 100%;
|
height: 100%;
|
||||||
height: auto;
|
|
||||||
border-radius: 16px;
|
border-radius: 16px;
|
||||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
|
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
|
||||||
|
|
||||||
|
@ -1155,9 +1492,8 @@ onMounted(async () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
.worker-table {
|
.worker-table {
|
||||||
min-height: calc(100vh - 300px);
|
max-height: 500px; // 设置最大高度
|
||||||
max-height: calc(100vh - 300px);
|
overflow-y: auto; // 添加垂直滚动
|
||||||
overflow-y: auto;
|
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1254,9 +1590,8 @@ onMounted(async () => {
|
||||||
|
|
||||||
// 工种分组
|
// 工种分组
|
||||||
.work-groups-content {
|
.work-groups-content {
|
||||||
min-height: calc(100vh - 300px);
|
max-height: 400px; // 设置最大高度
|
||||||
max-height: calc(100vh - 300px);
|
overflow-y: auto; // 添加垂直滚动
|
||||||
overflow-y: auto;
|
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1382,4 +1717,155 @@ onMounted(async () => {
|
||||||
color: #4e5969;
|
color: #4e5969;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 工作组详情弹窗
|
||||||
|
.work-group-detail {
|
||||||
|
.project-info-section {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
padding-bottom: 16px;
|
||||||
|
border-bottom: 1px solid #e9ecef;
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
margin: 0 0 8px 0;
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #1d2129;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-code {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #86909c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.work-groups-section {
|
||||||
|
h4 {
|
||||||
|
margin: 0 0 16px 0;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #1d2129;
|
||||||
|
}
|
||||||
|
|
||||||
|
.work-groups-detail-list {
|
||||||
|
.work-group-detail-item {
|
||||||
|
background: #f8f9fa;
|
||||||
|
border: 1px solid #e9ecef;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 16px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
|
||||||
|
.work-group-detail-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
|
||||||
|
h5 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #1d2129;
|
||||||
|
}
|
||||||
|
|
||||||
|
.work-group-detail-stats {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #86909c;
|
||||||
|
|
||||||
|
.member-count {
|
||||||
|
color: #52c41a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.work-group-detail-members {
|
||||||
|
.members-header {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #1d2129;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.members-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.member-detail-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
|
||||||
|
.member-detail-info {
|
||||||
|
.member-name {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #1d2129;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.member-role {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #86909c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.work-group-detail-description {
|
||||||
|
p {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #4e5969;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 响应式设计
|
||||||
|
@media (max-width: 1200px) {
|
||||||
|
.worker-assignment-layout {
|
||||||
|
grid-template-columns: 250px 1fr 280px;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 992px) {
|
||||||
|
.worker-assignment-layout {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-sidebar,
|
||||||
|
.work-groups-sidebar {
|
||||||
|
order: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.worker-table-section {
|
||||||
|
order: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.personnel-organization-container {
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.process-flow {
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16px;
|
||||||
|
|
||||||
|
.flow-arrow {
|
||||||
|
transform: rotate(90deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
Loading…
Reference in New Issue