xiaoyi
2026-10-30 9f6fef931a284acd73085847021b73437e29eb2c
feat(ui): 全系统人员选择统一改为下拉模糊搜索

## 背景
系统里人员选择控件形态不统一,且大部分不支持搜索:
- ApiSelect 拉全量用户(87 人)后是无搜索的普通下拉
- UserSelect(BPM 表单内)同样没有搜索
- HrmEmployeeSelect 是点击弹窗,不是下拉

员工数增长后,翻找人员非常低效。

## 改动

### 1. 底层组件(一处改动,全局生效)
- use-api-select.tsx:UserSelect 默认开启 showSearch + optionFilterProp='label'
覆盖 BPM 表单内所有 15 处 markRaw(UserSelect) 引用

### 2. ApiSelect 人员字段(46 处,38 个文件)
统一注入 showSearch: true + optionFilterProp: 'label',按标签模糊匹配。
覆盖范围:
- CRM 全部:客户/线索/联系人/合同/发票/回款/回款计划/报价/统计(4个)/权限
- MES:设备点检/保养、安灯配置与记录、生产报工、质检(IQC/IPQC/OQC/RQC/台账/NCR)
- 系统:部门负责人、通知模板接收人、操作日志
- WMS:包装、盘点任务
- AI:对话/绘图/思维导图/音乐/写作 5 个模块

### 3. 新建下拉式员工选择组件
views/hrm/employee/components/select-dropdown.vue
- 基于 a-select,数据源 getEmployeeSimpleList
- 展示「姓名(部门)」,支持按 姓名/工号/部门 模糊匹配
- 支持 deptId 限定部门、allowClear、disabled

### 4. 安全生产模块 15 处替换(9 个页面)
HrmEmployeeSelect(弹窗式)→ EmployeeSelect(下拉式)
涉及:隐患(上报人/整改责任人/复查人)、作业票(申请人/监护人/审批人/动火监护人)、
培训、演练、检查点、检查记录、证书、物料、相关方

## 验证
- vue-tsc 类型检查:无新增错误(仓库既有 318 个基线错误不变)
- 构建通过,已部署生产
- 前端 HTTP 200,服务正常
已添加1个文件
已修改48个文件
255 ■■■■■ 文件已修改
src/components/form-create/components/use-api-select.tsx 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/ai/chat/manager/data.ts 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/ai/image/manager/data.ts 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/ai/mindmap/manager/data.ts 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/ai/music/manager/data.ts 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/ai/write/manager/data.ts 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/crm/business/data.ts 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/crm/clue/data.ts 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/crm/contact/data.ts 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/crm/contract/data.ts 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/crm/customer/data.ts 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/crm/customer/detail/data.ts 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/crm/invoice/data.ts 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/crm/permission/modules/data.ts 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/crm/receivable/data.ts 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/crm/receivable/plan/data.ts 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/crm/saleQuotation/data.ts 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/crm/statistics/customer/data.ts 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/crm/statistics/funnel/data.ts 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/crm/statistics/performance/data.ts 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/crm/statistics/portrait/data.ts 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/hrm/employee/components/select-dropdown.vue 102 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/hrm/resignation/data.ts 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/hrm/salary/calculation/data.ts 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mes/dv/checkrecord/data.ts 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mes/dv/maintenrecord/data.ts 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mes/pro/andon/config/data.ts 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mes/pro/andon/record/data.ts 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mes/pro/workrecord/data.ts 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mes/qc/ipqc/data.ts 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mes/qc/iqc/data.ts 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mes/qc/ledger/data.ts 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mes/qc/ncr/data.ts 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mes/qc/oqc/data.ts 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mes/qc/rqc/data.ts 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/safety/cert/index.vue 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/safety/drill/index.vue 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/safety/hazard/index.vue 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/safety/inspection/point/index.vue 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/safety/inspection/record/index.vue 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/safety/material/index.vue 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/safety/org/index.vue 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/safety/permit/index.vue 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/safety/training/index.vue 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/dept/data.ts 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/notify/template/data.ts 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/operatelog/data.ts 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/wls/packages/data.ts 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/wls/stocktaking/task/data.ts 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/form-create/components/use-api-select.tsx
@@ -246,6 +246,19 @@
          ...restAttrs
        } = attrs;
        // äººå‘˜é€‰æ‹©å™¨ï¼ˆUserSelect)默认开启模糊搜索:支持按姓名输入过滤
        const searchProps =
          option.name === 'UserSelect'
            ? {
                showSearch: true,
                optionFilterProp: 'label',
                filterOption: (input: string, opt: any) =>
                  String(opt?.label ?? '')
                    .toLowerCase()
                    .includes(String(input).toLowerCase()),
              }
            : {};
        if (props.multiple) {
          // fix:多写此步是为了解决 multiple å±žæ€§é—®é¢˜
          return (
@@ -255,6 +268,7 @@
              mode="multiple"
              onUpdate:value={onUpdateModelValue as any}
              value={modelValue as any}
              {...searchProps}
              {...restAttrs}
              // TODO @xingyu remote å¯¹ç­‰å®žçް, è¿˜æ˜¯è¯´æ²¡ä½œç”¨
              // remote={props.remote}
@@ -276,6 +290,7 @@
            loading={loading.value}
            onUpdate:value={onUpdateModelValue as any}
            value={modelValue as any}
            {...searchProps}
            {...restAttrs}
            // TODO: @xingyu remote å¯¹ç­‰å®žçް, è¿˜æ˜¯è¯´æ²¡ä½œç”¨
            // remote={props.remote}
src/views/ai/chat/manager/data.ts
@@ -132,6 +132,8 @@
      label: '用户编号',
      component: 'ApiSelect',
      componentProps: {
        showSearch: true,
        optionFilterProp: 'label',
        api: getSimpleUserList,
        labelField: 'nickname',
        valueField: 'id',
src/views/ai/image/manager/data.ts
@@ -23,6 +23,8 @@
      label: '用户编号',
      component: 'ApiSelect',
      componentProps: {
        showSearch: true,
        optionFilterProp: 'label',
        api: getSimpleUserList,
        labelField: 'nickname',
        valueField: 'id',
src/views/ai/mindmap/manager/data.ts
@@ -17,6 +17,8 @@
      label: '用户编号',
      component: 'ApiSelect',
      componentProps: {
        showSearch: true,
        optionFilterProp: 'label',
        api: getSimpleUserList,
        labelField: 'nickname',
        valueField: 'id',
src/views/ai/music/manager/data.ts
@@ -20,6 +20,8 @@
      label: '用户编号',
      component: 'ApiSelect',
      componentProps: {
        showSearch: true,
        optionFilterProp: 'label',
        api: getSimpleUserList,
        labelField: 'nickname',
        valueField: 'id',
src/views/ai/write/manager/data.ts
@@ -20,6 +20,8 @@
      label: '用户编号',
      component: 'ApiSelect',
      componentProps: {
        showSearch: true,
        optionFilterProp: 'label',
        api: getSimpleUserList,
        labelField: 'nickname',
        valueField: 'id',
src/views/crm/business/data.ts
@@ -42,6 +42,8 @@
        disabled: (values) => values.id,
      },
      componentProps: {
        showSearch: true,
        optionFilterProp: 'label',
        api: getSimpleUserList,
        labelField: 'nickname',
        valueField: 'id',
src/views/crm/clue/data.ts
@@ -55,6 +55,8 @@
      label: '负责人',
      component: 'ApiSelect',
      componentProps: {
        showSearch: true,
        optionFilterProp: 'label',
        api: getSimpleUserList,
        labelField: 'nickname',
        valueField: 'id',
src/views/crm/contact/data.ts
@@ -43,6 +43,8 @@
        disabled: (values) => values.id,
      },
      componentProps: {
        showSearch: true,
        optionFilterProp: 'label',
        api: getSimpleUserList,
        labelField: 'nickname',
        valueField: 'id',
src/views/crm/contract/data.ts
@@ -47,6 +47,8 @@
      label: '负责人',
      component: 'ApiSelect',
      componentProps: {
        showSearch: true,
        optionFilterProp: 'label',
        api: getSimpleUserList,
        labelField: 'nickname',
        valueField: 'id',
src/views/crm/customer/data.ts
@@ -62,6 +62,8 @@
        disabled: (values) => values.id,
      },
      componentProps: {
        showSearch: true,
        optionFilterProp: 'label',
        api: getSimpleUserList,
        labelField: 'nickname',
        valueField: 'id',
@@ -247,6 +249,8 @@
      label: '负责人',
      component: 'ApiSelect',
      componentProps: {
        showSearch: true,
        optionFilterProp: 'label',
        api: getSimpleUserList,
        labelField: 'nickname',
        valueField: 'id',
src/views/crm/customer/detail/data.ts
@@ -27,6 +27,8 @@
      label: '负责人',
      component: 'ApiSelect',
      componentProps: {
        showSearch: true,
        optionFilterProp: 'label',
        api: getSimpleUserList,
        labelField: 'nickname',
        valueField: 'id',
src/views/crm/invoice/data.ts
@@ -42,6 +42,8 @@
        disabled: (values) => !!values.id,
      },
      componentProps: {
        showSearch: true,
        optionFilterProp: 'label',
        api: getSimpleUserList,
        labelField: 'nickname',
        valueField: 'id',
src/views/crm/permission/modules/data.ts
@@ -116,6 +116,8 @@
      label: '选择人员',
      component: 'ApiSelect',
      componentProps: {
        showSearch: true,
        optionFilterProp: 'label',
        api: getSimpleUserList,
        labelField: 'nickname',
        valueField: 'id',
src/views/crm/receivable/data.ts
@@ -47,6 +47,8 @@
        disabled: (values) => values.id,
      },
      componentProps: {
        showSearch: true,
        optionFilterProp: 'label',
        api: getSimpleUserList,
        labelField: 'nickname',
        valueField: 'id',
src/views/crm/receivable/plan/data.ts
@@ -31,6 +31,8 @@
      label: '负责人',
      component: 'ApiSelect',
      componentProps: {
        showSearch: true,
        optionFilterProp: 'label',
        api: getSimpleUserList,
        labelField: 'nickname',
        valueField: 'id',
src/views/crm/saleQuotation/data.ts
@@ -54,6 +54,8 @@
      label: '负责人',
      component: 'ApiSelect',
      componentProps: {
        showSearch: true,
        optionFilterProp: 'label',
        api: getSimpleUserList,
        labelField: 'nickname',
        valueField: 'id',
src/views/crm/statistics/customer/data.ts
@@ -103,6 +103,8 @@
      label: '员工',
      component: 'ApiSelect',
      componentProps: {
        showSearch: true,
        optionFilterProp: 'label',
        api: getSimpleUserList,
        labelField: 'nickname',
        valueField: 'id',
src/views/crm/statistics/funnel/data.ts
@@ -76,6 +76,8 @@
      label: '员工',
      component: 'ApiSelect',
      componentProps: {
        showSearch: true,
        optionFilterProp: 'label',
        api: getSimpleUserList,
        allowClear: true,
        labelField: 'nickname',
src/views/crm/statistics/performance/data.ts
@@ -60,6 +60,8 @@
      label: '员工',
      component: 'ApiSelect',
      componentProps: {
        showSearch: true,
        optionFilterProp: 'label',
        api: getSimpleUserList,
        labelField: 'nickname',
        valueField: 'id',
src/views/crm/statistics/portrait/data.ts
@@ -70,6 +70,8 @@
      label: '员工',
      component: 'ApiSelect',
      componentProps: {
        showSearch: true,
        optionFilterProp: 'label',
        api: getSimpleUserList,
        labelField: 'nickname',
        valueField: 'id',
src/views/hrm/employee/components/select-dropdown.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,102 @@
<script lang="ts" setup>
import type { HrmEmployeeApi } from '#/api/hrm/employee';
import { computed, onMounted, ref, watch } from 'vue';
import { Select } from 'ant-design-vue';
import { getEmployeeSimpleList } from '#/api/hrm/employee';
defineOptions({ name: 'EmployeeSelect', inheritAttrs: false });
const props = withDefaults(
  defineProps<{
    allowClear?: boolean;
    disabled?: boolean;
    /** éƒ¨é—¨ ID,传入则只显示该部门的员工 */
    deptId?: number;
    /** å ä½æ–‡æ¡ˆ */
    placeholder?: string;
    modelValue?: number;
  }>(),
  {
    allowClear: true,
    disabled: false,
    deptId: undefined,
    placeholder: '输入姓名或工号搜索',
    modelValue: undefined,
  },
);
const emit = defineEmits<{
  change: [item: HrmEmployeeApi.EmployeeSimple | undefined];
  'update:modelValue': [value: number | undefined];
}>();
const loading = ref(false);
const allOptions = ref<HrmEmployeeApi.EmployeeSimple[]>([]);
/** ä¸‹æ‹‰é€‰é¡¹ï¼šå§“名(部门) */
const options = computed(() =>
  allOptions.value
    .filter((e) => !props.deptId || (e as any).deptId === props.deptId)
    .map((e) => ({
      label: e.deptName ? `${e.name}(${e.deptName})` : e.name,
      value: e.id,
      raw: e,
    })),
);
onMounted(async () => {
  loading.value = true;
  try {
    allOptions.value = (await getEmployeeSimpleList()) || [];
  } finally {
    loading.value = false;
  }
});
/** æ¨¡ç³ŠåŒ¹é…ï¼šå§“名 / å·¥å· / éƒ¨é—¨ */
function filterOption(input: string, option: any) {
  const kw = String(input ?? '').toLowerCase().trim();
  if (!kw) {
    return true;
  }
  const raw = option?.raw || {};
  const hay = [raw.name, raw.employeeNo, raw.deptName, option?.label]
    .filter(Boolean)
    .join(' ')
    .toLowerCase();
  return hay.includes(kw);
}
function handleChange(val: any) {
  const id = typeof val === 'number' ? val : undefined;
  emit('update:modelValue', id);
  emit('change', allOptions.value.find((e) => e.id === id));
}
watch(
  () => props.modelValue,
  () => {
    // ä»…用于触发视图更新
  },
);
</script>
<template>
  <Select
    v-bind="$attrs"
    :allow-clear="allowClear"
    :disabled="disabled"
    :filter-option="filterOption"
    :loading="loading"
    :options="options"
    :placeholder="placeholder"
    :value="modelValue"
    class="w-full"
    option-filter-prop="label"
    show-search
    @change="handleChange"
  />
</template>
src/views/hrm/resignation/data.ts
@@ -48,6 +48,8 @@
      label: '交接人',
      component: 'ApiSelect',
      componentProps: {
        showSearch: true,
        optionFilterProp: 'label',
        api: getEmployeeSimpleList,
        labelField: 'name',
        valueField: 'id',
src/views/hrm/salary/calculation/data.ts
@@ -30,6 +30,8 @@
      label: '员工',
      component: 'ApiSelect',
      componentProps: {
        showSearch: true,
        optionFilterProp: 'label',
        api: getEmployeeSimpleList,
        labelField: 'name',
        valueField: 'id',
src/views/mes/dv/checkrecord/data.ts
@@ -64,6 +64,8 @@
      label: '点检人',
      component: 'ApiSelect',
      componentProps: {
        showSearch: true,
        optionFilterProp: 'label',
        allowClear: true,
        api: getSimpleUserList,
        labelField: 'nickname',
src/views/mes/dv/maintenrecord/data.ts
@@ -64,6 +64,8 @@
      label: '保养人',
      component: 'ApiSelect',
      componentProps: {
        showSearch: true,
        optionFilterProp: 'label',
        allowClear: true,
        api: getSimpleUserList,
        labelField: 'nickname',
src/views/mes/pro/andon/config/data.ts
@@ -80,6 +80,8 @@
      label: '处置人',
      component: 'ApiSelect',
      componentProps: {
        showSearch: true,
        optionFilterProp: 'label',
        allowClear: true,
        api: getSimpleUserList,
        labelField: 'nickname',
src/views/mes/pro/andon/record/data.ts
@@ -36,6 +36,8 @@
      label: '发起人',
      component: 'ApiSelect',
      componentProps: {
        showSearch: true,
        optionFilterProp: 'label',
        allowClear: true,
        api: getSimpleUserList,
        labelField: 'nickname',
@@ -48,6 +50,8 @@
      label: '处置人',
      component: 'ApiSelect',
      componentProps: {
        showSearch: true,
        optionFilterProp: 'label',
        allowClear: true,
        api: getSimpleUserList,
        labelField: 'nickname',
@@ -169,6 +173,8 @@
          label: '发起人',
          component: 'ApiSelect',
          componentProps: {
            showSearch: true,
            optionFilterProp: 'label',
            allowClear: true,
            api: getSimpleUserList,
            labelField: 'nickname',
@@ -283,6 +289,8 @@
                label: '处置人',
                component: 'ApiSelect',
                componentProps: {
                  showSearch: true,
                  optionFilterProp: 'label',
                  allowClear: true,
                  api: getSimpleUserList,
                  labelField: 'nickname',
src/views/mes/pro/workrecord/data.ts
@@ -24,6 +24,8 @@
      label: '用户',
      component: 'ApiSelect',
      componentProps: {
        showSearch: true,
        optionFilterProp: 'label',
        allowClear: true,
        api: getSimpleUserList,
        labelField: 'nickname',
src/views/mes/qc/ipqc/data.ts
@@ -346,6 +346,8 @@
      label: '检测人员',
      component: 'ApiSelect',
      componentProps: {
        showSearch: true,
        optionFilterProp: 'label',
        allowClear: true,
        api: getSimpleUserList,
        labelField: 'nickname',
src/views/mes/qc/iqc/data.ts
@@ -255,6 +255,8 @@
      label: '检测人员',
      component: 'ApiSelect',
      componentProps: {
        showSearch: true,
        optionFilterProp: 'label',
        allowClear: true,
        api: getSimpleUserList,
        labelField: 'nickname',
@@ -366,6 +368,8 @@
      label: '检测人员',
      component: 'ApiSelect',
      componentProps: {
        showSearch: true,
        optionFilterProp: 'label',
        allowClear: true,
        api: getSimpleUserList,
        labelField: 'nickname',
src/views/mes/qc/ledger/data.ts
@@ -73,6 +73,8 @@
      label: '检测人员',
      component: 'ApiSelect',
      componentProps: {
        showSearch: true,
        optionFilterProp: 'label',
        allowClear: true,
        api: getSimpleUserList,
        labelField: 'nickname',
src/views/mes/qc/ncr/data.ts
@@ -253,6 +253,8 @@
      label: '处理人',
      component: 'ApiSelect',
      componentProps: {
        showSearch: true,
        optionFilterProp: 'label',
        allowClear: true,
        api: getSimpleUserList,
        labelField: 'nickname',
src/views/mes/qc/oqc/data.ts
@@ -272,6 +272,8 @@
      label: '检测人员',
      component: 'ApiSelect',
      componentProps: {
        showSearch: true,
        optionFilterProp: 'label',
        allowClear: true,
        api: getSimpleUserList,
        labelField: 'nickname',
src/views/mes/qc/rqc/data.ts
@@ -258,6 +258,8 @@
      label: '检测人员',
      component: 'ApiSelect',
      componentProps: {
        showSearch: true,
        optionFilterProp: 'label',
        allowClear: true,
        api: getSimpleUserList,
        labelField: 'nickname',
@@ -352,6 +354,8 @@
      label: '检测人员',
      component: 'ApiSelect',
      componentProps: {
        showSearch: true,
        optionFilterProp: 'label',
        allowClear: true,
        api: getSimpleUserList,
        labelField: 'nickname',
src/views/safety/cert/index.vue
@@ -31,7 +31,7 @@
  getCertificatePage,
  updateCertificate,
} from '#/api/safety';
import HrmEmployeeSelect from '#/views/hrm/employee/components/select.vue';
import EmployeeSelect from '#/views/hrm/employee/components/select-dropdown.vue';
import { CERT_STATUS_COLOR, CERT_STATUS_OPTIONS, CERT_TYPE_OPTIONS } from '../shared';
@@ -319,7 +319,7 @@
        class="safety-form"
      >
        <FormItem label="持证人" name="employeeId" class="col-span-full">
          <HrmEmployeeSelect v-model="model.employeeId" placeholder="从员工档案中选择持证人" />
          <EmployeeSelect v-model="model.employeeId" placeholder="输入姓名或工号搜索持证人" />
          <div class="text-muted-foreground mt-1 text-xs">
            æŒè¯äººæ¥è‡ªäººåŠ›èµ„æºçš„å‘˜å·¥æ¡£æ¡ˆï¼Œå§“å / å·¥å· / éƒ¨é—¨è‡ªåŠ¨å¸¦å‡ºï¼Œå‘˜å·¥è°ƒå²—åŽå°è´¦ä¼šåŒæ­¥æ›´æ–°ã€‚
          </div>
src/views/safety/drill/index.vue
@@ -31,7 +31,7 @@
  getDrillPage,
  updateDrill,
} from '#/api/safety';
import HrmEmployeeSelect from '#/views/hrm/employee/components/select.vue';
import EmployeeSelect from '#/views/hrm/employee/components/select-dropdown.vue';
import { DRILL_TYPE_OPTIONS } from '../shared';
@@ -232,7 +232,7 @@
          <Input v-model:value="model.location" :maxlength="200" placeholder="如 åŽ‚åŒºä¸œä¾§æ¶ˆé˜²é€šé“" />
        </FormItem>
        <FormItem label="组织人" name="organizerId">
          <HrmEmployeeSelect v-model="model.organizerId" placeholder="从员工档案中选择组织人" />
          <EmployeeSelect v-model="model.organizerId" placeholder="输入姓名或工号搜索组织人" />
        </FormItem>
        <FormItem label="时长(分钟)" name="durationMinutes">
          <InputNumber v-model:value="model.durationMinutes" :min="0" style="width: 100%" />
src/views/safety/hazard/index.vue
@@ -37,7 +37,7 @@
  updateHazard,
  uploadSafetyFiles,
} from '#/api/safety';
import HrmEmployeeSelect from '#/views/hrm/employee/components/select.vue';
import EmployeeSelect from '#/views/hrm/employee/components/select-dropdown.vue';
import {
  HAZARD_LEVEL_COLOR,
@@ -458,7 +458,7 @@
          <DatePicker v-model:value="model.rectifyDeadline" value-format="YYYY-MM-DD" class="w-full" />
        </FormItem>
        <FormItem label="上报人" name="reporterId">
          <HrmEmployeeSelect v-model="model.reporterId" placeholder="从员工档案中选择上报人" />
          <EmployeeSelect v-model="model.reporterId" placeholder="输入姓名或工号搜索上报人" />
        </FormItem>
        <FormItem label="上报时间" name="reportTime">
          <DatePicker
@@ -494,7 +494,7 @@
    <Modal v-model:open="assignOpen" title="分派整改责任人" :confirm-loading="saving" ok-text="确认分派" cancel-text="取消" @ok="saveAssign">
      <Form layout="vertical" class="mt-4">
        <FormItem label="整改责任人" required>
          <HrmEmployeeSelect v-model="assignModel.assigneeId" placeholder="从员工档案中选择整改责任人" />
          <EmployeeSelect v-model="assignModel.assigneeId" placeholder="输入姓名或工号搜索整改责任人" />
        </FormItem>
        <FormItem label="整改期限">
          <DatePicker v-model:value="assignModel.rectifyDeadline" value-format="YYYY-MM-DD" class="w-full" />
@@ -528,7 +528,7 @@
    <Modal v-model:open="recheckOpen" title="隐患复查" :confirm-loading="saving" ok-text="提交复查" cancel-text="取消" @ok="saveRecheck">
      <Form layout="vertical" class="mt-4">
        <FormItem label="复查人" required>
          <HrmEmployeeSelect v-model="recheckModel.recheckerId" placeholder="从员工档案中选择复查人" />
          <EmployeeSelect v-model="recheckModel.recheckerId" placeholder="输入姓名或工号搜索复查人" />
          <div class="text-muted-foreground mt-1 text-xs">复查人不能与整改责任人为同一人。</div>
        </FormItem>
        <FormItem label="复查结论" required>
src/views/safety/inspection/point/index.vue
@@ -30,7 +30,7 @@
  getInspectionPointPage,
  updateInspectionPoint,
} from '#/api/safety';
import HrmEmployeeSelect from '#/views/hrm/employee/components/select.vue';
import EmployeeSelect from '#/views/hrm/employee/components/select-dropdown.vue';
import { INSPECT_CYCLE_OPTIONS, POINT_TYPE_OPTIONS } from '../../shared';
@@ -307,7 +307,7 @@
          />
        </FormItem>
        <FormItem label="责任人" name="ownerId">
          <HrmEmployeeSelect v-model="model.ownerId" placeholder="从员工档案中选择责任人" />
          <EmployeeSelect v-model="model.ownerId" placeholder="输入姓名或工号搜索责任人" />
        </FormItem>
        <FormItem label="具体位置" name="location" class="col-span-full">
          <Input v-model:value="model.location" :maxlength="200" placeholder="如 åŽ‚åŒºè¥¿åŒ—è§’ 1 å·é…ç”µæˆ¿" />
src/views/safety/inspection/record/index.vue
@@ -34,7 +34,7 @@
  updateInspection,
  uploadSafetyFiles,
} from '#/api/safety';
import HrmEmployeeSelect from '#/views/hrm/employee/components/select.vue';
import EmployeeSelect from '#/views/hrm/employee/components/select-dropdown.vue';
import { INSPECTION_RESULT_OPTIONS, splitUrls } from '../../shared';
@@ -368,7 +368,7 @@
          />
        </FormItem>
        <FormItem label="巡检人" name="inspectorId">
          <HrmEmployeeSelect v-model="model.inspectorId" placeholder="从员工档案中选择巡检人" />
          <EmployeeSelect v-model="model.inspectorId" placeholder="输入姓名或工号搜索巡检人" />
        </FormItem>
        <FormItem label="巡检结果" name="result">
          <Select v-model:value="model.result" :options="INSPECTION_RESULT_OPTIONS" />
src/views/safety/material/index.vue
@@ -35,7 +35,7 @@
  getMaterialStockPage,
  updateMaterial,
} from '#/api/safety';
import HrmEmployeeSelect from '#/views/hrm/employee/components/select.vue';
import EmployeeSelect from '#/views/hrm/employee/components/select-dropdown.vue';
import { MATERIAL_CATEGORY_COLOR, MATERIAL_CATEGORY_OPTIONS, numberText } from '../shared';
@@ -433,7 +433,7 @@
          <Input v-model:value="model.storageLocation" :maxlength="100" placeholder="如 å®‰å…¨å·¥å™¨å…·å®¤ A æŸœ" />
        </FormItem>
        <FormItem label="保管人" name="managerId">
          <HrmEmployeeSelect v-model="model.managerId" placeholder="从员工档案中选择保管人" />
          <EmployeeSelect v-model="model.managerId" placeholder="输入姓名或工号搜索保管人" />
        </FormItem>
        <FormItem :label="expireRequired ? '有效期至(必填)' : '有效期至'" name="expireDate">
          <DatePicker v-model:value="model.expireDate" value-format="YYYY-MM-DD" class="w-full" />
src/views/safety/org/index.vue
@@ -27,7 +27,7 @@
} from 'ant-design-vue';
import { createOrg, deleteOrg, getOrgTree, updateOrg } from '#/api/safety';
import HrmEmployeeSelect from '#/views/hrm/employee/components/select.vue';
import EmployeeSelect from '#/views/hrm/employee/components/select-dropdown.vue';
defineOptions({ name: 'SafetyOrg' });
@@ -294,7 +294,7 @@
          />
        </FormItem>
        <FormItem label="负责人" name="leaderId">
          <HrmEmployeeSelect v-model="model.leaderId" placeholder="从员工档案中选择负责人" />
          <EmployeeSelect v-model="model.leaderId" placeholder="输入姓名或工号搜索负责人" />
        </FormItem>
        <FormItem label="显示顺序" name="sort">
          <InputNumber v-model:value="model.sort" :min="0" :max="9999" style="width: 100%" />
src/views/safety/permit/index.vue
@@ -44,7 +44,7 @@
  updateWorkPermit,
  uploadSafetyFiles,
} from '#/api/safety';
import HrmEmployeeSelect from '#/views/hrm/employee/components/select.vue';
import EmployeeSelect from '#/views/hrm/employee/components/select-dropdown.vue';
import {
  PERMIT_STATUS_COLOR,
@@ -523,10 +523,10 @@
          <DatePicker v-model:value="model.planEndTime" show-time format="YYYY-MM-DD HH:mm:ss" value-format="YYYY-MM-DD HH:mm:ss" class="w-full" />
        </FormItem>
        <FormItem label="申请人" name="applicantId">
          <HrmEmployeeSelect v-model="model.applicantId" placeholder="从员工档案中选择申请人" />
          <EmployeeSelect v-model="model.applicantId" placeholder="输入姓名或工号搜索申请人" />
        </FormItem>
        <FormItem label="监护人" name="guardianId">
          <HrmEmployeeSelect v-model="model.guardianId" :placeholder="guardianRequired ? '动火/高压带电/有限空间必选' : '选填'" />
          <EmployeeSelect v-model="model.guardianId" :placeholder="guardianRequired ? '动火/高压带电/有限空间必选' : '选填'" />
        </FormItem>
        <FormItem label="作业内容与范围" name="workContent" class="col-span-full">
          <Input.TextArea v-model:value="model.workContent" :maxlength="2000" :rows="3" show-count placeholder="说明作业内容、涉及设备与作业范围" />
@@ -555,7 +555,7 @@
    <Modal v-model:open="approveOpen" title="作业票审批" :confirm-loading="saving" ok-text="提交审批" cancel-text="取消" @ok="saveApprove">
      <Form layout="vertical" class="mt-4">
        <FormItem label="审批人" required>
          <HrmEmployeeSelect v-model="approveModel.approverId" placeholder="从员工档案中选择审批人(不能与申请人相同)" />
          <EmployeeSelect v-model="approveModel.approverId" placeholder="输入姓名或工号搜索审批人(不能与申请人相同)" />
        </FormItem>
        <FormItem label="审批结论" required>
          <Select
@@ -614,7 +614,7 @@
              <div class="mb-2 text-sm font-semibold">添加监护记录</div>
              <Form layout="vertical">
                <FormItem label="监护人">
                  <HrmEmployeeSelect v-model="monitorForm.guardianId" placeholder="从员工档案中选择监护人" />
                  <EmployeeSelect v-model="monitorForm.guardianId" placeholder="输入姓名或工号搜索监护人" />
                </FormItem>
                <FormItem label="监护内容与情况">
                  <Input.TextArea v-model:value="monitorForm.monitorContent" :maxlength="1000" :rows="2" placeholder="记录监护时的现场情况" />
src/views/safety/training/index.vue
@@ -31,7 +31,7 @@
  getTrainingPage,
  updateTraining,
} from '#/api/safety';
import HrmEmployeeSelect from '#/views/hrm/employee/components/select.vue';
import EmployeeSelect from '#/views/hrm/employee/components/select-dropdown.vue';
import { TRAINING_TYPE_OPTIONS } from '../shared';
@@ -234,7 +234,7 @@
          <Input v-model:value="model.location" :maxlength="200" placeholder="如 ä¸‰æ¥¼åŸ¹è®­å®¤" />
        </FormItem>
        <FormItem label="讲师/组织人" name="trainerId">
          <HrmEmployeeSelect v-model="model.trainerId" placeholder="从员工档案中选择讲师/组织人" />
          <EmployeeSelect v-model="model.trainerId" placeholder="输入姓名或工号搜索讲师/组织人" />
        </FormItem>
        <FormItem label="参加人数" name="participantCount">
          <InputNumber v-model:value="model.participantCount" :min="0" style="width: 100%" placeholder="留空按名单自动统计" />
src/views/system/dept/data.ts
@@ -73,6 +73,8 @@
      label: '负责人',
      component: 'ApiSelect',
      componentProps: {
        showSearch: true,
        optionFilterProp: 'label',
        api: getSimpleUserList,
        labelField: 'nickname',
        valueField: 'id',
src/views/system/notify/template/data.ts
@@ -195,6 +195,8 @@
      label: '接收人',
      component: 'ApiSelect',
      componentProps: {
        showSearch: true,
        optionFilterProp: 'label',
        api: getSimpleUserList,
        labelField: 'nickname',
        valueField: 'id',
src/views/system/operatelog/data.ts
@@ -19,6 +19,8 @@
      label: '操作人',
      component: 'ApiSelect',
      componentProps: {
        showSearch: true,
        optionFilterProp: 'label',
        api: getSimpleUserList,
        labelField: 'nickname',
        valueField: 'id',
src/views/wls/packages/data.ts
@@ -87,6 +87,8 @@
      label: '检查员',
      component: 'ApiSelect',
      componentProps: {
        showSearch: true,
        optionFilterProp: 'label',
        allowClear: true,
        api: getSimpleUserList,
        labelField: 'nickname',
@@ -261,6 +263,8 @@
      label: '检查员',
      component: 'ApiSelect',
      componentProps: {
        showSearch: true,
        optionFilterProp: 'label',
        allowClear: true,
        api: getSimpleUserList,
        labelField: 'nickname',
@@ -572,6 +576,8 @@
      label: '检查员',
      component: 'ApiSelect',
      componentProps: {
        showSearch: true,
        optionFilterProp: 'label',
        allowClear: true,
        api: getSimpleUserList,
        labelField: 'nickname',
src/views/wls/stocktaking/task/data.ts
@@ -191,6 +191,8 @@
      label: '盘点人',
      component: 'ApiSelect',
      componentProps: {
        showSearch: true,
        optionFilterProp: 'label',
        allowClear: true,
        api: getSimpleUserList,
        labelField: 'nickname',