Merge branch 'devlopment' of http://pms.dtyx.net:3000/wuxueyu/Industrial-image-management-system---web into devlopment
This commit is contained in:
commit
66d4a1bbfe
|
@ -0,0 +1,54 @@
|
||||||
|
import type * as T from './type'
|
||||||
|
import http from '@/utils/http'
|
||||||
|
|
||||||
|
const BASE_URL = '/project/personnel-organization'
|
||||||
|
|
||||||
|
/** @desc 获取项目列表 */
|
||||||
|
export function getProjectList(query?: T.ProjectQuery) {
|
||||||
|
return http.get<PageRes<T.ProjectResp[]>>('/project/list', query)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @desc 获取项目人员组织信息 */
|
||||||
|
export function getPersonnelOrganization(projectId: string | number) {
|
||||||
|
return http.get<T.PersonnelOrganizationResp>(`${BASE_URL}/${projectId}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @desc 获取工种列表 */
|
||||||
|
export function getWorkTypeList() {
|
||||||
|
return http.get<T.WorkTypeResp[]>('/work-type/list')
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @desc 获取施工人员列表 */
|
||||||
|
export function getConstructorList(query: T.ConstructorQuery) {
|
||||||
|
return http.get<PageRes<T.ConstructorResp[]>>('/constructor/list', query)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @desc 获取施工人员技能证书 */
|
||||||
|
export function getConstructorCertifications(constructorId: string | number) {
|
||||||
|
return http.get<T.CertificationResp[]>(`/constructor/${constructorId}/certifications`)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @desc 分配施工人员到项目 */
|
||||||
|
export function assignConstructorToProject(data: T.AssignConstructorReq) {
|
||||||
|
return http.post(`${BASE_URL}/assign`, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @desc 移除项目施工人员 */
|
||||||
|
export function removeConstructorFromProject(data: T.RemoveConstructorReq) {
|
||||||
|
return http.delete(`${BASE_URL}/remove`, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @desc 更新施工人员分配信息 */
|
||||||
|
export function updateConstructorAssignment(data: T.UpdateAssignmentReq) {
|
||||||
|
return http.put(`${BASE_URL}/update`, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @desc 获取项目人员统计 */
|
||||||
|
export function getPersonnelStats(projectId: string | number) {
|
||||||
|
return http.get<T.PersonnelStatsResp>(`${BASE_URL}/${projectId}/stats`)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @desc 导出项目人员组织 */
|
||||||
|
export function exportPersonnelOrganization(projectId: string | number) {
|
||||||
|
return http.download(`${BASE_URL}/${projectId}/export`)
|
||||||
|
}
|
|
@ -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[]
|
||||||
|
@ -327,7 +407,137 @@ export interface UpdateRequirementStatusForm {
|
||||||
status: 'pending' | 'recruiting' | 'completed'
|
status: 'pending' | 'recruiting' | 'completed'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ==================== 人员组织相关类型 ====================
|
||||||
|
|
||||||
|
/** 工种响应 */
|
||||||
|
export interface WorkTypeResp {
|
||||||
|
id: string | number
|
||||||
|
name: string
|
||||||
|
code: string
|
||||||
|
description?: string
|
||||||
|
requiredCertifications?: string[]
|
||||||
|
sort?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 施工人员响应 */
|
||||||
|
export interface ConstructorResp {
|
||||||
|
id: string | number
|
||||||
|
name: string
|
||||||
|
phone: string
|
||||||
|
email?: string
|
||||||
|
avatar?: string
|
||||||
|
workTypes: string[] // 工种列表
|
||||||
|
certifications: CertificationResp[]
|
||||||
|
experience: number // 工作经验(年)
|
||||||
|
status: 'ACTIVE' | 'INACTIVE' | 'BUSY'
|
||||||
|
rating: number // 评分
|
||||||
|
joinDate: string
|
||||||
|
remark?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 证书响应 */
|
||||||
|
export interface CertificationResp {
|
||||||
|
id: string | number
|
||||||
|
name: string
|
||||||
|
type: string
|
||||||
|
code: string
|
||||||
|
issueDate: string
|
||||||
|
expiryDate: string
|
||||||
|
issuingAuthority: string
|
||||||
|
status: 'VALID' | 'EXPIRED' | 'EXPIRING_SOON'
|
||||||
|
imageUrl?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 施工人员查询参数 */
|
||||||
|
export interface ConstructorQuery extends PageQuery {
|
||||||
|
name?: string
|
||||||
|
workType?: string
|
||||||
|
status?: string
|
||||||
|
hasCertification?: boolean
|
||||||
|
experienceMin?: number
|
||||||
|
experienceMax?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 人员组织响应 */
|
||||||
|
export interface PersonnelOrganizationResp {
|
||||||
|
projectId: string | number
|
||||||
|
projectName: string
|
||||||
|
workTypeAssignments: WorkTypeAssignmentResp[]
|
||||||
|
totalPersonnel: number
|
||||||
|
assignedPersonnel: number
|
||||||
|
availablePersonnel: number
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 工种分配响应 */
|
||||||
|
export interface WorkTypeAssignmentResp {
|
||||||
|
workTypeId: string | number
|
||||||
|
workTypeName: string
|
||||||
|
workTypeCode: string
|
||||||
|
requiredCount: number
|
||||||
|
assignedCount: number
|
||||||
|
constructors: ConstructorAssignmentResp[]
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 施工人员分配响应 */
|
||||||
|
export interface ConstructorAssignmentResp {
|
||||||
|
constructorId: string | number
|
||||||
|
constructorName: string
|
||||||
|
phone: string
|
||||||
|
avatar?: string
|
||||||
|
workTypes: string[]
|
||||||
|
certifications: CertificationResp[]
|
||||||
|
experience: number
|
||||||
|
rating: number
|
||||||
|
assignmentDate: string
|
||||||
|
status: 'ASSIGNED' | 'WORKING' | 'COMPLETED'
|
||||||
|
remark?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 分配施工人员请求 */
|
||||||
|
export interface AssignConstructorReq {
|
||||||
|
projectId: string | number
|
||||||
|
workTypeId: string | number
|
||||||
|
constructorIds: (string | number)[]
|
||||||
|
assignmentDate?: string
|
||||||
|
remark?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 移除施工人员请求 */
|
||||||
|
export interface RemoveConstructorReq {
|
||||||
|
projectId: string | number
|
||||||
|
constructorIds: (string | number)[]
|
||||||
|
reason?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 更新分配信息请求 */
|
||||||
|
export interface UpdateAssignmentReq {
|
||||||
|
projectId: string | number
|
||||||
|
constructorId: string | number
|
||||||
|
workTypeId?: string | number
|
||||||
|
status?: string
|
||||||
|
remark?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 人员统计响应 */
|
||||||
|
export interface PersonnelStatsResp {
|
||||||
|
totalPersonnel: number
|
||||||
|
assignedPersonnel: number
|
||||||
|
availablePersonnel: number
|
||||||
|
workTypeStats: {
|
||||||
|
workTypeName: string
|
||||||
|
requiredCount: number
|
||||||
|
assignedCount: number
|
||||||
|
shortageCount: number
|
||||||
|
}[]
|
||||||
|
certificationStats: {
|
||||||
|
certificationType: string
|
||||||
|
count: number
|
||||||
|
}[]
|
||||||
|
experienceStats: {
|
||||||
|
range: string
|
||||||
|
count: number
|
||||||
|
}[]
|
||||||
|
}
|
||||||
|
|
||||||
/** 分页查询基础参数 */
|
/** 分页查询基础参数 */
|
||||||
export interface PageQuery {
|
export interface PageQuery {
|
||||||
|
@ -341,4 +551,89 @@ export interface PageRes<T> {
|
||||||
total: number
|
total: number
|
||||||
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 })
|
||||||
|
}
|
|
@ -63,3 +63,8 @@ export function resetUserPwd(data: any, id: string) {
|
||||||
export function updateUserRole(data: { roleIds: string[] }, id: string) {
|
export function updateUserRole(data: { roleIds: string[] }, id: string) {
|
||||||
return http.patch(`${BASE_URL}/${id}/role`, data)
|
return http.patch(`${BASE_URL}/${id}/role`, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @desc 按姓名模糊搜索用户 */
|
||||||
|
export function searchUserByName(name: string) {
|
||||||
|
return http.get<T.UserNewResp[]>(`${BASE_URL}/searchByName`, { name })
|
||||||
|
}
|
||||||
|
|
|
@ -816,7 +816,17 @@ export const systemRoutes: RouteRecordRaw[] = [
|
||||||
hidden: false,
|
hidden: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/project-management/projects/personnel-organization',
|
||||||
|
name: 'PersonnelOrganization',
|
||||||
|
component: () => import('@/views/project-management/projects/personnel-organization/index.vue'),
|
||||||
|
meta: {
|
||||||
|
title: '人员组织',
|
||||||
|
icon: 'user-group',
|
||||||
|
hidden: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
path: '/project-management/projects/device',
|
path: '/project-management/projects/device',
|
||||||
name: 'DeviceManagement',
|
name: 'DeviceManagement',
|
||||||
|
|
|
@ -180,7 +180,17 @@
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<div class="form-item">
|
<div class="form-item">
|
||||||
<label>姓名 <span class="required">*</span></label>
|
<label>姓名 <span class="required">*</span></label>
|
||||||
<a-input v-model="memberForm.name" placeholder="请输入姓名" />
|
<a-auto-complete
|
||||||
|
v-model="memberForm.name"
|
||||||
|
placeholder="请输入姓名进行搜索"
|
||||||
|
:data="userSearchOptions"
|
||||||
|
:loading="userSearchLoading"
|
||||||
|
@search="handleUserSearch"
|
||||||
|
@select="handleUserSelect"
|
||||||
|
allow-clear
|
||||||
|
:filter-option="false"
|
||||||
|
:trigger-on-focus="false"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-item">
|
<div class="form-item">
|
||||||
<label>联系电话 <span class="required">*</span></label>
|
<label>联系电话 <span class="required">*</span></label>
|
||||||
|
@ -304,7 +314,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, reactive, onMounted } from 'vue'
|
import { ref, reactive, onMounted, onUnmounted } from 'vue'
|
||||||
import { Message, Modal } from '@arco-design/web-vue'
|
import { Message, Modal } from '@arco-design/web-vue'
|
||||||
import { useRoute } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
import type { TeamMemberResp, TeamMemberQuery, TeamMemberExportQuery, CreateTeamMemberForm, UpdateTeamMemberForm, BackendTeamMemberResp } from '@/apis/project/type'
|
import type { TeamMemberResp, TeamMemberQuery, TeamMemberExportQuery, CreateTeamMemberForm, UpdateTeamMemberForm, BackendTeamMemberResp } from '@/apis/project/type'
|
||||||
|
@ -317,6 +327,8 @@ import {
|
||||||
exportTeamMembers,
|
exportTeamMembers,
|
||||||
downloadImportTemplate
|
downloadImportTemplate
|
||||||
} from '@/apis/project/personnel-dispatch'
|
} from '@/apis/project/personnel-dispatch'
|
||||||
|
import { searchUserByName } from '@/apis/system/user'
|
||||||
|
import type { UserNewResp } from '@/apis/system/type'
|
||||||
|
|
||||||
// 获取路由参数
|
// 获取路由参数
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
|
@ -411,6 +423,12 @@ const statusForm = reactive<{
|
||||||
|
|
||||||
const fileList = ref<any[]>([])
|
const fileList = ref<any[]>([])
|
||||||
|
|
||||||
|
// 用户搜索相关数据
|
||||||
|
const userSearchResults = ref<UserNewResp[]>([])
|
||||||
|
const userSearchOptions = ref<Array<{ label: string; value: string; user: UserNewResp }>>([])
|
||||||
|
const userSearchLoading = ref(false)
|
||||||
|
const searchTimeout = ref<NodeJS.Timeout | null>(null)
|
||||||
|
|
||||||
// 方法
|
// 方法
|
||||||
const loadData = async () => {
|
const loadData = async () => {
|
||||||
if (!projectId) {
|
if (!projectId) {
|
||||||
|
@ -505,6 +523,70 @@ const openAddModal = () => {
|
||||||
memberModalVisible.value = true
|
memberModalVisible.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 用户搜索处理函数(带防抖)
|
||||||
|
const handleUserSearch = async (value: string) => {
|
||||||
|
console.log('开始搜索用户,输入值:', value)
|
||||||
|
|
||||||
|
// 清除之前的定时器
|
||||||
|
if (searchTimeout.value) {
|
||||||
|
clearTimeout(searchTimeout.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果输入为空,清空结果
|
||||||
|
if (!value || value.trim().length < 1) {
|
||||||
|
userSearchResults.value = []
|
||||||
|
console.log('输入为空,清空搜索结果')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置防抖延迟(300ms)
|
||||||
|
searchTimeout.value = setTimeout(async () => {
|
||||||
|
console.log('执行搜索,搜索值:', value.trim())
|
||||||
|
userSearchLoading.value = true
|
||||||
|
try {
|
||||||
|
const response = await searchUserByName(value.trim())
|
||||||
|
console.log('API响应完整数据:', response)
|
||||||
|
// 根据后端返回的数据结构,使用 response.rows 而不是 response.data
|
||||||
|
const users = response.rows || []
|
||||||
|
userSearchResults.value = users
|
||||||
|
|
||||||
|
// 转换为 a-auto-complete 需要的格式
|
||||||
|
userSearchOptions.value = users.map(user => ({
|
||||||
|
label: `${user.name} | ${user.deptName || '未分配部门'}`,
|
||||||
|
value: user.name,
|
||||||
|
user: user
|
||||||
|
}))
|
||||||
|
|
||||||
|
console.log('设置搜索结果:', userSearchResults.value)
|
||||||
|
console.log('设置搜索选项:', userSearchOptions.value)
|
||||||
|
} catch (error) {
|
||||||
|
console.error('搜索用户失败:', error)
|
||||||
|
userSearchResults.value = []
|
||||||
|
userSearchOptions.value = []
|
||||||
|
Message.error('搜索用户失败')
|
||||||
|
} finally {
|
||||||
|
userSearchLoading.value = false
|
||||||
|
}
|
||||||
|
}, 300)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户选择处理函数
|
||||||
|
const handleUserSelect = (value: string, option: any) => {
|
||||||
|
const selectedOption = userSearchOptions.value.find(option => option.value === value)
|
||||||
|
if (selectedOption) {
|
||||||
|
const selectedUser = selectedOption.user
|
||||||
|
// 自动填充用户信息
|
||||||
|
memberForm.name = selectedUser.name
|
||||||
|
memberForm.phone = selectedUser.mobile || ''
|
||||||
|
// 后端返回的数据中没有email字段,所以不自动填充邮箱
|
||||||
|
// memberForm.email = selectedUser.email || ''
|
||||||
|
// 清空搜索结果
|
||||||
|
userSearchResults.value = []
|
||||||
|
userSearchOptions.value = []
|
||||||
|
console.log('选择的用户:', selectedUser)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const openEditModal = (record: TeamMemberResp) => {
|
const openEditModal = (record: TeamMemberResp) => {
|
||||||
isEdit.value = true
|
isEdit.value = true
|
||||||
Object.assign(memberForm, {
|
Object.assign(memberForm, {
|
||||||
|
@ -568,6 +650,9 @@ const saveMember = async () => {
|
||||||
const cancelMember = () => {
|
const cancelMember = () => {
|
||||||
memberModalVisible.value = false
|
memberModalVisible.value = false
|
||||||
resetMemberForm()
|
resetMemberForm()
|
||||||
|
// 清空用户搜索结果
|
||||||
|
userSearchResults.value = []
|
||||||
|
userSearchOptions.value = []
|
||||||
}
|
}
|
||||||
|
|
||||||
const resetMemberForm = () => {
|
const resetMemberForm = () => {
|
||||||
|
@ -582,6 +667,9 @@ const resetMemberForm = () => {
|
||||||
joinDate: '',
|
joinDate: '',
|
||||||
remark: ''
|
remark: ''
|
||||||
})
|
})
|
||||||
|
// 清空用户搜索结果
|
||||||
|
userSearchResults.value = []
|
||||||
|
userSearchOptions.value = []
|
||||||
}
|
}
|
||||||
|
|
||||||
const openStatusModal = (record: TeamMemberResp) => {
|
const openStatusModal = (record: TeamMemberResp) => {
|
||||||
|
@ -715,11 +803,11 @@ const getRoleTypeText = (roleType: string) => {
|
||||||
|
|
||||||
const getStatusColor = (status: string) => {
|
const getStatusColor = (status: string) => {
|
||||||
const colorMap: Record<string, string> = {
|
const colorMap: Record<string, string> = {
|
||||||
ACTIVE: 'success',
|
ACTIVE: '#52c41a', // 绿色 - 可用
|
||||||
SUSPENDEN: 'warning',
|
SUSPENDEN: '#faad14', // 橙色 - 忙碌
|
||||||
INACTIVE: 'danger'
|
INACTIVE: '#ff4d4f' // 红色 - 离线
|
||||||
}
|
}
|
||||||
return colorMap[status] || 'danger'
|
return colorMap[status] || '#ff4d4f'
|
||||||
}
|
}
|
||||||
|
|
||||||
const getStatusText = (status: string) => {
|
const getStatusText = (status: string) => {
|
||||||
|
@ -741,6 +829,13 @@ onMounted(() => {
|
||||||
Message.warning('未获取到项目信息,请从项目详情页面进入')
|
Message.warning('未获取到项目信息,请从项目详情页面进入')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
// 清理搜索定时器
|
||||||
|
if (searchTimeout.value) {
|
||||||
|
clearTimeout(searchTimeout.value)
|
||||||
|
}
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@ -1307,4 +1402,24 @@ onMounted(() => {
|
||||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 用户搜索选项样式
|
||||||
|
.user-option {
|
||||||
|
.user-name {
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--color-text-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 自动完成组件样式优化
|
||||||
|
:deep(.arco-auto-complete) {
|
||||||
|
.arco-input {
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
border-color: var(--color-primary-6);
|
||||||
|
box-shadow: 0 0 0 2px rgba(var(--color-primary-6), 0.1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
|
@ -79,7 +79,7 @@
|
||||||
<icon-user class="detail-icon" />
|
<icon-user class="detail-icon" />
|
||||||
<span>负责人: {{ project.manager || '未指定' }}</span>
|
<span>负责人: {{ project.manager || '未指定' }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="detail-item">
|
<div class="detail-item clickable" @click.stop="openPersonnelManagement(project)">
|
||||||
<icon-user-group class="detail-icon" />
|
<icon-user-group class="detail-icon" />
|
||||||
<span>团队: {{ project.teamSize > 0 ? project.teamSize + '人' : '未设置' }}</span>
|
<span>团队: {{ project.teamSize > 0 ? project.teamSize + '人' : '未设置' }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -215,7 +215,7 @@
|
||||||
<icon-user class="detail-icon" />
|
<icon-user class="detail-icon" />
|
||||||
<span>负责人: {{ project.manager || '未指定' }}</span>
|
<span>负责人: {{ project.manager || '未指定' }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="detail-item">
|
<div class="detail-item clickable" @click.stop="openPersonnelManagement(project)">
|
||||||
<icon-user-group class="detail-icon" />
|
<icon-user-group class="detail-icon" />
|
||||||
<span>团队: {{ project.teamSize > 0 ? project.teamSize + '人' : '未设置' }}</span>
|
<span>团队: {{ project.teamSize > 0 ? project.teamSize + '人' : '未设置' }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -351,7 +351,7 @@
|
||||||
<icon-user class="detail-icon" />
|
<icon-user class="detail-icon" />
|
||||||
<span>负责人: {{ project.manager || '未指定' }}</span>
|
<span>负责人: {{ project.manager || '未指定' }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="detail-item">
|
<div class="detail-item clickable" @click.stop="openPersonnelManagement(project)">
|
||||||
<icon-user-group class="detail-icon" />
|
<icon-user-group class="detail-icon" />
|
||||||
<span>团队: {{ project.teamSize > 0 ? project.teamSize + '人' : '未设置' }}</span>
|
<span>团队: {{ project.teamSize > 0 ? project.teamSize + '人' : '未设置' }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -487,7 +487,7 @@
|
||||||
<icon-user class="detail-icon" />
|
<icon-user class="detail-icon" />
|
||||||
<span>负责人: {{ project.manager || '未指定' }}</span>
|
<span>负责人: {{ project.manager || '未指定' }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="detail-item">
|
<div class="detail-item clickable" @click.stop="openPersonnelManagement(project)">
|
||||||
<icon-user-group class="detail-icon" />
|
<icon-user-group class="detail-icon" />
|
||||||
<span>团队: {{ project.teamSize > 0 ? project.teamSize + '人' : '未设置' }}</span>
|
<span>团队: {{ project.teamSize > 0 ? project.teamSize + '人' : '未设置' }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -623,7 +623,7 @@
|
||||||
<icon-user class="detail-icon" />
|
<icon-user class="detail-icon" />
|
||||||
<span>负责人: {{ project.manager || '未指定' }}</span>
|
<span>负责人: {{ project.manager || '未指定' }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="detail-item">
|
<div class="detail-item clickable" @click.stop="openPersonnelManagement(project)">
|
||||||
<icon-user-group class="detail-icon" />
|
<icon-user-group class="detail-icon" />
|
||||||
<span>团队: {{ project.teamSize > 0 ? project.teamSize + '人' : '未设置' }}</span>
|
<span>团队: {{ project.teamSize > 0 ? project.teamSize + '人' : '未设置' }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -759,7 +759,7 @@
|
||||||
<icon-user class="detail-icon" />
|
<icon-user class="detail-icon" />
|
||||||
<span>负责人: {{ project.manager || '未指定' }}</span>
|
<span>负责人: {{ project.manager || '未指定' }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="detail-item">
|
<div class="detail-item clickable" @click.stop="openPersonnelManagement(project)">
|
||||||
<icon-user-group class="detail-icon" />
|
<icon-user-group class="detail-icon" />
|
||||||
<span>团队: {{ project.teamSize > 0 ? project.teamSize + '人' : '未设置' }}</span>
|
<span>团队: {{ project.teamSize > 0 ? project.teamSize + '人' : '未设置' }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -895,7 +895,7 @@
|
||||||
<icon-user class="detail-icon" />
|
<icon-user class="detail-icon" />
|
||||||
<span>负责人: {{ project.manager || '未指定' }}</span>
|
<span>负责人: {{ project.manager || '未指定' }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="detail-item">
|
<div class="detail-item clickable" @click.stop="openPersonnelManagement(project)">
|
||||||
<icon-user-group class="detail-icon" />
|
<icon-user-group class="detail-icon" />
|
||||||
<span>团队: {{ project.teamSize > 0 ? project.teamSize + '人' : '未设置' }}</span>
|
<span>团队: {{ project.teamSize > 0 ? project.teamSize + '人' : '未设置' }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1031,7 +1031,7 @@
|
||||||
<icon-user class="detail-icon" />
|
<icon-user class="detail-icon" />
|
||||||
<span>负责人: {{ project.manager || '未指定' }}</span>
|
<span>负责人: {{ project.manager || '未指定' }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="detail-item">
|
<div class="detail-item clickable" @click.stop="openPersonnelManagement(project)">
|
||||||
<icon-user-group class="detail-icon" />
|
<icon-user-group class="detail-icon" />
|
||||||
<span>团队: {{ project.teamSize > 0 ? project.teamSize + '人' : '未设置' }}</span>
|
<span>团队: {{ project.teamSize > 0 ? project.teamSize + '人' : '未设置' }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1180,10 +1180,10 @@
|
||||||
<icon-user class="detail-icon" />
|
<icon-user class="detail-icon" />
|
||||||
<span>负责人: {{ project.manager || '未指定' }}</span>
|
<span>负责人: {{ project.manager || '未指定' }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="detail-item">
|
<div class="detail-item clickable" @click.stop="openPersonnelManagement(project)">
|
||||||
<icon-user-group class="detail-icon" />
|
<icon-user-group class="detail-icon" />
|
||||||
<span>团队: {{ project.teamSize > 0 ? project.teamSize + '人' : '未设置' }}</span>
|
<span>团队: {{ project.teamSize > 0 ? project.teamSize + '人' : '未设置' }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="progress-section">
|
<div class="progress-section">
|
||||||
<div class="progress-info">
|
<div class="progress-info">
|
||||||
<span>项目进度</span>
|
<span>项目进度</span>
|
||||||
|
@ -1327,7 +1327,7 @@
|
||||||
<icon-user class="detail-icon" />
|
<icon-user class="detail-icon" />
|
||||||
<span>负责人: {{ project.manager || '未指定' }}</span>
|
<span>负责人: {{ project.manager || '未指定' }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="detail-item">
|
<div class="detail-item clickable" @click.stop="openPersonnelManagement(project)">
|
||||||
<icon-user-group class="detail-icon" />
|
<icon-user-group class="detail-icon" />
|
||||||
<span>团队: {{ project.teamSize > 0 ? project.teamSize + '人' : '未设置' }}</span>
|
<span>团队: {{ project.teamSize > 0 ? project.teamSize + '人' : '未设置' }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1474,7 +1474,7 @@
|
||||||
<icon-user class="detail-icon" />
|
<icon-user class="detail-icon" />
|
||||||
<span>负责人: {{ project.manager || '未指定' }}</span>
|
<span>负责人: {{ project.manager || '未指定' }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="detail-item">
|
<div class="detail-item clickable" @click.stop="openPersonnelManagement(project)">
|
||||||
<icon-user-group class="detail-icon" />
|
<icon-user-group class="detail-icon" />
|
||||||
<span>团队: {{ project.teamSize > 0 ? project.teamSize + '人' : '未设置' }}</span>
|
<span>团队: {{ project.teamSize > 0 ? project.teamSize + '人' : '未设置' }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1621,7 +1621,7 @@
|
||||||
<icon-user class="detail-icon" />
|
<icon-user class="detail-icon" />
|
||||||
<span>负责人: {{ project.manager || '未指定' }}</span>
|
<span>负责人: {{ project.manager || '未指定' }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="detail-item">
|
<div class="detail-item clickable" @click.stop="openPersonnelManagement(project)">
|
||||||
<icon-user-group class="detail-icon" />
|
<icon-user-group class="detail-icon" />
|
||||||
<span>团队: {{ project.teamSize > 0 ? project.teamSize + '人' : '未设置' }}</span>
|
<span>团队: {{ project.teamSize > 0 ? project.teamSize + '人' : '未设置' }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1915,7 +1915,7 @@
|
||||||
<icon-user class="detail-icon" />
|
<icon-user class="detail-icon" />
|
||||||
<span>负责人: {{ project.manager || '未指定' }}</span>
|
<span>负责人: {{ project.manager || '未指定' }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="detail-item">
|
<div class="detail-item clickable" @click.stop="openPersonnelManagement(project)">
|
||||||
<icon-user-group class="detail-icon" />
|
<icon-user-group class="detail-icon" />
|
||||||
<span>团队: {{ project.teamSize > 0 ? project.teamSize + '人' : '未设置' }}</span>
|
<span>团队: {{ project.teamSize > 0 ? project.teamSize + '人' : '未设置' }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -2062,7 +2062,7 @@
|
||||||
<icon-user class="detail-icon" />
|
<icon-user class="detail-icon" />
|
||||||
<span>负责人: {{ project.manager || '未指定' }}</span>
|
<span>负责人: {{ project.manager || '未指定' }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="detail-item">
|
<div class="detail-item clickable" @click.stop="openPersonnelManagement(project)">
|
||||||
<icon-user-group class="detail-icon" />
|
<icon-user-group class="detail-icon" />
|
||||||
<span>团队: {{ project.teamSize > 0 ? project.teamSize + '人' : '未设置' }}</span>
|
<span>团队: {{ project.teamSize > 0 ? project.teamSize + '人' : '未设置' }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -3041,11 +3041,11 @@ const openSiteManagement = (project: any) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 人员管理
|
// 人员管理
|
||||||
const openPersonnelManagement = () => {
|
const openPersonnelManagement = (project: any) => {
|
||||||
if (currentProject.value && currentProject.value.id) {
|
if (project && project.id) {
|
||||||
router.push({
|
router.push({
|
||||||
path: '/project-management/personnel-dispatch/construction-personnel',
|
path: '/project-management/personnel-dispatch/construction-personnel',
|
||||||
query: { projectId: currentProject.value.id }
|
query: { projectId: project.id }
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
Message.error('项目信息不完整,无法进入团队成员管理')
|
Message.error('项目信息不完整,无法进入团队成员管理')
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue