添加功能下载验收单
This commit is contained in:
@@ -284,6 +284,15 @@ export function downloadDeliveryPackage(id) {
|
||||
});
|
||||
}
|
||||
|
||||
// 下载验收单(生成HTML格式的牛只发车验收单)
|
||||
export function downloadAcceptanceForm(id) {
|
||||
return request({
|
||||
url: `/delivery/downloadAcceptanceForm?id=${id}`,
|
||||
method: 'GET',
|
||||
responseType: 'blob', // 用于下载HTML文件
|
||||
});
|
||||
}
|
||||
|
||||
// 获取运送清单详情(用于编辑)
|
||||
export function getDeliveryDetail(id) {
|
||||
return request({
|
||||
|
||||
@@ -52,15 +52,17 @@ axios.interceptors.response.use(
|
||||
// 单独判断导出问题-start
|
||||
if(toString.call(responseData) === '[object Blob]' && (responseData.type !== 'application/json')) {
|
||||
download(response);
|
||||
return ElMessage({
|
||||
type: 'success',
|
||||
message: '导出成功!',
|
||||
});
|
||||
ElMessage({
|
||||
type: 'success',
|
||||
message: '导出成功!',
|
||||
});
|
||||
return Promise.resolve(response.data); // 返回 Promise,避免返回对象
|
||||
}else if(toString.call(responseData) === '[object Blob]' && (responseData.type == 'application/json')){
|
||||
setTimeout(() => {
|
||||
window.location.href = '/login';
|
||||
}, 1000);
|
||||
return ElMessage.error(`登录过期,请重新登录!`);
|
||||
ElMessage.error(`登录过期,请重新登录!`);
|
||||
return Promise.reject('登录过期,请重新登录!'); // 返回 Promise.reject,避免返回对象
|
||||
}
|
||||
// 单独判断导出问题-end
|
||||
|
||||
@@ -71,7 +73,8 @@ axios.interceptors.response.use(
|
||||
setTimeout(() => {
|
||||
window.location.href = '/login';
|
||||
}, 1000);
|
||||
return ElMessage.error(`登录过期,请重新登录!`);
|
||||
ElMessage.error(`登录过期,请重新登录!`);
|
||||
return Promise.reject('登录过期,请重新登录!'); // 返回 Promise.reject,避免返回对象
|
||||
}
|
||||
// console.log(responseData);
|
||||
// if (responseData && (responseData.code === 650)) {
|
||||
|
||||
@@ -102,6 +102,7 @@
|
||||
<el-button type="warning" link @click="editDelivery(scope.row)" v-hasPermi="['entry:edit']">编辑</el-button>
|
||||
<el-button type="success" link @click="updateStatus(scope.row)" v-hasPermi="['entry:status']">修改状态</el-button>
|
||||
<el-button type="info" link @click="downloadPackage(scope.row)" :loading="downLoading[scope.row.id]" v-hasPermi="['entry:download']">打包文件</el-button>
|
||||
<el-button type="primary" link @click="downloadAcceptanceFormHandler(scope.row)" :loading="downLoading[scope.row.id]" v-hasPermi="['entry:export']">下载验收单</el-button>
|
||||
<el-button type="danger" link @click="deleteDelivery(scope.row)" v-hasPermi="['entry:delete']">删除</el-button>
|
||||
</div>
|
||||
</template>
|
||||
@@ -125,7 +126,7 @@ import { ElMessage, ElMessageBox } from 'element-plus';
|
||||
import baseSearch from '@/components/common/searchCustom/index.vue';
|
||||
import createDeliveryDialog from '@/views/shipping/createDeliveryDialog.vue';
|
||||
import { inspectionList, downloadZip, pageDeviceList } from '@/api/abroad.js';
|
||||
import { updateDeliveryStatus, deleteDeliveryLogic, downloadDeliveryPackage, getDeliveryDetail } from '@/api/shipping.js';
|
||||
import { updateDeliveryStatus, deleteDeliveryLogic, downloadDeliveryPackage, getDeliveryDetail, downloadAcceptanceForm } from '@/api/shipping.js';
|
||||
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
@@ -679,10 +680,52 @@ const downloadPackage = async (row) => {
|
||||
ElMessage.info('正在打包文件,请稍候...');
|
||||
|
||||
// 调用后端API打包文件(包含图片、视频和信息)
|
||||
// 注意:由于响应拦截器设置了 responseType: 'blob',返回的是 Blob 对象
|
||||
const res = await downloadDeliveryPackage(row.id);
|
||||
|
||||
// 创建下载链接
|
||||
const blob = new Blob([res], { type: 'application/zip' });
|
||||
// 确保 res 是 Blob 对象,如果不是则转换为 Blob
|
||||
let blob;
|
||||
if (res instanceof Blob) {
|
||||
blob = res;
|
||||
} else {
|
||||
// 如果不是 Blob,尝试转换为 Blob
|
||||
blob = new Blob([res], { type: 'application/zip' });
|
||||
}
|
||||
|
||||
// 检查响应是否是有效的ZIP文件(通过检查ZIP文件魔数)
|
||||
// ZIP 文件的魔数是:50 4B 03 04 (PK\x03\x04)
|
||||
const arrayBuffer = await blob.arrayBuffer();
|
||||
const uint8Array = new Uint8Array(arrayBuffer);
|
||||
|
||||
// 检查是否是ZIP文件(前4个字节是 50 4B 03 04)
|
||||
const isZipFile = uint8Array.length >= 4 &&
|
||||
uint8Array[0] === 0x50 &&
|
||||
uint8Array[1] === 0x4B &&
|
||||
uint8Array[2] === 0x03 &&
|
||||
uint8Array[3] === 0x04;
|
||||
|
||||
if (!isZipFile) {
|
||||
// 响应是错误信息(JSON或文本),尝试读取并显示错误
|
||||
try {
|
||||
const decoder = new TextDecoder('utf-8');
|
||||
const errorText = decoder.decode(uint8Array);
|
||||
let errorMsg = '打包文件失败';
|
||||
try {
|
||||
// 尝试解析为 JSON
|
||||
const errorObj = JSON.parse(errorText);
|
||||
errorMsg = errorObj.msg || errorObj.message || errorText;
|
||||
} catch (e) {
|
||||
// 不是 JSON,直接使用文本
|
||||
errorMsg = errorText || '打包文件失败,请重试';
|
||||
}
|
||||
ElMessage.error(errorMsg);
|
||||
} catch (e) {
|
||||
ElMessage.error('打包文件失败,请重试');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 创建下载链接(使用验证后的 Blob)
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
const link = document.createElement('a');
|
||||
link.href = url;
|
||||
@@ -695,7 +738,69 @@ const downloadPackage = async (row) => {
|
||||
ElMessage.success('文件打包成功');
|
||||
} catch (error) {
|
||||
console.error('打包文件失败:', error);
|
||||
ElMessage.error('打包文件失败,请重试');
|
||||
ElMessage.error(error.message || '打包文件失败,请重试');
|
||||
} finally {
|
||||
downLoading[row.id] = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 下载验收单
|
||||
const downloadAcceptanceFormHandler = async (row) => {
|
||||
try {
|
||||
downLoading[row.id] = true;
|
||||
ElMessage.info('正在生成验收单,请稍候...');
|
||||
|
||||
// 调用后端API生成验收单
|
||||
const res = await downloadAcceptanceForm(row.id);
|
||||
|
||||
// 确保 res 是 Blob 对象
|
||||
let blob;
|
||||
if (res instanceof Blob) {
|
||||
blob = res;
|
||||
} else {
|
||||
blob = new Blob([res], { type: 'text/html;charset=UTF-8' });
|
||||
}
|
||||
|
||||
// 检查是否是HTML文件(通过检查内容)
|
||||
const arrayBuffer = await blob.arrayBuffer();
|
||||
const uint8Array = new Uint8Array(arrayBuffer);
|
||||
|
||||
// 尝试解码为文本,检查是否是HTML
|
||||
const decoder = new TextDecoder('utf-8');
|
||||
const htmlText = decoder.decode(uint8Array);
|
||||
|
||||
// 检查是否是错误响应(JSON格式)
|
||||
if (htmlText.trim().startsWith('{') || htmlText.trim().startsWith('[')) {
|
||||
try {
|
||||
const errorObj = JSON.parse(htmlText);
|
||||
ElMessage.error(errorObj.msg || errorObj.message || '生成验收单失败,请重试');
|
||||
} catch (e) {
|
||||
ElMessage.error('生成验收单失败,请重试');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 创建下载链接
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
const link = document.createElement('a');
|
||||
link.href = url;
|
||||
link.download = `牛只发车验收单_${row.deliveryNumber || row.id}_${new Date().getTime()}.html`;
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
window.URL.revokeObjectURL(url);
|
||||
|
||||
// 同时在新窗口中打开,方便预览
|
||||
const newWindow = window.open('', '_blank');
|
||||
if (newWindow) {
|
||||
newWindow.document.write(htmlText);
|
||||
newWindow.document.close();
|
||||
}
|
||||
|
||||
ElMessage.success('验收单生成成功');
|
||||
} catch (error) {
|
||||
console.error('生成验收单失败:', error);
|
||||
ElMessage.error(error.message || '生成验收单失败,请重试');
|
||||
} finally {
|
||||
downLoading[row.id] = false;
|
||||
}
|
||||
|
||||
@@ -224,17 +224,6 @@
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="预估重量(kg)" prop="estimatedWeight">
|
||||
<el-input-number
|
||||
v-model="formData.estimatedWeight"
|
||||
:min="0.01"
|
||||
:precision="2"
|
||||
placeholder="请输入预估重量"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20">
|
||||
@@ -671,7 +660,6 @@ const formData = reactive({
|
||||
endLat: '',
|
||||
endLon: '',
|
||||
cattleCount: 1,
|
||||
estimatedWeight: null,
|
||||
quarantineCertNo: '',
|
||||
remark: '',
|
||||
// 装车相关字段
|
||||
@@ -746,7 +734,6 @@ const rules = {
|
||||
startLocation: [{ required: true, message: '请输入起点地址', trigger: 'blur' }],
|
||||
endLocation: [{ required: true, message: '请输入目的地地址', trigger: 'blur' }],
|
||||
cattleCount: [{ required: true, message: '请输入牛只数量', trigger: 'blur' }],
|
||||
estimatedWeight: [{ required: true, message: '请输入预估重量', trigger: 'blur' }],
|
||||
};
|
||||
|
||||
// 计算耳标设备列表(包含体重输入)
|
||||
@@ -817,7 +804,6 @@ const buildSubmitData = () => {
|
||||
|
||||
// 其他信息
|
||||
cattleCount: formData.cattleCount,
|
||||
estimatedWeight: formData.estimatedWeight,
|
||||
quarantineCertNo: formData.quarantineCertNo,
|
||||
remark: formData.remark,
|
||||
|
||||
@@ -850,12 +836,24 @@ const buildSubmitData = () => {
|
||||
}
|
||||
|
||||
// 将所有undefined值转换为空字符串,确保字段被提交
|
||||
// 但是对于数值类型的字段(如cattleCount),保留null或原值,不要转换为空字符串
|
||||
Object.keys(data).forEach(key => {
|
||||
if (data[key] === undefined) {
|
||||
data[key] = '';
|
||||
// 数值类型字段保留null,其他字段转换为空字符串
|
||||
if (key === 'cattleCount' ||
|
||||
key === 'orderId' || key === 'shipperId' || key === 'buyerId' ||
|
||||
key === 'driverId' || key === 'serverId') {
|
||||
data[key] = null;
|
||||
} else {
|
||||
data[key] = '';
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 确保cattleCount不为空字符串,如果是空字符串则转换为null
|
||||
if (data.cattleCount === '') {
|
||||
data.cattleCount = null;
|
||||
}
|
||||
|
||||
return data;
|
||||
};
|
||||
@@ -955,6 +953,9 @@ const fillFormWithEditData = (editData) => {
|
||||
formData.entruckWeight = delivery.entruckWeight || null;
|
||||
formData.landingEntruckWeight = delivery.landingEntruckWeight || null;
|
||||
|
||||
// 牛只数量(从ratedQuantity字段映射)
|
||||
formData.cattleCount = delivery.ratedQuantity || 1;
|
||||
|
||||
// 照片
|
||||
formData.quarantineTickeyUrl = delivery.quarantineTickeyUrl || '';
|
||||
formData.poundListImg = delivery.poundListImg || '';
|
||||
@@ -1246,7 +1247,8 @@ const handleSubmit = () => {
|
||||
// 判断是编辑还是新增
|
||||
if (formData.editId) {
|
||||
// 编辑模式:调用更新接口
|
||||
|
||||
// 将cattleCount映射为ratedQuantity(后端DeliveryEditDto使用ratedQuantity字段)
|
||||
submitData.ratedQuantity = submitData.cattleCount;
|
||||
submitData.deliveryId = formData.editId; // 添加deliveryId字段(后端需要)
|
||||
res = await shippingApi.updateDeliveryInfo(submitData);
|
||||
} else {
|
||||
|
||||
@@ -76,6 +76,17 @@
|
||||
<el-option label="按肉价结算" :value="3"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="约定价格(元/斤)" prop="firmPrice">
|
||||
<el-input-number
|
||||
v-model="ruleForm.firmPrice"
|
||||
:precision="2"
|
||||
:min="0"
|
||||
:max="9999999.99"
|
||||
placeholder="请输入约定价格"
|
||||
style="width: 100%"
|
||||
></el-input-number>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<template #footer>
|
||||
@@ -89,6 +100,7 @@
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive } from 'vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { orderAddNew, orderUpdate } from '@/api/shipping.js';
|
||||
import { memberListByType } from '@/api/userManage.js';
|
||||
|
||||
@@ -119,12 +131,17 @@ const ruleForm = reactive({
|
||||
buyerId: [], // 买方ID数组
|
||||
sellerId: [], // 卖方ID数组
|
||||
settlementType: 1, // 结算方式:1-上车重量,2-下车重量,3-按肉价结算
|
||||
firmPrice: null, // 约定价格(元/斤)
|
||||
});
|
||||
|
||||
const rules = reactive({
|
||||
buyerId: [{ required: true, message: '请选择买方', trigger: 'change' }],
|
||||
sellerId: [{ required: true, message: '请选择卖方', trigger: 'change' }],
|
||||
settlementType: [{ required: true, message: '请选择结算方式', trigger: 'change' }],
|
||||
firmPrice: [
|
||||
{ required: true, message: '请输入约定价格', trigger: 'blur' },
|
||||
{ type: 'number', min: 0, message: '约定价格不能小于0', trigger: 'blur' }
|
||||
],
|
||||
});
|
||||
|
||||
const handleClose = () => {
|
||||
@@ -136,6 +153,7 @@ const handleClose = () => {
|
||||
ruleForm.buyerId = [];
|
||||
ruleForm.sellerId = [];
|
||||
ruleForm.settlementType = 1;
|
||||
ruleForm.firmPrice = null;
|
||||
data.dialogVisible = false;
|
||||
};
|
||||
|
||||
@@ -217,6 +235,7 @@ const onClickSave = () => {
|
||||
buyerId: ruleForm.buyerId.join(','), // 将数组转为逗号分隔的字符串
|
||||
sellerId: ruleForm.sellerId.join(','), // 将数组转为逗号分隔的字符串
|
||||
settlementType: ruleForm.settlementType,
|
||||
firmPrice: ruleForm.firmPrice, // 约定价格(元/斤)
|
||||
};
|
||||
|
||||
data.saveLoading = true;
|
||||
@@ -282,6 +301,7 @@ const onShowDialog = (orderData) => {
|
||||
}
|
||||
|
||||
ruleForm.settlementType = orderData?.settlementType || 1;
|
||||
ruleForm.firmPrice = orderData?.firmPrice != null ? orderData.firmPrice : null;
|
||||
|
||||
data.dialogVisible = true;
|
||||
getSupplierList();
|
||||
|
||||
Reference in New Issue
Block a user