前端第一版

This commit is contained in:
fuenmao
2026-08-24 16:36:28 +08:00
parent 3c52039b5b
commit c6509a3545
11 changed files with 5413 additions and 1 deletions
+525
View File
@@ -0,0 +1,525 @@
<template>
<div class="main-box setup-container">
<el-tabs v-model="activeTab" class="setup-tabs">
<!-- 1. 入职公司管理 -->
<el-tab-pane label="入职公司" name="company">
<div class="table-wrapper">
<ProTable
ref="companyTable"
title="入职公司列表"
:columns="companyColumns"
:request-api="onboardingTaskApi.companyPage"
:search-col="5"
>
<template #tableHeader>
<el-button type="primary" icon="Plus" @click="openCompanyCreate">
新增入职公司
</el-button>
</template>
<template #status="scope">
<el-tag size="small" :type="scope.row.status === 'enable' ? 'success' : 'info'">
{{ scope.row.status === "enable" ? "启用" : "停用" }}
</el-tag>
</template>
<template #operation="scope">
<el-button link type="primary" icon="Edit" @click="openCompanyEdit(scope.row)">
编辑
</el-button>
<el-button link type="danger" icon="Delete" @click="removeCompany(scope.row)">
删除
</el-button>
</template>
</ProTable>
</div>
</el-tab-pane>
<!-- 2. 入职岗位管理 -->
<el-tab-pane label="入职岗位" name="position">
<div class="table-wrapper">
<ProTable
ref="positionTable"
title="入职岗位列表"
:columns="positionColumns"
:request-api="onboardingTaskApi.positionPage"
:search-col="5"
>
<template #tableHeader>
<el-button type="primary" icon="Plus" @click="openPositionCreate">
新增入职岗位
</el-button>
</template>
<template #companyId="scope">
<el-tag effect="plain" type="primary">
{{ getCompanyName(scope.row.companyId) }}
</el-tag>
</template>
<template #status="scope">
<el-tag size="small" :type="scope.row.status === 'enable' ? 'success' : 'info'">
{{ scope.row.status === "enable" ? "启用" : "停用" }}
</el-tag>
</template>
<template #operation="scope">
<el-button link type="primary" icon="Edit" @click="openPositionEdit(scope.row)">
编辑
</el-button>
<el-button link type="danger" icon="Delete" @click="removePosition(scope.row)">
删除
</el-button>
</template>
</ProTable>
</div>
</el-tab-pane>
</el-tabs>
<!-- 新增 / 编辑弹窗 -->
<el-dialog
v-model="dialogVisible"
:title="dialogTitle"
width="680px"
destroy-on-close
append-to-body
>
<el-form v-if="dialogKind === 'company'" :model="companyForm" label-width="140px">
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="公司编码" required>
<el-input v-model="companyForm.companyCode" placeholder="如:TECH_CORP" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="公司简称/名称" required>
<el-input v-model="companyForm.companyName" placeholder="如:总公司 / 科技分部" />
</el-form-item>
</el-col>
</el-row>
<el-form-item label="合同甲方全称" required>
<el-input v-model="companyForm.legalName" placeholder="用于合同填写的法定主体全称" />
</el-form-item>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="统一社会信用代码">
<el-input v-model="companyForm.unifiedSocialCreditCode" placeholder="18位统一信用代码" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="法定代表人">
<el-input v-model="companyForm.legalRepresentative" placeholder="法定代表人姓名" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="联系电话">
<el-input v-model="companyForm.contactPhone" placeholder="企业联系电话" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="状态" required>
<el-select v-model="companyForm.status" class="w-full">
<el-option label="启用" value="enable" />
<el-option label="停用" value="disable" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-form-item label="注册地址">
<el-input v-model="companyForm.registeredAddress" placeholder="企业法定注册地址" />
</el-form-item>
<el-form-item label="备注">
<el-input v-model="companyForm.remark" type="textarea" :rows="2" placeholder="备注信息" />
</el-form-item>
</el-form>
<el-form v-else :model="positionForm" label-width="140px">
<el-form-item label="所属公司" required>
<el-select v-model="positionForm.companyId" placeholder="请选择所属公司" filterable class="w-full">
<el-option
v-for="company in companies"
:key="company.id"
:label="company.companyName"
:value="company.id"
/>
</el-select>
</el-form-item>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="岗位编码" required>
<el-input v-model="positionForm.positionCode" placeholder="如:DEV_FRONTEND" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="岗位名称" required>
<el-input v-model="positionForm.positionName" placeholder="如:高级前端开发工程师" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="默认合同年限">
<el-input-number v-model="positionForm.defaultContractYears" :min="1" :max="20" class="w-full" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="默认试用期(月)">
<el-input-number v-model="positionForm.defaultProbationMonths" :min="0" :max="12" class="w-full" />
</el-form-item>
</el-col>
</el-row>
<el-form-item label="状态" required>
<el-select v-model="positionForm.status" class="w-full">
<el-option label="启用" value="enable" />
<el-option label="停用" value="disable" />
</el-select>
</el-form-item>
<el-form-item label="备注">
<el-input v-model="positionForm.remark" type="textarea" :rows="2" placeholder="备注信息" />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="save">保存</el-button>
</template>
</el-dialog>
</div>
</template>
<script setup lang="ts" name="onboardingSetup">
import { ref, reactive, computed, onMounted } from "vue";
import { ElMessage, ElMessageBox } from "element-plus";
import { Plus, Edit, Delete } from "@element-plus/icons-vue";
import {
onboardingTaskApi,
type OnboardingCompany,
type OnboardingCompanyOption,
type OnboardingPosition
} from "@/api/modules/biz/onboarding";
import type { ColumnProps, ProTableInstance, EnumProps } from "@/components/ProTable/interface";
const activeTab = ref("company");
const companyTable = ref<ProTableInstance>();
const positionTable = ref<ProTableInstance>();
const companies = ref<OnboardingCompanyOption[]>([]);
const companyOptions = computed<EnumProps[]>(() =>
companies.value.map(c => ({
label: c.companyName,
value: c.id
}))
);
const getCompanyName = (companyId?: number) => {
if (!companyId) return "-";
const found = companies.value.find(c => c.id === companyId);
return found ? found.companyName : String(companyId);
};
const dialogVisible = ref(false);
const dialogKind = ref<"company" | "position">("company");
const editing = ref(false);
const emptyCompany = (): Partial<OnboardingCompany> => ({
companyCode: "",
companyName: "",
legalName: "",
unifiedSocialCreditCode: "",
legalRepresentative: "",
registeredAddress: "",
contactPhone: "",
status: "enable",
remark: ""
});
const emptyPosition = (): Partial<OnboardingPosition> => ({
companyId: undefined,
positionCode: "",
positionName: "",
defaultContractYears: 3,
defaultProbationMonths: 3,
status: "enable",
remark: ""
});
const companyForm = reactive<Partial<OnboardingCompany>>(emptyCompany());
const positionForm = reactive<Partial<OnboardingPosition>>(emptyPosition());
const dialogTitle = computed(
() => `${editing.value ? "编辑" : "新增"}${dialogKind.value === "company" ? "入职公司" : "入职岗位"}`
);
const companyColumns: ColumnProps<OnboardingCompany>[] = [
{
prop: "companyCode",
label: "公司编码",
width: 140,
search: { el: "input" }
},
{
prop: "companyName",
label: "公司名称",
minWidth: 180,
search: { el: "input" }
},
{
prop: "legalName",
label: "合同甲方全称",
minWidth: 220
},
{
prop: "unifiedSocialCreditCode",
label: "统一社会信用代码",
minWidth: 180
},
{
prop: "legalRepresentative",
label: "法定代表人",
width: 120
},
{
prop: "contactPhone",
label: "联系电话",
width: 140
},
{
prop: "status",
label: "状态",
width: 100,
align: "center",
enum: [
{ label: "启用", value: "enable" },
{ label: "停用", value: "disable" }
],
search: { el: "select" }
},
{
prop: "operation",
label: "操作",
fixed: "right",
width: 160
}
];
const positionColumns: ColumnProps<OnboardingPosition>[] = [
{
prop: "companyId",
label: "所属公司",
minWidth: 200,
enum: companyOptions,
search: {
el: "select",
props: { filterable: true, placeholder: "请选择所属公司" }
}
},
{
prop: "positionCode",
label: "岗位编码",
width: 150,
search: { el: "input" }
},
{
prop: "positionName",
label: "岗位名称",
minWidth: 180,
search: { el: "input" }
},
{
prop: "defaultContractYears",
label: "默认合同年限",
width: 130,
align: "center",
render: scope => `${scope.row.defaultContractYears || 3} 年`
},
{
prop: "defaultProbationMonths",
label: "默认试用期",
width: 130,
align: "center",
render: scope => `${scope.row.defaultProbationMonths ?? 0} 个月`
},
{
prop: "status",
label: "状态",
width: 100,
align: "center",
enum: [
{ label: "启用", value: "enable" },
{ label: "停用", value: "disable" }
],
search: { el: "select" }
},
{
prop: "operation",
label: "操作",
fixed: "right",
width: 160
}
];
async function loadCompanies() {
const { data } = await onboardingTaskApi.listCompanies();
companies.value = data;
}
function resetCompany() {
Object.assign(companyForm, emptyCompany());
}
function resetPosition() {
Object.assign(positionForm, emptyPosition());
}
function openCompanyCreate() {
dialogKind.value = "company";
editing.value = false;
resetCompany();
dialogVisible.value = true;
}
function openPositionCreate() {
dialogKind.value = "position";
editing.value = false;
resetPosition();
dialogVisible.value = true;
}
async function openCompanyEdit(row: OnboardingCompany) {
const { data } = await onboardingTaskApi.companyDetail({ id: row.id });
dialogKind.value = "company";
editing.value = true;
Object.assign(companyForm, data);
dialogVisible.value = true;
}
async function openPositionEdit(row: OnboardingPosition) {
const { data } = await onboardingTaskApi.positionDetail({ id: row.id });
dialogKind.value = "position";
editing.value = true;
Object.assign(positionForm, data);
dialogVisible.value = true;
}
async function save() {
if (dialogKind.value === "company") {
if (!companyForm.companyCode || !companyForm.companyName || !companyForm.legalName) {
return ElMessage.warning("请填写公司编码、公司名称和合同甲方全称");
}
await onboardingTaskApi.saveCompany(companyForm, editing.value);
companyTable.value?.refresh();
await loadCompanies();
} else {
if (!positionForm.companyId || !positionForm.positionCode || !positionForm.positionName) {
return ElMessage.warning("请填写所属公司、岗位编码和岗位名称");
}
await onboardingTaskApi.savePosition(positionForm, editing.value);
positionTable.value?.refresh();
}
dialogVisible.value = false;
ElMessage.success("保存成功");
}
async function removeCompany(row: OnboardingCompany) {
await ElMessageBox.confirm(`确认删除公司“${row.companyName}”?`, "删除确认", { type: "warning" });
await onboardingTaskApi.deleteCompany([row.id]);
companyTable.value?.refresh();
await loadCompanies();
}
async function removePosition(row: OnboardingPosition) {
await ElMessageBox.confirm(`确认删除岗位“${row.positionName}”?`, "删除确认", { type: "warning" });
await onboardingTaskApi.deletePosition([row.id]);
positionTable.value?.refresh();
}
onMounted(loadCompanies);
</script>
<style scoped>
.setup-container {
height: 100%;
display: flex;
flex-direction: column;
box-sizing: border-box;
padding: 0 !important;
background: transparent !important;
}
.setup-tabs {
height: 100%;
display: flex;
flex-direction: column;
background: transparent;
}
.setup-tabs :deep(.el-tabs__header) {
background: #fff;
padding: 10px 16px 0;
margin: 0 0 10px 0;
border-radius: 8px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
}
.setup-tabs :deep(.el-tabs__content) {
flex: 1;
height: 0;
overflow: hidden;
}
.setup-tabs :deep(.el-tab-pane) {
height: 100%;
display: flex;
flex-direction: column;
}
.table-wrapper {
height: 100%;
width: 100%;
display: flex;
flex-direction: column;
}
.table-wrapper :deep(.table-search) {
margin-bottom: 12px !important;
border-radius: 8px;
}
.table-wrapper :deep(.table-search .search-isOpen) {
display: none !important;
}
.table-wrapper :deep(.table-search .el-form-item) {
margin-bottom: 0 !important;
}
.table-wrapper :deep(.table-search .el-select),
.table-wrapper :deep(.table-search .el-input) {
max-width: 200px !important;
}
.table-wrapper :deep(.table-main) {
border-radius: 8px;
}
.w-full {
width: 100%;
}
</style>