TechnicianAssign 技术员分配组件

概述

TechnicianAssign 是一个用于技术员分配的 Vue 3 组件,支持多选技术员,显示技术员名称和编码,并提供工作状态和任务负载信息。

功能特点

  • ✅ 技术员多选支持
  • ✅ 显示技术员名称和编码格式:姓名 (编码)
  • ✅ 显示技术员工作状态(空闲/忙碌/休假/出差)
  • ✅ 显示技术员任务负载
  • ✅ 按任务负载自动排序(负载低的在前)
  • ✅ 过滤和搜索功能
  • ✅ 支持排除指定技术员
  • ✅ 可选的选中技术员详情卡片
  • ✅ 响应式数据绑定

基础用法

<template>
  <TechnicianAssign
    v-model="selectedTechnicianIds"
    label="分配技术员"
    placeholder="请选择技术员"
    @technician-selected="handleTechnicianSelected"
  />
</template>

<script setup>
import { ref } from 'vue';
import TechnicianAssign from '@/components/TechnicianAssign/index.vue';

const selectedTechnicianIds = ref([]);

function handleTechnicianSelected(technicians) {
  console.log('选中的技术员:', technicians);
}
</script>

组件属性 (Props)

属性名 类型 默认值 必填 说明
modelValue Array [] v-model 绑定的技术员ID数组
label String '分配技术员' 表单项标签文本
prop String '' 表单项 prop 属性
rules Object/Array null 表单验证规则
placeholder String '请选择技术员' 选择器占位符
disabled Boolean false 是否禁用选择器
showCard Boolean false 是否显示选中技术员的详情卡片
filterParams Object {} 技术员过滤条件
excludeTechnicianId Number/String null 要排除的技术员ID

组件事件 (Events)

事件名 参数 说明
update:modelValue (technicianIds: Array) 选中的技术员ID数组变化时触发
change (technicianIds: Array, technicians: Array) 技术员选择变化时触发
technician-selected (technicians: Array) 选择技术员时触发,返回完整的技术员对象数组

数据结构

技术员对象结构

interface Technician {
  id: number;              // 技术员ID
  technicianName: string;    // 技术员姓名
  technicianCode: string;    // 技术员编码
  workStatus: string;       // 工作状态:'idle'空闲, 'busy'忙碌, 'vacation'休假, 'business_trip'出差
  currentTasks: number;     // 当前任务数
  maxTasks: number;        // 最大任务数
  phone: string;            // 联系电话
  department: string;       // 所属部门
  position: string;         // 职位
  avatar: string;           // 头像URL
}

显示格式

  • 下拉选项显示张三 (T001) + 工作状态标签 + 2/5(任务负载)
  • 选中标签显示张三 (T001)李四 (T002),…
  • 详情卡片:显示选中的技术员列表,包含详细信息

高级用法

多选与表单验证

<template>
  <el-form :model="form" :rules="rules">
    <TechnicianAssign
      v-model="form.assignedTechnicianIds"
      label="分配技术员"
      prop="assignedTechnicianIds"
      :rules="rules.assignedTechnicianIds"
      placeholder="请至少选择一个技术员"
      @technician-selected="handleTechnicianSelected"
    />
  </el-form>
</template>

<script setup>
import { reactive } from 'vue';
import TechnicianAssign from '@/components/TechnicianAssign/index.vue';

const form = reactive({
  assignedTechnicianIds: []
});

const rules = {
  assignedTechnicianIds: [
    { required: true, message: '请至少选择一个技术员', trigger: 'change' }
  ]
};

function handleTechnicianSelected(technicians) {
  // technicians 是选中的技术员对象数组
  form.assignedTechnicians = technicians;
}
</script>

带过滤条件

<template>
  <TechnicianAssign
    v-model="selectedIds"
    :filterParams="{
      status: 'active',    // 只显示在职技术员
      skillLevel: 'senior' // 只显示高级技术员
    }"
    :exclude-technician-id="currentUserId" // 排除当前用户
  />
</template>

显示详情卡片

<template>
  <TechnicianAssign
    v-model="selectedIds"
    :show-card="true"
    label="选择技术员"
  />
</template>

与其他组件配合使用

<template>
  <el-form :model="subtaskForm">
    <el-form-item label="子任务标题">
      <el-input v-model="subtaskForm.title" />
    </el-form-item>

    <el-form-item label="分配技术员">
      <TechnicianAssign
        v-model="subtaskForm.assignedTechnicianIds"
        :label="''"
        :show-card="false"
        placeholder="请选择负责技术员"
        @technician-selected="(technicians) => updateTechnicians(technicians)"
      />
    </el-form-item>
  </el-form>
</template>

<script setup>
import { reactive } from 'vue';

const subtaskForm = reactive({
  title: '',
  assignedTechnicianIds: [],
  assignedTechnicians: []
});

function updateTechnicians(technicians) {
  subtaskForm.assignedTechnicians = technicians;
  // 更新兼容字段
  if (technicians.length > 0) {
    subtaskForm.assignedTechnicianNames = technicians.map(t => t.technicianName).join(',');
    subtaskForm.assignedTechnicianId = technicians[0].id;
  } else {
    subtaskForm.assignedTechnicianNames = '';
    subtaskForm.assignedTechnicianId = null;
  }
}
</script>

样式定制

组件支持通过 CSS 变量进行样式定制:

/* 在父组件中覆盖样式 */
.technician-assign {
  /* 修改选项间距 */
  --technician-option-gap: 16px;

  /* 修改字体大小 */
  --tech-name-size: 16px;
  --tech-code-size: 13px;
}

/* 自定义详情卡片样式 */
:deep(.selected-technician-card) {
  .tech-card-item {
    background: #f0f9ff;
    border-color: #0ea5e9;
  }
}

常见问题

Q: 如何获取选中的技术员详细信息?

A: 使用 @technician-selected 事件,它会返回完整的技术员对象数组:

function handleTechnicianSelected(technicians) {
  // technicians 数组包含完整的技师对象
  technicians.forEach(tech => {
    console.log(tech.technicianName, tech.technicianCode, tech.workStatus);
  });
}

Q: 如何限制只能选择一个技术员?

A: 组件默认支持多选,如需单选可通过以下方式:

<template>
  <TechnicianAssign
    v-model="selectedIds"
    @change="handleSingleSelect"
  />
</template>

<script setup>
function handleSingleSelect(ids, technicians) {
  if (ids.length > 1) {
    // 只保留最后一个选中的
    selectedIds.value = [ids[ids.length - 1]];
  }
}
</script>

Q: 如何自定义技术员数据源?

A: 组件内部调用 listTechnician API,如需自定义可通过 filterParams 传入过滤条件,或修改组件内部的加载逻辑。

Q: 如何处理技术员加载失败的情况?

A: 组件内部有错误处理,会在控制台输出错误信息并显示空列表。你也可以监听组件的 refresh 方法:

const technicianAssignRef = ref();

// 手动刷新
async function refreshTechnicians() {
  try {
    await technicianAssignRef.value.refresh();
  } catch (error) {
    // 处理错误
  }
}

API 依赖

组件依赖以下 API:

  • listTechnician - 获取技术员列表

相关文件

  • 组件文件:@/components/TechnicianAssign/index.vue
  • API 文件:@/api/business/technician.js

更新日志

v2.0.0 (2025-01-22)

  • 🔄 重写组件:简化界面,专注于显示技术员名称和编码
  • 新功能:支持名称+编码格式显示
  • 🗑️ 移除:移除头像、评分、技能等级等复杂信息
  • 🎨 优化:改进下拉选项和详情卡片布局

v1.0.0 (2024-XX-XX)

  • 🎉 初始版本:基础技术员选择功能

作者: Claude Assistant
维护: Husky Equipment Maintenance Service Team
更新时间: 2025-01-22

作者:聂盼盼  创建时间:2025-10-27 23:08
最后编辑:聂盼盼  更新时间:2025-10-28 19:53