相关bug调整
This commit is contained in:
@@ -243,36 +243,54 @@
|
||||
:key="record.id"
|
||||
:timestamp="formatTime(record.createTime)"
|
||||
placement="top"
|
||||
type="primary"
|
||||
:type="changeTimelineType(record.changeType)"
|
||||
>
|
||||
<div class="change-record-card">
|
||||
<!-- 顶部信息:操作类型标签 + 生效日期 + 操作人 -->
|
||||
<div class="change-record-header">
|
||||
<strong>{{ changeTypeText(record.changeType) }}</strong>
|
||||
<span>{{ record.createUser || "系统" }}</span>
|
||||
<div class="change-record-title-wrap">
|
||||
<el-tag :type="changeTypeTagType(record.changeType)" size="default" effect="light" class="change-type-tag">
|
||||
{{ changeTypeText(record.changeType) }}
|
||||
</el-tag>
|
||||
<span v-if="record.effectiveDate" class="change-effective-badge">
|
||||
<el-icon class="mr-1"><Calendar /></el-icon>生效于 {{ formatDate(record.effectiveDate) }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="change-operator">
|
||||
<el-icon class="operator-icon"><User /></el-icon>
|
||||
<span class="operator-name">{{ record.createUser || "系统" }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="record.effectiveDate" class="change-record-line">
|
||||
生效日期:{{ formatDate(record.effectiveDate) }}
|
||||
</div>
|
||||
<div v-if="record.remark" class="change-record-line">
|
||||
备注:{{ record.remark }}
|
||||
</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"
|
||||
|
||||
<!-- 变更明细:轻量 Diff 流向列表 -->
|
||||
<div v-if="hasChangeSnapshot(record)" class="change-diff-flow">
|
||||
<div
|
||||
v-for="diff in changeDiffRows(record)"
|
||||
:key="diff.key"
|
||||
class="change-diff-item"
|
||||
>
|
||||
<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>
|
||||
<span class="diff-field-label">{{ diff.label }}</span>
|
||||
<div class="diff-values">
|
||||
<span class="diff-val-before">{{ diff.beforeText }}</span>
|
||||
<el-icon class="diff-arrow"><Right /></el-icon>
|
||||
<span class="diff-val-after">{{ diff.afterText }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="!changeDiffRows(record).length" class="change-diff-none">
|
||||
前后字段值无实质差异
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="change-record-empty">
|
||||
该记录未保存修改前后值
|
||||
该记录未保存修改前后快照
|
||||
</div>
|
||||
|
||||
<!-- 真实备注(过滤掉无意义系统默认同义反复文案) -->
|
||||
<div v-if="shouldShowRemark(record)" class="change-remark-box">
|
||||
<el-icon class="remark-icon"><ChatDotRound /></el-icon>
|
||||
<span class="remark-text">{{ record.remark }}</span>
|
||||
</div>
|
||||
|
||||
<!-- 附件列表 -->
|
||||
<div v-if="record.attachments?.length" class="change-attachments">
|
||||
<el-button
|
||||
v-for="file in record.attachments"
|
||||
@@ -536,6 +554,7 @@
|
||||
v-model:file-list="regularizationFiles"
|
||||
multiple
|
||||
:limit="10"
|
||||
:on-exceed="handleRegularizationExceed"
|
||||
:http-request="uploadRegularizationFile"
|
||||
:before-upload="beforeRegularizationUpload"
|
||||
:on-remove="removeRegularizationFile"
|
||||
@@ -560,11 +579,14 @@
|
||||
import { computed, onBeforeUnmount, onMounted, reactive, ref } from "vue";
|
||||
import {
|
||||
Briefcase,
|
||||
Calendar,
|
||||
ChatDotRound,
|
||||
Clock,
|
||||
Connection,
|
||||
Document,
|
||||
Download,
|
||||
FirstAidKit,
|
||||
Right,
|
||||
User,
|
||||
UserFilled,
|
||||
WarningFilled
|
||||
@@ -1206,6 +1228,44 @@ function changeTypeText(value?: string) {
|
||||
return map[value || ""] || value || "人事变更";
|
||||
}
|
||||
|
||||
function changeTypeTagType(value?: string): "primary" | "success" | "warning" | "danger" | "info" {
|
||||
switch (value) {
|
||||
case "regularization":
|
||||
return "success";
|
||||
case "regularization_revoke":
|
||||
return "warning";
|
||||
case "hr_info_update":
|
||||
return "primary";
|
||||
default:
|
||||
return "info";
|
||||
}
|
||||
}
|
||||
|
||||
function changeTimelineType(value?: string): "primary" | "success" | "warning" | "info" {
|
||||
switch (value) {
|
||||
case "regularization":
|
||||
return "success";
|
||||
case "regularization_revoke":
|
||||
return "warning";
|
||||
default:
|
||||
return "primary";
|
||||
}
|
||||
}
|
||||
|
||||
function shouldShowRemark(record: any) {
|
||||
if (!record?.remark || !String(record.remark).trim()) return false;
|
||||
const remark = String(record.remark).trim();
|
||||
const defaultRemarks = [
|
||||
"编辑员工人事信息",
|
||||
"办理员工转正",
|
||||
"撤销员工转正",
|
||||
"编辑人事信息",
|
||||
"办理转正",
|
||||
"撤销转正"
|
||||
];
|
||||
return !defaultRemarks.includes(remark) && remark !== changeTypeText(record?.changeType);
|
||||
}
|
||||
|
||||
type EmployeeChangeFieldKey =
|
||||
| "employmentType"
|
||||
| "regularizationStatus"
|
||||
@@ -1467,7 +1527,15 @@ function openRegularization(row: OnboardingEmployee) {
|
||||
regularizationVisible.value = true;
|
||||
}
|
||||
|
||||
function handleRegularizationExceed() {
|
||||
ElMessage.warning("文件总数不超过 10");
|
||||
}
|
||||
|
||||
function beforeRegularizationUpload(file: File) {
|
||||
if (regularizationFiles.value.length >= 10) {
|
||||
ElMessage.warning("文件总数不超过 10");
|
||||
return false;
|
||||
}
|
||||
const extension = "." + (file.name.split(".").pop() || "").toLowerCase();
|
||||
const allowed = [
|
||||
".pdf", ".doc", ".docx", ".xls", ".xlsx",
|
||||
@@ -1506,6 +1574,9 @@ async function submitRegularization() {
|
||||
if (!regularizationForm.regularizationDate) {
|
||||
return ElMessage.warning("请选择转正日期");
|
||||
}
|
||||
if (regularizationFiles.value.length > 10) {
|
||||
return ElMessage.warning("文件总数不超过 10");
|
||||
}
|
||||
if (regularizationFiles.value.some(file => file.status === "uploading")) {
|
||||
return ElMessage.warning("材料仍在上传,请稍候");
|
||||
}
|
||||
@@ -1513,6 +1584,9 @@ async function submitRegularization() {
|
||||
const fileIds = regularizationFiles.value
|
||||
.map(file => Number((file.response as any)?.fileId))
|
||||
.filter(fileId => Number.isFinite(fileId) && fileId > 0);
|
||||
if (fileIds.length > 10) {
|
||||
return ElMessage.warning("文件总数不超过 10");
|
||||
}
|
||||
if (
|
||||
regularizationFiles.value.some(file => file.status === "fail")
|
||||
|| fileIds.length !== regularizationFiles.value.length
|
||||
@@ -1753,59 +1827,175 @@ onBeforeUnmount(clearMaterialPreviews);
|
||||
}
|
||||
|
||||
.change-record-card {
|
||||
padding: 12px 14px;
|
||||
padding: 14px 16px;
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 8px;
|
||||
background: #f8fafc;
|
||||
border-radius: 10px;
|
||||
background: #ffffff;
|
||||
box-shadow: 0 1px 3px rgba(15, 23, 42, 0.04);
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.change-record-card:hover {
|
||||
border-color: #cbd5e1;
|
||||
box-shadow: 0 4px 12px rgba(15, 23, 42, 0.06);
|
||||
}
|
||||
|
||||
.change-record-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
color: #1e293b;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px dashed #f1f5f9;
|
||||
}
|
||||
|
||||
.change-record-header span,
|
||||
.change-record-line {
|
||||
.change-record-title-wrap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.change-type-tag {
|
||||
font-weight: 600;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.change-effective-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
font-size: 12px;
|
||||
color: #64748b;
|
||||
background: #f8fafc;
|
||||
padding: 2px 8px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.change-operator {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
font-size: 13px;
|
||||
color: #475569;
|
||||
background: #f1f5f9;
|
||||
padding: 3px 10px;
|
||||
border-radius: 20px;
|
||||
}
|
||||
|
||||
.change-record-line {
|
||||
margin-top: 6px;
|
||||
.operator-icon {
|
||||
font-size: 13px;
|
||||
color: #64748b;
|
||||
}
|
||||
|
||||
.change-diff {
|
||||
.operator-name {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* 变更 Diff 标签流 */
|
||||
.change-diff-flow {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.change-diff-title {
|
||||
margin-bottom: 8px;
|
||||
color: #334155;
|
||||
.change-diff-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
padding: 8px 12px;
|
||||
background: #f8fafc;
|
||||
border-radius: 6px;
|
||||
border: 1px solid #f1f5f9;
|
||||
}
|
||||
|
||||
.change-diff-table {
|
||||
width: 100%;
|
||||
.diff-field-label {
|
||||
min-width: 90px;
|
||||
font-weight: 600;
|
||||
color: #475569;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.diff-values {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.diff-val-before {
|
||||
color: #64748b;
|
||||
background: #ffffff;
|
||||
padding: 2px 8px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #e2e8f0;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.diff-arrow {
|
||||
color: #94a3b8;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.diff-val-after {
|
||||
color: #2563eb;
|
||||
background: #eff6ff;
|
||||
padding: 2px 10px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #bfdbfe;
|
||||
font-weight: 600;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.change-diff-none {
|
||||
color: #94a3b8;
|
||||
font-size: 13px;
|
||||
padding: 6px 0;
|
||||
}
|
||||
|
||||
.change-record-empty {
|
||||
margin-top: 10px;
|
||||
padding: 8px 10px;
|
||||
border-radius: 4px;
|
||||
background: #f1f5f9;
|
||||
border-radius: 6px;
|
||||
background: #f8fafc;
|
||||
color: #94a3b8;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
/* 真实备注气泡框 */
|
||||
.change-remark-box {
|
||||
margin-top: 10px;
|
||||
padding: 8px 12px;
|
||||
border-radius: 6px;
|
||||
background: #f8fafc;
|
||||
border-left: 3px solid #cbd5e1;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 6px;
|
||||
font-size: 13px;
|
||||
color: #475569;
|
||||
}
|
||||
|
||||
.remark-icon {
|
||||
margin-top: 2px;
|
||||
color: #94a3b8;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.remark-text {
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.change-attachments {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
margin-top: 8px;
|
||||
margin-top: 10px;
|
||||
padding-top: 8px;
|
||||
border-top: 1px dashed #f1f5f9;
|
||||
}
|
||||
|
||||
.section-card {
|
||||
|
||||
@@ -92,7 +92,7 @@
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="单文件大小">
|
||||
<el-input-number v-model="materialForm.maxFileSizeMb" :min="1" :max="100" />
|
||||
<el-input-number v-model="materialForm.maxFileSizeMb" :min="1" :max="20" />
|
||||
<span class="unit-suffix">MB</span>
|
||||
</el-form-item>
|
||||
|
||||
|
||||
@@ -888,21 +888,10 @@
|
||||
plain
|
||||
:disabled="item.reviewStatus === 'passed' || !canManage(detail.task)"
|
||||
:title="disabledReason(detail.task)"
|
||||
@click="reviewMaterial(item.id, 'passed')"
|
||||
@click="reviewMaterial(item.id)"
|
||||
>
|
||||
合格
|
||||
</el-button>
|
||||
<el-button
|
||||
v-auth="'onboardingTaskMaterialReview'"
|
||||
size="small"
|
||||
type="danger"
|
||||
plain
|
||||
:disabled="item.reviewStatus === 'need_supplement' || !canManage(detail.task)"
|
||||
:title="disabledReason(detail.task)"
|
||||
@click="reviewMaterial(item.id, 'need_supplement')"
|
||||
>
|
||||
需补充
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -2869,21 +2858,9 @@ async function download(fileId: number, fallbackFileName?: string) {
|
||||
|
||||
onBeforeUnmount(clearMaterialPreviews);
|
||||
|
||||
async function reviewMaterial(taskMaterialId: number, reviewStatus: string) {
|
||||
let reviewRemark = "";
|
||||
if (reviewStatus === "need_supplement") {
|
||||
const result = await getMessageBoxPromptResult(
|
||||
ElMessageBox.prompt("请输入该材料退回补充说明:", "材料不合格退回", {
|
||||
inputPattern: /\S+/,
|
||||
inputErrorMessage: "请填写说明"
|
||||
})
|
||||
);
|
||||
if (!result) return;
|
||||
reviewRemark = result.value;
|
||||
}
|
||||
|
||||
await onboardingTaskApi.reviewMaterial({ taskMaterialId, reviewStatus, reviewRemark });
|
||||
ElMessage.success(reviewStatus === "passed" ? "该材料已标记为合格" : "已标记需补充");
|
||||
async function reviewMaterial(taskMaterialId: number) {
|
||||
await onboardingTaskApi.reviewMaterial({ taskMaterialId, reviewStatus: "passed", reviewRemark: "" });
|
||||
ElMessage.success("该材料已标记为合格");
|
||||
|
||||
if (detail.value?.task) {
|
||||
await showDetail(detail.value.task, true);
|
||||
|
||||
Reference in New Issue
Block a user