342 lines
10 KiB
Vue
342 lines
10 KiB
Vue
|
|
<script setup lang="ts">
|
||
|
|
import { computed, reactive, watch } from 'vue';
|
||
|
|
import dayjs from 'dayjs';
|
||
|
|
import BusinessFormDialog from '@/components/custom/business-form-dialog.vue';
|
||
|
|
import BusinessFormSection from '@/components/custom/business-form-section.vue';
|
||
|
|
import { WORK_REPORT_TYPE_LABEL, type WorkReportType } from '../types';
|
||
|
|
|
||
|
|
defineOptions({ name: 'WorkReportActionDialog' });
|
||
|
|
|
||
|
|
type ActionType = 'approve' | 'reject';
|
||
|
|
type ApprovalConclusion = 'approve' | 'reject';
|
||
|
|
|
||
|
|
const visible = defineModel<boolean>('visible', { default: false });
|
||
|
|
|
||
|
|
const props = withDefaults(
|
||
|
|
defineProps<{
|
||
|
|
reportType: WorkReportType;
|
||
|
|
actionType: ActionType;
|
||
|
|
initialMonthlyApproveData?: Partial<Api.WorkReport.Monthly.MonthlyReportApproveParams> | null;
|
||
|
|
loading?: boolean;
|
||
|
|
}>(),
|
||
|
|
{
|
||
|
|
initialMonthlyApproveData: null,
|
||
|
|
loading: false
|
||
|
|
}
|
||
|
|
);
|
||
|
|
|
||
|
|
const emit = defineEmits<{
|
||
|
|
(
|
||
|
|
e: 'submit',
|
||
|
|
payload: Api.WorkReport.Common.StatusActionParams | Api.WorkReport.Monthly.MonthlyReportApproveParams,
|
||
|
|
actionType?: ActionType
|
||
|
|
): void;
|
||
|
|
}>();
|
||
|
|
|
||
|
|
const reasonModel = reactive<Api.WorkReport.Common.StatusActionParams>({
|
||
|
|
reason: ''
|
||
|
|
});
|
||
|
|
const commonApprovalModel = reactive<{
|
||
|
|
conclusion: ApprovalConclusion | '';
|
||
|
|
opinion: string;
|
||
|
|
}>({
|
||
|
|
conclusion: 'approve',
|
||
|
|
opinion: ''
|
||
|
|
});
|
||
|
|
|
||
|
|
const monthlyModel = reactive<Api.WorkReport.Monthly.MonthlyReportApproveParams>({
|
||
|
|
reason: '',
|
||
|
|
meetingDate: '',
|
||
|
|
strengthDesc: '',
|
||
|
|
strengthExample: '',
|
||
|
|
weaknessDesc: '',
|
||
|
|
weaknessExample: '',
|
||
|
|
improvementSuggestion: '',
|
||
|
|
performanceResult: '',
|
||
|
|
employeeSignName: '',
|
||
|
|
employeeSignedDate: '',
|
||
|
|
supervisorSignName: '',
|
||
|
|
supervisorSignedDate: ''
|
||
|
|
});
|
||
|
|
|
||
|
|
const isMonthlyApprove = computed(() => props.reportType === 'monthly' && props.actionType === 'approve');
|
||
|
|
const isCommonApprove = computed(() => props.reportType !== 'monthly' && props.actionType === 'approve');
|
||
|
|
const title = computed(() => {
|
||
|
|
if (isCommonApprove.value) {
|
||
|
|
return `审批${WORK_REPORT_TYPE_LABEL[props.reportType]}`;
|
||
|
|
}
|
||
|
|
|
||
|
|
const actionLabel = props.actionType === 'approve' ? '审批通过' : '退回';
|
||
|
|
|
||
|
|
return `${actionLabel}${WORK_REPORT_TYPE_LABEL[props.reportType]}`;
|
||
|
|
});
|
||
|
|
|
||
|
|
const preset = computed(() => (isMonthlyApprove.value ? 'lg' : 'sm'));
|
||
|
|
const confirmText = computed(() => {
|
||
|
|
if (isCommonApprove.value) return '确认提交';
|
||
|
|
if (props.actionType === 'approve') return '通过';
|
||
|
|
return '退回';
|
||
|
|
});
|
||
|
|
const confirmDisabled = computed(() => isCommonApprove.value && !commonApprovalModel.conclusion);
|
||
|
|
|
||
|
|
watch(visible, isVisible => {
|
||
|
|
if (!isVisible) return;
|
||
|
|
reasonModel.reason = '';
|
||
|
|
Object.assign(commonApprovalModel, {
|
||
|
|
conclusion: 'approve',
|
||
|
|
opinion: ''
|
||
|
|
});
|
||
|
|
Object.assign(monthlyModel, {
|
||
|
|
reason: '',
|
||
|
|
meetingDate: dayjs().format('YYYY-MM-DD'),
|
||
|
|
strengthDesc: '',
|
||
|
|
strengthExample: '',
|
||
|
|
weaknessDesc: '',
|
||
|
|
weaknessExample: '',
|
||
|
|
improvementSuggestion: '',
|
||
|
|
performanceResult: '',
|
||
|
|
employeeSignName: '',
|
||
|
|
employeeSignedDate: dayjs().format('YYYY-MM-DD'),
|
||
|
|
supervisorSignName: '',
|
||
|
|
supervisorSignedDate: dayjs().format('YYYY-MM-DD')
|
||
|
|
});
|
||
|
|
|
||
|
|
if (props.initialMonthlyApproveData) {
|
||
|
|
Object.assign(monthlyModel, props.initialMonthlyApproveData);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
function handleSubmit() {
|
||
|
|
if (isCommonApprove.value) {
|
||
|
|
if (!commonApprovalModel.conclusion) {
|
||
|
|
window.$message?.warning('请选择审批结论');
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
emit(
|
||
|
|
'submit',
|
||
|
|
{
|
||
|
|
reason: commonApprovalModel.opinion || (commonApprovalModel.conclusion === 'approve' ? '通过' : '不通过')
|
||
|
|
},
|
||
|
|
commonApprovalModel.conclusion
|
||
|
|
);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
emit('submit', isMonthlyApprove.value ? { ...monthlyModel } : { ...reasonModel });
|
||
|
|
}
|
||
|
|
</script>
|
||
|
|
|
||
|
|
<template>
|
||
|
|
<BusinessFormDialog
|
||
|
|
v-model="visible"
|
||
|
|
:title="title"
|
||
|
|
:preset="preset"
|
||
|
|
:confirm-loading="loading"
|
||
|
|
:confirm-disabled="confirmDisabled"
|
||
|
|
:confirm-text="confirmText"
|
||
|
|
max-body-height="76vh"
|
||
|
|
@confirm="handleSubmit"
|
||
|
|
>
|
||
|
|
<template v-if="isCommonApprove">
|
||
|
|
<div class="audit-form">
|
||
|
|
<div class="audit-field">
|
||
|
|
<label>审批结论</label>
|
||
|
|
<div class="audit-conclusion">
|
||
|
|
<button
|
||
|
|
type="button"
|
||
|
|
class="conclusion-btn"
|
||
|
|
:class="{
|
||
|
|
active: commonApprovalModel.conclusion === 'approve',
|
||
|
|
pass: commonApprovalModel.conclusion === 'approve'
|
||
|
|
}"
|
||
|
|
@click="commonApprovalModel.conclusion = 'approve'"
|
||
|
|
>
|
||
|
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none">
|
||
|
|
<circle cx="8" cy="8" r="7" stroke="currentColor" stroke-width="1.5" />
|
||
|
|
<path
|
||
|
|
d="M5 8.5L7 10.5L11 6"
|
||
|
|
stroke="currentColor"
|
||
|
|
stroke-width="1.5"
|
||
|
|
stroke-linecap="round"
|
||
|
|
stroke-linejoin="round"
|
||
|
|
/>
|
||
|
|
</svg>
|
||
|
|
通过
|
||
|
|
</button>
|
||
|
|
<button
|
||
|
|
type="button"
|
||
|
|
class="conclusion-btn"
|
||
|
|
:class="{
|
||
|
|
active: commonApprovalModel.conclusion === 'reject',
|
||
|
|
reject: commonApprovalModel.conclusion === 'reject'
|
||
|
|
}"
|
||
|
|
@click="commonApprovalModel.conclusion = 'reject'"
|
||
|
|
>
|
||
|
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none">
|
||
|
|
<circle cx="8" cy="8" r="7" stroke="currentColor" stroke-width="1.5" />
|
||
|
|
<path d="M6 6L10 10M10 6L6 10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" />
|
||
|
|
</svg>
|
||
|
|
不通过
|
||
|
|
</button>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
<div class="audit-field">
|
||
|
|
<label>审批意见</label>
|
||
|
|
<ElInput v-model="commonApprovalModel.opinion" type="textarea" :rows="3" placeholder="请输入审批意见" />
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</template>
|
||
|
|
|
||
|
|
<template v-else-if="isMonthlyApprove">
|
||
|
|
<BusinessFormSection title="当期工作反馈">
|
||
|
|
<ElRow :gutter="16">
|
||
|
|
<ElCol :span="12">
|
||
|
|
<ElFormItem label="面谈时间">
|
||
|
|
<ElDatePicker v-model="monthlyModel.meetingDate" class="w-full" type="date" value-format="YYYY-MM-DD" />
|
||
|
|
</ElFormItem>
|
||
|
|
</ElCol>
|
||
|
|
<ElCol :span="12">
|
||
|
|
<ElFormItem label="绩效考核结果">
|
||
|
|
<ElInput v-model="monthlyModel.performanceResult" placeholder="请输入绩效结果" />
|
||
|
|
</ElFormItem>
|
||
|
|
</ElCol>
|
||
|
|
<ElCol :span="24">
|
||
|
|
<ElFormItem label="审批意见">
|
||
|
|
<ElInput v-model="monthlyModel.reason" type="textarea" :rows="3" />
|
||
|
|
</ElFormItem>
|
||
|
|
</ElCol>
|
||
|
|
</ElRow>
|
||
|
|
</BusinessFormSection>
|
||
|
|
|
||
|
|
<BusinessFormSection title="优势与不足">
|
||
|
|
<ElRow :gutter="16">
|
||
|
|
<ElCol :span="12">
|
||
|
|
<ElFormItem label="优势描述">
|
||
|
|
<ElInput v-model="monthlyModel.strengthDesc" type="textarea" :rows="3" />
|
||
|
|
</ElFormItem>
|
||
|
|
</ElCol>
|
||
|
|
<ElCol :span="12">
|
||
|
|
<ElFormItem label="优势行为事例">
|
||
|
|
<ElInput v-model="monthlyModel.strengthExample" type="textarea" :rows="3" />
|
||
|
|
</ElFormItem>
|
||
|
|
</ElCol>
|
||
|
|
<ElCol :span="12">
|
||
|
|
<ElFormItem label="劣势描述">
|
||
|
|
<ElInput v-model="monthlyModel.weaknessDesc" type="textarea" :rows="3" />
|
||
|
|
</ElFormItem>
|
||
|
|
</ElCol>
|
||
|
|
<ElCol :span="12">
|
||
|
|
<ElFormItem label="劣势行为事例">
|
||
|
|
<ElInput v-model="monthlyModel.weaknessExample" type="textarea" :rows="3" />
|
||
|
|
</ElFormItem>
|
||
|
|
</ElCol>
|
||
|
|
<ElCol :span="24">
|
||
|
|
<ElFormItem label="改进建议">
|
||
|
|
<ElInput v-model="monthlyModel.improvementSuggestion" type="textarea" :rows="3" />
|
||
|
|
</ElFormItem>
|
||
|
|
</ElCol>
|
||
|
|
</ElRow>
|
||
|
|
</BusinessFormSection>
|
||
|
|
|
||
|
|
<BusinessFormSection title="签字区">
|
||
|
|
<ElRow :gutter="16">
|
||
|
|
<ElCol :span="12">
|
||
|
|
<ElFormItem label="被考核人签名">
|
||
|
|
<ElInput v-model="monthlyModel.employeeSignName" />
|
||
|
|
</ElFormItem>
|
||
|
|
</ElCol>
|
||
|
|
<ElCol :span="12">
|
||
|
|
<ElFormItem label="被考核人签字日期">
|
||
|
|
<ElDatePicker
|
||
|
|
v-model="monthlyModel.employeeSignedDate"
|
||
|
|
class="w-full"
|
||
|
|
type="date"
|
||
|
|
value-format="YYYY-MM-DD"
|
||
|
|
/>
|
||
|
|
</ElFormItem>
|
||
|
|
</ElCol>
|
||
|
|
<ElCol :span="12">
|
||
|
|
<ElFormItem label="上级签名">
|
||
|
|
<ElInput v-model="monthlyModel.supervisorSignName" />
|
||
|
|
</ElFormItem>
|
||
|
|
</ElCol>
|
||
|
|
<ElCol :span="12">
|
||
|
|
<ElFormItem label="上级签字日期">
|
||
|
|
<ElDatePicker
|
||
|
|
v-model="monthlyModel.supervisorSignedDate"
|
||
|
|
class="w-full"
|
||
|
|
type="date"
|
||
|
|
value-format="YYYY-MM-DD"
|
||
|
|
/>
|
||
|
|
</ElFormItem>
|
||
|
|
</ElCol>
|
||
|
|
</ElRow>
|
||
|
|
</BusinessFormSection>
|
||
|
|
</template>
|
||
|
|
|
||
|
|
<ElForm v-else label-position="top">
|
||
|
|
<ElFormItem :label="actionType === 'approve' ? '审批意见' : '原因'">
|
||
|
|
<ElInput v-model="reasonModel.reason" type="textarea" :rows="5" placeholder="请输入原因或意见" />
|
||
|
|
</ElFormItem>
|
||
|
|
</ElForm>
|
||
|
|
</BusinessFormDialog>
|
||
|
|
</template>
|
||
|
|
|
||
|
|
<style scoped>
|
||
|
|
.audit-form {
|
||
|
|
display: grid;
|
||
|
|
gap: 18px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.audit-field {
|
||
|
|
display: grid;
|
||
|
|
gap: 8px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.audit-field label {
|
||
|
|
color: #475467;
|
||
|
|
font-size: 13px;
|
||
|
|
font-weight: 800;
|
||
|
|
}
|
||
|
|
|
||
|
|
.audit-conclusion {
|
||
|
|
display: grid;
|
||
|
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||
|
|
gap: 12px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.conclusion-btn {
|
||
|
|
height: 44px;
|
||
|
|
display: inline-flex;
|
||
|
|
align-items: center;
|
||
|
|
justify-content: center;
|
||
|
|
gap: 8px;
|
||
|
|
border: 1px solid #d8e0e8;
|
||
|
|
border-radius: 8px;
|
||
|
|
background: #fff;
|
||
|
|
color: #475467;
|
||
|
|
font: inherit;
|
||
|
|
font-size: 14px;
|
||
|
|
font-weight: 800;
|
||
|
|
cursor: pointer;
|
||
|
|
transition: all 0.18s ease;
|
||
|
|
}
|
||
|
|
|
||
|
|
.conclusion-btn:hover {
|
||
|
|
border-color: #0f766e;
|
||
|
|
color: #0f766e;
|
||
|
|
}
|
||
|
|
|
||
|
|
.conclusion-btn.active.pass {
|
||
|
|
border-color: #0f766e;
|
||
|
|
background: #f0fdfa;
|
||
|
|
color: #0f766e;
|
||
|
|
}
|
||
|
|
|
||
|
|
.conclusion-btn.active.reject {
|
||
|
|
border-color: #dc2626;
|
||
|
|
background: #fef2f2;
|
||
|
|
color: #dc2626;
|
||
|
|
}
|
||
|
|
</style>
|