|
|
|
|
@ -0,0 +1,528 @@
|
|
|
|
|
<template>
|
|
|
|
|
<div class="p-2">
|
|
|
|
|
<el-card shadow="never" style="margin-top: 0">
|
|
|
|
|
<!-- 审批按钮组件 -->
|
|
|
|
|
<approvalButton
|
|
|
|
|
@submitForm="submitForm"
|
|
|
|
|
@approvalVerifyOpen="approvalVerifyOpen"
|
|
|
|
|
@handleApprovalRecord="handleApprovalRecord"
|
|
|
|
|
:buttonLoading="buttonLoading"
|
|
|
|
|
:id="form.tripId"
|
|
|
|
|
:status="form.flowStatus"
|
|
|
|
|
:pageType="routeParams.type"
|
|
|
|
|
:mode="false"
|
|
|
|
|
/>
|
|
|
|
|
</el-card>
|
|
|
|
|
|
|
|
|
|
<el-card shadow="never" style="margin-top: 0">
|
|
|
|
|
<template #header>
|
|
|
|
|
<div style="text-align: left; font-weight: bold; font-size: 24px">出差申请{{ form.tripId ? ' - 修改' : ' - 新增' }}</div>
|
|
|
|
|
</template>
|
|
|
|
|
<el-form ref="businessTripApplyFormRef" :model="form" :loading="buttonLoading" :rules="rules" label-width="120px">
|
|
|
|
|
<!-- 通用字段区域 -->
|
|
|
|
|
<el-row :gutter="20">
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
<el-form-item label="出差类型" prop="tripType">
|
|
|
|
|
<el-select v-model="form.tripType" placeholder="请选择出差类型" :disabled="isFormDisabled || !!form.tripId">
|
|
|
|
|
<el-option v-for="dict in trip_type" :key="dict.value" :label="dict.label" :value="dict.value" />
|
|
|
|
|
</el-select>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
</el-col>
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
<el-form-item label="申请单号" prop="applyCode">
|
|
|
|
|
<el-input v-model="form.applyCode" placeholder="点击生成申请单号" :disabled="isFormDisabled">
|
|
|
|
|
<template #append>
|
|
|
|
|
<el-button type="primary" @click="generateApplyCode" :disabled="isCodeGenerated || isFormDisabled">生成编号</el-button>
|
|
|
|
|
</template>
|
|
|
|
|
</el-input>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
</el-col>
|
|
|
|
|
|
|
|
|
|
<!-- 动态字段:安装调试 (Type 1) -->
|
|
|
|
|
<template v-if="form.tripType === '1'">
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
<el-form-item label="项目名称" prop="projectId">
|
|
|
|
|
<el-input v-model="form.projectName" placeholder="请选择项目" readonly :disabled="isFormDisabled" @click="openProjectSelect">
|
|
|
|
|
<template #suffix>
|
|
|
|
|
<el-icon style="cursor: pointer" @click.stop="openProjectSelect"><Search /></el-icon>
|
|
|
|
|
</template>
|
|
|
|
|
</el-input>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
</el-col>
|
|
|
|
|
<!-- 隐藏字段用于存储ID -->
|
|
|
|
|
<el-col :span="0">
|
|
|
|
|
<el-form-item v-show="false" prop="projectId">
|
|
|
|
|
<el-input v-model="form.projectId" />
|
|
|
|
|
</el-form-item>
|
|
|
|
|
</el-col>
|
|
|
|
|
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
<el-form-item label="项目号" prop="projectCode">
|
|
|
|
|
<el-input v-model="form.projectCode" placeholder="选择项目后自动显示" disabled />
|
|
|
|
|
</el-form-item>
|
|
|
|
|
</el-col>
|
|
|
|
|
<el-col :span="24">
|
|
|
|
|
<el-form-item label="出差事由" prop="tripReason">
|
|
|
|
|
<el-input
|
|
|
|
|
v-model="form.tripReason"
|
|
|
|
|
type="textarea"
|
|
|
|
|
placeholder="请输入出差事由"
|
|
|
|
|
:disabled="isFormDisabled"
|
|
|
|
|
maxlength="800"
|
|
|
|
|
show-word-limit
|
|
|
|
|
:rows="3"
|
|
|
|
|
/>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
</el-col>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<!-- 动态字段:市场交流 (Type 2) -->
|
|
|
|
|
<template v-if="form.tripType === '2'">
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
<el-form-item label="出差地点" prop="tripLocation">
|
|
|
|
|
<el-input v-model="form.tripLocation" placeholder="如:北京、上海、杭州" :disabled="isFormDisabled" />
|
|
|
|
|
</el-form-item>
|
|
|
|
|
</el-col>
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
<el-form-item label="交流对象" prop="exchangeObject">
|
|
|
|
|
<el-input v-model="form.exchangeObject" placeholder="拜访客户名称" :disabled="isFormDisabled" />
|
|
|
|
|
</el-form-item>
|
|
|
|
|
</el-col>
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
<el-form-item label="业务方向" prop="businessDirection">
|
|
|
|
|
<el-select v-model="form.businessDirection" placeholder="选择业务方向" :disabled="isFormDisabled">
|
|
|
|
|
<el-option v-for="dict in business_direction" :key="dict.value" :label="dict.label" :value="dict.value" />
|
|
|
|
|
</el-select>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
</el-col>
|
|
|
|
|
<el-col :span="24">
|
|
|
|
|
<el-form-item label="交流目的" prop="exchangePurpose">
|
|
|
|
|
<el-input v-model="form.exchangePurpose" placeholder="请输入交流目的" :disabled="isFormDisabled" />
|
|
|
|
|
</el-form-item>
|
|
|
|
|
</el-col>
|
|
|
|
|
<el-col :span="24">
|
|
|
|
|
<el-form-item label="交流过程简述" prop="exchangeProcess">
|
|
|
|
|
<el-input
|
|
|
|
|
v-model="form.exchangeProcess"
|
|
|
|
|
type="textarea"
|
|
|
|
|
placeholder="如与某某客户某某负责人交谈,参观XX等"
|
|
|
|
|
:disabled="isFormDisabled"
|
|
|
|
|
:rows="3"
|
|
|
|
|
/>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
</el-col>
|
|
|
|
|
<el-col :span="24">
|
|
|
|
|
<el-form-item label="结果反馈" prop="feedback">
|
|
|
|
|
<el-input
|
|
|
|
|
v-model="form.feedback"
|
|
|
|
|
type="textarea"
|
|
|
|
|
placeholder="达成某种共识或初步合作意向或会议成果"
|
|
|
|
|
:disabled="isFormDisabled"
|
|
|
|
|
:rows="3"
|
|
|
|
|
/>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
</el-col>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<!-- 动态字段:展会/会议 (Type 3) -->
|
|
|
|
|
<template v-if="form.tripType === '3'">
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
<el-form-item label="出差地点" prop="tripLocation">
|
|
|
|
|
<el-input v-model="form.tripLocation" placeholder="如:北京、上海、杭州" :disabled="isFormDisabled" />
|
|
|
|
|
</el-form-item>
|
|
|
|
|
</el-col>
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
<el-form-item label="会议/展会名称" prop="meetingName">
|
|
|
|
|
<el-input v-model="form.meetingName" placeholder="请输入" :disabled="isFormDisabled" />
|
|
|
|
|
</el-form-item>
|
|
|
|
|
</el-col>
|
|
|
|
|
<el-col :span="24">
|
|
|
|
|
<el-form-item label="结果反馈" prop="feedback">
|
|
|
|
|
<el-input
|
|
|
|
|
v-model="form.feedback"
|
|
|
|
|
type="textarea"
|
|
|
|
|
placeholder="达成某种共识或初步合作意向或会议成果"
|
|
|
|
|
:disabled="isFormDisabled"
|
|
|
|
|
:rows="3"
|
|
|
|
|
/>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
</el-col>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<!-- 动态字段:其他 (Type 4),以及Type 1的部分复用字段 -->
|
|
|
|
|
<template v-if="form.tripType === '4'">
|
|
|
|
|
<el-col :span="24">
|
|
|
|
|
<el-form-item label="出差地点" prop="tripLocation">
|
|
|
|
|
<el-input v-model="form.tripLocation" placeholder="如:北京、上海、杭州" :disabled="isFormDisabled" />
|
|
|
|
|
</el-form-item>
|
|
|
|
|
</el-col>
|
|
|
|
|
<el-col :span="24">
|
|
|
|
|
<el-form-item label="出差事由" prop="tripReason">
|
|
|
|
|
<el-input
|
|
|
|
|
v-model="form.tripReason"
|
|
|
|
|
type="textarea"
|
|
|
|
|
placeholder="请输入出差事由"
|
|
|
|
|
:disabled="isFormDisabled"
|
|
|
|
|
maxlength="800"
|
|
|
|
|
show-word-limit
|
|
|
|
|
:rows="3"
|
|
|
|
|
/>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
</el-col>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<!-- 安装调试的出差地点统一放这里 -->
|
|
|
|
|
<template v-if="form.tripType === '1'">
|
|
|
|
|
<el-col :span="24">
|
|
|
|
|
<el-form-item label="出差地点" prop="tripLocation">
|
|
|
|
|
<el-input v-model="form.tripLocation" placeholder="如:北京、上海、杭州" :disabled="isFormDisabled" />
|
|
|
|
|
</el-form-item>
|
|
|
|
|
</el-col>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
<el-form-item label="开始时间" prop="startTime">
|
|
|
|
|
<el-date-picker
|
|
|
|
|
v-model="form.startTime"
|
|
|
|
|
type="date"
|
|
|
|
|
value-format="YYYY-MM-DD"
|
|
|
|
|
placeholder="选择日期"
|
|
|
|
|
:disabled="isFormDisabled"
|
|
|
|
|
@change="calculateDuration"
|
|
|
|
|
style="width: 100%"
|
|
|
|
|
/>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
</el-col>
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
<el-form-item label="结束时间" prop="endTime">
|
|
|
|
|
<el-date-picker
|
|
|
|
|
v-model="form.endTime"
|
|
|
|
|
type="date"
|
|
|
|
|
value-format="YYYY-MM-DD"
|
|
|
|
|
placeholder="选择日期"
|
|
|
|
|
:disabled="isFormDisabled"
|
|
|
|
|
@change="calculateDuration"
|
|
|
|
|
style="width: 100%"
|
|
|
|
|
/>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
</el-col>
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
<el-form-item label="时长(天)" prop="durationDays">
|
|
|
|
|
<el-input-number v-model="form.durationDays" :precision="1" :step="0.5" :min="0" disabled style="width: 100%" />
|
|
|
|
|
</el-form-item>
|
|
|
|
|
</el-col>
|
|
|
|
|
|
|
|
|
|
<el-col :span="24">
|
|
|
|
|
<el-form-item label="备注" prop="remark">
|
|
|
|
|
<el-input v-model="form.remark" type="textarea" placeholder="请输入备注" :disabled="isFormDisabled" />
|
|
|
|
|
</el-form-item>
|
|
|
|
|
</el-col>
|
|
|
|
|
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
<el-form-item label="下一步审批人" prop="variables.approverId">
|
|
|
|
|
<el-select
|
|
|
|
|
v-model="form.variables.approverId"
|
|
|
|
|
placeholder="请选择或搜索审批人"
|
|
|
|
|
filterable
|
|
|
|
|
clearable
|
|
|
|
|
style="width: 100%"
|
|
|
|
|
:disabled="isFormDisabled"
|
|
|
|
|
@change="handleApproverSelectChange"
|
|
|
|
|
>
|
|
|
|
|
<el-option v-for="user in userList" :key="user.userId" :label="user.nickName" :value="user.userId" />
|
|
|
|
|
</el-select>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
</el-col>
|
|
|
|
|
</el-row>
|
|
|
|
|
</el-form>
|
|
|
|
|
</el-card>
|
|
|
|
|
|
|
|
|
|
<!-- 提交审批组件 -->
|
|
|
|
|
<submitVerify ref="submitVerifyRef" :task-variables="taskVariables" @submit-callback="submitCallback" />
|
|
|
|
|
<!-- 审批记录 -->
|
|
|
|
|
<approvalRecord ref="approvalRecordRef" />
|
|
|
|
|
<!-- 项目选择组件 -->
|
|
|
|
|
<ProjectSelect ref="projectSelectRef" :multiple="false" @confirm-call-back="projectInfoSelectCallBack"></ProjectSelect>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script setup name="BusinessTripApplyEdit" lang="ts">
|
|
|
|
|
import {
|
|
|
|
|
addBusinessTripApply,
|
|
|
|
|
updateBusinessTripApply,
|
|
|
|
|
getBusinessTripApply,
|
|
|
|
|
submitBusinessTripApplyAndFlowStart
|
|
|
|
|
} from '@/api/oa/crm/businessTripApply';
|
|
|
|
|
import { BusinessTripApplyForm } from '@/api/oa/crm/businessTripApply/types';
|
|
|
|
|
import { getRuleGenerateCode } from '@/api/system/codeRule';
|
|
|
|
|
import { startWorkFlow } from '@/api/workflow/task';
|
|
|
|
|
import { StartProcessBo } from '@/api/workflow/workflowCommon/types';
|
|
|
|
|
import ApprovalButton from '@/components/Process/approvalButton.vue';
|
|
|
|
|
import SubmitVerify from '@/components/Process/submitVerify.vue';
|
|
|
|
|
import ApprovalRecord from '@/components/Process/approvalRecord.vue';
|
|
|
|
|
import ProjectSelect from '@/components/ProjectSelect/index.vue';
|
|
|
|
|
import { CodeRuleEnum, FlowCodeEnum } from '@/enums/OAEnum';
|
|
|
|
|
import { getInfo } from '@/api/login';
|
|
|
|
|
import { listUser } from '@/api/system/user'; // 导入用户列表API
|
|
|
|
|
import { ProjectInfoVO } from '@/api/oa/erp/projectInfo/types';
|
|
|
|
|
import dayjs from 'dayjs';
|
|
|
|
|
|
|
|
|
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
|
|
|
|
const route = useRoute();
|
|
|
|
|
const router = useRouter();
|
|
|
|
|
|
|
|
|
|
// 字典加载
|
|
|
|
|
const { trip_type, business_direction } = toRefs<any>(proxy?.useDict('trip_type', 'business_direction'));
|
|
|
|
|
|
|
|
|
|
// 路由参数
|
|
|
|
|
const routeParams = ref<Record<string, any>>({});
|
|
|
|
|
const buttonLoading = ref(false);
|
|
|
|
|
|
|
|
|
|
const businessTripApplyFormRef = ref<ElFormInstance>();
|
|
|
|
|
const submitVerifyRef = ref<InstanceType<typeof SubmitVerify>>();
|
|
|
|
|
const approvalRecordRef = ref<InstanceType<typeof ApprovalRecord>>();
|
|
|
|
|
const projectSelectRef = ref<InstanceType<typeof ProjectSelect>>();
|
|
|
|
|
// const userSelectRef = ref<InstanceType<typeof UserSelect>>(); // 审批人选择 ref
|
|
|
|
|
|
|
|
|
|
const userList = ref<any[]>([]); // 用户列表
|
|
|
|
|
|
|
|
|
|
const isCodeGenerated = ref(false);
|
|
|
|
|
|
|
|
|
|
// 流程相关数据
|
|
|
|
|
const submitFormData = ref<StartProcessBo>({
|
|
|
|
|
businessId: '',
|
|
|
|
|
flowCode: FlowCodeEnum.BUSINESS_TRIP_CODE,
|
|
|
|
|
variables: {},
|
|
|
|
|
bizExt: {}
|
|
|
|
|
});
|
|
|
|
|
const taskVariables = ref<Record<string, any>>({});
|
|
|
|
|
|
|
|
|
|
const initFormData: BusinessTripApplyForm = {
|
|
|
|
|
tripId: undefined,
|
|
|
|
|
applyCode: undefined,
|
|
|
|
|
tripType: undefined,
|
|
|
|
|
applicantId: undefined,
|
|
|
|
|
applicantName: undefined,
|
|
|
|
|
deptId: undefined,
|
|
|
|
|
deptName: undefined,
|
|
|
|
|
tripLocation: undefined,
|
|
|
|
|
startTime: undefined,
|
|
|
|
|
endTime: undefined,
|
|
|
|
|
durationDays: undefined,
|
|
|
|
|
tripReason: undefined,
|
|
|
|
|
projectId: undefined,
|
|
|
|
|
customerId: undefined,
|
|
|
|
|
exchangeObject: undefined,
|
|
|
|
|
businessDirection: undefined,
|
|
|
|
|
exchangePurpose: undefined,
|
|
|
|
|
exchangeProcess: undefined,
|
|
|
|
|
meetingName: undefined,
|
|
|
|
|
feedback: undefined,
|
|
|
|
|
tripStatus: '1', // 默认暂存
|
|
|
|
|
flowStatus: 'draft',
|
|
|
|
|
remark: undefined,
|
|
|
|
|
ossId: undefined,
|
|
|
|
|
variables: {} // 初始化 variables
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const data = reactive({
|
|
|
|
|
form: { ...initFormData },
|
|
|
|
|
rules: {
|
|
|
|
|
tripType: [{ required: true, message: '出差类型不能为空', trigger: 'change' }],
|
|
|
|
|
applyCode: [{ required: true, message: '申请单号不能为空', trigger: 'blur' }],
|
|
|
|
|
tripLocation: [{ required: true, message: '出差地点不能为空', trigger: 'blur' }],
|
|
|
|
|
startTime: [{ required: true, message: '开始时间不能为空', trigger: 'change' }],
|
|
|
|
|
endTime: [{ required: true, message: '结束时间不能为空', trigger: 'change' }],
|
|
|
|
|
durationDays: [{ required: true, message: '时长不能为空', trigger: 'blur' }],
|
|
|
|
|
// 动态校验
|
|
|
|
|
projectId: [{ required: true, message: '项目名称不能为空', trigger: 'change' }],
|
|
|
|
|
exchangeObject: [{ required: true, message: '交流对象不能为空', trigger: 'blur' }],
|
|
|
|
|
businessDirection: [{ required: true, message: '业务方向不能为空', trigger: 'change' }],
|
|
|
|
|
exchangePurpose: [{ required: true, message: '交流目的不能为空', trigger: 'blur' }],
|
|
|
|
|
exchangeProcess: [{ required: true, message: '交流过程简述不能为空', trigger: 'blur' }],
|
|
|
|
|
feedback: [{ required: true, message: '结果反馈不能为空', trigger: 'blur' }],
|
|
|
|
|
meetingName: [{ required: true, message: '会议/展会名称不能为空', trigger: 'blur' }],
|
|
|
|
|
'variables.approverId': [{ required: true, message: '请选择下一步审批人', trigger: 'change' }]
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const { form, rules } = toRefs(data);
|
|
|
|
|
|
|
|
|
|
const isFormDisabled = computed(() => {
|
|
|
|
|
return routeParams.value.type === 'view' || routeParams.value.type === 'approval';
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 计算动态校验规则
|
|
|
|
|
const computedRules = computed(() => {
|
|
|
|
|
const baseRules = { ...rules.value };
|
|
|
|
|
// 根据 tripType 过滤不需要的规则 (简单处理:校验时 el-form-item 不渲染则不校验,或者在这里动态调整)
|
|
|
|
|
// Element Plus Form 组件通常只校验渲染出来的 Item,所以只要 v-if 控制好了,rules 可以放全集。
|
|
|
|
|
// 但是为了保险,可以在提交时做更严格的检查。
|
|
|
|
|
return baseRules;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
onMounted(async () => {
|
|
|
|
|
nextTick(async () => {
|
|
|
|
|
routeParams.value = route.query;
|
|
|
|
|
const id = routeParams.value.id;
|
|
|
|
|
|
|
|
|
|
// 自动填充申请人信息
|
|
|
|
|
if (!id) {
|
|
|
|
|
try {
|
|
|
|
|
const userRes = await getInfo();
|
|
|
|
|
if (userRes.data?.user) {
|
|
|
|
|
form.value.applicantId = userRes.data.user.userId;
|
|
|
|
|
form.value.applicantName = userRes.data.user.nickName;
|
|
|
|
|
form.value.deptId = userRes.data.user.deptId;
|
|
|
|
|
form.value.deptName = userRes.data.user.deptName;
|
|
|
|
|
}
|
|
|
|
|
} catch (e) {
|
|
|
|
|
console.error('获取用户信息失败', e);
|
|
|
|
|
}
|
|
|
|
|
// 从 index 页面传来 tripType
|
|
|
|
|
if (routeParams.value.tripType) {
|
|
|
|
|
form.value.tripType = routeParams.value.tripType;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 加载用户列表 (用于审批人选择)
|
|
|
|
|
listUser({ pageNum: 1, pageSize: 1000 }).then((res: any) => {
|
|
|
|
|
userList.value = res.rows;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (id && (routeParams.value.type === 'update' || routeParams.value.type === 'view' || routeParams.value.type === 'approval')) {
|
|
|
|
|
const res = await getBusinessTripApply(id);
|
|
|
|
|
Object.assign(form.value, res.data);
|
|
|
|
|
if (form.value.applyCode) {
|
|
|
|
|
isCodeGenerated.value = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 生成申请编号
|
|
|
|
|
const generateApplyCode = async () => {
|
|
|
|
|
if (isCodeGenerated.value) return;
|
|
|
|
|
try {
|
|
|
|
|
const params = { codeRuleCode: CodeRuleEnum.BUSINESS_TRIP } as any;
|
|
|
|
|
const res = await getRuleGenerateCode(params);
|
|
|
|
|
if (res.code === 200) {
|
|
|
|
|
form.value.applyCode = res.msg;
|
|
|
|
|
isCodeGenerated.value = true;
|
|
|
|
|
proxy?.$modal.msgSuccess('编号生成成功');
|
|
|
|
|
}
|
|
|
|
|
} catch (e) {
|
|
|
|
|
console.error(e);
|
|
|
|
|
proxy?.$modal.msgError('编号生成失败');
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 计算时长
|
|
|
|
|
const calculateDuration = () => {
|
|
|
|
|
if (form.value.startTime && form.value.endTime) {
|
|
|
|
|
const start = dayjs(form.value.startTime);
|
|
|
|
|
const end = dayjs(form.value.endTime);
|
|
|
|
|
const diff = end.diff(start, 'day');
|
|
|
|
|
// 简单的天数计算,实际可能需要包含半天,这里先按自然日 + 1 (如果是同一天算1天) 或者 diff
|
|
|
|
|
// 需求是 decimal(10,1),通常是 0.5 天为单位。
|
|
|
|
|
// 假设同一天算 1 天
|
|
|
|
|
if (diff >= 0) {
|
|
|
|
|
form.value.durationDays = diff + 1;
|
|
|
|
|
} else {
|
|
|
|
|
form.value.durationDays = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 打开项目选择
|
|
|
|
|
const openProjectSelect = () => {
|
|
|
|
|
if (isFormDisabled.value) return;
|
|
|
|
|
projectSelectRef.value?.open();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 项目选择回调
|
|
|
|
|
const projectInfoSelectCallBack = (data: ProjectInfoVO[]) => {
|
|
|
|
|
if (data && data.length > 0) {
|
|
|
|
|
form.value.projectId = data[0].projectId;
|
|
|
|
|
form.value.projectName = data[0].projectName;
|
|
|
|
|
form.value.projectCode = data[0].projectCode;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 审批人选择变更
|
|
|
|
|
const handleApproverSelectChange = (val: any) => {
|
|
|
|
|
const user = userList.value.find((u) => u.userId === val);
|
|
|
|
|
if (user) {
|
|
|
|
|
form.value.variables = {
|
|
|
|
|
...form.value.variables,
|
|
|
|
|
approverName: user.nickName
|
|
|
|
|
};
|
|
|
|
|
} else {
|
|
|
|
|
form.value.variables = {
|
|
|
|
|
...form.value.variables,
|
|
|
|
|
approverName: undefined
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 提交表单 (包含暂存和提交审批)
|
|
|
|
|
const submitForm = (status: string, mode: boolean) => {
|
|
|
|
|
businessTripApplyFormRef.value?.validate(async (valid) => {
|
|
|
|
|
if (valid) {
|
|
|
|
|
buttonLoading.value = true;
|
|
|
|
|
try {
|
|
|
|
|
if (status !== 'draft') {
|
|
|
|
|
// 提交审批
|
|
|
|
|
form.value.tripStatus = '2'; // 审批中
|
|
|
|
|
form.value.flowStatus = 'waiting';
|
|
|
|
|
form.value.variables = {
|
|
|
|
|
...form.value.variables,
|
|
|
|
|
tripType: form.value.tripType
|
|
|
|
|
};
|
|
|
|
|
form.value.bizExt = {
|
|
|
|
|
businessTitle: '出差申请',
|
|
|
|
|
businessCode: form.value.applyCode
|
|
|
|
|
};
|
|
|
|
|
// 确保流程编码存在
|
|
|
|
|
form.value.flowCode = FlowCodeEnum.BUSINESS_TRIP_CODE;
|
|
|
|
|
const res = await submitBusinessTripApplyAndFlowStart(form.value);
|
|
|
|
|
// 成功后处理
|
|
|
|
|
proxy?.$modal.msgSuccess('提交成功');
|
|
|
|
|
submitCallback();
|
|
|
|
|
} else {
|
|
|
|
|
// 暂存
|
|
|
|
|
form.value.tripStatus = '1';
|
|
|
|
|
form.value.flowStatus = 'draft';
|
|
|
|
|
if (form.value.tripId) {
|
|
|
|
|
await updateBusinessTripApply(form.value);
|
|
|
|
|
} else {
|
|
|
|
|
const res = await addBusinessTripApply(form.value);
|
|
|
|
|
}
|
|
|
|
|
proxy?.$modal.msgSuccess('暂存成功');
|
|
|
|
|
submitCallback();
|
|
|
|
|
}
|
|
|
|
|
} catch (e) {
|
|
|
|
|
console.error(e);
|
|
|
|
|
} finally {
|
|
|
|
|
buttonLoading.value = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 审批记录
|
|
|
|
|
const handleApprovalRecord = () => {
|
|
|
|
|
approvalRecordRef.value?.init(form.value.tripId);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 打开审批详情
|
|
|
|
|
const approvalVerifyOpen = async () => {
|
|
|
|
|
await submitVerifyRef.value?.openDialog(routeParams.value.taskId);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 提交成功回调
|
|
|
|
|
const submitCallback = () => {
|
|
|
|
|
proxy?.$tab.closePage(route);
|
|
|
|
|
router.go(-1);
|
|
|
|
|
};
|
|
|
|
|
</script>
|