976 lines
34 KiB
Vue
976 lines
34 KiB
Vue
<template>
|
||
<el-dialog
|
||
v-model="data.dialogVisible"
|
||
:title="data.isDetail ? '进仓详情' : (data.editId ? '编辑进仓记录' : '新增进仓记录')"
|
||
:before-close="handleClose"
|
||
width="900px"
|
||
:close-on-click-modal="false"
|
||
>
|
||
<el-form ref="formDataRef" :model="ruleForm" :rules="rules" label-width="120px" :disabled="data.isDetail">
|
||
<el-row :gutter="20">
|
||
<el-col :span="12">
|
||
<el-form-item label="中转仓" prop="warehouseId">
|
||
<el-select
|
||
v-model="ruleForm.warehouseId"
|
||
placeholder="请选择中转仓"
|
||
clearable
|
||
filterable
|
||
style="width: 100%"
|
||
@change="handleWarehouseChange"
|
||
>
|
||
<el-option
|
||
v-for="item in warehouseList"
|
||
:key="item.id"
|
||
:label="item.warehouseName"
|
||
:value="item.id"
|
||
/>
|
||
</el-select>
|
||
</el-form-item>
|
||
</el-col>
|
||
<el-col :span="12">
|
||
<el-form-item label="运送清单" prop="deliveryId">
|
||
<el-select
|
||
v-model="ruleForm.deliveryId"
|
||
placeholder="请选择运送清单"
|
||
clearable
|
||
filterable
|
||
style="width: 100%"
|
||
@change="handleDeliveryChange"
|
||
>
|
||
<el-option
|
||
v-for="item in deliveryList"
|
||
:key="item.id"
|
||
:label="`${item.deliveryNumber || '--'} - ${item.licensePlate || '--'}`"
|
||
:value="item.id"
|
||
/>
|
||
</el-select>
|
||
</el-form-item>
|
||
</el-col>
|
||
</el-row>
|
||
|
||
<el-row :gutter="20">
|
||
<el-col :span="12">
|
||
<el-form-item label="订单" prop="orderId">
|
||
<el-select
|
||
v-model="ruleForm.orderId"
|
||
placeholder="请选择订单(可多选)"
|
||
multiple
|
||
clearable
|
||
filterable
|
||
style="width: 100%"
|
||
>
|
||
<el-option
|
||
v-for="item in orderList"
|
||
:key="item.id"
|
||
:label="`订单${item.id} - 单价: ${item.firmPrice || '--'}元/斤`"
|
||
:value="item.id"
|
||
/>
|
||
</el-select>
|
||
</el-form-item>
|
||
</el-col>
|
||
<el-col :span="12">
|
||
<el-form-item label="进仓时间" prop="inTime">
|
||
<el-date-picker
|
||
v-model="ruleForm.inTime"
|
||
type="datetime"
|
||
placeholder="请选择进仓时间"
|
||
style="width: 100%"
|
||
value-format="YYYY-MM-DD HH:mm:ss"
|
||
/>
|
||
</el-form-item>
|
||
</el-col>
|
||
</el-row>
|
||
|
||
<el-row :gutter="20">
|
||
<el-col :span="24">
|
||
<el-form-item label="来源地" prop="sourceLocation">
|
||
<el-input
|
||
v-model="ruleForm.sourceLocation"
|
||
placeholder="请输入来源地"
|
||
maxlength="255"
|
||
style="width: calc(100% - 100px); margin-right: 10px;"
|
||
/>
|
||
<el-button type="primary" @click="openSourceLocationMap">选择位置</el-button>
|
||
</el-form-item>
|
||
</el-col>
|
||
</el-row>
|
||
|
||
<el-row :gutter="20">
|
||
<el-col :span="12">
|
||
<el-form-item label="来源地经度">
|
||
<el-input v-model="ruleForm.sourceLon" placeholder="经度" disabled />
|
||
</el-form-item>
|
||
</el-col>
|
||
<el-col :span="12">
|
||
<el-form-item label="来源地纬度">
|
||
<el-input v-model="ruleForm.sourceLat" placeholder="纬度" disabled />
|
||
</el-form-item>
|
||
</el-col>
|
||
</el-row>
|
||
|
||
<el-row :gutter="20">
|
||
<el-col :span="12">
|
||
<el-form-item label="牛只数量(头)" prop="cattleCount">
|
||
<el-input-number
|
||
v-model="ruleForm.cattleCount"
|
||
:min="1"
|
||
:max="9999"
|
||
placeholder="请输入牛只数量"
|
||
style="width: 100%"
|
||
/>
|
||
</el-form-item>
|
||
</el-col>
|
||
<el-col :span="12">
|
||
<el-form-item label="重量(公斤)" prop="weight">
|
||
<el-input-number
|
||
v-model="ruleForm.weight"
|
||
:min="0"
|
||
:precision="2"
|
||
placeholder="请输入重量"
|
||
style="width: 100%"
|
||
>
|
||
<template #append>kg</template>
|
||
</el-input-number>
|
||
</el-form-item>
|
||
</el-col>
|
||
</el-row>
|
||
|
||
<el-row :gutter="20">
|
||
<el-col :span="12">
|
||
<el-form-item label="状态" prop="status">
|
||
<el-select v-model="ruleForm.status" placeholder="请选择状态" style="width: 100%">
|
||
<el-option label="待进仓" :value="1" />
|
||
<el-option label="已进仓" :value="2" />
|
||
<el-option label="已出仓" :value="3" />
|
||
</el-select>
|
||
</el-form-item>
|
||
</el-col>
|
||
</el-row>
|
||
|
||
<el-row :gutter="20">
|
||
<el-col :span="24">
|
||
<el-form-item label="照片">
|
||
<div style="display: flex; flex-direction: column; gap: 10px;">
|
||
<!-- 拖拽上传区域 -->
|
||
<el-upload
|
||
drag
|
||
action="#"
|
||
:auto-upload="false"
|
||
:before-upload="beforePhotoUpload"
|
||
:limit="9"
|
||
accept="image/*"
|
||
:on-change="handlePhotoChange"
|
||
:show-file-list="false"
|
||
style="width: 100%"
|
||
>
|
||
<el-icon class="el-icon--upload"><UploadFilled /></el-icon>
|
||
<div class="el-upload__text">将图片文件拖到此处,或<em>点击上传</em></div>
|
||
<template #tip>
|
||
<div class="el-upload__tip">支持 jpg/png/gif 格式,单个文件不超过 10MB,最多上传 9 张</div>
|
||
</template>
|
||
</el-upload>
|
||
<!-- 图片预览列表 -->
|
||
<div v-if="photoFileList.length > 0" class="photo-preview-list">
|
||
<div
|
||
v-for="(file, index) in photoFileList"
|
||
:key="index"
|
||
class="photo-preview-item"
|
||
>
|
||
<el-image
|
||
:src="file.url || file.response?.data?.url || ''"
|
||
fit="cover"
|
||
class="photo-preview-image"
|
||
:preview-src-list="photoFileList.map(f => f.url || f.response?.data?.url || '').filter(Boolean)"
|
||
:initial-index="index"
|
||
/>
|
||
<el-button
|
||
type="danger"
|
||
:icon="Delete"
|
||
circle
|
||
size="small"
|
||
class="photo-delete-btn"
|
||
@click="handlePhotoRemove(file)"
|
||
/>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</el-form-item>
|
||
</el-col>
|
||
</el-row>
|
||
|
||
<el-row :gutter="20">
|
||
<el-col :span="24">
|
||
<el-form-item label="视频">
|
||
<el-upload
|
||
drag
|
||
action="#"
|
||
:auto-upload="false"
|
||
:on-change="handleVideoChange"
|
||
:on-remove="handleVideoRemove"
|
||
:before-upload="beforeVideoUpload"
|
||
:limit="3"
|
||
accept="video/*"
|
||
:show-file-list="false"
|
||
style="width: 100%"
|
||
>
|
||
<el-icon class="el-icon--upload"><UploadFilled /></el-icon>
|
||
<div class="el-upload__text">将视频文件拖到此处,或<em>点击上传</em></div>
|
||
<template #tip>
|
||
<div class="el-upload__tip">支持 mp4/avi/rmvb/mkv 格式,单个文件不超过 100MB,最多上传 3 个</div>
|
||
</template>
|
||
</el-upload>
|
||
<!-- 视频预览列表 -->
|
||
<div v-if="videoFileList.length > 0" class="video-preview-list">
|
||
<div
|
||
v-for="(file, index) in videoFileList"
|
||
:key="index"
|
||
class="video-preview-item"
|
||
>
|
||
<video
|
||
:src="file.url || file.response?.data?.url || ''"
|
||
controls
|
||
class="video-preview-player"
|
||
></video>
|
||
<div class="video-name">{{ file.name || '视频' }}</div>
|
||
<el-button
|
||
type="danger"
|
||
:icon="Delete"
|
||
circle
|
||
size="small"
|
||
class="video-delete-btn"
|
||
@click="handleVideoRemove(file)"
|
||
/>
|
||
</div>
|
||
</div>
|
||
</el-form-item>
|
||
</el-col>
|
||
</el-row>
|
||
|
||
<el-row :gutter="20">
|
||
<el-col :span="24">
|
||
<el-form-item label="备注">
|
||
<el-input
|
||
v-model="ruleForm.remark"
|
||
type="textarea"
|
||
:rows="3"
|
||
placeholder="请输入备注"
|
||
maxlength="500"
|
||
show-word-limit
|
||
/>
|
||
</el-form-item>
|
||
</el-col>
|
||
</el-row>
|
||
</el-form>
|
||
|
||
<template #footer>
|
||
<span class="dialog-footer">
|
||
<el-button v-if="!data.isDetail" :loading="data.saveLoading" type="primary" @click="onClickSave">
|
||
保存
|
||
</el-button>
|
||
<el-button @click="handleClose">{{ data.isDetail ? '关闭' : '取消' }}</el-button>
|
||
</span>
|
||
</template>
|
||
</el-dialog>
|
||
|
||
<!-- 来源地地址选择地图 -->
|
||
<el-dialog v-model="showSourceLocationMap" title="选择来源地地址" width="900px">
|
||
<baidu-map
|
||
class="map"
|
||
:center="ruleForm.sourceLon && ruleForm.sourceLat ? {lng: parseFloat(ruleForm.sourceLon), lat: parseFloat(ruleForm.sourceLat)} : {lng: 116.404, lat: 39.915}"
|
||
:zoom="15"
|
||
:scroll-wheel-zoom="true"
|
||
@click="handleSourceLocationClick"
|
||
style="height: 500px"
|
||
>
|
||
<bm-marker
|
||
v-if="ruleForm.sourceLon && ruleForm.sourceLat"
|
||
:position="{lng: parseFloat(ruleForm.sourceLon), lat: parseFloat(ruleForm.sourceLat)}"
|
||
:dragging="true"
|
||
@dragging="handleSourceMarkerDrag"
|
||
/>
|
||
<bm-map-type :map-types="['BMAP_NORMAL_MAP', 'BMAP_HYBRID_MAP']"></bm-map-type>
|
||
</baidu-map>
|
||
<template #footer>
|
||
<span class="dialog-footer">
|
||
<el-button @click="showSourceLocationMap = false">取消</el-button>
|
||
<el-button type="primary" @click="showSourceLocationMap = false">确定</el-button>
|
||
</span>
|
||
</template>
|
||
</el-dialog>
|
||
|
||
<!-- 图片预览 -->
|
||
<el-dialog v-model="showImageViewer" title="图片预览" width="800px">
|
||
<el-image :src="imageViewerUrl" style="width: 100%" fit="contain" />
|
||
</el-dialog>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, reactive, watch } from 'vue';
|
||
import { ElMessage } from 'element-plus';
|
||
import { Plus, UploadFilled, Delete } from '@element-plus/icons-vue';
|
||
import { BaiduMap, BmMapType, BmMarker } from 'vue-baidu-map-3x';
|
||
import { warehouseInAdd, warehouseInEdit, warehouseInDetail } from '@/api/warehouseIn.js';
|
||
import { warehouseAll } from '@/api/warehouse.js';
|
||
import { orderPageQuery, shippingList } from '@/api/shipping.js';
|
||
|
||
const emits = defineEmits(['success']);
|
||
const formDataRef = ref(null);
|
||
const showSourceLocationMap = ref(false);
|
||
const showImageViewer = ref(false);
|
||
const imageViewerUrl = ref('');
|
||
const photoFileList = ref([]);
|
||
const videoFileList = ref([]);
|
||
|
||
const warehouseList = ref([]);
|
||
const orderList = ref([]);
|
||
const deliveryList = ref([]);
|
||
|
||
const data = reactive({
|
||
dialogVisible: false,
|
||
saveLoading: false,
|
||
editId: null,
|
||
isDetail: false,
|
||
});
|
||
|
||
const ruleForm = reactive({
|
||
id: null,
|
||
warehouseId: null,
|
||
orderId: [],
|
||
deliveryId: null,
|
||
sourceLocation: '',
|
||
sourceLon: '',
|
||
sourceLat: '',
|
||
cattleCount: null,
|
||
weight: null,
|
||
inTime: '',
|
||
photos: '',
|
||
videos: '',
|
||
remark: '',
|
||
status: 1,
|
||
});
|
||
|
||
const rules = reactive({
|
||
warehouseId: [
|
||
{ required: true, message: '请选择中转仓', trigger: 'change' },
|
||
],
|
||
deliveryId: [
|
||
{ required: true, message: '请选择运送清单', trigger: 'change' },
|
||
],
|
||
cattleCount: [
|
||
{ required: true, message: '请输入牛只数量', trigger: 'blur' },
|
||
{ type: 'number', min: 1, message: '牛只数量必须大于0', trigger: 'blur' },
|
||
],
|
||
inTime: [
|
||
{ required: true, message: '请选择进仓时间', trigger: 'change' },
|
||
],
|
||
});
|
||
|
||
// 加载中转仓列表
|
||
const loadWarehouseList = async () => {
|
||
try {
|
||
const res = await warehouseAll();
|
||
if (res.code === 200) {
|
||
warehouseList.value = res.data || [];
|
||
}
|
||
} catch (error) {
|
||
console.error('加载中转仓列表失败', error);
|
||
}
|
||
};
|
||
|
||
// 加载订单列表
|
||
const loadOrderList = async () => {
|
||
try {
|
||
const res = await orderPageQuery({ pageNum: 1, pageSize: 1000 });
|
||
if (res.code === 200) {
|
||
const responseData = res.data || res;
|
||
if (responseData && typeof responseData === 'object' && 'rows' in responseData) {
|
||
orderList.value = responseData.rows || [];
|
||
} else if (responseData && responseData.data && 'rows' in responseData.data) {
|
||
orderList.value = responseData.data.rows || [];
|
||
} else {
|
||
orderList.value = [];
|
||
}
|
||
}
|
||
} catch (error) {
|
||
console.error('加载订单列表失败', error);
|
||
}
|
||
};
|
||
|
||
// 加载运送清单列表
|
||
const loadDeliveryList = async () => {
|
||
try {
|
||
const res = await shippingList({ pageNum: 1, pageSize: 1000 });
|
||
if (res.code === 200) {
|
||
const responseData = res.data || res;
|
||
if (responseData && typeof responseData === 'object' && 'rows' in responseData) {
|
||
deliveryList.value = responseData.rows || [];
|
||
} else if (responseData && responseData.data && 'rows' in responseData.data) {
|
||
deliveryList.value = responseData.data.rows || [];
|
||
} else {
|
||
deliveryList.value = [];
|
||
}
|
||
}
|
||
} catch (error) {
|
||
console.error('加载运送清单列表失败', error);
|
||
}
|
||
};
|
||
|
||
const handleClose = () => {
|
||
if (formDataRef.value) {
|
||
formDataRef.value.resetFields();
|
||
}
|
||
Object.assign(ruleForm, {
|
||
id: null,
|
||
warehouseId: null,
|
||
orderId: [],
|
||
deliveryId: null,
|
||
sourceLocation: '',
|
||
sourceLon: '',
|
||
sourceLat: '',
|
||
cattleCount: null,
|
||
weight: null,
|
||
inTime: '',
|
||
photos: '',
|
||
videos: '',
|
||
remark: '',
|
||
status: 1,
|
||
});
|
||
photoFileList.value = [];
|
||
videoFileList.value = [];
|
||
data.editId = null;
|
||
data.isDetail = false;
|
||
data.dialogVisible = false;
|
||
};
|
||
|
||
const onClickSave = () => {
|
||
if (!formDataRef.value) {
|
||
return;
|
||
}
|
||
|
||
formDataRef.value.validate((valid) => {
|
||
if (!valid) {
|
||
return false;
|
||
}
|
||
|
||
data.saveLoading = true;
|
||
|
||
// 处理订单ID(多个订单用逗号分隔)
|
||
const orderIdStr = ruleForm.orderId && ruleForm.orderId.length > 0
|
||
? ruleForm.orderId.join(',')
|
||
: null;
|
||
|
||
// 处理照片和视频URL(多个用逗号分隔)
|
||
const photosStr = photoFileList.value.map(file => file.url || file.response?.data?.url || '').filter(url => url).join(',');
|
||
const videosStr = videoFileList.value.map(file => file.url || file.response?.data?.url || '').filter(url => url).join(',');
|
||
|
||
const params = {
|
||
warehouseId: ruleForm.warehouseId,
|
||
orderId: orderIdStr,
|
||
deliveryId: ruleForm.deliveryId,
|
||
sourceLocation: ruleForm.sourceLocation,
|
||
sourceLon: ruleForm.sourceLon,
|
||
sourceLat: ruleForm.sourceLat,
|
||
cattleCount: ruleForm.cattleCount,
|
||
weight: ruleForm.weight,
|
||
inTime: ruleForm.inTime,
|
||
photos: photosStr,
|
||
videos: videosStr,
|
||
remark: ruleForm.remark,
|
||
};
|
||
|
||
if (data.editId) {
|
||
// 编辑
|
||
params.id = data.editId;
|
||
params.status = ruleForm.status;
|
||
warehouseInEdit(params)
|
||
.then((res) => {
|
||
if (res.code === 200) {
|
||
ElMessage.success('编辑成功');
|
||
handleClose();
|
||
emits('success');
|
||
} else {
|
||
ElMessage.error(res.msg || '编辑失败');
|
||
}
|
||
})
|
||
.catch((error) => {
|
||
ElMessage.error('编辑失败:' + (error.message || '未知错误'));
|
||
})
|
||
.finally(() => {
|
||
data.saveLoading = false;
|
||
});
|
||
} else {
|
||
// 新增
|
||
warehouseInAdd(params)
|
||
.then((res) => {
|
||
if (res.code === 200) {
|
||
ElMessage.success('新增成功');
|
||
handleClose();
|
||
emits('success');
|
||
} else {
|
||
ElMessage.error(res.msg || '新增失败');
|
||
}
|
||
})
|
||
.catch((error) => {
|
||
ElMessage.error('新增失败:' + (error.message || '未知错误'));
|
||
})
|
||
.finally(() => {
|
||
data.saveLoading = false;
|
||
});
|
||
}
|
||
});
|
||
};
|
||
|
||
const onShowDialog = (row, isDetail = false) => {
|
||
data.isDetail = isDetail || false;
|
||
data.editId = null;
|
||
|
||
if (row) {
|
||
data.editId = row.id;
|
||
// 如果是详情模式,先获取详情数据
|
||
if (isDetail) {
|
||
warehouseInDetail(row.id)
|
||
.then((res) => {
|
||
if (res.code === 200 && res.data) {
|
||
const detailData = res.data;
|
||
Object.assign(ruleForm, {
|
||
id: detailData.id,
|
||
warehouseId: detailData.warehouseId,
|
||
orderId: detailData.orderId ? detailData.orderId.split(',').map(id => parseInt(id)) : [],
|
||
deliveryId: detailData.deliveryId,
|
||
sourceLocation: detailData.sourceLocation || '',
|
||
sourceLon: detailData.sourceLon || '',
|
||
sourceLat: detailData.sourceLat || '',
|
||
cattleCount: detailData.cattleCount,
|
||
weight: detailData.weight,
|
||
inTime: detailData.inTime || '',
|
||
photos: detailData.photos || '',
|
||
videos: detailData.videos || '',
|
||
remark: detailData.remark || '',
|
||
status: detailData.status !== undefined ? detailData.status : 1,
|
||
});
|
||
// 处理照片和视频文件列表
|
||
if (detailData.photos) {
|
||
photoFileList.value = detailData.photos.split(',').map(url => ({ url, name: 'photo' }));
|
||
}
|
||
if (detailData.videos) {
|
||
videoFileList.value = detailData.videos.split(',').map(url => ({ url, name: 'video' }));
|
||
}
|
||
}
|
||
})
|
||
.catch((error) => {
|
||
ElMessage.error('获取详情失败:' + (error.message || '未知错误'));
|
||
});
|
||
} else {
|
||
// 编辑模式,直接使用传入的数据
|
||
Object.assign(ruleForm, {
|
||
id: row.id,
|
||
warehouseId: row.warehouseId,
|
||
orderId: row.orderId ? row.orderId.split(',').map(id => parseInt(id)) : [],
|
||
deliveryId: row.deliveryId,
|
||
sourceLocation: row.sourceLocation || '',
|
||
sourceLon: row.sourceLon || '',
|
||
sourceLat: row.sourceLat || '',
|
||
cattleCount: row.cattleCount,
|
||
weight: row.weight,
|
||
inTime: row.inTime || '',
|
||
photos: row.photos || '',
|
||
videos: row.videos || '',
|
||
remark: row.remark || '',
|
||
status: row.status !== undefined ? row.status : 1,
|
||
});
|
||
// 处理照片和视频文件列表
|
||
if (row.photos) {
|
||
photoFileList.value = row.photos.split(',').map(url => ({ url, name: 'photo' }));
|
||
}
|
||
if (row.videos) {
|
||
videoFileList.value = row.videos.split(',').map(url => ({ url, name: 'video' }));
|
||
}
|
||
}
|
||
} else {
|
||
// 新增模式,重置表单
|
||
Object.assign(ruleForm, {
|
||
id: null,
|
||
warehouseId: null,
|
||
orderId: [],
|
||
deliveryId: null,
|
||
sourceLocation: '',
|
||
sourceLon: '',
|
||
sourceLat: '',
|
||
cattleCount: null,
|
||
weight: null,
|
||
inTime: '',
|
||
photos: '',
|
||
videos: '',
|
||
remark: '',
|
||
status: 1,
|
||
});
|
||
photoFileList.value = [];
|
||
videoFileList.value = [];
|
||
}
|
||
|
||
data.dialogVisible = true;
|
||
};
|
||
|
||
// 中转仓选择变化
|
||
const handleWarehouseChange = (warehouseId) => {
|
||
// 可以在这里添加逻辑
|
||
};
|
||
|
||
// 运送清单选择变化
|
||
const handleDeliveryChange = (deliveryId) => {
|
||
if (!deliveryId) {
|
||
// 清空相关字段
|
||
ruleForm.sourceLocation = '';
|
||
ruleForm.sourceLon = '';
|
||
ruleForm.sourceLat = '';
|
||
ruleForm.cattleCount = null;
|
||
ruleForm.weight = null;
|
||
return;
|
||
}
|
||
|
||
// 从 deliveryList 中找到对应的运送清单
|
||
const selectedDelivery = deliveryList.value.find(item => item.id === deliveryId);
|
||
if (selectedDelivery) {
|
||
// 自动填充来源地信息
|
||
if (selectedDelivery.startLocation) {
|
||
ruleForm.sourceLocation = selectedDelivery.startLocation;
|
||
}
|
||
if (selectedDelivery.startLon) {
|
||
ruleForm.sourceLon = selectedDelivery.startLon;
|
||
}
|
||
if (selectedDelivery.startLat) {
|
||
ruleForm.sourceLat = selectedDelivery.startLat;
|
||
}
|
||
|
||
// 自动填充牛只数量
|
||
if (selectedDelivery.ratedQuantity) {
|
||
ruleForm.cattleCount = selectedDelivery.ratedQuantity;
|
||
}
|
||
|
||
// 自动计算重量:entruckWeight - emptyWeight
|
||
if (selectedDelivery.entruckWeight && selectedDelivery.emptyWeight) {
|
||
const entruckWeight = parseFloat(selectedDelivery.entruckWeight) || 0;
|
||
const emptyWeight = parseFloat(selectedDelivery.emptyWeight) || 0;
|
||
const calculatedWeight = entruckWeight - emptyWeight;
|
||
if (calculatedWeight > 0) {
|
||
ruleForm.weight = parseFloat(calculatedWeight.toFixed(2));
|
||
}
|
||
} else if (selectedDelivery.entruckWeight) {
|
||
// 如果只有装车重量,也可以填充
|
||
ruleForm.weight = parseFloat(selectedDelivery.entruckWeight) || null;
|
||
}
|
||
}
|
||
};
|
||
|
||
// 打开来源地地图选择地址
|
||
const openSourceLocationMap = () => {
|
||
if (ruleForm.sourceLocation && ruleForm.sourceLocation.trim()) {
|
||
showSourceLocationMap.value = true;
|
||
setTimeout(() => {
|
||
if (window.BMap && window.BMap.Geocoder) {
|
||
const geocoder = new window.BMap.Geocoder();
|
||
geocoder.getPoint(ruleForm.sourceLocation, (point) => {
|
||
if (point) {
|
||
ruleForm.sourceLon = point.lng;
|
||
ruleForm.sourceLat = point.lat;
|
||
ElMessage.success('已定位到该地址');
|
||
} else {
|
||
ElMessage.warning('未找到该地址,请在地图上手动选择');
|
||
}
|
||
});
|
||
}
|
||
}, 500);
|
||
} else {
|
||
showSourceLocationMap.value = true;
|
||
}
|
||
};
|
||
|
||
// 地图点击事件
|
||
const handleSourceLocationClick = (e) => {
|
||
ruleForm.sourceLon = e.point.lng;
|
||
ruleForm.sourceLat = e.point.lat;
|
||
if (window.BMap && window.BMap.Geocoder) {
|
||
const geocoder = new window.BMap.Geocoder();
|
||
geocoder.getLocation(e.point, (res) => {
|
||
if (res) {
|
||
ruleForm.sourceLocation = res.address;
|
||
ElMessage.success('已设置来源地地址');
|
||
}
|
||
});
|
||
}
|
||
};
|
||
|
||
// 标记拖拽事件
|
||
const handleSourceMarkerDrag = (e) => {
|
||
ruleForm.sourceLon = e.point.lng;
|
||
ruleForm.sourceLat = e.point.lat;
|
||
if (window.BMap && window.BMap.Geocoder) {
|
||
const geocoder = new window.BMap.Geocoder();
|
||
geocoder.getLocation(e.point, (res) => {
|
||
if (res) {
|
||
ruleForm.sourceLocation = res.address;
|
||
}
|
||
});
|
||
}
|
||
};
|
||
|
||
// 图片预览(保留用于兼容)
|
||
const handlePictureCardPreview = (file) => {
|
||
imageViewerUrl.value = file.url || file.response?.data?.url || '';
|
||
showImageViewer.value = true;
|
||
};
|
||
|
||
// 照片文件变化处理(拖拽上传时触发)
|
||
const handlePhotoChange = (file, fileList) => {
|
||
// 验证文件
|
||
if (!beforePhotoUpload(file)) {
|
||
return;
|
||
}
|
||
|
||
// 手动上传文件
|
||
uploadPhotoFile(file);
|
||
};
|
||
|
||
// 手动上传照片文件
|
||
const uploadPhotoFile = async (file) => {
|
||
const formData = new FormData();
|
||
formData.append('file', file.raw || file);
|
||
|
||
try {
|
||
// 获取 token
|
||
let token = '';
|
||
const userStore = localStorage.getItem('userStore');
|
||
if (userStore) {
|
||
const us = JSON.parse(userStore);
|
||
token = us.token || '';
|
||
}
|
||
|
||
const response = await fetch('/api/common/upload', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Authorization': token,
|
||
},
|
||
body: formData,
|
||
});
|
||
|
||
const result = await response.json();
|
||
if (result.code === 200) {
|
||
const photoUrl = result.data?.url || result.data;
|
||
photoFileList.value.push({
|
||
url: photoUrl,
|
||
name: file.name,
|
||
uid: file.uid || Date.now(),
|
||
});
|
||
ElMessage.success('照片上传成功');
|
||
} else {
|
||
ElMessage.error(result.msg || '照片上传失败');
|
||
}
|
||
} catch (error) {
|
||
console.error('照片上传失败:', error);
|
||
ElMessage.error('照片上传失败');
|
||
}
|
||
};
|
||
|
||
// 删除照片
|
||
const handlePhotoRemove = (file) => {
|
||
const index = photoFileList.value.findIndex(item => item.uid === file.uid || item.url === file.url);
|
||
if (index > -1) {
|
||
photoFileList.value.splice(index, 1);
|
||
}
|
||
};
|
||
|
||
// 视频文件变化处理(拖拽上传时触发)
|
||
const handleVideoChange = (file, fileList) => {
|
||
// 验证文件
|
||
if (!beforeVideoUpload(file)) {
|
||
return;
|
||
}
|
||
|
||
// 手动上传文件
|
||
uploadVideoFile(file);
|
||
};
|
||
|
||
// 手动上传视频文件
|
||
const uploadVideoFile = async (file) => {
|
||
const formData = new FormData();
|
||
formData.append('file', file.raw || file);
|
||
|
||
try {
|
||
// 获取 token
|
||
let token = '';
|
||
const userStore = localStorage.getItem('userStore');
|
||
if (userStore) {
|
||
const us = JSON.parse(userStore);
|
||
token = us.token || '';
|
||
}
|
||
|
||
const response = await fetch('/api/common/upload', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Authorization': token,
|
||
},
|
||
body: formData,
|
||
});
|
||
|
||
const result = await response.json();
|
||
if (result.code === 200) {
|
||
const videoUrl = result.data?.url || result.data;
|
||
videoFileList.value.push({
|
||
url: videoUrl,
|
||
name: file.name,
|
||
uid: file.uid || Date.now(),
|
||
});
|
||
ElMessage.success('视频上传成功');
|
||
} else {
|
||
ElMessage.error(result.msg || '视频上传失败');
|
||
}
|
||
} catch (error) {
|
||
console.error('视频上传失败:', error);
|
||
ElMessage.error('视频上传失败');
|
||
}
|
||
};
|
||
|
||
// 删除视频
|
||
const handleVideoRemove = (file) => {
|
||
const index = videoFileList.value.findIndex(item => item.uid === file.uid || item.url === file.url);
|
||
if (index > -1) {
|
||
videoFileList.value.splice(index, 1);
|
||
}
|
||
};
|
||
|
||
// 上传前验证照片
|
||
const beforePhotoUpload = (file) => {
|
||
const isImage = file.type.startsWith('image/');
|
||
const isLt10M = file.size / 1024 / 1024 < 10;
|
||
|
||
if (!isImage) {
|
||
ElMessage.error('只能上传图片文件!');
|
||
return false;
|
||
}
|
||
if (!isLt10M) {
|
||
ElMessage.error('图片大小不能超过 10MB!');
|
||
return false;
|
||
}
|
||
|
||
// 检查数量限制
|
||
if (photoFileList.value.length >= 9) {
|
||
ElMessage.error('最多只能上传 9 张照片!');
|
||
return false;
|
||
}
|
||
|
||
return true; // 允许继续处理
|
||
};
|
||
|
||
// 上传前验证视频
|
||
const beforeVideoUpload = (file) => {
|
||
const isVideo = file.type.startsWith('video/');
|
||
const isLt100M = file.size / 1024 / 1024 < 100;
|
||
|
||
if (!isVideo) {
|
||
ElMessage.error('只能上传视频文件!');
|
||
return false;
|
||
}
|
||
if (!isLt100M) {
|
||
ElMessage.error('视频大小不能超过 100MB!');
|
||
return false;
|
||
}
|
||
|
||
// 检查数量限制
|
||
if (videoFileList.value.length >= 3) {
|
||
ElMessage.error('最多只能上传 3 个视频!');
|
||
return false;
|
||
}
|
||
|
||
return true; // 允许继续处理
|
||
};
|
||
|
||
// 监听对话框打开,加载数据
|
||
watch(() => data.dialogVisible, (newVal) => {
|
||
if (newVal) {
|
||
loadWarehouseList();
|
||
loadOrderList();
|
||
loadDeliveryList();
|
||
}
|
||
});
|
||
|
||
// 暴露方法给父组件调用
|
||
defineExpose({
|
||
onShowDialog,
|
||
});
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
.map {
|
||
width: 100%;
|
||
height: 500px;
|
||
}
|
||
|
||
/* 照片预览列表样式 */
|
||
.photo-preview-list {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 10px;
|
||
margin-top: 10px;
|
||
}
|
||
|
||
.photo-preview-item {
|
||
position: relative;
|
||
width: 120px;
|
||
height: 120px;
|
||
border: 1px solid #dcdfe6;
|
||
border-radius: 6px;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.photo-preview-image {
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
|
||
.photo-delete-btn {
|
||
position: absolute;
|
||
top: 5px;
|
||
right: 5px;
|
||
z-index: 10;
|
||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
|
||
}
|
||
|
||
/* 视频预览列表样式 */
|
||
.video-preview-list {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 15px;
|
||
margin-top: 15px;
|
||
}
|
||
|
||
.video-preview-item {
|
||
position: relative;
|
||
border: 1px solid #dcdfe6;
|
||
border-radius: 6px;
|
||
padding: 10px;
|
||
background-color: #f5f7fa;
|
||
}
|
||
|
||
.video-preview-player {
|
||
width: 100%;
|
||
max-height: 300px;
|
||
border-radius: 4px;
|
||
}
|
||
|
||
.video-name {
|
||
margin-top: 8px;
|
||
font-size: 12px;
|
||
color: #606266;
|
||
text-align: center;
|
||
}
|
||
|
||
.video-delete-btn {
|
||
position: absolute;
|
||
top: 15px;
|
||
right: 15px;
|
||
z-index: 10;
|
||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
|
||
}
|
||
</style>
|
||
|