This commit is contained in:
fuenmao
2026-08-28 11:09:20 +08:00
parent d0d7ca8e69
commit 14515ccdd6
8 changed files with 1073 additions and 254 deletions
@@ -1,12 +1,60 @@
<template>
<div class="template-panel">
<div class="toolbar">
<el-input v-model="query.keyword" clearable placeholder="搜索模板编码或名称" class="keyword-input"
@keyup.enter="loadTemplates" />
<el-select v-model="query.companyId" clearable filterable placeholder="全部公司" class="company-filter">
<el-input
v-model="query.keyword"
clearable
placeholder="搜索模板编码或名称"
class="keyword-input"
@keyup.enter="loadTemplates"
@clear="loadTemplates"
/>
<el-select
v-model="query.companyId"
clearable
filterable
placeholder="全部公司"
class="company-filter"
@change="onQueryCompanyChange"
@clear="onQueryCompanyChange"
>
<el-option v-for="item in companies" :key="item.id" :label="item.companyName" :value="item.id" />
</el-select>
<el-button type="primary" @click="loadTemplates">查询</el-button>
<el-select
v-model="query.departmentId"
clearable
filterable
placeholder="全部部门"
class="department-filter"
@change="onQueryDepartmentChange"
@clear="onQueryDepartmentChange"
>
<el-option v-for="item in queryDepartments" :key="item.id" :label="item.departmentName" :value="item.id" />
</el-select>
<el-select
v-model="query.positionId"
clearable
filterable
placeholder="全部岗位"
class="position-filter"
@change="loadTemplates"
@clear="loadTemplates"
>
<el-option v-for="item in queryPositions" :key="item.id" :label="item.positionName" :value="item.id" />
</el-select>
<el-select
v-model="query.status"
clearable
placeholder="模板状态"
class="status-filter"
@change="loadTemplates"
@clear="loadTemplates"
>
<el-option label="全部状态" value="" />
<el-option label="启用" value="enable" />
<el-option label="停用" value="disable" />
</el-select>
<el-button type="primary" icon="Search" @click="loadTemplates">查询</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
<div class="toolbar-spacer" />
<el-button type="primary" icon="Plus" @click="openCreate">新增入职模板</el-button>
@@ -235,6 +283,7 @@ import {
OnboardingDepartmentOption,
OnboardingMaterialType,
OnboardingPosition,
OnboardingPositionOption,
OnboardingTemplate,
onboardingTaskApi
} from "@/api/modules/biz/onboarding";
@@ -246,6 +295,8 @@ const rows = ref<OnboardingTemplate[]>([]);
const total = ref(0);
const companies = ref<OnboardingCompany[]>([]);
const queryDepartments = ref<OnboardingDepartmentOption[]>([]);
const queryPositions = ref<OnboardingPositionOption[]>([]);
const departments = ref<OnboardingDepartmentOption[]>([]);
const positions = ref<OnboardingPosition[]>([]);
const contractTemplates = ref<OnboardingContractTemplate[]>([]);
@@ -255,6 +306,9 @@ const versionOptions = reactive<Record<number, OnboardingContractVersion[]>>({})
const query = reactive({
keyword: "",
companyId: undefined as number | undefined,
departmentId: undefined as number | undefined,
positionId: undefined as number | undefined,
status: "enable" as string | undefined,
pageNum: 1,
pageSize: 20
});
@@ -273,6 +327,30 @@ const form = reactive<OnboardingTemplate>({
materials: []
});
async function loadAllQueryOptions() {
if (!companies.value || companies.value.length === 0) return;
const deptList: OnboardingDepartmentOption[] = [];
const posList: OnboardingPositionOption[] = [];
const promises = companies.value.map(async comp => {
const [depRes, posRes] = await Promise.all([
onboardingTaskApi.listDepartments(comp.id).catch(() => ({ data: [] })),
onboardingTaskApi.listPositions(comp.id).catch(() => ({ data: [] }))
]);
if (depRes.data) deptList.push(...depRes.data);
if (posRes.data) posList.push(...posRes.data);
});
await Promise.all(promises);
const uniqueDeptMap = new Map<number, OnboardingDepartmentOption>();
deptList.forEach(d => uniqueDeptMap.set(d.id, d));
queryDepartments.value = Array.from(uniqueDeptMap.values());
const uniquePosMap = new Map<number, OnboardingPositionOption>();
posList.forEach(p => uniquePosMap.set(p.id, p));
queryPositions.value = Array.from(uniquePosMap.values());
}
async function loadBaseData() {
const [companyRes, materialRes] = await Promise.all([
onboardingTaskApi.companyPage({ pageNum: 1, pageSize: 100, status: "enable" }).catch(() => ({ data: { list: [] } })),
@@ -280,6 +358,7 @@ async function loadBaseData() {
]);
companies.value = companyRes.data?.list || [];
materialTypes.value = materialRes.data || [];
await loadAllQueryOptions();
}
async function loadTemplates() {
@@ -293,10 +372,61 @@ async function loadTemplates() {
}
}
async function onQueryCompanyChange(companyId?: number) {
query.departmentId = undefined;
query.positionId = undefined;
if (!companyId) {
await loadAllQueryOptions();
} else {
const [depRes, posRes] = await Promise.all([
onboardingTaskApi.listDepartments(companyId).catch(() => ({ data: [] })),
onboardingTaskApi.listPositions(companyId).catch(() => ({ data: [] }))
]);
queryDepartments.value = depRes.data || [];
queryPositions.value = (posRes.data || []).map(p => ({
id: p.id,
positionName: p.positionName,
companyId: companyId,
departmentId: p.departmentId
} as any));
}
loadTemplates();
}
async function onQueryDepartmentChange(departmentId?: number) {
query.positionId = undefined;
if (!departmentId) {
if (query.companyId) {
const posRes = await onboardingTaskApi.listPositions(query.companyId).catch(() => ({ data: [] }));
queryPositions.value = (posRes.data || []).map(p => ({
id: p.id,
positionName: p.positionName,
companyId: query.companyId!,
departmentId: p.departmentId
} as any));
} else {
await loadAllQueryOptions();
}
} else {
const posRes = await onboardingTaskApi.listPositionsByDepartment(departmentId).catch(() => ({ data: [] }));
queryPositions.value = (posRes.data || []).map(p => ({
id: p.id,
positionName: p.positionName,
companyId: p.companyId,
departmentId: departmentId
} as any));
}
loadTemplates();
}
function resetQuery() {
query.keyword = "";
query.companyId = undefined;
query.departmentId = undefined;
query.positionId = undefined;
query.status = "enable";
query.pageNum = 1;
loadAllQueryOptions();
loadTemplates();
}
@@ -521,7 +651,19 @@ onMounted(async () => {
}
.company-filter {
width: 180px;
width: 170px;
}
.department-filter {
width: 160px;
}
.position-filter {
width: 160px;
}
.status-filter {
width: 120px;
}
.toolbar-spacer {