274 lines
8.2 KiB
Vue
274 lines
8.2 KiB
Vue
<script setup lang="ts">
|
|
import { computed, nextTick, reactive, ref, watch } from 'vue';
|
|
import { RDMS_OVERTIME_DURATION_DICT_CODE } from '@/constants/dict';
|
|
import {
|
|
fetchCreateOvertimeApplication,
|
|
fetchGetLoginUserDirectManager,
|
|
fetchGetOvertimeApplicationDetail,
|
|
fetchUpdateRejectedOvertimeApplication
|
|
} from '@/service/api';
|
|
import { useAuthStore } from '@/store/modules/auth';
|
|
import { useForm, useFormRules } from '@/hooks/common/form';
|
|
import BusinessFormDialog from '@/components/custom/business-form-dialog.vue';
|
|
import BusinessFormSection from '@/components/custom/business-form-section.vue';
|
|
import DictSelect from '@/components/custom/dict-select.vue';
|
|
|
|
defineOptions({ name: 'OvertimeApplicationOperateDialog' });
|
|
|
|
type OperateType = 'add' | 'edit';
|
|
|
|
interface Props {
|
|
operateType: OperateType;
|
|
rowData?: Api.OvertimeApplication.OvertimeApplication | null;
|
|
}
|
|
|
|
const props = defineProps<Props>();
|
|
|
|
const emit = defineEmits<{
|
|
submitted: [];
|
|
}>();
|
|
|
|
const visible = defineModel<boolean>('visible', {
|
|
default: false
|
|
});
|
|
|
|
const authStore = useAuthStore();
|
|
const { formRef, validate } = useForm();
|
|
const { createRequiredRule } = useFormRules();
|
|
|
|
const detailLoading = ref(false);
|
|
const submitting = ref(false);
|
|
const approverName = ref('');
|
|
|
|
const currentUserName = computed(() => authStore.userInfo.nickname || authStore.userInfo.userName || '--');
|
|
const isEdit = computed(() => props.operateType === 'edit');
|
|
const title = computed(() => (isEdit.value ? '修改并重新提交' : '新增加班申请'));
|
|
|
|
const model = reactive<Api.OvertimeApplication.SaveOvertimeApplicationParams>(createDefaultModel());
|
|
|
|
const rules = computed(
|
|
() =>
|
|
({
|
|
overtimeDate: [createRequiredRule('请选择加班日期')],
|
|
overtimeDuration: [createRequiredRule('请选择加班时长')],
|
|
overtimeReason: [
|
|
createRequiredRule('请输入加班原因'),
|
|
{
|
|
validator: (_rule, value: string, callback) => {
|
|
if (!value?.trim()) {
|
|
callback(new Error('请输入加班原因'));
|
|
return;
|
|
}
|
|
|
|
callback();
|
|
},
|
|
trigger: 'blur'
|
|
}
|
|
],
|
|
overtimeContent: [
|
|
createRequiredRule('请输入加班内容'),
|
|
{
|
|
validator: (_rule, value: string, callback) => {
|
|
if (!value?.trim()) {
|
|
callback(new Error('请输入加班内容'));
|
|
return;
|
|
}
|
|
|
|
callback();
|
|
},
|
|
trigger: 'blur'
|
|
}
|
|
],
|
|
approverId: [createRequiredRule('请选择审核人')]
|
|
}) satisfies Record<keyof Api.OvertimeApplication.SaveOvertimeApplicationParams, App.Global.FormRule[]>
|
|
);
|
|
|
|
function createDefaultModel(): Api.OvertimeApplication.SaveOvertimeApplicationParams {
|
|
return {
|
|
overtimeDate: '',
|
|
overtimeDuration: '',
|
|
overtimeReason: '',
|
|
overtimeContent: '',
|
|
approverId: ''
|
|
};
|
|
}
|
|
|
|
async function loadDirectManagerAsDefaultApprover() {
|
|
const { error, data } = await fetchGetLoginUserDirectManager();
|
|
|
|
if (!error && data?.id) {
|
|
model.approverId = data.id;
|
|
approverName.value = data.nickname;
|
|
}
|
|
}
|
|
|
|
async function initModel() {
|
|
detailLoading.value = true;
|
|
Object.assign(model, createDefaultModel());
|
|
approverName.value = '';
|
|
|
|
if (isEdit.value && props.rowData) {
|
|
const { error, data } = await fetchGetOvertimeApplicationDetail(props.rowData.id);
|
|
const detail = error || !data ? props.rowData : data;
|
|
|
|
model.overtimeDate = detail.overtimeDate;
|
|
model.overtimeDuration = detail.overtimeDuration;
|
|
model.overtimeReason = detail.overtimeReason;
|
|
model.overtimeContent = detail.overtimeContent;
|
|
model.approverId = detail.approverId;
|
|
approverName.value = detail.approverName;
|
|
} else {
|
|
await loadDirectManagerAsDefaultApprover();
|
|
}
|
|
|
|
detailLoading.value = false;
|
|
|
|
await nextTick();
|
|
formRef.value?.clearValidate();
|
|
}
|
|
|
|
async function handleSubmit() {
|
|
await validate();
|
|
|
|
const payload: Api.OvertimeApplication.SaveOvertimeApplicationParams = {
|
|
overtimeDate: model.overtimeDate,
|
|
overtimeDuration: model.overtimeDuration,
|
|
overtimeReason: model.overtimeReason.trim(),
|
|
overtimeContent: model.overtimeContent.trim(),
|
|
approverId: model.approverId
|
|
};
|
|
|
|
submitting.value = true;
|
|
|
|
const result =
|
|
isEdit.value && props.rowData
|
|
? await fetchUpdateRejectedOvertimeApplication(props.rowData.id, payload)
|
|
: await fetchCreateOvertimeApplication(payload);
|
|
|
|
submitting.value = false;
|
|
|
|
if (result.error) {
|
|
return;
|
|
}
|
|
|
|
window.$message?.success(isEdit.value ? '加班申请已重新提交' : '加班申请已提交');
|
|
visible.value = false;
|
|
emit('submitted');
|
|
}
|
|
|
|
watch(
|
|
() => visible.value,
|
|
value => {
|
|
if (value) {
|
|
initModel();
|
|
}
|
|
}
|
|
);
|
|
</script>
|
|
|
|
<template>
|
|
<BusinessFormDialog
|
|
v-model="visible"
|
|
:title="title"
|
|
preset="md"
|
|
:loading="detailLoading"
|
|
:confirm-loading="submitting"
|
|
@confirm="handleSubmit"
|
|
>
|
|
<ElForm ref="formRef" :model="model" :rules="rules" label-position="top" :validate-on-rule-change="false">
|
|
<BusinessFormSection title="申请信息">
|
|
<ElRow :gutter="16">
|
|
<ElCol :span="12">
|
|
<ElFormItem label="申请人">
|
|
<ElInput
|
|
class="overtime-application-operate-dialog__readonly-input"
|
|
:model-value="currentUserName"
|
|
readonly
|
|
/>
|
|
</ElFormItem>
|
|
</ElCol>
|
|
<ElCol :span="12">
|
|
<ElFormItem label="审核人" prop="approverId">
|
|
<ElInput
|
|
class="overtime-application-operate-dialog__readonly-input"
|
|
:model-value="approverName"
|
|
readonly
|
|
placeholder="暂无直属上级"
|
|
/>
|
|
</ElFormItem>
|
|
</ElCol>
|
|
<ElCol :span="12">
|
|
<ElFormItem label="加班日期" prop="overtimeDate" style="width: 100%">
|
|
<ElDatePicker
|
|
v-model="model.overtimeDate"
|
|
class="w-full"
|
|
type="date"
|
|
value-format="YYYY-MM-DD"
|
|
style="width: 100%"
|
|
placeholder="请选择加班日期"
|
|
/>
|
|
</ElFormItem>
|
|
</ElCol>
|
|
<ElCol :span="12">
|
|
<ElFormItem label="加班时长" prop="overtimeDuration">
|
|
<DictSelect
|
|
v-model="model.overtimeDuration"
|
|
:dict-code="RDMS_OVERTIME_DURATION_DICT_CODE"
|
|
placeholder="请选择加班时长"
|
|
/>
|
|
</ElFormItem>
|
|
</ElCol>
|
|
</ElRow>
|
|
</BusinessFormSection>
|
|
|
|
<BusinessFormSection title="加班说明">
|
|
<ElRow :gutter="16">
|
|
<ElCol :span="24">
|
|
<ElFormItem label="加班原因" prop="overtimeReason">
|
|
<ElInput
|
|
v-model="model.overtimeReason"
|
|
type="textarea"
|
|
:rows="3"
|
|
maxlength="500"
|
|
show-word-limit
|
|
placeholder="请输入加班原因"
|
|
/>
|
|
</ElFormItem>
|
|
</ElCol>
|
|
<ElCol :span="24">
|
|
<ElFormItem label="加班内容" prop="overtimeContent">
|
|
<ElInput
|
|
v-model="model.overtimeContent"
|
|
type="textarea"
|
|
:rows="4"
|
|
maxlength="1000"
|
|
show-word-limit
|
|
placeholder="请输入加班内容"
|
|
/>
|
|
</ElFormItem>
|
|
</ElCol>
|
|
</ElRow>
|
|
</BusinessFormSection>
|
|
</ElForm>
|
|
</BusinessFormDialog>
|
|
</template>
|
|
|
|
<style scoped>
|
|
:deep(.overtime-application-operate-dialog__readonly-input .el-input__wrapper) {
|
|
background: linear-gradient(180deg, rgb(241 245 249 / 98%), rgb(226 232 240 / 94%)), rgb(241 245 249);
|
|
box-shadow: 0 0 0 1px rgb(203 213 225 / 96%) inset;
|
|
cursor: default;
|
|
}
|
|
|
|
:deep(.overtime-application-operate-dialog__readonly-input .el-input__wrapper:hover),
|
|
:deep(.overtime-application-operate-dialog__readonly-input.is-focus .el-input__wrapper) {
|
|
box-shadow: 0 0 0 1px rgb(203 213 225 / 96%) inset;
|
|
}
|
|
|
|
:deep(.overtime-application-operate-dialog__readonly-input .el-input__inner) {
|
|
color: rgb(51 65 85 / 96%);
|
|
cursor: default;
|
|
-webkit-text-fill-color: rgb(51 65 85 / 96%);
|
|
}
|
|
</style>
|