969 lines
31 KiB
Vue
969 lines
31 KiB
Vue
<template>
|
||
<div class="p-2">
|
||
<div v-show="showSearch" class="mb-10">
|
||
<el-card shadow="hover">
|
||
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
||
<el-form-item label="物流模板名称" prop="templateName" label-width="100">
|
||
<el-input v-model="queryParams.templateName" placeholder="请输入物流模板名称" clearable @keyup.enter="handleQuery" />
|
||
</el-form-item>
|
||
|
||
<el-form-item label="详细地址" prop="deliveryAddress" label-width="100">
|
||
<el-input v-model="queryParams.deliveryAddress" placeholder="请输入详细地址" clearable @keyup.enter="handleQuery" />
|
||
</el-form-item>
|
||
|
||
<el-form-item label="运送方式" prop="shipping">
|
||
<el-input v-model="queryParams.shipping" placeholder="请输入运送方式" clearable @keyup.enter="handleQuery" />
|
||
</el-form-item>
|
||
|
||
<el-form-item>
|
||
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||
</el-form-item>
|
||
</el-form>
|
||
</el-card>
|
||
</div>
|
||
|
||
<el-card shadow="never">
|
||
<template #header>
|
||
<el-row :gutter="10" class="mb8">
|
||
<el-col :span="1.5">
|
||
<el-button type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
|
||
</el-col>
|
||
<el-col :span="1.5">
|
||
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()">修改</el-button>
|
||
</el-col>
|
||
<el-col :span="1.5">
|
||
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()">删除</el-button>
|
||
</el-col>
|
||
<!-- <el-col :span="1.5">-->
|
||
<!-- <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['zhishu:logistics:export']">导出</el-button>-->
|
||
<!-- </el-col>-->
|
||
<el-button icon="Search" @click="showSearch = !showSearch">{{ showSearch ? '隐藏搜索' : '显示搜索' }}</el-button>
|
||
</el-row>
|
||
</template>
|
||
|
||
<el-table v-loading="loading" :data="logisticsList" @selection-change="handleSelectionChange">
|
||
<el-table-column type="selection" width="55" align="center" />
|
||
<el-table-column label="" align="center" prop="id" v-if="false" />
|
||
<el-table-column label="物流模板名称" align="center" prop="templateName" />
|
||
<el-table-column label="详细地址" align="center" prop="deliveryAddress">
|
||
<template #default="{ row }">
|
||
<span v-if="row.deliveryAddress!=null">{{row.deliveryAddress}}</span>
|
||
<span v-else></span>
|
||
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="计价方式" align="center" prop="pricingMethod">
|
||
<template #default="{ row }">
|
||
<span v-if="row.pricingMethod==0">按重量</span>
|
||
<span v-else-if="row.pricingMethod==1">按标准本数(图书专用)</span>
|
||
<span v-else-if="row.pricingMethod==2">按件数</span>
|
||
<span v-else-if="row.pricingMethod==3">单独设置运费</span>
|
||
<span v-else></span>
|
||
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="运送方式" align="center" prop="shipping">
|
||
<template #default="{ row }">
|
||
<span v-if="row.shipping==0">快递</span>
|
||
<span v-else-if="row.shipping==1">物流</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="模板状态" align="center" prop="status">
|
||
<template #default="{ row }">
|
||
<el-tag :type="row.status === '0' ? 'success' : 'danger'" :effect="row.status === '0' ? 'dark' : 'light'"
|
||
size="large">
|
||
{{ row.status === '0' ? '正常' : '异常(请先修改模版内容)' }}
|
||
</el-tag>
|
||
</template>
|
||
</el-table-column>
|
||
|
||
<!-- <el-table-column label="仓库名称" align="center" prop="warehouseName" />-->
|
||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||
<template #default="scope">
|
||
<el-tooltip content="修改运费模版" placement="top">
|
||
<el-button link type="primary" icon="Document" @click="handleFreightTemplate(scope.row)"></el-button>
|
||
</el-tooltip>
|
||
<el-tooltip content="删除" placement="top">
|
||
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button>
|
||
</el-tooltip>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
|
||
<el-pagination
|
||
v-show="total > 0"
|
||
:total="total"
|
||
v-model:current-page="queryParams.pageNum"
|
||
v-model:page-size="queryParams.pageSize"
|
||
:page-sizes="[10, 20, 50, 100]"
|
||
layout="total, sizes, prev, pager, next, jumper"
|
||
@size-change="getList"
|
||
@current-change="getList"
|
||
/>
|
||
</el-card>
|
||
|
||
<!-- 添加或修改物流管理对话框 -->
|
||
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
|
||
<el-form ref="logisticsFormRef" :model="form" :rules="Temrules" label-width="80px">
|
||
<!-- <el-form-item label="货区名称" prop="depotId" >-->
|
||
<!-- <el-select v-model="selectedId" value-key="id" placeholder="请选择一级货区" :reserve-keyword="false" clearable filterable style="width: 100%" :loading="loading" @update:model-value="handleDepotChange">-->
|
||
<!-- <el-option v-for="item in depotList" :key="item.id" :label="item.name+''+item.unit" :value="item" />-->
|
||
<!-- </el-select>-->
|
||
<!-- </el-form-item>-->
|
||
<el-form-item label="模板名称" prop="templateName">
|
||
<el-input v-model="form.templateName" placeholder="请输入物流模板名称" />
|
||
</el-form-item>
|
||
<el-form-item label="发货地" prop="deliveryArea">
|
||
<el-cascader v-model="freightForm.deliveryArea" :props="cascaderProps" placeholder="请选择发货地" clearable
|
||
style="width: 100%" />
|
||
</el-form-item>
|
||
</el-form>
|
||
<template #footer>
|
||
<div class="dialog-footer">
|
||
<el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
|
||
<el-button @click="cancel">取 消</el-button>
|
||
</div>
|
||
</template>
|
||
</el-dialog>
|
||
|
||
<!-- 运费模板对话框 -->
|
||
<el-dialog title="运费模板设置" v-model="freightDialog.visible" width="1000px" append-to-body>
|
||
<div class="freight-template-container">
|
||
<el-form :model="freightForm" ref="templatesFrom" label-width="80px" :rules="freightRule" >
|
||
<el-form-item label="模板名称">
|
||
<el-input v-model="freightForm.templateName" placeholder="请输入模板名称" />
|
||
</el-form-item>
|
||
<el-form-item label="发货地">
|
||
<el-cascader v-model="freightForm.deliveryArea" :props="cascaderProps" placeholder="请选择发货地" clearable
|
||
style="width: 100%" />
|
||
</el-form-item>
|
||
<el-row :gutter="20">
|
||
<el-col :span="8">
|
||
<el-form-item label="默认联系人" label-width="100" prop="contact">
|
||
<el-input v-model="freightForm.contact" placeholder="请输入联系人" />
|
||
</el-form-item>
|
||
</el-col>
|
||
<el-col :span="8">
|
||
<el-form-item label="手机号" prop="phoneNumber">
|
||
<el-input v-model="freightForm.phoneNumber" placeholder="请输入手机号" />
|
||
</el-form-item>
|
||
</el-col>
|
||
</el-row>
|
||
<el-form-item label="详细地址" prop="fullAddress">
|
||
<el-input v-model="freightForm.fullAddress" placeholder="请输入详细地址" />
|
||
</el-form-item>
|
||
|
||
<el-form-item label="计价方式">
|
||
<el-radio-group v-model="freightForm.pricingMethod">
|
||
<el-radio :value="'weight'" border size="large">按重量</el-radio>
|
||
<el-radio :value="'book'" border size="large">按标准本数(图书专用)</el-radio>
|
||
<el-radio :value="'piece'" border size="large">按件数</el-radio>
|
||
<el-radio :value="'custom'" border size="large">单独设置运费</el-radio>
|
||
</el-radio-group>
|
||
</el-form-item>
|
||
<el-form-item label="运送方式">
|
||
<el-select v-model="freightForm.deliveryMethod" placeholder="请选择运送方式">
|
||
<el-option label="快递" value="express" />
|
||
<el-option label="物流" value="logistics" />
|
||
</el-select>
|
||
<el-button type="danger" plain size="small" style="margin-left: 10px"
|
||
@click="deleteDeliveryMethod">删除</el-button>
|
||
</el-form-item>
|
||
|
||
<el-form-item label="运送范围">
|
||
<el-table :data="deliveryRanges" style="width: 100%" border>
|
||
<el-table-column label="运送范围" width="200">
|
||
<template #default="{ row }">
|
||
{{ row.region }}
|
||
</template>
|
||
</el-table-column>
|
||
|
||
<!-- 动态列 -->
|
||
<template v-for="column in dynamicColumns" :key="column.prop">
|
||
<el-table-column :label="column.label" :width="column.width">
|
||
<template #default="{ row }">
|
||
<el-input
|
||
v-model="row[column.prop]"
|
||
type="number"
|
||
:placeholder="column.placeholder"
|
||
@blur="column.validate ? validateFee(row[column.prop]) : null"
|
||
/>
|
||
</template>
|
||
</el-table-column>
|
||
</template>
|
||
|
||
<el-table-column label="操作" width="150">
|
||
<template #default="{ row }">
|
||
<el-button size="small" type="primary" link @click="editRegion(row)">编辑地区</el-button>
|
||
<el-button size="small" type="danger" link @click="deleteRegion(row)">删除</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
</el-form-item>
|
||
|
||
<el-form-item label="配送说明">
|
||
<el-input v-model="freightForm.deliveryNote" type="textarea" :rows="3"
|
||
placeholder="请输入配送说明,输入的内容将会在商品详情页面展示,不超过500个字" />
|
||
</el-form-item>
|
||
</el-form>
|
||
</div>
|
||
<template #footer>
|
||
<div class="dialog-footer">
|
||
<el-button :loading="buttonLoading" type="primary" @click="saveFreightTemplate">确定</el-button>
|
||
<el-button @click="cancelFreightTemplate">取 消</el-button>
|
||
</div>
|
||
</template>
|
||
</el-dialog>
|
||
<!-- 区域编辑对话框 -->
|
||
<el-dialog :title="regionDialog.title" v-model="regionDialog.visible" width="600px" append-to-body>
|
||
<div class="region-edit-container">
|
||
<el-checkbox-group v-model="selectedProvinces">
|
||
<el-checkbox v-for="province in allProvinces" :key="province" :value="province" :disabled="deliveryRanges.some(item => item.region !== regionDialog.currentRegion && item.region.includes(province))">
|
||
{{ province }}
|
||
</el-checkbox>
|
||
</el-checkbox-group>
|
||
</div>
|
||
<template #footer>
|
||
<div class="dialog-footer">
|
||
<el-button type="primary" @click="handleSaveRegion">确 定</el-button>
|
||
<el-button @click="regionDialog.visible = false">取 消</el-button>
|
||
</div>
|
||
</template>
|
||
</el-dialog>
|
||
</div>
|
||
|
||
|
||
|
||
</template>
|
||
|
||
<script setup name="Logistics">
|
||
import { ref, reactive, computed, onMounted, toRefs } from 'vue'
|
||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||
|
||
// 导入API模块
|
||
import {
|
||
listLogistics,
|
||
getLogistics,
|
||
delLogistics,
|
||
addLogistics,
|
||
updateLogistics,
|
||
} from '@/api/modules/logistics'
|
||
import {
|
||
getCitiesByProvinceId,
|
||
getDistrictsByCityId,
|
||
getFreInfo,
|
||
getProvinces,
|
||
UpdateTemplate
|
||
} from '@/api/modules/district'
|
||
// import { depotNameList } from '@/api/modules/shelves'
|
||
|
||
let curruntRow = null;
|
||
|
||
let isValid = true; // 全局校验标志
|
||
const queryFormRef = ref();
|
||
const logisticsFormRef = ref();
|
||
const templatesFrom = ref();
|
||
// 运费模板对话框状态
|
||
const freightDialog = reactive({
|
||
visible: false,
|
||
title: '运费模板设置'
|
||
});
|
||
// 运费模板表单数据
|
||
const freightForm = reactive({
|
||
templateName: '',
|
||
contact: '',
|
||
phoneNumber: '',
|
||
fullAddress: '',
|
||
deliveryArea: [],
|
||
pricingMethod: '',
|
||
deliveryMethod: 'express',
|
||
deliveryNote: ''
|
||
});
|
||
|
||
const validateFee = async (row) => {
|
||
if(row === null || row === ''){
|
||
isValid = false;
|
||
ElMessage.error(' 首费/运费不能为空');
|
||
} else {
|
||
isValid = true;
|
||
}
|
||
}
|
||
|
||
// 默认的运送范围
|
||
const defaultDeliveryRanges = ref([
|
||
{
|
||
region: '河北',
|
||
firstWeight: 1.0,
|
||
firstFee: 1.0,
|
||
cities: ['保定', '沧州', '承德', '邯郸', '衡水', '廊坊', '秦皇岛', '石家庄', '唐山', '邢台', '张家口'], // 写死的市级名称
|
||
continueWeight: 1.0,
|
||
continueFee: 1.0
|
||
},
|
||
{
|
||
region: '北京',
|
||
firstWeight: 1.0,
|
||
firstFee: 1.0,
|
||
continueWeight: 1.0,
|
||
continueFee: 1.0
|
||
},
|
||
{
|
||
region: '天津',
|
||
firstWeight: 1.0,
|
||
firstFee: 1.0,
|
||
continueWeight: 1.0,
|
||
continueFee: 1.0
|
||
},
|
||
{
|
||
region: '重庆',
|
||
firstWeight: 1.0,
|
||
firstFee: 1.0,
|
||
continueWeight: 1.0,
|
||
continueFee: 1.0
|
||
},
|
||
{
|
||
region: '上海、江苏、浙江、安徽、江西、山西、山东、内蒙古、湖南、湖北、河南、广东、广西、福建、海南、辽宁、吉林、黑龙江、陕西、云南、贵州、四川',
|
||
firstWeight: 1.0,
|
||
firstFee: 1.0,
|
||
continueWeight: 1.0,
|
||
continueFee: 1.0
|
||
},
|
||
{
|
||
region: '甘肃、宁夏、青海',
|
||
firstWeight: 1.0,
|
||
firstFee: 1.0,
|
||
continueWeight: 1.0,
|
||
continueFee: 1.0
|
||
},
|
||
{
|
||
region: '新疆、西藏',
|
||
firstWeight: 1.0,
|
||
firstFee: 1.0,
|
||
continueWeight: 1.0,
|
||
continueFee: 1.0
|
||
},
|
||
{
|
||
region: '香港、澳门、台湾、海外',
|
||
firstWeight: 1.0,
|
||
firstFee: 1.0,
|
||
continueWeight: 1.0,
|
||
continueFee: 1.0
|
||
}
|
||
]);
|
||
// 模拟运送范围数据
|
||
const deliveryRanges =ref([
|
||
{
|
||
region: '河北',
|
||
firstWeight: 1.0,
|
||
firstFee: 1.0,
|
||
cities: ['保定', '沧州', '承德', '邯郸', '衡水', '廊坊', '秦皇岛', '石家庄', '唐山', '邢台', '张家口'], // 写死的市级名称
|
||
continueWeight: 1.0,
|
||
continueFee: 1.0
|
||
},
|
||
{
|
||
region: '北京',
|
||
firstWeight: 1.0,
|
||
firstFee: 1.0,
|
||
continueWeight: 1.0,
|
||
continueFee: 1.0
|
||
},
|
||
{
|
||
region: '天津',
|
||
firstWeight: 1.0,
|
||
firstFee: 1.0,
|
||
continueWeight: 1.0,
|
||
continueFee: 1.0
|
||
},
|
||
{
|
||
region: '重庆',
|
||
firstWeight: 1.0,
|
||
firstFee: 1.0,
|
||
continueWeight: 1.0,
|
||
continueFee: 1.0
|
||
},
|
||
{
|
||
region: '上海、江苏、浙江、安徽、江西、山西、山东、内蒙古、湖南、湖北、河南、广东、广西、福建、海南、辽宁、吉林、黑龙江、陕西、云南、贵州、四川',
|
||
firstWeight: 1.0,
|
||
firstFee: 1.0,
|
||
continueWeight: 1.0,
|
||
continueFee: 1.0
|
||
},
|
||
{
|
||
region: '甘肃、宁夏、青海',
|
||
firstWeight: 1.0,
|
||
firstFee: 1.0,
|
||
continueWeight: 1.0,
|
||
continueFee: 1.0
|
||
},
|
||
{
|
||
region: '新疆、西藏',
|
||
firstWeight: 1.0,
|
||
firstFee: 1.0,
|
||
continueWeight: 1.0,
|
||
continueFee: 1.0
|
||
},
|
||
{
|
||
region: '香港、澳门、台湾、海外',
|
||
firstWeight: 1.0,
|
||
firstFee: 1.0,
|
||
continueWeight: 1.0,
|
||
continueFee: 1.0
|
||
}
|
||
]);
|
||
// @blur="validateFee(row.firstFee)"
|
||
|
||
// 根据计价方式展示不同内容
|
||
const dynamicColumns = computed(() => {
|
||
const method = freightForm.pricingMethod;
|
||
|
||
if (method === 'weight') {
|
||
return [
|
||
{ prop: 'firstWeight', label: '首重(千克)', placeholder: '请输入首重', width: '120' },
|
||
{ prop: 'firstFee', label: '首费(元)', placeholder: '请输入首费', width: '120',validate: true },
|
||
{ prop: 'continueWeight', label: '续重(千克)', placeholder: '请输入续重', width: '120' },
|
||
{ prop: 'continueFee', label: '续费(元)', placeholder: '请输入续费', width: '120' },
|
||
];
|
||
} else if (method === 'book') {
|
||
return [
|
||
{ prop: 'firstWeight', label: '首重本数(本)', placeholder: '请输入首本', width: '120' },
|
||
{ prop: 'firstFee', label: '首费(元)', placeholder: '请输入首费', width: '120',validate: true },
|
||
{ prop: 'continueWeight', label: '续重本数(本)', placeholder: '请输入续本', width: '120' },
|
||
{ prop: 'continueFee', label: '续费(元)', placeholder: '请输入续费', width: '120' },
|
||
];
|
||
} else if (method === 'piece') {
|
||
return [
|
||
{ prop: 'firstWeight', label: '首件数(件)', placeholder: '请输入首件', width: '120' },
|
||
{ prop: 'firstFee', label: '首费(元)', placeholder: '请输入首费', width: '120',validate: true },
|
||
{ prop: 'continueWeight', label: '续件数(件)', placeholder: '请输入续件', width: '120' },
|
||
{ prop: 'continueFee', label: '续费(元)', placeholder: '请输入续费', width: '120' },
|
||
];
|
||
} else if(method === 'custom'){
|
||
return [
|
||
{ prop: 'firstFee', label: '运费(元)', placeholder: '请输入运费', width: '120',validate: true },
|
||
|
||
];
|
||
|
||
}
|
||
});
|
||
|
||
const handleFreightTemplate = async (row) => {
|
||
freightDialog.visible = true;
|
||
// 加载省级数据
|
||
// 可以根据仓库信息加载对应的运费模板数据
|
||
const res = await getFreInfo(row.id);
|
||
console.log(row.id);
|
||
freightForm.templateName=row.templateName;
|
||
const { deliveryProvince: pro, deliveryCity: city, deliveryArea: area } = res;
|
||
freightForm.deliveryArea=[Number(pro),Number(city),Number(area)]
|
||
// 数字编码 转换 对应的计价方式
|
||
const pricingMethodMap = {
|
||
0:'weight',
|
||
1:'book',
|
||
2:'piece',
|
||
3:'custom'
|
||
};
|
||
freightForm.pricingMethod= pricingMethodMap[row.pricingMethod];
|
||
// 数字编码对应运送方式
|
||
const deliveryMethodMap = {
|
||
0:'express',
|
||
1:'logistics'
|
||
};
|
||
freightForm.deliveryMethod=deliveryMethodMap[row.shipping]
|
||
// dataRange=row.shippingRange;
|
||
if(row.shippingRange!=null){
|
||
const parsedData=JSON.parse(row.shippingRange);
|
||
deliveryRanges.value = transformData(parsedData)
|
||
|
||
}else{
|
||
// 使用深拷贝创建全新的默认值
|
||
deliveryRanges.value = JSON.parse(JSON.stringify(defaultDeliveryRanges.value))
|
||
}
|
||
freightForm.contact=res.contact;
|
||
freightForm.phoneNumber=res.phoneNumber;
|
||
freightForm.fullAddress=res.fullAddress;
|
||
freightForm.deliveryNote=res.remark;
|
||
curruntRow = row;
|
||
console.log(freightForm)
|
||
};
|
||
|
||
const transformData= (dataRange) => {
|
||
const result=[];
|
||
for (const region in dataRange) {
|
||
const [firstWeight, firstFee, continueWeight, continueFee] = dataRange[region];
|
||
result.push({
|
||
region,
|
||
firstWeight: parseFloat(firstWeight) || 0.0,
|
||
firstFee: parseFloat(firstFee)||0.0,
|
||
continueWeight: parseFloat(continueWeight) || 0.0,
|
||
continueFee: parseFloat(continueFee)||0.0
|
||
});
|
||
}
|
||
return result;
|
||
}
|
||
const freightRule= reactive({
|
||
contact: [
|
||
{ required: true, message: '请输入默认联系人', trigger: 'blur' }
|
||
],
|
||
phoneNumber: [
|
||
{ required: true, message: '请输入联系电话', trigger: 'blur' },
|
||
{ pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号码', trigger: 'blur' }
|
||
],
|
||
fullAddress: [
|
||
{ required: true, message: '请输入详细地址', trigger: 'blur' }
|
||
]
|
||
}
|
||
)
|
||
|
||
/** 删除运送方式 */
|
||
const deleteDeliveryMethod = async () => {
|
||
try {
|
||
await ElMessageBox.confirm('确定要删除该运送方式吗?', '提示', {
|
||
confirmButtonText: '确定',
|
||
cancelButtonText: '取消',
|
||
type: 'warning'
|
||
});
|
||
ElMessage.success('删除成功');
|
||
// 实际应用中应调用API删除数据
|
||
} catch (error) {
|
||
console.log('取消删除');
|
||
}
|
||
};
|
||
|
||
const allProvinces = ['北京', '天津', '河北', '山西', '内蒙古', '辽宁', '吉林', '黑龙江', '上海', '江苏', '浙江', '安徽', '福建', '江西', '山东', '河南', '湖北', '湖南', '广东', '广西', '海南', '重庆', '四川', '贵州', '云南', '西藏', '陕西', '甘肃', '青海', '宁夏', '新疆', '香港', '澳门', '台湾'];
|
||
|
||
|
||
|
||
// 区域编辑对话框状态
|
||
const regionDialog = reactive({
|
||
visible: false,
|
||
title: '编辑地区',
|
||
currentRegion: ''
|
||
});
|
||
// 当前选中的省份列表
|
||
const selectedProvinces = ref([]);
|
||
const editRegion = (row) => {
|
||
regionDialog.visible = true;
|
||
regionDialog.currentRegion = row.region;
|
||
// 将当前行的地区字符串转换为数组
|
||
selectedProvinces.value = row.region.split('、');
|
||
};
|
||
/** 删除地区 */
|
||
const deleteRegion = async (row) => {
|
||
try {
|
||
await ElMessageBox.confirm('确定要删除该地区吗?', '提示', {
|
||
confirmButtonText: '确定',
|
||
cancelButtonText: '取消',
|
||
type: 'warning'
|
||
});
|
||
|
||
const index = deliveryRanges.value.findIndex(item => item.region === row.region);
|
||
if (index !== -1) {
|
||
deliveryRanges.value.splice(index, 1);
|
||
ElMessage.success('删除成功');
|
||
}
|
||
} catch (error) {
|
||
console.log('取消删除');
|
||
}
|
||
};
|
||
/** 保存运费模板 */
|
||
const saveFreightTemplate = async () => {
|
||
if (!templatesFrom.value) return;
|
||
|
||
try {
|
||
const valid = await templatesFrom.value.validate();
|
||
if(valid) {
|
||
buttonLoading.value = true;
|
||
|
||
// 获取选择的地区信息(省、市、区)
|
||
const [provinceId, cityId, districtId] = freightForm.deliveryArea;
|
||
|
||
// 转换计价方式为数字编码
|
||
const pricingMethodMap = {
|
||
'weight': 0,
|
||
'book': 1,
|
||
'piece': 2,
|
||
'custom': 3
|
||
};
|
||
// 转换运送方式为数字编码
|
||
const deliveryMethodMap = {
|
||
'express': 0,
|
||
'logistics': 1
|
||
};
|
||
|
||
const shippingRanges = deliveryRanges.value.reduce((acc, range) => {
|
||
acc[range.region] = [range.firstWeight, range.firstFee, range.continueWeight, range.continueFee];
|
||
return acc;
|
||
}, {});
|
||
|
||
// 收集所有数据
|
||
const templateData = {
|
||
id: curruntRow.id,
|
||
template_name: freightForm.templateName,
|
||
contact: freightForm.contact,
|
||
phoneNumber: freightForm.phoneNumber,
|
||
fullAddress: freightForm.fullAddress,
|
||
delivery_province: provinceId,
|
||
delivery_city: cityId,
|
||
delivery_area: districtId,
|
||
pricing_method: pricingMethodMap[freightForm.pricingMethod],
|
||
shipping: deliveryMethodMap[freightForm.deliveryMethod],
|
||
shipping_range: shippingRanges,
|
||
warehouse_id: curruntRow.id,
|
||
remark: freightForm.deliveryNote
|
||
};
|
||
|
||
if (isValid) {
|
||
await UpdateTemplate(templateData);
|
||
ElMessage.success('运费模板保存成功');
|
||
freightDialog.visible = false;
|
||
} else {
|
||
ElMessage.error('首费/运费不能为空');
|
||
}
|
||
|
||
buttonLoading.value = false;
|
||
getList();
|
||
}
|
||
} catch (error) {
|
||
console.error('表单验证或保存失败:', error);
|
||
ElMessage.error('操作失败,请检查输入信息');
|
||
buttonLoading.value = false;
|
||
}
|
||
};
|
||
|
||
/** 取消运费模板 */
|
||
const cancelFreightTemplate = () => {
|
||
freightDialog.visible = false;
|
||
};
|
||
/** 保存区域设置 */
|
||
const handleSaveRegion = () => {
|
||
if (selectedProvinces.value.length === 0) {
|
||
ElMessage.error('请至少选择一个省份');
|
||
return;
|
||
}
|
||
|
||
// 获取未选中的省份
|
||
const unselectedProvinces = getUnselectedProvinces();
|
||
// 更新deliveryRanges中对应行的region数据
|
||
const index = deliveryRanges.value.findIndex(item => item.region === regionDialog.currentRegion);
|
||
if (index !== -1) {
|
||
// 更新当前选中的省份
|
||
deliveryRanges.value[index].region = selectedProvinces.value.join('、');
|
||
// 如果有取消勾选的省份,添加到最后一行或更新现有的取消勾选省份行
|
||
if (unselectedProvinces.length > 0) {
|
||
// 查找是否已存在取消勾选的省份行
|
||
const unselectedIndex = deliveryRanges.value.findIndex(item =>
|
||
// 检查是否包含取消勾选的任一省份
|
||
unselectedProvinces.some(province => item.region.includes(province)));
|
||
|
||
if (unselectedIndex !== -1 && unselectedIndex !== index) {
|
||
// 如果已存在包含这些省份的行,则更新该行
|
||
deliveryRanges.value[unselectedIndex].region = unselectedProvinces.join('、');
|
||
} else {
|
||
// 否则添加新行
|
||
deliveryRanges.value.push({
|
||
region: unselectedProvinces.join('、'),
|
||
firstWeight: 1.0,
|
||
firstFee: 1.0,
|
||
continueWeight: 1.0,
|
||
continueFee: 1.0
|
||
});
|
||
}
|
||
}
|
||
}
|
||
|
||
regionDialog.visible = false;
|
||
};
|
||
// 级联选择器配置
|
||
const cascaderProps = reactive({
|
||
lazy: true,
|
||
async lazyLoad(node, resolve) {
|
||
const { level, value: parentId } = node;
|
||
try {
|
||
let nodes = [];
|
||
|
||
if (level === 0) { // 加载省份
|
||
const res = await getProvinces();
|
||
nodes = res.data.map(formatNode(0));
|
||
}
|
||
else if (level === 1) { // 加载城市
|
||
const res = await getCitiesByProvinceId(parentId);
|
||
nodes = res.data.map(formatNode(1));
|
||
}
|
||
else if (level === 2) { // 加载区县
|
||
const res = await getDistrictsByCityId(parentId);
|
||
nodes = res.data.map(formatNode(2, true));
|
||
}
|
||
|
||
resolve(nodes);
|
||
} catch (error) {
|
||
resolve([]);
|
||
}
|
||
}
|
||
});
|
||
const formatNode = (level, isLeaf = false) => (item) => ({
|
||
value: item.id,
|
||
label: item.name,
|
||
leaf: isLeaf,
|
||
level: level
|
||
});
|
||
// 获取本次编辑中取消勾选的省份
|
||
const getUnselectedProvinces = () => {
|
||
// 获取编辑前的省份列表
|
||
const originalProvinces = regionDialog.currentRegion.split('、');
|
||
// 获取当前选中的省份集合
|
||
const selectedProvincesSet = new Set(selectedProvinces.value);
|
||
// 只返回那些在原始列表中存在但在当前选择中不存在的省份(即用户取消勾选的省份)
|
||
return originalProvinces.filter(province => !selectedProvincesSet.has(province));
|
||
};
|
||
|
||
|
||
|
||
|
||
|
||
const logisticsList = ref([]);
|
||
const buttonLoading = ref(false);
|
||
const loading = ref(true);
|
||
const showSearch = ref(true);
|
||
const ids = ref([]);
|
||
const single = ref(true);
|
||
const multiple = ref(true);
|
||
const total = ref(0);
|
||
|
||
|
||
|
||
const dialog = reactive({
|
||
visible: false,
|
||
title: ''
|
||
});
|
||
|
||
const initFormData = {
|
||
id: undefined,
|
||
templateName: undefined,
|
||
deliveryProvince: undefined,
|
||
deliveryCity: undefined,
|
||
deliveryArea: undefined,
|
||
deliveryAddress: undefined,
|
||
pricingMethod: undefined,
|
||
shipping: undefined,
|
||
firWbv: undefined,
|
||
firPrice: undefined,
|
||
continueWbv: undefined,
|
||
continuePrice: undefined,
|
||
status: undefined,
|
||
shippingRange: undefined,
|
||
warehouseId: undefined,
|
||
warehouseName: undefined
|
||
}
|
||
const data = reactive({
|
||
form: {...initFormData},
|
||
queryParams: {
|
||
pageNum: 1,
|
||
pageSize: 10,
|
||
id:undefined,
|
||
templateName: undefined,
|
||
deliveryProvince: undefined,
|
||
deliveryCity: undefined,
|
||
deliveryArea: undefined,
|
||
deliveryAddress: undefined,
|
||
pricingMethod: undefined,
|
||
shipping: undefined,
|
||
firWbv: undefined,
|
||
firPrice: undefined,
|
||
continueWbv: undefined,
|
||
continuePrice: undefined,
|
||
status: undefined,
|
||
shippingRange: undefined,
|
||
warehouseId: undefined,
|
||
warehouseName:undefined,
|
||
params: {
|
||
}
|
||
},
|
||
rules: {
|
||
}
|
||
});
|
||
|
||
const { queryParams, form } = toRefs(data);
|
||
|
||
// 新增中选择一级货区
|
||
const Temrules = reactive({
|
||
templateName: [
|
||
{
|
||
required: true,
|
||
message: '模版名称不能为空',
|
||
trigger: ['blur', 'change']
|
||
}
|
||
],
|
||
// 发货地址校验
|
||
deliveryArea: [
|
||
{
|
||
required: true,
|
||
message: '请选择发货地',
|
||
trigger: 'change', // 触发时机
|
||
validator: (_, __, callback) => {
|
||
const message = freightForm.deliveryArea;
|
||
if(message.length == 0){
|
||
callback(new Error('请选择完整地址'));
|
||
} else {
|
||
callback();
|
||
}
|
||
}
|
||
}
|
||
]
|
||
})
|
||
|
||
// 这些变量和函数暂时未使用,可以在需要时添加
|
||
// const selectedId = ref(null)
|
||
// const depotList = ref([])
|
||
// const loadData = async () => {
|
||
// loading.value = true
|
||
// try {
|
||
// const res = await depotNameList()
|
||
// depotList.value = res.rows
|
||
// } catch (error) {
|
||
// console.error('加载数据失败:', error)
|
||
// } finally {
|
||
// loading.value = false
|
||
// }
|
||
// }
|
||
|
||
// const handleDepotChange = (val) => {
|
||
// form.value.depotId = val?.id || null
|
||
// form.value.depotName = val?.name || ''
|
||
// }
|
||
|
||
/** 查询物流管理列表 */
|
||
const getList = async () => {
|
||
loading.value = true;
|
||
const res = await listLogistics(queryParams.value);
|
||
logisticsList.value = res.rows;
|
||
total.value = res.total;
|
||
loading.value = false;
|
||
}
|
||
|
||
/** 取消按钮 */
|
||
const cancel = () => {
|
||
reset();
|
||
dialog.visible = false;
|
||
}
|
||
|
||
/** 表单重置 */
|
||
const reset = () => {
|
||
form.value = {...initFormData};
|
||
logisticsFormRef.value?.resetFields();
|
||
}
|
||
|
||
/** 搜索按钮操作 */
|
||
const handleQuery = () => {
|
||
queryParams.value.pageNum = 1;
|
||
getList();
|
||
}
|
||
|
||
/** 重置按钮操作 */
|
||
const resetQuery = () => {
|
||
queryFormRef.value?.resetFields();
|
||
handleQuery();
|
||
}
|
||
|
||
/** 多选框选中数据 */
|
||
const handleSelectionChange = (selection) => {
|
||
ids.value = selection.map(item => item.id);
|
||
single.value = selection.length != 1;
|
||
multiple.value = !selection.length;
|
||
}
|
||
|
||
/** 新增按钮操作 */
|
||
const handleAdd = () => {
|
||
reset();
|
||
freightForm.deliveryArea = [];
|
||
freightForm.pricingMethod = '2'
|
||
dialog.visible = true;
|
||
dialog.title = "添加物流管理";
|
||
}
|
||
|
||
/** 修改按钮操作 */
|
||
const handleUpdate = async (row) => {
|
||
reset();
|
||
const _id = row?.id || ids.value[0]
|
||
const res = await getLogistics(_id);
|
||
Object.assign(form.value, res.data);
|
||
dialog.visible = true;
|
||
dialog.title = "修改物流管理";
|
||
}
|
||
|
||
/** 提交按钮 */
|
||
const submitForm = () => {
|
||
logisticsFormRef.value?.validate(async (valid) => {
|
||
if (valid) {
|
||
buttonLoading.value = true;
|
||
if (form.value.id) {
|
||
await updateLogistics(form.value).finally(() => buttonLoading.value = false);
|
||
} else {
|
||
const [provinceId, cityId, districtId] = freightForm.deliveryArea;
|
||
form.value.deliveryProvince = provinceId;
|
||
form.value.deliveryCity = cityId;
|
||
form.value.deliveryArea = districtId;
|
||
form.value.pricingMethod = 1;
|
||
await addLogistics(form.value).finally(() => buttonLoading.value = false);
|
||
}
|
||
ElMessage.success("操作成功");
|
||
dialog.visible = false;
|
||
await getList();
|
||
}
|
||
});
|
||
}
|
||
|
||
/** 删除按钮操作 */
|
||
const handleDelete = async (row) => {
|
||
const _ids = row?.id || ids.value;
|
||
try {
|
||
await ElMessageBox.confirm('是否确认删除物流管理编号为"' + _ids + '"的数据项?', '提示', {
|
||
confirmButtonText: '确定',
|
||
cancelButtonText: '取消',
|
||
type: 'warning'
|
||
});
|
||
await delLogistics(_ids);
|
||
ElMessage.success("删除成功");
|
||
await getList();
|
||
} catch (error) {
|
||
console.log('取消删除')
|
||
}
|
||
}
|
||
|
||
onMounted(() => {
|
||
getList();
|
||
// loadData(); // 暂时注释掉,因为相关函数被注释了
|
||
});
|
||
</script>
|
||
|
||
<style scoped>
|
||
.freight-template-container {
|
||
padding: 20px;
|
||
}
|
||
|
||
.region-edit-container {
|
||
max-height: 400px;
|
||
overflow-y: auto;
|
||
}
|
||
|
||
.region-edit-container .el-checkbox {
|
||
display: block;
|
||
margin: 10px 0;
|
||
}
|
||
|
||
.dialog-footer {
|
||
text-align: right;
|
||
}
|
||
|
||
.mb8 {
|
||
margin-bottom: 8px;
|
||
}
|
||
|
||
.p-2 {
|
||
padding: 8px;
|
||
}
|
||
|
||
.mb-10 {
|
||
margin-bottom: 10px;
|
||
}
|
||
</style>
|