前端第一版

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
+975
View File
@@ -0,0 +1,975 @@
<template>
<div class="table-box">
<ProTable
ref="templateTable"
title="合同模板列表"
:columns="templateColumns"
:request-api="onboardingTaskApi.templatePage"
>
<template #tableHeader>
<el-button type="primary" icon="Plus" @click="openTemplateCreate">
新增合同模板
</el-button>
</template>
<template #contractType="scope">
<el-tag effect="plain" type="primary">
{{ scope.row.contractType }}
</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="Files" @click="openManagementDrawer(scope.row)">
版本与配置
</el-button>
<el-button link type="primary" icon="Edit" @click="openTemplateEdit(scope.row)">
编辑
</el-button>
<el-button link type="danger" icon="Delete" @click="removeTemplate(scope.row)">
删除
</el-button>
</template>
</ProTable>
<!-- 新增 / 编辑合同模板基础信息弹窗 -->
<el-dialog
v-model="templateVisible"
:title="templateEditing ? '编辑合同模板' : '新增合同模板'"
width="580px"
destroy-on-close
append-to-body
>
<el-form :model="templateForm" label-width="110px">
<el-form-item label="模板编码" required>
<el-input v-model="templateForm.templateCode" placeholder="如:LABOR_CONTRACT" />
</el-form-item>
<el-form-item label="模板名称" required>
<el-input v-model="templateForm.templateName" placeholder="如:标准全职劳动合同" />
</el-form-item>
<el-form-item label="合同类型" required>
<el-input v-model="templateForm.contractType" placeholder="如:劳动合同、保密协议、竞业协议" />
</el-form-item>
<el-form-item label="状态" required>
<el-select v-model="templateForm.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="templateForm.description" type="textarea" :rows="3" placeholder="合同模板适用说明或签署注意事项" />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="templateVisible = false">取消</el-button>
<el-button type="primary" @click="saveTemplate">保存</el-button>
</template>
</el-dialog>
<!-- 一站式合同版本与配置大抽屉 -->
<el-drawer
v-model="drawerVisible"
:title="`合同模板管理 · ${selectedTemplate?.templateName || ''}`"
size="960px"
destroy-on-close
>
<div v-if="selectedTemplate" class="drawer-content-box">
<!-- 头部简要卡片 -->
<div class="template-header-card">
<div class="header-left">
<div class="template-title-row">
<span class="template-title">{{ selectedTemplate.templateName }}</span>
<el-tag type="primary">{{ selectedTemplate.contractType }}</el-tag>
<el-tag :type="selectedTemplate.status === 'enable' ? 'success' : 'info'">
{{ selectedTemplate.status === 'enable' ? '启用中' : '已停用' }}
</el-tag>
</div>
<div class="template-meta-row">
<span>模板编码:<code>{{ selectedTemplate.templateCode }}</code></span>
<span v-if="selectedTemplate.description">说明:{{ selectedTemplate.description }}</span>
</div>
</div>
</div>
<el-tabs v-model="drawerActiveTab" class="management-tabs">
<!-- 1. 版本与 DOCX 模板管理 -->
<el-tab-pane label="版本与DOCX模板" name="versions">
<div class="tab-pane-content">
<div class="pane-action-bar">
<el-button type="primary" icon="Upload" @click="openVersionCreate">
上传新版本 DOCX
</el-button>
<span class="pane-tip-text">
支持多版本迭代。启用某个版本后,该版本的 DOCX 将用于生成新入职员工的合同。
</span>
</div>
<el-table :data="versions" border stripe class="mt-3">
<el-table-column prop="versionNo" label="版本号" width="130" align="center">
<template #default="scope">
<span class="font-bold">{{ scope.row.versionNo }}</span>
</template>
</el-table-column>
<el-table-column prop="versionStatus" label="状态" width="100" align="center">
<template #default="scope">
<el-tag size="small" :type="versionType(scope.row.versionStatus)">
{{ versionText(scope.row.versionStatus) }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="effectiveDate" label="生效日期" width="130" align="center" />
<el-table-column prop="expiryDate" label="失效日期" width="130" align="center" />
<el-table-column prop="remark" label="版本说明" min-width="150" />
<el-table-column label="操作" width="280" fixed="right">
<template #default="scope">
<el-button
link
type="primary"
icon="Setting"
@click="openVariables(scope.row)"
>
变量
</el-button>
<el-button
link
type="primary"
icon="Download"
@click="downloadDocx(scope.row.sourceDocxFileId)"
>
下载源文件
</el-button>
<el-button
v-if="scope.row.versionStatus !== 'enabled'"
link
type="success"
icon="Check"
@click="changeVersionStatus(scope.row, 'enabled')"
>
启用
</el-button>
<el-button
v-else
link
type="warning"
icon="Close"
@click="changeVersionStatus(scope.row, 'disabled')"
>
停用
</el-button>
</template>
</el-table-column>
</el-table>
</div>
</el-tab-pane>
<!-- 2. 适用范围配置 -->
<el-tab-pane label="适用范围 (公司与岗位)" name="scopes">
<div class="tab-pane-content">
<el-card shadow="never" class="scope-add-card">
<template #header>
<span class="font-bold">为公司/岗位分配此合同模板</span>
</template>
<el-form :model="scopeForm" inline class="scope-inline-form">
<el-form-item label="所属公司" required>
<el-select
v-model="scopeForm.companyId"
placeholder="请选择公司"
filterable
style="width: 200px"
@change="onScopeCompanyChange"
>
<el-option
v-for="company in companies"
:key="company.id"
:label="company.companyName"
:value="company.id"
/>
</el-select>
</el-form-item>
<el-form-item label="适用岗位">
<el-select
v-model="scopeForm.positionId"
placeholder="全公司所有岗位"
clearable
style="width: 200px"
>
<el-option
v-for="position in scopePositions"
:key="position.id"
:label="position.positionName"
:value="position.id"
/>
</el-select>
</el-form-item>
<el-form-item label="绑定版本" required>
<el-select
v-model="scopeForm.templateVersionId"
placeholder="请选择合同版本"
style="width: 180px"
>
<el-option
v-for="ver in enabledVersions"
:key="ver.id"
:label="`版本 ${ver.versionNo}`"
:value="ver.id"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Plus" @click="saveScope">
添加适用范围
</el-button>
</el-form-item>
</el-form>
</el-card>
<el-table :data="scopes" border stripe class="mt-4">
<el-table-column label="所属公司" min-width="180">
<template #default="scope">
<el-tag effect="plain" type="primary">
{{ companyName(scope.row.companyId) }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="适用岗位" min-width="180">
<template #default="scope">
{{ positionName(scope.row.positionId) }}
</template>
</el-table-column>
<el-table-column label="生效版本" width="140" align="center">
<template #default="scope">
<el-tag size="small" type="success">
版本 {{ versionName(scope.row.templateVersionId) }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="110" align="center">
<template #default="scope">
<el-button link type="danger" icon="Delete" @click="removeScope(scope.row)">
移除
</el-button>
</template>
</el-table-column>
</el-table>
</div>
</el-tab-pane>
</el-tabs>
</div>
<template #footer>
<el-button @click="drawerVisible = false">关闭</el-button>
</template>
</el-drawer>
<!-- 上传合同 DOCX 版本弹窗 -->
<el-dialog
v-model="versionVisible"
title="上传新版本 DOCX"
width="600px"
destroy-on-close
append-to-body
>
<el-alert
title="仅支持 .docx 文件。请在 Word 文档中使用 {{变量编码}}(如 {{EmployeeName}}、{{Salary}})作为占位符。"
type="info"
:closable="false"
style="margin-bottom: 16px"
/>
<el-form :model="versionForm" label-width="120px">
<el-form-item label="版本编号" required>
<el-input v-model="versionForm.versionNo" placeholder="如:v2026.01" />
</el-form-item>
<el-form-item label="DOCX源文件" required>
<el-upload
:http-request="uploadDocx"
:before-upload="beforeDocxUpload"
:show-file-list="false"
accept=".docx"
>
<el-button type="primary" plain icon="Upload">
{{ versionForm.sourceDocxFileId ? '重新选择DOCX文件' : '选择并上传DOCX' }}
</el-button>
</el-upload>
<div v-if="versionForm.sourceDocxFileId" class="file-uploaded-tag">
<el-icon color="#10b981"><Check /></el-icon>
<span>文件上传成功(ID: {{ versionForm.sourceDocxFileId }})</span>
</div>
</el-form-item>
<el-form-item label="生效日期">
<el-date-picker v-model="versionForm.effectiveDate" value-format="YYYY-MM-DD" class="w-full" />
</el-form-item>
<el-form-item label="失效日期">
<el-date-picker v-model="versionForm.expiryDate" value-format="YYYY-MM-DD" class="w-full" />
</el-form-item>
<el-form-item label="版本备注">
<el-input v-model="versionForm.remark" type="textarea" :rows="2" placeholder="本次版本修订说明" />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="versionVisible = false">取消</el-button>
<el-button type="primary" @click="saveVersion">保存版本</el-button>
</template>
</el-dialog>
<!-- 变量配置弹窗 -->
<el-dialog
v-model="variablesVisible"
:title="`合同变量配置 · 版本 ${selectedVersion?.versionNo || ''}`"
width="1050px"
destroy-on-close
append-to-body
>
<div class="toolbar-flex">
<el-button type="primary" icon="Plus" @click="openVariableCreate">
新增变量定义
</el-button>
<el-alert
title="在 DOCX 模板中使用 {{变量编码}} 作为占位符。点击变量编码旁复制按钮可直接复制占位符。"
type="info"
show-icon
:closable="false"
style="flex: 1; margin: 0 0 0 16px;"
/>
</div>
<el-table :data="variables" border stripe class="mt-3">
<el-table-column prop="variableCode" label="变量编码 (DOCX占位符)" min-width="220">
<template #default="scope">
<div style="display: flex; align-items: center; justify-content: space-between;">
<code style="font-weight: 600; color: #2563eb;">{{ formatPlaceholder(scope.row.variableCode) }}</code>
<el-button
size="small"
link
type="primary"
icon="CopyDocument"
@click="copyPlaceholder(scope.row.variableCode)"
>
复制
</el-button>
</div>
</template>
</el-table-column>
<el-table-column prop="variableName" label="变量显示名称" min-width="160" />
<el-table-column prop="variableType" label="来源类型" width="130" align="center">
<template #default="scope">
<el-tag size="small" :type="variableTypeTag(scope.row.variableType)">
{{ variableTypeText(scope.row.variableType) }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="dataType" label="数据类型" width="100" align="center">
<template #default="scope">
<el-tag size="small" type="info">{{ scope.row.dataType }}</el-tag>
</template>
</el-table-column>
<el-table-column prop="employeeField" label="对应员工字段" min-width="140" />
<el-table-column label="必填" width="80" align="center">
<template #default="scope">
<el-tag size="small" :type="scope.row.required ? 'danger' : 'info'">
{{ scope.row.required ? "是" : "否" }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="150" fixed="right">
<template #default="scope">
<el-button link type="primary" icon="Edit" @click="openVariableEdit(scope.row)">
编辑
</el-button>
<el-button link type="danger" icon="Delete" @click="removeVariable(scope.row)">
删除
</el-button>
</template>
</el-table-column>
</el-table>
</el-dialog>
<!-- 新增 / 编辑单个变量 -->
<el-dialog
v-model="variableVisible"
:title="variableEditing ? '编辑变量' : '新增变量'"
width="640px"
destroy-on-close
append-to-body
>
<el-form :model="variableForm" label-width="130px">
<el-form-item label="变量编码" required>
<el-input v-model="variableForm.variableCode" placeholder="如:EMPLOYEE_NAME" />
</el-form-item>
<el-form-item label="变量名称" required>
<el-input v-model="variableForm.variableName" placeholder="如:员工姓名" />
</el-form-item>
<el-form-item label="变量类型" required>
<el-select v-model="variableForm.variableType" class="w-full">
<el-option label="员工填写(从新员工基本信息/动态字段读取)" value="employee" />
<el-option label="公司信息(从公司档案自动读取)" value="company" />
<el-option label="合同/人事填写(人事发起时录入)" value="contract" />
<el-option label="系统生成(签署日期等)" value="system" />
</el-select>
</el-form-item>
<el-form-item label="数据类型" required>
<el-select v-model="variableForm.dataType" class="w-full">
<el-option label="文本" value="string" />
<el-option label="日期" value="date" />
<el-option label="数字" value="number" />
<el-option label="金额" value="decimal" />
</el-select>
</el-form-item>
<el-form-item v-if="variableForm.variableType === 'employee'" label="员工字段">
<el-input v-model="variableForm.employeeField" placeholder="如:EmployeeName、IdCardNumber、Phone" />
</el-form-item>
<el-form-item label="默认值">
<el-input v-model="variableForm.defaultValue" placeholder="未填写时的备选默认值" />
</el-form-item>
<el-form-item label="排序">
<el-input-number v-model="variableForm.sortCode" :min="0" />
</el-form-item>
<el-form-item label="必填">
<el-switch v-model="variableForm.required" />
</el-form-item>
<el-form-item label="人事可修改">
<el-switch v-model="variableForm.hrEditable" />
</el-form-item>
<el-form-item label="备注">
<el-input v-model="variableForm.remark" type="textarea" :rows="2" />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="variableVisible = false">取消</el-button>
<el-button type="primary" @click="saveVariable">保存</el-button>
</template>
</el-dialog>
</div>
</template>
<script setup lang="ts" name="onboardingContract">
import { ref, reactive, computed, onMounted } from "vue";
import { ElMessage, ElMessageBox } from "element-plus";
import { Plus, Edit, Delete, Files, Upload, Setting, Download, Check, CopyDocument } from "@element-plus/icons-vue";
import {
onboardingTaskApi,
type OnboardingCompanyOption,
type OnboardingContractScope,
type OnboardingContractTemplate,
type OnboardingContractVersion,
type OnboardingPositionOption,
type OnboardingTemplateVariable
} from "@/api/modules/biz/onboarding";
import type { ColumnProps, ProTableInstance } from "@/components/ProTable/interface";
const templateTable = ref<ProTableInstance>();
const companies = ref<OnboardingCompanyOption[]>([]);
const scopePositions = ref<OnboardingPositionOption[]>([]);
const selectedTemplate = ref<OnboardingContractTemplate>();
const selectedVersion = ref<OnboardingContractVersion>();
const drawerVisible = ref(false);
const drawerActiveTab = ref("versions");
const templateVisible = ref(false);
const templateEditing = ref(false);
const versions = ref<OnboardingContractVersion[]>([]);
const versionVisible = ref(false);
const variablesVisible = ref(false);
const variableEditing = ref(false);
const variables = ref<OnboardingTemplateVariable[]>([]);
const variableVisible = ref(false);
const scopes = ref<OnboardingContractScope[]>([]);
const emptyTemplate = (): Partial<OnboardingContractTemplate> => ({
templateCode: "",
templateName: "",
contractType: "",
status: "enable",
description: ""
});
const emptyVersion = (): Partial<OnboardingContractVersion> => ({
versionNo: "",
sourceDocxFileId: undefined,
effectiveDate: undefined,
expiryDate: undefined,
remark: ""
});
const emptyVariable = (): Partial<OnboardingTemplateVariable> => ({
variableCode: "",
variableName: "",
variableType: "employee",
dataType: "string",
employeeField: "",
defaultValue: "",
sortCode: 10,
required: true,
hrEditable: true,
remark: ""
});
const emptyScope = (): Partial<OnboardingContractScope> => ({
companyId: undefined,
positionId: undefined,
templateVersionId: undefined
});
const templateForm = reactive<Partial<OnboardingContractTemplate>>(emptyTemplate());
const versionForm = reactive<Partial<OnboardingContractVersion>>(emptyVersion());
const variableForm = reactive<Partial<OnboardingTemplateVariable>>(emptyVariable());
const scopeForm = reactive<Partial<OnboardingContractScope>>(emptyScope());
const enabledVersions = computed(() =>
versions.value.filter(item => item.versionStatus === "enabled")
);
const templateColumns: ColumnProps<OnboardingContractTemplate>[] = [
{
prop: "templateCode",
label: "模板编码",
minWidth: 160,
search: { el: "input" }
},
{
prop: "templateName",
label: "模板名称",
minWidth: 200,
search: { el: "input" }
},
{
prop: "contractType",
label: "合同类型",
width: 140,
search: { el: "input" }
},
{
prop: "status",
label: "状态",
width: 100,
align: "center",
enum: [
{ label: "启用", value: "enable" },
{ label: "停用", value: "disable" }
],
search: { el: "select" }
},
{
prop: "description",
label: "模板说明",
minWidth: 200
},
{
prop: "operation",
label: "操作",
fixed: "right",
width: 260
}
];
function formatTime(timeStr?: string) {
if (!timeStr) return "-";
return timeStr.replace("T", " ").substring(0, 19);
}
function resetTemplate() {
Object.assign(templateForm, emptyTemplate());
}
function resetVersion() {
Object.assign(versionForm, emptyVersion());
}
function resetVariable() {
Object.assign(variableForm, emptyVariable());
}
function resetScope() {
Object.assign(scopeForm, emptyScope());
}
async function loadCompanies() {
const { data } = await onboardingTaskApi.listCompanies();
companies.value = data;
}
async function loadVersions() {
if (!selectedTemplate.value) return;
const { data } = await onboardingTaskApi.versionPage({
templateId: selectedTemplate.value.id,
pageNum: 1,
pageSize: 100
});
versions.value = data.list;
}
async function loadVariables() {
if (!selectedVersion.value) return;
const { data } = await onboardingTaskApi.variablePage({
templateVersionId: selectedVersion.value.id,
pageNum: 1,
pageSize: 100
});
variables.value = data.list;
}
async function loadScopes() {
if (!selectedTemplate.value) return;
const { data } = await onboardingTaskApi.scopePage({
templateId: selectedTemplate.value.id,
pageNum: 1,
pageSize: 100
});
scopes.value = data.list;
}
async function openManagementDrawer(row: OnboardingContractTemplate) {
selectedTemplate.value = row;
drawerActiveTab.value = "versions";
await Promise.all([loadVersions(), loadScopes()]);
drawerVisible.value = true;
}
function openTemplateCreate() {
templateEditing.value = false;
resetTemplate();
templateVisible.value = true;
}
async function openTemplateEdit(row: OnboardingContractTemplate) {
const { data } = await onboardingTaskApi.templateDetail({ id: row.id });
templateEditing.value = true;
Object.assign(templateForm, data);
templateVisible.value = true;
}
async function saveTemplate() {
if (!templateForm.templateCode || !templateForm.templateName || !templateForm.contractType) {
return ElMessage.warning("请填写模板编码、名称和合同类型");
}
await onboardingTaskApi.saveTemplate(templateForm, templateEditing.value);
templateVisible.value = false;
templateTable.value?.refresh();
ElMessage.success("保存成功");
}
async function removeTemplate(row: OnboardingContractTemplate) {
await ElMessageBox.confirm(`确认删除合同模板“${row.templateName}”?`, "删除确认", { type: "warning" });
await onboardingTaskApi.deleteTemplate([row.id]);
templateTable.value?.refresh();
ElMessage.success("删除成功");
}
function openVersionCreate() {
resetVersion();
versionVisible.value = true;
}
function beforeDocxUpload(file: File) {
if (!file.name.toLowerCase().endsWith(".docx")) {
ElMessage.error("合同模板仅支持 DOCX 文件");
return false;
}
return true;
}
async function uploadDocx(options: any) {
const form = new FormData();
form.append("file", options.file);
try {
const { data } = await onboardingTaskApi.uploadDocx(form);
versionForm.sourceDocxFileId = data;
options.onSuccess?.(data);
ElMessage.success("DOCX 文件上传成功");
} catch (error) {
options.onError?.(error);
}
}
async function saveVersion() {
if (!selectedTemplate.value || !versionForm.versionNo || !versionForm.sourceDocxFileId) {
return ElMessage.warning("请填写版本号并上传DOCX文件");
}
await onboardingTaskApi.addVersion({
...versionForm,
templateId: selectedTemplate.value.id
});
versionVisible.value = false;
await loadVersions();
ElMessage.success("版本已保存");
}
async function changeVersionStatus(row: OnboardingContractVersion, status: string) {
await onboardingTaskApi.setVersionStatus({ id: row.id, versionStatus: status });
await loadVersions();
ElMessage.success(`版本状态已更新为:${versionText(status)}`);
}
function downloadDocx(fileId?: number) {
if (!fileId) return ElMessage.warning("暂无DOCX源文件");
window.open(`/api/sys/dev/file/download?id=${fileId}`, "_blank");
}
type EpTagType = "success" | "warning" | "info" | "primary" | "danger";
function versionText(status: string) {
return status === "enabled" ? "已启用" : status === "disabled" ? "已停用" : "草稿";
}
function versionType(status: string): EpTagType {
return status === "enabled" ? "success" : status === "disabled" ? "info" : "warning";
}
function variableTypeTag(type: string): EpTagType {
const map: Record<string, EpTagType> = {
employee: "primary",
company: "success",
contract: "warning",
system: "info"
};
return map[type] || "info";
}
function variableTypeText(type: string) {
const map: Record<string, string> = {
employee: "员工填写",
company: "公司信息",
contract: "人事合同参数",
system: "系统自动"
};
return map[type] || type;
}
function formatPlaceholder(code: string) {
return `{{${code}}}`;
}
function copyPlaceholder(code: string) {
navigator.clipboard.writeText(`{{${code}}}`);
ElMessage.success(`占位符 {{${code}}} 已复制到剪贴板`);
}
async function openVariables(row: OnboardingContractVersion) {
selectedVersion.value = row;
await loadVariables();
variablesVisible.value = true;
}
function openVariableCreate() {
variableEditing.value = false;
resetVariable();
variableVisible.value = true;
}
function openVariableEdit(row: OnboardingTemplateVariable) {
variableEditing.value = true;
Object.assign(variableForm, row);
variableVisible.value = true;
}
async function saveVariable() {
if (
!selectedVersion.value ||
!variableForm.variableCode ||
!variableForm.variableName ||
!variableForm.variableType ||
!variableForm.dataType
) {
return ElMessage.warning("请填写变量编码、名称、类型和数据类型");
}
await onboardingTaskApi.saveVariable(
{
...variableForm,
templateVersionId: selectedVersion.value.id
},
variableEditing.value
);
variableVisible.value = false;
await loadVariables();
ElMessage.success("变量已保存");
}
async function removeVariable(row: OnboardingTemplateVariable) {
await ElMessageBox.confirm(`确认删除变量“${row.variableName}”?`, "删除确认", { type: "warning" });
await onboardingTaskApi.deleteVariable([row.id]);
await loadVariables();
ElMessage.success("删除成功");
}
async function onScopeCompanyChange(companyId: number) {
scopeForm.positionId = undefined;
const { data } = await onboardingTaskApi.listPositions(companyId);
scopePositions.value = data;
}
async function saveScope() {
if (!selectedTemplate.value || !scopeForm.companyId || !scopeForm.templateVersionId) {
return ElMessage.warning("请选择公司和已启用的合同版本");
}
await onboardingTaskApi.addScope({
...scopeForm,
templateId: selectedTemplate.value.id
});
await loadScopes();
resetScope();
ElMessage.success("适用范围已添加");
}
async function removeScope(row: OnboardingContractScope) {
await ElMessageBox.confirm("确认删除该适用范围?", "删除确认", { type: "warning" });
await onboardingTaskApi.deleteScope([row.id]);
await loadScopes();
ElMessage.success("删除成功");
}
const companyName = (id: number) => companies.value.find(c => c.id === id)?.companyName || id;
const positionName = (id?: number) => {
if (!id) return "全公司 (所有岗位)";
return scopePositions.value.find(p => p.id === id)?.positionName || id;
};
const versionName = (id: number) => versions.value.find(v => v.id === id)?.versionNo || id;
onMounted(loadCompanies);
</script>
<style scoped>
:deep(.table-search) {
margin-bottom: 12px !important;
border-radius: 8px;
}
:deep(.table-main) {
border-radius: 8px;
}
.drawer-content-box {
padding: 0 4px;
}
.template-header-card {
background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
border: 1px solid #e2e8f0;
border-radius: 8px;
padding: 16px 20px;
margin-bottom: 16px;
}
.template-title-row {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 8px;
}
.template-title {
font-size: 18px;
font-weight: 700;
color: #1e293b;
}
.template-meta-row {
display: flex;
gap: 20px;
font-size: 13px;
color: #64748b;
}
.pane-action-bar {
display: flex;
align-items: center;
gap: 16px;
margin-bottom: 12px;
}
.pane-tip-text {
font-size: 13px;
color: #64748b;
}
.mt-3 {
margin-top: 12px;
}
.mt-4 {
margin-top: 16px;
}
.font-bold {
font-weight: 600;
}
.w-full {
width: 100%;
}
.file-uploaded-tag {
display: flex;
align-items: center;
gap: 6px;
font-size: 13px;
color: #10b981;
margin-top: 6px;
}
.toolbar-flex {
display: flex;
align-items: center;
}
</style>