You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

614 lines
22 KiB
Vue

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<div class="p-2">
<el-card shadow="never" style="margin-top: 0">
<!-- 审批按钮组件 -->
<approvalButton
@submitForm="submitForm"
@approvalVerifyOpen="approvalVerifyOpen"
@handleApprovalRecord="handleApprovalRecord"
:buttonLoading="buttonLoading"
:id="form.mailingApplyId"
:status="form.flowStatus"
:pageType="routeParams.type"
:mode="false"
>
<el-button
v-if="form.mailingApplyId && routeParams.type !== 'approval'"
v-hasPermi="['oa/crm:crmMailingApply:edit']"
type="success"
@click="openSignTimeDialog"
>更新签收时间</el-button
>
</approvalButton>
</el-card>
<el-card shadow="never" style="margin-top: 0">
<el-form ref="mailingApplyFormRef" :model="form" :loading="buttonLoading" :rules="rules" label-width="130px">
<el-divider content-position="left">基本信息</el-divider>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="邮寄申请编号" prop="mailingApplyCode">
<el-input v-model="form.mailingApplyCode" placeholder="自动生成邮寄申请编号" readonly>
<template #append>
<el-button type="primary" @click="generateMailingApplyCode" :disabled="isCodeGenerated">生成邮寄申请编号</el-button>
</template>
</el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="日期" prop="applicationDate">
<el-date-picker
clearable
v-model="form.applicationDate"
type="date"
value-format="YYYY-MM-DD"
placeholder="请选择日期"
:disabled="!isFormEditable"
style="width: 100%"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="经手人" prop="handlerId">
<el-select
v-model="form.handlerId"
placeholder="选择经手人"
filterable
@change="onHandlerChange"
:disabled="!isFormEditable"
style="width: 100%"
>
<el-option v-for="item in userList" :key="item.userId" :label="item.nickName" :value="item.userId" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="部门" prop="deptId">
<el-select
v-model="form.deptId"
placeholder="请选择部门"
filterable
clearable
:disabled="!isFormEditable"
style="width: 100%"
>
<el-option v-for="item in deptList" :key="item.deptId" :label="item.deptName" :value="item.deptId" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="省份" prop="province">
<el-input v-model="form.province" placeholder="例如目的地为山东省,请输入“山东”" :disabled="!isFormEditable" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="重量" prop="weight">
<el-input-number
v-model="form.weight"
:precision="2"
:step="0.1"
:min="0"
placeholder="请输入重量"
:disabled="!isFormEditable"
style="width: 100%"
>
<template #append>kg</template>
</el-input-number>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="发起邮寄类型" prop="mailingType">
<el-select v-model="form.mailingType" placeholder="请选择邮寄类型" :disabled="!isFormEditable" style="width: 100%">
<el-option v-for="dict in mailing_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="mailingFee">
<el-input-number
v-model="form.mailingFee"
:precision="2"
:step="1"
:min="0"
placeholder="请输入邮寄费用"
:disabled="!isFormEditable"
style="width: 100%"
>
<template #append>元</template>
</el-input-number>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="快递单号" prop="expressNo">
<el-input v-model="form.expressNo" placeholder="请输入快递单号" :disabled="!isFormEditable" />
</el-form-item>
</el-col>
</el-row>
<el-divider content-position="left">邮寄物品及事由</el-divider>
<el-row :gutter="20">
<el-col :span="24">
<el-form-item label="邮寄物品信息及申请事由" prop="itemInfo" label-width="180px">
<el-input v-model="form.itemInfo" type="textarea" :rows="4" placeholder="请输入邮寄物品信息及申请事由" :disabled="!isFormEditable" />
</el-form-item>
</el-col>
</el-row>
<el-divider content-position="left">附件及关联项目</el-divider>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="附件图片" prop="ossId">
<FileUpload
v-model="ossFileModel"
:limit="5"
:fileSize="20"
:fileType="['doc', 'docx', 'pdf', 'xls', 'xlsx', 'png', 'jpg', 'jpeg', 'gif']"
:disabled="!isFormEditable"
:isShowTip="true"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="项目名称" prop="projectId">
<el-input v-model="form.projectName" placeholder="点击选择项目" readonly @click="openProjectSelect">
<template #append>
<el-button icon="Search" @click="openProjectSelect" />
</template>
</el-input>
<el-button
v-if="form.projectId && !(routeParams.type === 'view' || routeParams.type === 'approval')"
link
type="danger"
@click="clearProjectSelect"
style="margin-left: 8px"
>
清空
</el-button>
</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-row>
<el-divider content-position="left">物流信息</el-divider>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="物流状态" prop="logisticsStatus">
<el-select v-model="form.logisticsStatus" placeholder="请选择物流状态" :disabled="!isFormEditable" style="width: 100%">
<el-option v-for="dict in logistics_status" :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="mailingTime">
<el-date-picker
clearable
v-model="form.mailingTime"
type="datetime"
value-format="YYYY-MM-DD HH:mm:ss"
placeholder="请选择邮寄时间"
:disabled="!isFormEditable"
style="width: 100%"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="签收时间" prop="signTime">
<el-date-picker
clearable
v-model="form.signTime"
type="datetime"
value-format="YYYY-MM-DD HH:mm:ss"
placeholder="请选择签收时间"
:disabled="!isFormEditable"
style="width: 100%"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" placeholder="请输入备注" :disabled="!isFormEditable" />
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-card>
<!-- 审批验证组件 -->
<SubmitVerify ref="submitVerifyRef" :task-variables="taskVariables" @submit-callback="submitCallback" />
<!-- 审批记录组件 -->
<ApprovalRecord ref="approvalRecordRef" />
<!-- 更新签收时间弹窗 -->
<el-dialog title="更新签收时间" v-model="signTimeDialog.visible" width="420px" append-to-body>
<el-form label-width="100px">
<el-form-item label="签收时间">
<el-date-picker
clearable
v-model="signTimeForm.signTime"
type="datetime"
value-format="YYYY-MM-DD HH:mm:ss"
placeholder="请选择签收时间"
style="width: 100%"
/>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="signTimeDialog.visible = false">取消</el-button>
<el-button type="primary" :loading="signTimeDialog.loading" @click="submitSignTime">保存</el-button>
</div>
</template>
</el-dialog>
<!-- 项目选择弹窗 -->
<ProjectSelect ref="projectSelectRef" :multiple="false" @confirm-call-back="projectSelectCallback" />
</div>
</template>
<script setup name="CrmMailingApplyEdit" lang="ts">
import {
addCrmMailingApply,
getCrmMailingApply,
mailingApplySubmitAndFlowStart,
updateCrmMailingApply,
updateCrmMailingApplySignTime
} from '@/api/oa/crm/crmMailingApply';
import { CrmMailingApplyForm } from '@/api/oa/crm/crmMailingApply/types';
import { getUserList, listUser } from '@/api/system/user';
import { UserQuery } from '@/api/system/user/types';
import { allListDept } from '@/api/system/dept';
import ProjectSelect from '@/components/ProjectSelect/index.vue';
import { getRuleGenerateCode } from '@/api/system/codeRule';
import { CodeRuleEnum, FlowCodeEnum } from '@/enums/OAEnum';
import { getInfo } from '@/api/login';
import SubmitVerify from '@/components/Process/submitVerify.vue';
import ApprovalRecord from '@/components/Process/approvalRecord.vue';
import approvalButton from '@/components/Process/approvalButton.vue';
import { useUserStore } from '@/store/modules/user';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { mailing_type, logistics_status, mailing_apply_status, wf_business_status } = toRefs<any>(
proxy?.useDict('mailing_type', 'logistics_status', 'mailing_apply_status', 'wf_business_status')
);
const router = useRouter();
const route = useRoute();
const userStore = useUserStore();
const mailingApplyFormRef = ref<ElFormInstance>();
const submitVerifyRef = ref<InstanceType<typeof SubmitVerify>>();
const approvalRecordRef = ref<InstanceType<typeof ApprovalRecord>>();
const projectSelectRef = ref<InstanceType<typeof ProjectSelect>>();
const buttonLoading = ref(false);
const isCodeGenerated = ref(false);
// P0修复计算属性控制表单是否可编辑仅草稿状态且非update模式才可编辑
const isFormEditable = computed(() => {
// 查看模式或审批模式永远不可编辑
if (routeParams.value.type === 'view' || routeParams.value.type === 'approval') {
return false;
}
// 新增模式可编辑
if (routeParams.value.type === 'add' || !form.value.mailingApplyId) {
return true;
}
// 修改模式:仅草稿状态可编辑
return form.value.mailingApplyStatus === '1';
});
const signTimeDialog = reactive({ visible: false, loading: false });
const signTimeForm = reactive<{ signTime: string | undefined }>({ signTime: undefined });
// 路由参数统一使用query方式与projectInfo保持一致
const routeParams = ref<Record<string, any>>({});
// 任务变量
const taskVariables = ref<any>({});
// 用户列表
const userList = ref<any[]>([]);
// 部门列表
const deptList = ref<any[]>([]);
// OSS 上传内部 v-model 中转,避免直接绑定到 form 的字段类型导致TS报错
const ossFileModel = ref<string | string[] | undefined>(undefined);
const initFormData: CrmMailingApplyForm = {
mailingApplyId: undefined,
mailingApplyCode: undefined,
applicationDate: undefined,
handlerId: undefined,
handlerName: undefined,
deptId: undefined,
province: undefined,
weight: undefined,
mailingType: undefined,
mailingFee: undefined,
expressNo: undefined,
itemInfo: undefined,
projectId: undefined,
projectCode: undefined,
projectName: undefined,
ossId: undefined,
mailingApplyStatus: '1',
flowStatus: undefined,
logisticsStatus: undefined,
mailingTime: undefined,
signTime: undefined,
remark: undefined,
flowCode: undefined,
variables: undefined,
bizExt: undefined
};
const data = reactive<{ form: CrmMailingApplyForm; rules: any }>({
form: { ...initFormData },
rules: {
applicationDate: [{ required: true, message: '申请日期不能为空', trigger: 'blur' }],
handlerId: [{ required: true, message: '经手人不能为空', trigger: 'change' }],
province: [{ required: true, message: '省份不能为空', trigger: 'blur' }],
weight: [{ required: true, message: '重量不能为空', trigger: 'blur' }],
mailingType: [{ required: true, message: '邮寄类型不能为空', trigger: 'change' }],
mailingFee: [{ required: true, message: '邮寄费用不能为空', trigger: 'blur' }],
itemInfo: [{ required: true, message: '邮寄物品信息及申请事由不能为空', trigger: 'blur' }],
expressNo: [{ required: true, message: '快递单号不能为空', trigger: 'blur' }],
logisticsStatus: [{ required: true, message: '物流状态不能为空', trigger: 'change' }],
mailingTime: [{ required: true, message: '邮寄时间不能为空', trigger: 'change' }]
}
});
const { form, rules } = toRefs(data);
/** 加载用户列表 */
const loadUserList = async () => {
try {
const res = await getUserList({} as any);
userList.value = res.data;
} catch (e) {
userList.value = [];
}
};
/** 加载部门列表 */
const loadDeptList = async () => {
try {
const res = await allListDept({ deptCategory: '03' } as any);
deptList.value = res.data || [];
} catch (e) {
deptList.value = [];
}
};
/** 打开项目选择弹窗 */
const openProjectSelect = () => {
if (routeParams.value.type === 'view' || routeParams.value.type === 'approval') {
return;
}
projectSelectRef.value?.open();
};
/** 项目选择回调 */
const projectSelectCallback = (selectedProjects: any[]) => {
if (selectedProjects && selectedProjects.length > 0) {
const project = selectedProjects[0];
form.value.projectId = project.projectId;
form.value.projectCode = project.projectCode;
form.value.projectName = project.projectName;
}
};
/** 清空项目选择 */
const clearProjectSelect = () => {
if (routeParams.value.type === 'view' || routeParams.value.type === 'approval') {
return;
}
form.value.projectId = undefined;
form.value.projectCode = undefined;
form.value.projectName = undefined;
};
watch(
() => form.value.ossId,
(val) => {
ossFileModel.value = val as any;
},
{ immediate: true }
);
watch(
() => ossFileModel.value,
(val) => {
form.value.ossId = val as any;
}
);
/** 经手人变更时自动填充姓名和部门 */
const onHandlerChange = (userId: number) => {
const user = userList.value.find((u) => u.userId === userId);
if (user) {
form.value.handlerName = user.nickName;
form.value.deptId = user.deptId;
}
};
/** 生成邮寄申请编号 */
const generateMailingApplyCode = async () => {
if (isCodeGenerated.value) return;
try {
const params = { codeRuleCode: CodeRuleEnum.MAILING_APPLY } as any;
const res = await getRuleGenerateCode(params);
form.value.mailingApplyCode = res.msg;
if (form.value.mailingApplyCode) {
isCodeGenerated.value = true;
proxy?.$modal.msgSuccess('邮寄申请编号生成成功');
}
} catch (error) {
console.error('生成邮寄申请编号失败:', error);
proxy?.$modal.msgError('生成邮寄申请编号失败');
}
};
/** 加载表单数据 */
const loadFormData = async () => {
// 获取路由参数(兼容新旧路由)
const id = (route.query.id as string | number) || (route.params.mailingApplyId as string | number);
const type = (route.query.type as string) || (id && id !== '0' ? 'update' : 'add');
routeParams.value = { ...route.query, id, type } as any;
if (id && id !== '0' && (routeParams.value.type === 'update' || routeParams.value.type === 'view' || routeParams.value.type === 'approval')) {
const res = await getCrmMailingApply(id);
Object.assign(form.value, res.data);
console.log('ossId:', form.value.ossId); //
if (form.value.mailingApplyCode) {
isCodeGenerated.value = true;
}
} else {
// 新增时生成编号并设置默认值
await generateMailingApplyCode();
form.value.applicationDate = new Date().toISOString().split('T')[0];
// 默认设置当前登录用户为经手人getUserList无权限时使用getInfo兜底部门信息
form.value.handlerId = userStore.userId;
form.value.handlerName = userStore.nickname as any;
try {
const userInfoRes = await getInfo();
const userVO = userInfoRes.data?.user;
if (userVO) {
form.value.handlerName = userVO.nickName;
form.value.deptId = userVO.deptId;
}
} catch (e) {
// 忽略异常:避免因权限/网络问题导致新增页不可用
}
onHandlerChange(userStore.userId as number);
}
};
/** 审批验证组件打开 */
const approvalVerifyOpen = () => {
submitVerifyRef.value?.openDialog(routeParams.value.taskId as any);
};
/** 审批记录 */
const handleApprovalRecord = () => {
approvalRecordRef.value?.init(form.value.mailingApplyId);
};
/** 审批回调 */
const submitCallback = () => {
proxy?.$modal.msgSuccess('操作成功');
proxy?.$tab.closePage();
router.go(-1);
};
const openSignTimeDialog = () => {
signTimeForm.signTime = form.value.signTime as any;
signTimeDialog.visible = true;
};
const submitSignTime = async () => {
if (!form.value.mailingApplyId) {
proxy?.$modal.msgError('请先保存单据');
return;
}
signTimeDialog.loading = true;
try {
const res = await updateCrmMailingApplySignTime({ mailingApplyId: form.value.mailingApplyId, signTime: signTimeForm.signTime } as any);
form.value = res.data;
proxy?.$modal.msgSuccess('签收时间更新成功');
signTimeDialog.visible = false;
} finally {
signTimeDialog.loading = false;
}
};
/** 提交表单 */
const submitForm = async (status: string, mode: boolean) => {
if (!mailingApplyFormRef.value) {
return;
}
if (routeParams.value.type !== 'view' && routeParams.value.type !== 'approval' && !form.value.mailingApplyCode) {
await generateMailingApplyCode();
if (!form.value.mailingApplyCode) {
proxy?.$modal.msgError('邮寄申请编号生成失败,请稍后重试');
return;
}
}
try {
if (status === 'draft') {
await mailingApplyFormRef.value.validateField(['applicationDate', 'handlerId', 'province', 'weight', 'mailingType', 'mailingFee', 'itemInfo']);
} else {
await mailingApplyFormRef.value.validate();
}
} catch (e) {
return;
}
buttonLoading.value = true;
try {
if (status !== 'draft') {
form.value.flowCode = FlowCodeEnum.MAILING_APPLY_CODE;
form.value.variables = {
mailingApplyId: form.value.mailingApplyId,
mailingApplyCode: form.value.mailingApplyCode,
applicationDate: form.value.applicationDate,
handlerId: form.value.handlerId,
handlerName: form.value.handlerName,
deptId: form.value.deptId,
province: form.value.province,
weight: form.value.weight,
mailingType: form.value.mailingType,
mailingFee: form.value.mailingFee,
expressNo: form.value.expressNo,
itemInfo: form.value.itemInfo,
projectId: form.value.projectId,
projectCode: form.value.projectCode,
projectName: form.value.projectName,
logisticsStatus: form.value.logisticsStatus,
mailingTime: form.value.mailingTime,
signTime: form.value.signTime,
remark: form.value.remark,
entity: { ...form.value }
};
form.value.bizExt = {
businessTitle: '邮寄申请',
businessCode: form.value.mailingApplyCode
};
const res = await mailingApplySubmitAndFlowStart(form.value);
form.value = res.data;
proxy?.$modal.msgSuccess('提交成功');
proxy?.$tab.closePage();
router.go(-1);
} else {
form.value.mailingApplyStatus = '1';
form.value.flowStatus = 'draft';
if (form.value.mailingApplyId) {
await updateCrmMailingApply(form.value);
} else {
const res = await addCrmMailingApply(form.value);
form.value = res.data;
}
proxy?.$modal.msgSuccess('暂存成功');
// P1修复暂存成功后关闭tab返回列表与projectInfo保持一致
proxy?.$tab.closePage();
router.go(-1);
}
} finally {
buttonLoading.value = false;
}
};
onMounted(async () => {
nextTick(async () => {
proxy?.$modal.loading('正在加载数据,请稍后...');
await loadUserList();
await loadDeptList();
await loadFormData();
proxy?.$modal.closeLoading();
});
});
</script>