|
|
@@ -57,6 +57,7 @@
|
|
|
>
|
|
|
<el-table-column align="left" label="员工编号" prop="员工编号" min-width="120" />
|
|
|
<el-table-column align="left" label="员工姓名" prop="员工姓名" min-width="120" />
|
|
|
+ <el-table-column align="left" label="小组名称" prop="小组名称" min-width="120" />
|
|
|
<el-table-column align="left" label="职位" prop="职位" min-width="100" />
|
|
|
<el-table-column label="操作" width="188" align="center" fixed="right">
|
|
|
<template #default="{ row }">
|
|
|
@@ -78,13 +79,15 @@
|
|
|
<el-dialog
|
|
|
v-model="addMemberVisible"
|
|
|
title="小组新增成员"
|
|
|
- width="480px"
|
|
|
+ width="860px"
|
|
|
align-center
|
|
|
destroy-on-close
|
|
|
append-to-body
|
|
|
+ class="group-add-member-dialog"
|
|
|
@closed="resetAddMemberForm"
|
|
|
>
|
|
|
- <el-form :model="addMemberForm" label-width="100px" class="add-member-form">
|
|
|
+ <div class="add-member-dialog-split">
|
|
|
+ <el-form :model="addMemberForm" label-width="100px" class="add-member-form add-member-left">
|
|
|
<el-form-item label="生产工序" required>
|
|
|
<el-select
|
|
|
v-model="addMemberForm['生产工序']"
|
|
|
@@ -116,31 +119,31 @@
|
|
|
</el-select>
|
|
|
</el-form-item>
|
|
|
<el-form-item label="选择人员" required>
|
|
|
- <el-select
|
|
|
- v-model="addMemberStaffId"
|
|
|
- class="add-member-select"
|
|
|
- filterable
|
|
|
- remote
|
|
|
- reserve-keyword
|
|
|
- clearable
|
|
|
- placeholder="输入员工编号或姓名搜索并选择"
|
|
|
- :remote-method="searchStaffForAdd"
|
|
|
- :loading="staffPickerLoading"
|
|
|
- @change="onAddMemberStaffPick"
|
|
|
- >
|
|
|
- <el-option
|
|
|
- v-for="s in mergedStaffOptions"
|
|
|
- :key="staffRowKey(s)"
|
|
|
- :label="formatStaffOptionLabel(s)"
|
|
|
- :value="staffRowId(s)"
|
|
|
- />
|
|
|
- </el-select>
|
|
|
- </el-form-item>
|
|
|
- <el-form-item label="员工编号">
|
|
|
- <el-input :model-value="addMemberForm['员工编号']" readonly placeholder="选择人员后显示" />
|
|
|
- </el-form-item>
|
|
|
- <el-form-item label="员工姓名">
|
|
|
- <el-input :model-value="addMemberForm['员工姓名']" readonly placeholder="选择人员后显示" />
|
|
|
+ <div class="add-member-pick-row">
|
|
|
+ <el-select
|
|
|
+ v-model="addMemberStaffIds"
|
|
|
+ class="add-member-select"
|
|
|
+ multiple
|
|
|
+ collapse-tags
|
|
|
+ collapse-tags-tooltip
|
|
|
+ filterable
|
|
|
+ remote
|
|
|
+ clearable
|
|
|
+ placeholder="输入员工编号或姓名搜索,选中后自动加入"
|
|
|
+ :remote-method="searchStaffForAdd"
|
|
|
+ :loading="staffPickerLoading"
|
|
|
+ @visible-change="onAddMemberStaffDropdownVisible"
|
|
|
+ @change="onAddMemberStaffPick"
|
|
|
+ >
|
|
|
+ <template #tag></template>
|
|
|
+ <el-option
|
|
|
+ v-for="s in mergedStaffOptions"
|
|
|
+ :key="staffRowKey(s)"
|
|
|
+ :label="formatStaffOptionLabel(s)"
|
|
|
+ :value="staffRowId(s)"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ </div>
|
|
|
</el-form-item>
|
|
|
<el-form-item label="职位">
|
|
|
<el-select v-model="addMemberForm['职位']" placeholder="请选择职位" clearable class="add-member-select">
|
|
|
@@ -148,6 +151,42 @@
|
|
|
</el-select>
|
|
|
</el-form-item>
|
|
|
</el-form>
|
|
|
+ <div class="add-member-right">
|
|
|
+ <div class="picked-title">已选人员({{ selectedStaffRows.length }})</div>
|
|
|
+ <div v-if="selectedStaffRows.length" class="picked-staff-table-wrap">
|
|
|
+ <el-table
|
|
|
+ :data="selectedStaffRows"
|
|
|
+ size="small"
|
|
|
+ border
|
|
|
+ height="360"
|
|
|
+ class="picked-staff-table"
|
|
|
+ >
|
|
|
+ <el-table-column label="员工编号" min-width="92" show-overflow-tooltip>
|
|
|
+ <template #default="{ row }">
|
|
|
+ {{ row['员工编号'] ?? row.staff_no ?? '' }}
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="员工姓名" min-width="92" show-overflow-tooltip>
|
|
|
+ <template #default="{ row }">
|
|
|
+ {{ row['员工姓名'] ?? row.staff_name ?? '' }}
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="操作" width="58" align="center">
|
|
|
+ <template #default="{ row }">
|
|
|
+ <el-button
|
|
|
+ link
|
|
|
+ type="danger"
|
|
|
+ @click="removePickedStaff(staffRowId(row))"
|
|
|
+ >
|
|
|
+ 删除
|
|
|
+ </el-button>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+ </div>
|
|
|
+ <div v-else class="picked-staff-empty">暂未选择人员</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
<template #footer>
|
|
|
<el-button @click="addMemberVisible = false">取消</el-button>
|
|
|
<el-button type="primary" :loading="addMemberSubmitting" @click="submitAddMember">确定</el-button>
|
|
|
@@ -268,11 +307,12 @@ function parseTeamStaffRowsFromApi(res) {
|
|
|
const list = Array.isArray(team.staff_list) ? team.staff_list : []
|
|
|
const gid = team['小组ID'] ?? team.team_id
|
|
|
const gxTeam = String(team['生产工序'] ?? team.big_process ?? '').trim()
|
|
|
- const nameTeam = String(team['设备编组'] ?? team.team_name ?? '').trim()
|
|
|
+ const nameTeam = String(team['小组名称'] ?? team['设备编组'] ?? team.team_name ?? '').trim()
|
|
|
for (const s of list) {
|
|
|
idx += 1
|
|
|
const ybh = s['员工编号'] ?? s.staff_no
|
|
|
const sid = s.id ?? s.ID ?? s.staff_id
|
|
|
+ const rowTeamName = String(s['小组名称'] ?? s.team_name ?? nameTeam).trim()
|
|
|
rows.push({
|
|
|
_rowKey: `${gid ?? 't'}-${ybh ?? idx}-${idx}`,
|
|
|
id: sid,
|
|
|
@@ -280,7 +320,8 @@ function parseTeamStaffRowsFromApi(res) {
|
|
|
员工姓名: s['员工姓名'] ?? s.staff_name,
|
|
|
职位: s['职位'] ?? s.position,
|
|
|
生产工序: gxTeam,
|
|
|
- 设备编组: nameTeam,
|
|
|
+ 小组名称: rowTeamName,
|
|
|
+ 设备编组: rowTeamName,
|
|
|
})
|
|
|
}
|
|
|
}
|
|
|
@@ -364,10 +405,10 @@ const addMemberForm = reactive({
|
|
|
})
|
|
|
|
|
|
/** 新增成员:getStaffList 远程搜索选人 */
|
|
|
-const addMemberStaffId = ref(null)
|
|
|
+const addMemberStaffIds = ref([])
|
|
|
const staffPickerLoading = ref(false)
|
|
|
const staffPickerOptions = ref([])
|
|
|
-const selectedStaffRow = ref(null)
|
|
|
+const selectedStaffRows = ref([])
|
|
|
let staffSearchTimer = null
|
|
|
|
|
|
const staffRowId = (s) => s?.id ?? s?.ID
|
|
|
@@ -379,8 +420,7 @@ const mergedStaffOptions = computed(() => {
|
|
|
const id = staffRowId(s)
|
|
|
if (id != null && id !== '') map.set(id, s)
|
|
|
}
|
|
|
- const sel = selectedStaffRow.value
|
|
|
- if (sel) {
|
|
|
+ for (const sel of selectedStaffRows.value) {
|
|
|
const id = staffRowId(sel)
|
|
|
if (id != null && id !== '' && !map.has(id)) map.set(id, sel)
|
|
|
}
|
|
|
@@ -393,56 +433,68 @@ const formatStaffOptionLabel = (s) => {
|
|
|
return `${a} ${b}`.trim() || String(staffRowId(s) ?? '')
|
|
|
}
|
|
|
|
|
|
+const fetchStaffOptionsForAdd = async (query = '') => {
|
|
|
+ staffPickerLoading.value = true
|
|
|
+ try {
|
|
|
+ const res = await getStaffList({
|
|
|
+ search: String(query ?? '').trim(),
|
|
|
+ page: 1,
|
|
|
+ limit: 30,
|
|
|
+ })
|
|
|
+ if (res?.code === 0) {
|
|
|
+ staffPickerOptions.value = res.data?.list ?? []
|
|
|
+ } else {
|
|
|
+ staffPickerOptions.value = []
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ console.error(e)
|
|
|
+ staffPickerOptions.value = []
|
|
|
+ } finally {
|
|
|
+ staffPickerLoading.value = false
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const onAddMemberStaffDropdownVisible = async (visible) => {
|
|
|
+ if (!visible) return
|
|
|
+ if (staffPickerOptions.value.length > 0) return
|
|
|
+ await fetchStaffOptionsForAdd('')
|
|
|
+}
|
|
|
+
|
|
|
const searchStaffForAdd = (query) => {
|
|
|
if (staffSearchTimer) clearTimeout(staffSearchTimer)
|
|
|
const q = String(query ?? '').trim()
|
|
|
if (!q) {
|
|
|
- staffPickerOptions.value = []
|
|
|
+ fetchStaffOptionsForAdd('')
|
|
|
return
|
|
|
}
|
|
|
staffSearchTimer = setTimeout(async () => {
|
|
|
- staffPickerLoading.value = true
|
|
|
- try {
|
|
|
- const res = await getStaffList({
|
|
|
- search: q,
|
|
|
- page: 1,
|
|
|
- limit: 50,
|
|
|
- })
|
|
|
- if (res?.code === 0) {
|
|
|
- staffPickerOptions.value = res.data?.list ?? []
|
|
|
- } else {
|
|
|
- staffPickerOptions.value = []
|
|
|
- }
|
|
|
- } catch (e) {
|
|
|
- console.error(e)
|
|
|
- staffPickerOptions.value = []
|
|
|
- } finally {
|
|
|
- staffPickerLoading.value = false
|
|
|
- }
|
|
|
+ await fetchStaffOptionsForAdd(q)
|
|
|
}, 300)
|
|
|
}
|
|
|
|
|
|
-const onAddMemberStaffPick = (id) => {
|
|
|
- if (id === null || id === undefined || id === '') {
|
|
|
- selectedStaffRow.value = null
|
|
|
- addMemberForm['员工编号'] = ''
|
|
|
- addMemberForm['员工姓名'] = ''
|
|
|
+const onAddMemberStaffPick = (pickedIds) => {
|
|
|
+ const ids = Array.isArray(pickedIds) ? pickedIds : []
|
|
|
+ if (ids.length === 0) {
|
|
|
+ selectedStaffRows.value = []
|
|
|
return
|
|
|
}
|
|
|
- const row = mergedStaffOptions.value.find((x) => staffRowId(x) === id)
|
|
|
- selectedStaffRow.value = row || null
|
|
|
- if (row) {
|
|
|
- addMemberForm['员工编号'] = String(row['员工编号'] ?? '')
|
|
|
- addMemberForm['员工姓名'] = String(row['员工姓名'] ?? '')
|
|
|
- } else {
|
|
|
- addMemberForm['员工编号'] = ''
|
|
|
- addMemberForm['员工姓名'] = ''
|
|
|
+ const byId = new Map(mergedStaffOptions.value.map((x) => [staffRowId(x), x]))
|
|
|
+ const rows = []
|
|
|
+ for (const id of ids) {
|
|
|
+ const row = byId.get(id)
|
|
|
+ if (row) rows.push(row)
|
|
|
}
|
|
|
+ selectedStaffRows.value = rows
|
|
|
+}
|
|
|
+
|
|
|
+const removePickedStaff = (id) => {
|
|
|
+ selectedStaffRows.value = selectedStaffRows.value.filter((s) => staffRowId(s) !== id)
|
|
|
+ addMemberStaffIds.value = addMemberStaffIds.value.filter((x) => x !== id)
|
|
|
}
|
|
|
|
|
|
const resetStaffPicker = () => {
|
|
|
- addMemberStaffId.value = null
|
|
|
- selectedStaffRow.value = null
|
|
|
+ addMemberStaffIds.value = []
|
|
|
+ selectedStaffRows.value = []
|
|
|
staffPickerOptions.value = []
|
|
|
if (staffSearchTimer) {
|
|
|
clearTimeout(staffSearchTimer)
|
|
|
@@ -793,26 +845,47 @@ const submitAddMember = async () => {
|
|
|
return
|
|
|
}
|
|
|
syncUniqIdFromAddForm()
|
|
|
- const ybh = String(addMemberForm['员工编号'] ?? '').trim()
|
|
|
- const xm = String(addMemberForm['员工姓名'] ?? '').trim()
|
|
|
- const staffId = addMemberStaffId.value
|
|
|
- if (!ybh || !xm || staffId === null || staffId === undefined || staffId === '') {
|
|
|
- ElMessage.warning('请先搜索并选择人员')
|
|
|
+ const picked = selectedStaffRows.value
|
|
|
+ if (!Array.isArray(picked) || picked.length === 0) {
|
|
|
+ ElMessage.warning('请先搜索并选择人员(可多选)')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const dedupByNo = new Map()
|
|
|
+ for (const row of picked) {
|
|
|
+ const ybh = String(row?.['员工编号'] ?? row?.staff_no ?? '').trim()
|
|
|
+ const xm = String(row?.['员工姓名'] ?? row?.staff_name ?? '').trim()
|
|
|
+ if (!ybh || !xm) continue
|
|
|
+ if (!dedupByNo.has(ybh)) dedupByNo.set(ybh, { ybh, xm })
|
|
|
+ }
|
|
|
+ const staffList = Array.from(dedupByNo.values())
|
|
|
+ if (staffList.length === 0) {
|
|
|
+ ElMessage.warning('所选人员缺少员工编号或姓名,请重新选择')
|
|
|
return
|
|
|
}
|
|
|
addMemberSubmitting.value = true
|
|
|
try {
|
|
|
- const res = await AddTeamStaff({
|
|
|
- team_id: addMemberForm.UniqId,
|
|
|
- big_process: gx,
|
|
|
- team_name: team,
|
|
|
- staff_no: ybh,
|
|
|
- staff_name: xm,
|
|
|
- position: addMemberForm['职位'] || '',
|
|
|
- sys_id: userStore.userInfo?.nickName ?? '',
|
|
|
- })
|
|
|
- if (res?.code === 0) {
|
|
|
- ElMessage.success(res?.msg || '新增成功')
|
|
|
+ const reqs = staffList.map((s) =>
|
|
|
+ AddTeamStaff({
|
|
|
+ team_id: addMemberForm.UniqId,
|
|
|
+ big_process: gx,
|
|
|
+ team_name: team,
|
|
|
+ staff_no: s.ybh,
|
|
|
+ staff_name: s.xm,
|
|
|
+ position: addMemberForm['职位'] || '',
|
|
|
+ sys_id: userStore.userInfo?.nickName ?? '',
|
|
|
+ })
|
|
|
+ )
|
|
|
+ const results = await Promise.allSettled(reqs)
|
|
|
+ let ok = 0
|
|
|
+ let fail = 0
|
|
|
+ for (const r of results) {
|
|
|
+ if (r.status === 'fulfilled' && r.value?.code === 0) ok += 1
|
|
|
+ else fail += 1
|
|
|
+ }
|
|
|
+ if (ok > 0) {
|
|
|
+ ElMessage.success(
|
|
|
+ fail > 0 ? `批量新增完成:成功 ${ok} 人,失败 ${fail} 人` : `批量新增成功:共 ${ok} 人`
|
|
|
+ )
|
|
|
addMemberVisible.value = false
|
|
|
if (globalSearchMode.value) {
|
|
|
const q = (staffSearchInput.value || '').trim()
|
|
|
@@ -826,7 +899,7 @@ const submitAddMember = async () => {
|
|
|
}
|
|
|
} catch (e) {
|
|
|
console.error(e)
|
|
|
- ElMessage.error('新增失败')
|
|
|
+ ElMessage.error('批量新增失败')
|
|
|
} finally {
|
|
|
addMemberSubmitting.value = false
|
|
|
}
|
|
|
@@ -1067,9 +1140,75 @@ onMounted(() => {
|
|
|
.add-member-form :deep(.el-select) {
|
|
|
width: 100%;
|
|
|
}
|
|
|
+.add-member-dialog-split {
|
|
|
+ display: flex;
|
|
|
+ gap: 16px;
|
|
|
+}
|
|
|
+.add-member-left {
|
|
|
+ flex: 0 0 58%;
|
|
|
+ min-width: 0;
|
|
|
+}
|
|
|
+.add-member-right {
|
|
|
+ flex: 1;
|
|
|
+ min-width: 300px;
|
|
|
+ border: 1px solid var(--el-border-color-lighter);
|
|
|
+ border-radius: 6px;
|
|
|
+ padding: 10px;
|
|
|
+ box-sizing: border-box;
|
|
|
+ background: var(--el-fill-color-extra-light);
|
|
|
+}
|
|
|
+.picked-title {
|
|
|
+ margin-bottom: 8px;
|
|
|
+ font-size: 13px;
|
|
|
+ font-weight: 600;
|
|
|
+}
|
|
|
.add-member-select {
|
|
|
width: 100%;
|
|
|
}
|
|
|
+.add-member-pick-row {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 8px;
|
|
|
+ width: 100%;
|
|
|
+}
|
|
|
+.add-member-pick-row .add-member-select {
|
|
|
+ flex: 1;
|
|
|
+ min-width: 0;
|
|
|
+}
|
|
|
+.add-member-pick-row :deep(.el-select__wrapper) {
|
|
|
+ min-height: 32px;
|
|
|
+}
|
|
|
+.add-member-pick-row :deep(.el-select__input) {
|
|
|
+ min-width: 120px;
|
|
|
+}
|
|
|
+.picked-staff-table-wrap {
|
|
|
+ margin-top: 0;
|
|
|
+ height: 360px;
|
|
|
+ border: 1px solid var(--el-border-color-lighter);
|
|
|
+ border-radius: 4px;
|
|
|
+ padding: 0;
|
|
|
+ box-sizing: border-box;
|
|
|
+ background: var(--el-fill-color-blank);
|
|
|
+ overflow: hidden;
|
|
|
+}
|
|
|
+.picked-staff-table :deep(.el-table__header th.el-table__cell) {
|
|
|
+ padding: 4px 0;
|
|
|
+}
|
|
|
+.picked-staff-table :deep(.el-table__body td.el-table__cell) {
|
|
|
+ padding: 4px 0;
|
|
|
+}
|
|
|
+.picked-staff-empty {
|
|
|
+ margin-top: 0;
|
|
|
+ height: 360px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ padding: 0 10px;
|
|
|
+ border: 1px dashed var(--el-border-color);
|
|
|
+ border-radius: 4px;
|
|
|
+ color: var(--el-text-color-placeholder);
|
|
|
+ box-sizing: border-box;
|
|
|
+}
|
|
|
.change-team-hint {
|
|
|
margin: 0 0 14px;
|
|
|
font-size: 13px;
|
|
|
@@ -1080,3 +1219,17 @@ onMounted(() => {
|
|
|
margin-left: 8px;
|
|
|
}
|
|
|
</style>
|
|
|
+
|
|
|
+<style>
|
|
|
+/* 小组新增成员:固定弹窗高度,内容超出时在 body 内滚动 */
|
|
|
+.group-add-member-dialog .el-dialog {
|
|
|
+ height: 540px;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+}
|
|
|
+.group-add-member-dialog .el-dialog__body {
|
|
|
+ flex: 1;
|
|
|
+ min-height: 0;
|
|
|
+ overflow-y: auto;
|
|
|
+}
|
|
|
+</style>
|