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,服务正常
| | |
| | | ...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 ( |
| | |
| | | mode="multiple" |
| | | onUpdate:value={onUpdateModelValue as any} |
| | | value={modelValue as any} |
| | | {...searchProps} |
| | | {...restAttrs} |
| | | // TODO @xingyu remote 对çå®ç°, è¿æ¯è¯´æ²¡ä½ç¨ |
| | | // remote={props.remote} |
| | |
| | | loading={loading.value} |
| | | onUpdate:value={onUpdateModelValue as any} |
| | | value={modelValue as any} |
| | | {...searchProps} |
| | | {...restAttrs} |
| | | // TODO: @xingyu remote 对çå®ç°, è¿æ¯è¯´æ²¡ä½ç¨ |
| | | // remote={props.remote} |
| | |
| | | label: 'ç¨æ·ç¼å·', |
| | | component: 'ApiSelect', |
| | | componentProps: { |
| | | showSearch: true, |
| | | optionFilterProp: 'label', |
| | | api: getSimpleUserList, |
| | | labelField: 'nickname', |
| | | valueField: 'id', |
| | |
| | | label: 'ç¨æ·ç¼å·', |
| | | component: 'ApiSelect', |
| | | componentProps: { |
| | | showSearch: true, |
| | | optionFilterProp: 'label', |
| | | api: getSimpleUserList, |
| | | labelField: 'nickname', |
| | | valueField: 'id', |
| | |
| | | label: 'ç¨æ·ç¼å·', |
| | | component: 'ApiSelect', |
| | | componentProps: { |
| | | showSearch: true, |
| | | optionFilterProp: 'label', |
| | | api: getSimpleUserList, |
| | | labelField: 'nickname', |
| | | valueField: 'id', |
| | |
| | | label: 'ç¨æ·ç¼å·', |
| | | component: 'ApiSelect', |
| | | componentProps: { |
| | | showSearch: true, |
| | | optionFilterProp: 'label', |
| | | api: getSimpleUserList, |
| | | labelField: 'nickname', |
| | | valueField: 'id', |
| | |
| | | label: 'ç¨æ·ç¼å·', |
| | | component: 'ApiSelect', |
| | | componentProps: { |
| | | showSearch: true, |
| | | optionFilterProp: 'label', |
| | | api: getSimpleUserList, |
| | | labelField: 'nickname', |
| | | valueField: 'id', |
| | |
| | | disabled: (values) => values.id, |
| | | }, |
| | | componentProps: { |
| | | showSearch: true, |
| | | optionFilterProp: 'label', |
| | | api: getSimpleUserList, |
| | | labelField: 'nickname', |
| | | valueField: 'id', |
| | |
| | | label: 'è´è´£äºº', |
| | | component: 'ApiSelect', |
| | | componentProps: { |
| | | showSearch: true, |
| | | optionFilterProp: 'label', |
| | | api: getSimpleUserList, |
| | | labelField: 'nickname', |
| | | valueField: 'id', |
| | |
| | | disabled: (values) => values.id, |
| | | }, |
| | | componentProps: { |
| | | showSearch: true, |
| | | optionFilterProp: 'label', |
| | | api: getSimpleUserList, |
| | | labelField: 'nickname', |
| | | valueField: 'id', |
| | |
| | | label: 'è´è´£äºº', |
| | | component: 'ApiSelect', |
| | | componentProps: { |
| | | showSearch: true, |
| | | optionFilterProp: 'label', |
| | | api: getSimpleUserList, |
| | | labelField: 'nickname', |
| | | valueField: 'id', |
| | |
| | | disabled: (values) => values.id, |
| | | }, |
| | | componentProps: { |
| | | showSearch: true, |
| | | optionFilterProp: 'label', |
| | | api: getSimpleUserList, |
| | | labelField: 'nickname', |
| | | valueField: 'id', |
| | |
| | | label: 'è´è´£äºº', |
| | | component: 'ApiSelect', |
| | | componentProps: { |
| | | showSearch: true, |
| | | optionFilterProp: 'label', |
| | | api: getSimpleUserList, |
| | | labelField: 'nickname', |
| | | valueField: 'id', |
| | |
| | | label: 'è´è´£äºº', |
| | | component: 'ApiSelect', |
| | | componentProps: { |
| | | showSearch: true, |
| | | optionFilterProp: 'label', |
| | | api: getSimpleUserList, |
| | | labelField: 'nickname', |
| | | valueField: 'id', |
| | |
| | | disabled: (values) => !!values.id, |
| | | }, |
| | | componentProps: { |
| | | showSearch: true, |
| | | optionFilterProp: 'label', |
| | | api: getSimpleUserList, |
| | | labelField: 'nickname', |
| | | valueField: 'id', |
| | |
| | | label: 'éæ©äººå', |
| | | component: 'ApiSelect', |
| | | componentProps: { |
| | | showSearch: true, |
| | | optionFilterProp: 'label', |
| | | api: getSimpleUserList, |
| | | labelField: 'nickname', |
| | | valueField: 'id', |
| | |
| | | disabled: (values) => values.id, |
| | | }, |
| | | componentProps: { |
| | | showSearch: true, |
| | | optionFilterProp: 'label', |
| | | api: getSimpleUserList, |
| | | labelField: 'nickname', |
| | | valueField: 'id', |
| | |
| | | label: 'è´è´£äºº', |
| | | component: 'ApiSelect', |
| | | componentProps: { |
| | | showSearch: true, |
| | | optionFilterProp: 'label', |
| | | api: getSimpleUserList, |
| | | labelField: 'nickname', |
| | | valueField: 'id', |
| | |
| | | label: 'è´è´£äºº', |
| | | component: 'ApiSelect', |
| | | componentProps: { |
| | | showSearch: true, |
| | | optionFilterProp: 'label', |
| | | api: getSimpleUserList, |
| | | labelField: 'nickname', |
| | | valueField: 'id', |
| | |
| | | label: 'åå·¥', |
| | | component: 'ApiSelect', |
| | | componentProps: { |
| | | showSearch: true, |
| | | optionFilterProp: 'label', |
| | | api: getSimpleUserList, |
| | | labelField: 'nickname', |
| | | valueField: 'id', |
| | |
| | | label: 'åå·¥', |
| | | component: 'ApiSelect', |
| | | componentProps: { |
| | | showSearch: true, |
| | | optionFilterProp: 'label', |
| | | api: getSimpleUserList, |
| | | allowClear: true, |
| | | labelField: 'nickname', |
| | |
| | | label: 'åå·¥', |
| | | component: 'ApiSelect', |
| | | componentProps: { |
| | | showSearch: true, |
| | | optionFilterProp: 'label', |
| | | api: getSimpleUserList, |
| | | labelField: 'nickname', |
| | | valueField: 'id', |
| | |
| | | label: 'åå·¥', |
| | | component: 'ApiSelect', |
| | | componentProps: { |
| | | showSearch: true, |
| | | optionFilterProp: 'label', |
| | | api: getSimpleUserList, |
| | | labelField: 'nickname', |
| | | valueField: 'id', |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <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> |
| | |
| | | label: '交æ¥äºº', |
| | | component: 'ApiSelect', |
| | | componentProps: { |
| | | showSearch: true, |
| | | optionFilterProp: 'label', |
| | | api: getEmployeeSimpleList, |
| | | labelField: 'name', |
| | | valueField: 'id', |
| | |
| | | label: 'åå·¥', |
| | | component: 'ApiSelect', |
| | | componentProps: { |
| | | showSearch: true, |
| | | optionFilterProp: 'label', |
| | | api: getEmployeeSimpleList, |
| | | labelField: 'name', |
| | | valueField: 'id', |
| | |
| | | label: 'ç¹æ£äºº', |
| | | component: 'ApiSelect', |
| | | componentProps: { |
| | | showSearch: true, |
| | | optionFilterProp: 'label', |
| | | allowClear: true, |
| | | api: getSimpleUserList, |
| | | labelField: 'nickname', |
| | |
| | | label: 'ä¿å
»äºº', |
| | | component: 'ApiSelect', |
| | | componentProps: { |
| | | showSearch: true, |
| | | optionFilterProp: 'label', |
| | | allowClear: true, |
| | | api: getSimpleUserList, |
| | | labelField: 'nickname', |
| | |
| | | label: 'å¤ç½®äºº', |
| | | component: 'ApiSelect', |
| | | componentProps: { |
| | | showSearch: true, |
| | | optionFilterProp: 'label', |
| | | allowClear: true, |
| | | api: getSimpleUserList, |
| | | labelField: 'nickname', |
| | |
| | | label: 'å起人', |
| | | component: 'ApiSelect', |
| | | componentProps: { |
| | | showSearch: true, |
| | | optionFilterProp: 'label', |
| | | allowClear: true, |
| | | api: getSimpleUserList, |
| | | labelField: 'nickname', |
| | |
| | | label: 'å¤ç½®äºº', |
| | | component: 'ApiSelect', |
| | | componentProps: { |
| | | showSearch: true, |
| | | optionFilterProp: 'label', |
| | | allowClear: true, |
| | | api: getSimpleUserList, |
| | | labelField: 'nickname', |
| | |
| | | label: 'å起人', |
| | | component: 'ApiSelect', |
| | | componentProps: { |
| | | showSearch: true, |
| | | optionFilterProp: 'label', |
| | | allowClear: true, |
| | | api: getSimpleUserList, |
| | | labelField: 'nickname', |
| | |
| | | label: 'å¤ç½®äºº', |
| | | component: 'ApiSelect', |
| | | componentProps: { |
| | | showSearch: true, |
| | | optionFilterProp: 'label', |
| | | allowClear: true, |
| | | api: getSimpleUserList, |
| | | labelField: 'nickname', |
| | |
| | | label: 'ç¨æ·', |
| | | component: 'ApiSelect', |
| | | componentProps: { |
| | | showSearch: true, |
| | | optionFilterProp: 'label', |
| | | allowClear: true, |
| | | api: getSimpleUserList, |
| | | labelField: 'nickname', |
| | |
| | | label: 'æ£æµäººå', |
| | | component: 'ApiSelect', |
| | | componentProps: { |
| | | showSearch: true, |
| | | optionFilterProp: 'label', |
| | | allowClear: true, |
| | | api: getSimpleUserList, |
| | | labelField: 'nickname', |
| | |
| | | label: 'æ£æµäººå', |
| | | component: 'ApiSelect', |
| | | componentProps: { |
| | | showSearch: true, |
| | | optionFilterProp: 'label', |
| | | allowClear: true, |
| | | api: getSimpleUserList, |
| | | labelField: 'nickname', |
| | |
| | | label: 'æ£æµäººå', |
| | | component: 'ApiSelect', |
| | | componentProps: { |
| | | showSearch: true, |
| | | optionFilterProp: 'label', |
| | | allowClear: true, |
| | | api: getSimpleUserList, |
| | | labelField: 'nickname', |
| | |
| | | label: 'æ£æµäººå', |
| | | component: 'ApiSelect', |
| | | componentProps: { |
| | | showSearch: true, |
| | | optionFilterProp: 'label', |
| | | allowClear: true, |
| | | api: getSimpleUserList, |
| | | labelField: 'nickname', |
| | |
| | | label: 'å¤ç人', |
| | | component: 'ApiSelect', |
| | | componentProps: { |
| | | showSearch: true, |
| | | optionFilterProp: 'label', |
| | | allowClear: true, |
| | | api: getSimpleUserList, |
| | | labelField: 'nickname', |
| | |
| | | label: 'æ£æµäººå', |
| | | component: 'ApiSelect', |
| | | componentProps: { |
| | | showSearch: true, |
| | | optionFilterProp: 'label', |
| | | allowClear: true, |
| | | api: getSimpleUserList, |
| | | labelField: 'nickname', |
| | |
| | | label: 'æ£æµäººå', |
| | | component: 'ApiSelect', |
| | | componentProps: { |
| | | showSearch: true, |
| | | optionFilterProp: 'label', |
| | | allowClear: true, |
| | | api: getSimpleUserList, |
| | | labelField: 'nickname', |
| | |
| | | label: 'æ£æµäººå', |
| | | component: 'ApiSelect', |
| | | componentProps: { |
| | | showSearch: true, |
| | | optionFilterProp: 'label', |
| | | allowClear: true, |
| | | api: getSimpleUserList, |
| | | labelField: 'nickname', |
| | |
| | | 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'; |
| | | |
| | |
| | | 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> |
| | |
| | | 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'; |
| | | |
| | |
| | | <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%" /> |
| | |
| | | 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, |
| | |
| | | <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 |
| | |
| | | <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" /> |
| | |
| | | <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> |
| | |
| | | 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'; |
| | | |
| | |
| | | /> |
| | | </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 å·é
çµæ¿" /> |
| | |
| | | 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'; |
| | | |
| | |
| | | /> |
| | | </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" /> |
| | |
| | | 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'; |
| | | |
| | |
| | | <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" /> |
| | |
| | | } 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' }); |
| | | |
| | |
| | | /> |
| | | </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%" /> |
| | |
| | | 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, |
| | |
| | | <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="说æä½ä¸å
å®¹ãæ¶å设å¤ä¸ä½ä¸èå´" /> |
| | |
| | | <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 |
| | |
| | | <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="è®°å½çæ¤æ¶çç°åºæ
åµ" /> |
| | |
| | | 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'; |
| | | |
| | |
| | | <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="ç空æååèªå¨ç»è®¡" /> |
| | |
| | | label: 'è´è´£äºº', |
| | | component: 'ApiSelect', |
| | | componentProps: { |
| | | showSearch: true, |
| | | optionFilterProp: 'label', |
| | | api: getSimpleUserList, |
| | | labelField: 'nickname', |
| | | valueField: 'id', |
| | |
| | | label: 'æ¥æ¶äºº', |
| | | component: 'ApiSelect', |
| | | componentProps: { |
| | | showSearch: true, |
| | | optionFilterProp: 'label', |
| | | api: getSimpleUserList, |
| | | labelField: 'nickname', |
| | | valueField: 'id', |
| | |
| | | label: 'æä½äºº', |
| | | component: 'ApiSelect', |
| | | componentProps: { |
| | | showSearch: true, |
| | | optionFilterProp: 'label', |
| | | api: getSimpleUserList, |
| | | labelField: 'nickname', |
| | | valueField: 'id', |
| | |
| | | label: 'æ£æ¥å', |
| | | component: 'ApiSelect', |
| | | componentProps: { |
| | | showSearch: true, |
| | | optionFilterProp: 'label', |
| | | allowClear: true, |
| | | api: getSimpleUserList, |
| | | labelField: 'nickname', |
| | |
| | | label: 'æ£æ¥å', |
| | | component: 'ApiSelect', |
| | | componentProps: { |
| | | showSearch: true, |
| | | optionFilterProp: 'label', |
| | | allowClear: true, |
| | | api: getSimpleUserList, |
| | | labelField: 'nickname', |
| | |
| | | label: 'æ£æ¥å', |
| | | component: 'ApiSelect', |
| | | componentProps: { |
| | | showSearch: true, |
| | | optionFilterProp: 'label', |
| | | allowClear: true, |
| | | api: getSimpleUserList, |
| | | labelField: 'nickname', |
| | |
| | | label: 'çç¹äºº', |
| | | component: 'ApiSelect', |
| | | componentProps: { |
| | | showSearch: true, |
| | | optionFilterProp: 'label', |
| | | allowClear: true, |
| | | api: getSimpleUserList, |
| | | labelField: 'nickname', |