修改相关问题

This commit is contained in:
fuenmao
2026-09-18 10:53:56 +08:00
parent 2f0d04b982
commit c812071d8a
2 changed files with 159 additions and 8 deletions
-3
View File
@@ -21,12 +21,10 @@ declare module 'vue' {
ElAlert: typeof import('element-plus/es')['ElAlert'] ElAlert: typeof import('element-plus/es')['ElAlert']
ElAside: typeof import('element-plus/es')['ElAside'] ElAside: typeof import('element-plus/es')['ElAside']
ElAvatar: typeof import('element-plus/es')['ElAvatar'] ElAvatar: typeof import('element-plus/es')['ElAvatar']
ElBadge: typeof import('element-plus/es')['ElBadge']
ElBreadcrumb: typeof import('element-plus/es')['ElBreadcrumb'] ElBreadcrumb: typeof import('element-plus/es')['ElBreadcrumb']
ElBreadcrumbItem: typeof import('element-plus/es')['ElBreadcrumbItem'] ElBreadcrumbItem: typeof import('element-plus/es')['ElBreadcrumbItem']
ElButton: typeof import('element-plus/es')['ElButton'] ElButton: typeof import('element-plus/es')['ElButton']
ElCard: typeof import('element-plus/es')['ElCard'] ElCard: typeof import('element-plus/es')['ElCard']
ElCascader: typeof import('element-plus/es')['ElCascader']
ElCheckbox: typeof import('element-plus/es')['ElCheckbox'] ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
ElCol: typeof import('element-plus/es')['ElCol'] ElCol: typeof import('element-plus/es')['ElCol']
ElCollapse: typeof import('element-plus/es')['ElCollapse'] ElCollapse: typeof import('element-plus/es')['ElCollapse']
@@ -52,7 +50,6 @@ declare module 'vue' {
ElImageViewer: typeof import('element-plus/es')['ElImageViewer'] ElImageViewer: typeof import('element-plus/es')['ElImageViewer']
ElInput: typeof import('element-plus/es')['ElInput'] ElInput: typeof import('element-plus/es')['ElInput']
ElInputNumber: typeof import('element-plus/es')['ElInputNumber'] ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
ElLink: typeof import('element-plus/es')['ElLink']
ElMain: typeof import('element-plus/es')['ElMain'] ElMain: typeof import('element-plus/es')['ElMain']
ElMenu: typeof import('element-plus/es')['ElMenu'] ElMenu: typeof import('element-plus/es')['ElMenu']
ElMenuItem: typeof import('element-plus/es')['ElMenuItem'] ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
+159 -5
View File
@@ -162,7 +162,7 @@
<el-descriptions-item label="所属岗位">{{ <el-descriptions-item label="所属岗位">{{
detail.employee.positionName || employeeInfo.onboardingPosition || "-" detail.employee.positionName || employeeInfo.onboardingPosition || "-"
}}</el-descriptions-item> }}</el-descriptions-item>
<el-descriptions-item label="员工编号">{{ detail.employee.employeeNo || employeeInfo.employeeNo || "-" }}</el-descriptions-item> <el-descriptions-item label="员工编号">{{ resolvedEmployeeNo }}</el-descriptions-item>
<el-descriptions-item label="入职日期">{{ formatDate(detail.employee.entryDate) }}</el-descriptions-item> <el-descriptions-item label="入职日期">{{ formatDate(detail.employee.entryDate) }}</el-descriptions-item>
<el-descriptions-item label="员工司龄">{{ formatSeniority(detail.employee.entryDate) }}</el-descriptions-item> <el-descriptions-item label="员工司龄">{{ formatSeniority(detail.employee.entryDate) }}</el-descriptions-item>
<el-descriptions-item label="用工类型">{{ employmentTypeText(detail.employee.employmentType) }}</el-descriptions-item> <el-descriptions-item label="用工类型">{{ employmentTypeText(detail.employee.employmentType) }}</el-descriptions-item>
@@ -256,6 +256,23 @@
<div v-if="record.remark" class="change-record-line"> <div v-if="record.remark" class="change-record-line">
备注:{{ record.remark }} 备注:{{ record.remark }}
</div> </div>
<div v-if="hasChangeSnapshot(record)" class="change-diff">
<div class="change-diff-title">变更明细</div>
<el-table
:data="changeDiffRows(record)"
border
size="small"
empty-text="前后值无差异"
class="change-diff-table"
>
<el-table-column prop="label" label="字段" min-width="120" />
<el-table-column prop="beforeText" label="修改前" min-width="150" />
<el-table-column prop="afterText" label="修改后" min-width="150" />
</el-table>
</div>
<div v-else class="change-record-empty">
该记录未保存修改前后值
</div>
<div v-if="record.attachments?.length" class="change-attachments"> <div v-if="record.attachments?.length" class="change-attachments">
<el-button <el-button
v-for="file in record.attachments" v-for="file in record.attachments"
@@ -456,6 +473,7 @@
filterable filterable
allow-create allow-create
clearable clearable
:value-on-clear="''"
default-first-option default-first-option
placeholder="请选择或输入合同性质" placeholder="请选择或输入合同性质"
class="full-width" class="full-width"
@@ -724,6 +742,34 @@ const regularizationForm = reactive({
remark: "" remark: ""
}); });
const employeeInfo = computed<Record<string, any>>(() => detail.value?.employeeInfo || {}); const employeeInfo = computed<Record<string, any>>(() => detail.value?.employeeInfo || {});
const resolvedEmployeeNo = computed(() => {
if (detail.value?.employee?.employeeNo && String(detail.value.employee.employeeNo).trim()) {
return String(detail.value.employee.employeeNo).trim();
}
const snapshots = detail.value?.contractSnapshots || [];
for (const item of snapshots) {
if (item?.employeeNo && String(item.employeeNo).trim()) {
return String(item.employeeNo).trim();
}
if (item?.variablesJson) {
try {
const vars = typeof item.variablesJson === "string" ? JSON.parse(item.variablesJson) : item.variablesJson;
const target = vars?.["hr.EmployeeNo"] || vars?.["hr.employeeno"];
const val = typeof target === "object" ? target?.variableValue : target;
if (val && String(val).trim()) {
return String(val).trim();
}
} catch {
// 忽略变量快照反序列化异常
}
}
}
if (employeeInfo.value?.employeeNo && String(employeeInfo.value.employeeNo).trim()) {
return String(employeeInfo.value.employeeNo).trim();
}
return "-";
});
const materialPreviewUrls = reactive<Record<number, string>>({}); const materialPreviewUrls = reactive<Record<number, string>>({});
const materialPreviewLoading = reactive<Record<number, boolean>>({}); const materialPreviewLoading = reactive<Record<number, boolean>>({});
const materialPreviewFailed = reactive<Record<number, boolean>>({}); const materialPreviewFailed = reactive<Record<number, boolean>>({});
@@ -911,10 +957,10 @@ function safeDownloadName(value: string) {
} }
function getEmployeeDownloadPrefix(): string { function getEmployeeDownloadPrefix(): string {
const empNo = resolvedEmployeeNo.value !== "-" ? resolvedEmployeeNo.value : "";
const taskNo = String( const taskNo = String(
detail.value?.task?.taskNo detail.value?.task?.taskNo
|| detail.value?.employee?.employeeNo || empNo
|| detail.value?.employeeInfo?.employeeNo
|| "" || ""
).trim(); ).trim();
const employeeName = String( const employeeName = String(
@@ -1160,6 +1206,90 @@ function changeTypeText(value?: string) {
return map[value || ""] || value || "人事变更"; return map[value || ""] || value || "人事变更";
} }
type EmployeeChangeFieldKey =
| "employmentType"
| "regularizationStatus"
| "regularizationDate"
| "contractNature"
| "socialInsuranceStatus"
| "socialInsuranceCompany";
type EmployeeChangeDiffRow = {
key: EmployeeChangeFieldKey;
label: string;
beforeText: string;
afterText: string;
};
const employeeChangeFields: Array<{ key: EmployeeChangeFieldKey; label: string }> = [
{ key: "employmentType", label: "用工类型" },
{ key: "regularizationStatus", label: "转正状态" },
{ key: "regularizationDate", label: "转正日期" },
{ key: "contractNature", label: "合同性质" },
{ key: "socialInsuranceStatus", label: "社保状态" },
{ key: "socialInsuranceCompany", label: "合同社保单位" }
];
function parseChangeSnapshot(value: unknown): Record<string, unknown> | null {
if (value && typeof value === "object" && !Array.isArray(value)) {
return value as Record<string, unknown>;
}
if (typeof value !== "string" || !value.trim()) return null;
try {
const parsed = JSON.parse(value);
return parsed && typeof parsed === "object" && !Array.isArray(parsed)
? parsed as Record<string, unknown>
: null;
} catch {
return null;
}
}
function getSnapshot(record: any, field: "beforeJson" | "afterJson") {
const pascalField = field === "beforeJson" ? "BeforeJson" : "AfterJson";
return parseChangeSnapshot(record?.[field] ?? record?.[pascalField]);
}
function getSnapshotValue(snapshot: Record<string, unknown>, key: string) {
const matchedKey = Object.keys(snapshot).find(item => item.toLowerCase() === key.toLowerCase());
return matchedKey ? snapshot[matchedKey] : undefined;
}
function normalizeChangeValue(value: unknown) {
if (value === null || value === undefined) return "";
return typeof value === "string" ? value.trim() : JSON.stringify(value);
}
function formatChangeValue(key: EmployeeChangeFieldKey, value: unknown) {
if (value === null || value === undefined || value === "") return "—";
const text = String(value);
if (key === "employmentType") return employmentTypeText(text);
if (key === "regularizationStatus") return regularizationText(text);
if (key === "regularizationDate") return formatDate(text);
if (key === "socialInsuranceStatus") return socialInsuranceText(text);
return text;
}
function hasChangeSnapshot(record: any) {
return Boolean(getSnapshot(record, "beforeJson") || getSnapshot(record, "afterJson"));
}
function changeDiffRows(record: any): EmployeeChangeDiffRow[] {
const before = getSnapshot(record, "beforeJson") || {};
const after = getSnapshot(record, "afterJson") || {};
return employeeChangeFields.flatMap(field => {
const beforeValue = getSnapshotValue(before, field.key);
const afterValue = getSnapshotValue(after, field.key);
if (normalizeChangeValue(beforeValue) === normalizeChangeValue(afterValue)) return [];
return [{
key: field.key,
label: field.label,
beforeText: formatChangeValue(field.key, beforeValue),
afterText: formatChangeValue(field.key, afterValue)
}];
});
}
function canRegularize(employee?: OnboardingEmployee) { function canRegularize(employee?: OnboardingEmployee) {
return Boolean( return Boolean(
employee employee
@@ -1301,9 +1431,9 @@ async function saveHrInfo() {
await onboardingTaskApi.updateEmployeeHrInfo({ await onboardingTaskApi.updateEmployeeHrInfo({
id: hrForm.id, id: hrForm.id,
employmentType: hrForm.employmentType, employmentType: hrForm.employmentType,
contractNature: hrForm.contractNature.trim() || undefined, contractNature: String(hrForm.contractNature ?? "").trim() || undefined,
socialInsuranceStatus: hrForm.socialInsuranceStatus, socialInsuranceStatus: hrForm.socialInsuranceStatus,
socialInsuranceCompany: hrForm.socialInsuranceCompany.trim() || undefined socialInsuranceCompany: String(hrForm.socialInsuranceCompany ?? "").trim() || undefined
}); });
hrEditVisible.value = false; hrEditVisible.value = false;
await refreshEmployee(hrForm.id); await refreshEmployee(hrForm.id);
@@ -1647,6 +1777,30 @@ onBeforeUnmount(clearMaterialPreviews);
margin-top: 6px; margin-top: 6px;
} }
.change-diff {
margin-top: 12px;
}
.change-diff-title {
margin-bottom: 8px;
color: #334155;
font-size: 13px;
font-weight: 600;
}
.change-diff-table {
width: 100%;
}
.change-record-empty {
margin-top: 10px;
padding: 8px 10px;
border-radius: 4px;
background: #f1f5f9;
color: #94a3b8;
font-size: 13px;
}
.change-attachments { .change-attachments {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;