| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400 |
- <template>
- <el-dialog :model-value="modelValue" title="发货" width="50%" @update:model-value="handleDialogChange" @open="handleOpen" @close="handleClose">
- <el-form :model="form" :rules="rules" ref="formRef" label-width="120px">
- <el-row :gutter="20">
- <el-col :span="12">
- <el-form-item label="订单编号" prop="orderCode">
- <el-input v-model="form.orderCode" disabled />
- </el-form-item>
- </el-col>
- <el-col :span="12" v-if="form.deliverMethod === '0'">
- <el-form-item label="送货人" prop="deliverMan">
- <el-input v-model="form.deliverMan" placeholder="请输入送货人姓名" />
- </el-form-item>
- </el-col>
- <el-col :span="12" v-if="form.deliverMethod === '1'">
- <el-form-item label="物流公司名称" prop="logisticsCompanyId">
- <el-select v-model="form.logisticsCompanyId" placeholder="请选择" style="width: 100%" filterable @change="handleLogisticsCompanyChange">
- <el-option v-for="company in logisticsCompanyList" :key="company.id" :label="company.logisticsName" :value="company.id" />
- </el-select>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="20">
- <el-col :span="12">
- <el-form-item v-if="form.deliverMethod === '1'" label="物流单号" prop="logisticNo">
- <el-input v-model="form.logisticNo" placeholder="请输入物流单号" />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="发货方式" prop="deliverMethod">
- <el-radio-group v-model="form.deliverMethod">
- <el-radio v-for="dict in deliver_method" :key="dict.value" :value="dict.value">{{ dict.label }}</el-radio>
- </el-radio-group>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="20">
- <el-col :span="12" v-if="form.deliverMethod === '1'">
- <el-form-item label="收货人手机" prop="consigneePhone">
- <el-input v-model="form.consigneePhone" placeholder="请输入收货人手机" />
- </el-form-item>
- </el-col>
- <el-col :span="12" v-if="form.deliverMethod === '0'">
- <el-form-item label="手机号码" prop="phone">
- <el-input v-model="form.phone" placeholder="请输入手机号码" />
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="20">
- <el-col :span="24">
- <el-form-item label="发货备注" prop="deliverRemark">
- <el-input v-model="form.deliverRemark" type="textarea" :rows="3" placeholder="请输入内容" />
- </el-form-item>
- </el-col>
- </el-row>
- </el-form>
- <!-- 商品列表 -->
- <el-table :data="productList" border style="width: 100%" max-height="600px">
- <el-table-column prop="productNo" label="产品编号" width="100" />
- <el-table-column label="产品图片" width="100">
- <template #default="scope">
- <el-image v-if="scope.row.productImage" :src="scope.row.productImage" style="width: 60px; height: 60px" fit="cover" />
- <span v-else>暂无图片</span>
- </template>
- </el-table-column>
- <el-table-column prop="productName" label="产品名称" min-width="200" show-overflow-tooltip />
- <el-table-column prop="categoryName" label="类别" width="120" />
- <el-table-column prop="productUnit" label="单位" width="80" />
- <el-table-column prop="orderQuantity" label="商品总数" width="100" />
- <el-table-column prop="orderPrice" label="商品单价" width="100" />
- <el-table-column prop="quantitySent" label="已发货数量" width="100" />
- <el-table-column prop="unsentQuantity" label="未发货数量" width="100" />
- <el-table-column label="发货数量">
- <template #default="scope">
- <el-input-number
- v-model="scope.row.deliverNum"
- :min="0"
- :max="scope.row.unsentQuantity"
- :precision="0"
- size="small"
- :controls="false"
- style="width: 100%"
- @change="handleDeliveryQuantityChange(scope.$index)"
- />
- </template>
- </el-table-column>
- <el-table-column label="操作" width="100" fixed="right" align="center">
- <template #default="scope">
- <el-button link type="danger" size="small" @click="handleDeleteProduct(scope.$index)">删除</el-button>
- </template>
- </el-table-column>
- </el-table>
- <!-- 分页 -->
- <el-pagination
- v-model:current-page="queryParams.pageNum"
- v-model:page-size="queryParams.pageSize"
- :total="total"
- :page-sizes="[20, 50, 100]"
- layout="total, sizes, prev, pager, next, jumper"
- @size-change="handleSizeChange"
- @current-change="handleCurrentChange"
- class="mt-4"
- />
- <template #footer>
- <div class="dialog-footer">
- <el-button @click="handleCancel">取消</el-button>
- <el-button type="primary" :loading="submitLoading" @click="handleSubmit">确认</el-button>
- </div>
- </template>
- </el-dialog>
- </template>
- <script setup lang="ts">
- import { ref, reactive, computed, onMounted } from 'vue';
- import { getOrderMain } from '@/api/order/orderMain';
- import { OrderMainVO } from '@/api/order/orderMain/types';
- import { listOrderProduct } from '@/api/order/orderProduct';
- import { OrderProductVO } from '@/api/order/orderProduct/types';
- import { listLogisticsCompany } from '@/api/company/logisticsCompany';
- import { LogisticsCompanyVO } from '@/api/company/logisticsCompany/types';
- import { addOrderDeliver } from '@/api/order/orderDeliver';
- import { OrderDeliverVO, OrderDeliverForm } from '@/api/order/orderDeliver/types';
- import { ElMessage } from 'element-plus';
- const { proxy } = getCurrentInstance() as ComponentInternalInstance;
- const { deliver_method } = toRefs<any>(proxy?.useDict('deliver_method'));
- interface Props {
- modelValue: boolean;
- orderId?: string | number;
- orderNo?: string;
- }
- interface Emits {
- (e: 'update:modelValue', value: boolean): void;
- (e: 'success'): void;
- }
- const props = defineProps<Props>();
- const emit = defineEmits<Emits>();
- const formRef = ref();
- const submitLoading = ref(false);
- const productList = ref<any[]>([]);
- const total = ref(0);
- // 物流公司列表
- const logisticsCompanyList = ref<LogisticsCompanyVO[]>([]);
- // 查询参数
- const queryParams = ref({
- pageNum: 1,
- pageSize: 20,
- orderId: undefined as string | number | undefined
- });
- // 表单数据
- const form = reactive<OrderDeliverForm>({
- orderId: undefined,
- orderCode: '',
- logisticPackNo: '',
- deliverMethod: '1',
- deliverMan: '',
- phone: '',
- logisticsStatus: '',
- deliverRemark: '',
- checklistRemark: '',
- logisticsCompanyId: undefined,
- logisticsCompanyCode: '',
- logisticNo: '',
- logisticPackStatus: '',
- consigneePhone: '',
- remark: '',
- orderDeliverProducts: []
- });
- // 动态校验规则
- const rules = computed(() => {
- const baseRules: any = {
- deliverMethod: [{ required: true, message: '请选择发货方式', trigger: 'change' }]
- };
- // 第三方物流(deliverMethod === '1')
- if (form.deliverMethod === '1') {
- baseRules.logisticsCompanyId = [{ required: true, message: '请选择物流公司', trigger: 'change' }];
- baseRules.logisticNo = [{ required: true, message: '请输入物流单号', trigger: 'blur' }];
- baseRules.consigneePhone = [
- { required: true, message: '请输入收货人手机号码', trigger: 'blur' },
- { pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号码', trigger: 'blur' }
- ];
- }
- // 自有物流(deliverMethod === '0')
- if (form.deliverMethod === '0') {
- baseRules.deliverMan = [{ required: true, message: '请输入送货人姓名', trigger: 'blur' }];
- baseRules.phone = [
- { required: true, message: '请输入手机号码', trigger: 'blur' },
- { pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号码', trigger: 'blur' }
- ];
- }
- return baseRules;
- });
- // 对话框状态变化
- const handleDialogChange = (val: boolean) => {
- emit('update:modelValue', val);
- };
- // 对话框打开时触发
- const handleOpen = () => {
- resetForm();
- if (props.orderId) {
- form.orderId = props.orderId;
- form.orderCode = props.orderNo || '';
- queryParams.value.orderId = props.orderId;
- loadProductList();
- }
- };
- // 对话框关闭时触发
- const handleClose = () => {
- resetForm();
- };
- // 重置表单
- const resetForm = () => {
- form.orderId = undefined;
- form.orderCode = '';
- form.logisticsCompanyId = undefined;
- form.logisticsCompanyCode = '';
- form.logisticNo = '';
- form.deliverMethod = '1';
- form.deliverMan = '';
- form.phone = '';
- form.consigneePhone = '';
- form.deliverRemark = '';
- productList.value = [];
- queryParams.value.pageNum = 1;
- formRef.value?.clearValidate();
- };
- const handleLogisticsCompanyChange = (val: any) => {
- const selectedCompany = logisticsCompanyList.value.find((item) => item.id === val);
- if (selectedCompany) {
- form.logisticsCompanyCode = selectedCompany.logisticsCode;
- }
- };
- // 加载商品列表
- const loadProductList = async () => {
- try {
- const res = await getOrderMain(props.orderId);
- // 为每个商品添加发货数量字段,默认为未发货数量
- productList.value = (res.data.orderProductList || []).map((item: OrderProductVO) => ({
- ...item,
- deliverNum: 0,
- productNo: item.productNo,
- productId: item.productId,
- orderPrice: item.orderPrice,
- productUnit: item.productUnit,
- productUnitId: item.productUnitId
- }));
- total.value = res.data.orderProductList.length || 0;
- } catch (error) {
- console.error('加载商品列表失败:', error);
- ElMessage.error('加载商品列表失败');
- productList.value = [];
- total.value = 0;
- }
- };
- // 加载物流公司列表
- const loadLogisticsCompanyList = async () => {
- try {
- const res = await listLogisticsCompany({
- isShow: '0',
- pageNum: 1,
- pageSize: 1000
- });
- logisticsCompanyList.value = res.rows || [];
- } catch (error) {
- console.error('加载物流公司列表失败:', error);
- logisticsCompanyList.value = [];
- }
- };
- // 发货数量变化
- const handleDeliveryQuantityChange = (index: number) => {
- const product = productList.value[index];
- if (product) {
- // 确保发货数量不超过未发货数量
- if (product.deliverNum > product.unsentQuantity) {
- product.deliverNum = product.unsentQuantity;
- ElMessage.warning('发货数量不能大于未发货数量');
- }
- // 确保发货数量不小于0
- if (product.deliverNum < 0) {
- product.deliverNum = 0;
- }
- }
- };
- // 删除商品
- const handleDeleteProduct = (index: number) => {
- productList.value.splice(index, 1);
- };
- // 分页大小变化
- const handleSizeChange = () => {
- queryParams.value.pageNum = 1;
- loadProductList();
- };
- // 页码变化
- const handleCurrentChange = () => {
- loadProductList();
- };
- // 取消
- const handleCancel = () => {
- emit('update:modelValue', false);
- };
- // 提交
- const handleSubmit = async () => {
- try {
- // 验证表单
- await formRef.value?.validate();
- // 验证是否有发货商品
- const deliveryProducts = productList.value.filter((item) => item.deliverNum > 0);
- if (deliveryProducts.length === 0) {
- ElMessage.warning('请至少选择一个商品进行发货');
- return;
- }
- submitLoading.value = true;
- // 组装发货数据
- const deliveryData: OrderDeliverForm = {
- orderId: form.orderId,
- orderCode: form.orderCode,
- logisticsCompanyId: form.logisticsCompanyId,
- logisticsCompanyCode: form.logisticsCompanyCode,
- logisticNo: form.logisticNo,
- deliverMethod: form.deliverMethod,
- deliverMan: form.deliverMan,
- phone: form.phone,
- consigneePhone: form.consigneePhone,
- deliverRemark: form.deliverRemark,
- orderDeliverProducts: deliveryProducts.map((item) => ({
- productId: item.productId,
- productNo: item.productNo,
- productName: item.productName,
- productUnitId: item.productUnitId,
- productUnit: item.productUnit,
- deliverNum: item.deliverNum,
- orderPrice: item.orderPrice
- }))
- };
- // 调用发货API
- await addOrderDeliver(deliveryData);
- ElMessage.success('发货成功');
- emit('success');
- emit('update:modelValue', false);
- } catch (error) {
- console.error('发货失败:', error);
- if (error !== false) {
- // 不是表单验证失败
- ElMessage.error('发货失败,请重试');
- }
- } finally {
- submitLoading.value = false;
- }
- };
- // 组件挂载时加载物流公司列表
- onMounted(() => {
- loadLogisticsCompanyList();
- });
- </script>
- <style scoped lang="scss">
- .mt-4 {
- margin-top: 16px;
- }
- .dialog-footer {
- display: flex;
- justify-content: flex-end;
- gap: 10px;
- }
- </style>
|