839 lines
26 KiB
Vue
839 lines
26 KiB
Vue
<template>
|
||
<basic-container class="transport-plan-dispatch-page">
|
||
<div v-loading="loading" class="transport-plan-dispatch-page__shell">
|
||
<!-- 顶部信息区:对齐运单详情汇总样式 -->
|
||
<section-card class="transport-plan-dispatch-page__summary">
|
||
<div class="transport-plan-dispatch-page__heading">
|
||
<el-button icon="el-icon-arrow-left" text @click="handleBack">返回</el-button>
|
||
<strong>计划调度</strong>
|
||
<span>{{ planData.planNo || planData.loadingNo || '-' }}</span>
|
||
<span class="detail-status-text" :class="statusTextClass">
|
||
{{ planData.businessStatusName || '-' }}
|
||
</span>
|
||
<span class="detail-status-text detail-transport-type">
|
||
{{ planData.transportTypeName || '公路整车' }}
|
||
</span>
|
||
</div>
|
||
<div class="transport-plan-dispatch-page__summary-grid">
|
||
<div class="transport-plan-dispatch-page__summary-item">
|
||
<span class="transport-plan-dispatch-page__summary-label">客户</span>
|
||
<span class="transport-plan-dispatch-page__summary-value">
|
||
{{ planData.customerName || '-' }}
|
||
</span>
|
||
</div>
|
||
<div class="transport-plan-dispatch-page__summary-item">
|
||
<span class="transport-plan-dispatch-page__summary-label">合同编号</span>
|
||
<span class="transport-plan-dispatch-page__summary-value is-link">
|
||
{{ planData.contractNo || '-' }}
|
||
</span>
|
||
</div>
|
||
<div class="transport-plan-dispatch-page__summary-item">
|
||
<span class="transport-plan-dispatch-page__summary-label">项目</span>
|
||
<span class="transport-plan-dispatch-page__summary-value">
|
||
{{ planData.projectName || '-' }}
|
||
</span>
|
||
</div>
|
||
<div class="transport-plan-dispatch-page__summary-item">
|
||
<span class="transport-plan-dispatch-page__summary-label">计划执行时间</span>
|
||
<span class="transport-plan-dispatch-page__summary-value">
|
||
{{ formatDateRange(planData.planStartDate, planData.planEndDate) }}
|
||
</span>
|
||
</div>
|
||
<div class="transport-plan-dispatch-page__summary-item is-goods">
|
||
<span class="transport-plan-dispatch-page__summary-label">货物信息</span>
|
||
<span class="transport-plan-dispatch-page__summary-value is-wrap">
|
||
{{ planData.goodsInfo || formatGoodsInfo(planData) }}
|
||
</span>
|
||
</div>
|
||
<div class="transport-plan-dispatch-page__route">
|
||
<div class="transport-plan-dispatch-page__route-item is-start">
|
||
<div class="transport-plan-dispatch-page__route-marker">起</div>
|
||
<div class="transport-plan-dispatch-page__route-detail">
|
||
<strong class="transport-plan-dispatch-page__route-name">
|
||
{{
|
||
formatRouteCityDistrict(planData.departureAddress || planData.departureName)
|
||
}}
|
||
</strong>
|
||
<el-tooltip
|
||
:content="planData.departureAddress || planData.departureName || '-'"
|
||
placement="top"
|
||
>
|
||
<span class="transport-plan-dispatch-page__route-addr">
|
||
{{ planData.departureAddress || planData.departureName || '-' }}
|
||
</span>
|
||
</el-tooltip>
|
||
<div class="transport-plan-dispatch-page__route-contact">
|
||
<span>联系人:{{ planData.departureContact || '-' }}</span>
|
||
<span>联系方式:{{ planData.departurePhone || '-' }}</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<span class="transport-plan-dispatch-page__route-line" aria-hidden="true" />
|
||
<div class="transport-plan-dispatch-page__route-item is-end">
|
||
<div class="transport-plan-dispatch-page__route-marker">终</div>
|
||
<div class="transport-plan-dispatch-page__route-detail">
|
||
<strong class="transport-plan-dispatch-page__route-name">
|
||
{{ formatRouteCityDistrict(planData.arrivalAddress || planData.arrivalName) }}
|
||
</strong>
|
||
<el-tooltip
|
||
:content="planData.arrivalAddress || planData.arrivalName || '-'"
|
||
placement="top"
|
||
>
|
||
<span class="transport-plan-dispatch-page__route-addr">
|
||
{{ planData.arrivalAddress || planData.arrivalName || '-' }}
|
||
</span>
|
||
</el-tooltip>
|
||
<div class="transport-plan-dispatch-page__route-contact">
|
||
<span>联系人:{{ planData.arrivalContact || '-' }}</span>
|
||
<span>联系方式:{{ planData.arrivalPhone || '-' }}</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="transport-plan-dispatch-page__attachments">
|
||
<span class="transport-plan-dispatch-page__summary-label">附件</span>
|
||
<div>
|
||
<el-link
|
||
v-for="(item, index) in attachmentList"
|
||
:key="index"
|
||
type="primary"
|
||
:href="item.url"
|
||
:underline="false"
|
||
target="_blank"
|
||
>
|
||
{{ item.name || item.originalName || '附件' }}
|
||
</el-link>
|
||
<span v-if="!attachmentList.length">-</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section-card>
|
||
|
||
<!-- 调度列表 -->
|
||
<section-card class="transport-plan-dispatch-page__list-card">
|
||
<template #title>
|
||
<span>待调度列表</span>
|
||
<span class="transport-plan-dispatch-page__list-summary">
|
||
{{ summaryText }}
|
||
</span>
|
||
</template>
|
||
<template #extra>
|
||
<el-button type="primary" :disabled="!canAddDispatch" @click="handleAdd">
|
||
新增
|
||
</el-button>
|
||
</template>
|
||
<el-table
|
||
:data="dispatchList"
|
||
border
|
||
height="100%"
|
||
row-key="id"
|
||
class="transport-plan-dispatch-page__table"
|
||
>
|
||
<el-table-column type="index" label="序号" width="70" align="center" fixed="left" />
|
||
<el-table-column label="运输方式" min-width="180" align="center" show-overflow-tooltip>
|
||
<template #default="{ row }">
|
||
{{ row.transportTypeName || '-' }}
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="carrierType" label="承运类型" min-width="150" align="center" show-overflow-tooltip />
|
||
<el-table-column prop="carrierName" label="承运商" min-width="150" align="center" show-overflow-tooltip />
|
||
<el-table-column prop="driverName" label="司机" min-width="260" align="center" show-overflow-tooltip>
|
||
<template #default="{ row }">
|
||
<span>{{ formatDriver(row) }}</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="vehicleNo" label="车牌号" min-width="150" align="center" show-overflow-tooltip />
|
||
<el-table-column prop="cargoType" label="货物类型" min-width="170" align="center" show-overflow-tooltip />
|
||
<el-table-column prop="cargoInfo" label="货物信息" min-width="280" align="center" show-overflow-tooltip>
|
||
<template #default="{ row }">
|
||
{{ row.cargoInfo || formatCargoInfo(row) }}
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="发货地址" min-width="220" align="center" show-overflow-tooltip>
|
||
<template #default="{ row }">
|
||
{{ formatAddress(row.departureAddress) }}
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="收货地址" min-width="220" align="center" show-overflow-tooltip>
|
||
<template #default="{ row }">
|
||
{{ formatAddress(row.arrivalAddress) }}
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="quantity" label="数量" min-width="120" align="center">
|
||
<template #default="{ row }">
|
||
{{ row.quantity ? `${row.quantity}${row.quantityUnit || '吨'}` : '-' }}
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="unitPrice" label="单价" min-width="120" align="center" />
|
||
<el-table-column prop="freight" label="运费" min-width="120" align="center" />
|
||
<el-table-column prop="otherFeeTotal" label="其他费用" min-width="120" align="center" />
|
||
<el-table-column prop="freightTotal" label="运费合计" min-width="120" align="center" />
|
||
<el-table-column label="操作" width="100" align="center" fixed="right">
|
||
<template #default="{ row, $index }">
|
||
<div class="transport-plan-dispatch-page__actions">
|
||
<el-link type="primary" @click="handleEdit(row, $index)">编辑</el-link>
|
||
<el-link type="danger" @click="handleDelete($index)">删除</el-link>
|
||
</div>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
</section-card>
|
||
|
||
<!-- 底部按钮 -->
|
||
<div class="transport-plan-dispatch-page__footer">
|
||
<el-button @click="handleBack">关闭</el-button>
|
||
<el-button type="primary" :loading="saving" @click="handleSubmit">
|
||
确认生成
|
||
</el-button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 调度明细编辑弹窗 - 将使用原组件的弹窗 -->
|
||
<transport-plan-page
|
||
v-if="transportPlanPageVisible"
|
||
ref="transportPlanPageRef"
|
||
:api="api"
|
||
:config="config"
|
||
:crud-option="option"
|
||
style="display: none"
|
||
/>
|
||
</basic-container>
|
||
</template>
|
||
|
||
<script>
|
||
import { getDetail, dispatch } from '@/api/business/transport-plan';
|
||
import SectionCard from '@/components/section-card/main.vue';
|
||
import TransportPlanPage from './components/transport-plan-page.vue';
|
||
import * as api from '@/api/business/transport-plan';
|
||
import { config, option } from '@/option/business/transport-plan';
|
||
|
||
const TRANSPORT_PLAN_QUANTITY_UNIT = '吨';
|
||
|
||
export default {
|
||
name: 'TransportPlanDispatch',
|
||
components: {
|
||
SectionCard,
|
||
TransportPlanPage,
|
||
},
|
||
data() {
|
||
return {
|
||
loading: false,
|
||
saving: false,
|
||
planData: {},
|
||
dispatchList: [],
|
||
attachmentList: [],
|
||
transportPlanPageVisible: false,
|
||
api,
|
||
config,
|
||
option,
|
||
};
|
||
},
|
||
computed: {
|
||
planId() {
|
||
return this.$route.query.planId;
|
||
},
|
||
statusTextClass() {
|
||
const status = this.planData.businessStatus;
|
||
if (status === 2 || status === '2') return 'status-text-success';
|
||
if (status === 1 || status === '1') return 'is-dispatching';
|
||
if (status === 3 || status === '3') return 'is-danger';
|
||
return 'is-info';
|
||
},
|
||
summaryText() {
|
||
const goodsList = this.parseGoodsList(this.planData.goodsJson);
|
||
if (!goodsList.length) {
|
||
const total = Number(this.planData.totalQuantity || 0);
|
||
const dispatched = this.calculateDispatchedQuantity();
|
||
if (total <= 0) {
|
||
return `已调度 ${dispatched.toFixed(2)}吨`;
|
||
}
|
||
const remaining = Math.max(total - dispatched, 0);
|
||
return `共${total}吨 | 已调度 ${dispatched.toFixed(2)}吨,剩余${remaining.toFixed(2)}吨`;
|
||
}
|
||
|
||
const summary = {};
|
||
goodsList.forEach(goods => {
|
||
const unit = goods.quantityUnit || TRANSPORT_PLAN_QUANTITY_UNIT;
|
||
if (!summary[unit]) {
|
||
summary[unit] = { total: 0, dispatched: 0 };
|
||
}
|
||
summary[unit].total += Number(goods.quantity || 0);
|
||
});
|
||
|
||
this.dispatchList.forEach(item => {
|
||
const unit = item.quantityUnit || TRANSPORT_PLAN_QUANTITY_UNIT;
|
||
if (!summary[unit]) {
|
||
summary[unit] = { total: 0, dispatched: 0 };
|
||
}
|
||
summary[unit].dispatched += Number(item.quantity || 0);
|
||
});
|
||
|
||
const parts = Object.entries(summary).map(([unit, data]) => {
|
||
if (data.total <= 0) {
|
||
return `已调度 ${data.dispatched.toFixed(2)}${unit}`;
|
||
}
|
||
const remaining = Math.max(data.total - data.dispatched, 0);
|
||
return `${data.total}${unit} | 已调度 ${data.dispatched.toFixed(2)}${unit},剩余${remaining.toFixed(
|
||
2
|
||
)}${unit}`;
|
||
});
|
||
|
||
return parts.join(' | ');
|
||
},
|
||
canAddDispatch() {
|
||
const goodsList = this.parseGoodsList(this.planData.goodsJson);
|
||
if (!goodsList.length) {
|
||
const total = Number(this.planData.totalQuantity || 0);
|
||
if (total <= 0) return true;
|
||
const dispatched = this.calculateDispatchedQuantity();
|
||
return dispatched < total;
|
||
}
|
||
|
||
const hasPositiveTotal = goodsList.some(
|
||
goods => Number(goods.quantity || 0) > 0
|
||
);
|
||
if (!hasPositiveTotal) return true;
|
||
|
||
return goodsList.some(goods => {
|
||
const unit = goods.quantityUnit || TRANSPORT_PLAN_QUANTITY_UNIT;
|
||
const totalQty = Number(goods.quantity || 0);
|
||
if (totalQty <= 0) return true;
|
||
const dispatchedQty = this.dispatchList
|
||
.filter(item => item.quantityUnit === unit)
|
||
.reduce((sum, item) => sum + Number(item.quantity || 0), 0);
|
||
return dispatchedQty < totalQty;
|
||
});
|
||
},
|
||
},
|
||
created() {
|
||
this.loadPlanData();
|
||
},
|
||
mounted() {
|
||
// 初始化 transport-plan-page 组件用于打开弹窗
|
||
this.transportPlanPageVisible = true;
|
||
},
|
||
methods: {
|
||
loadPlanData() {
|
||
if (!this.planId) {
|
||
this.$message.error('缺少计划ID参数');
|
||
this.handleBack();
|
||
return;
|
||
}
|
||
|
||
this.loading = true;
|
||
getDetail(this.planId)
|
||
.then(res => {
|
||
if (res.data?.success) {
|
||
this.planData = res.data.data || {};
|
||
this.attachmentList = this.parseAttachments(this.planData.attachmentsJson);
|
||
this.dispatchList = this.parseDispatchList(this.planData);
|
||
} else {
|
||
this.$message.error(res.data?.msg || '加载数据失败');
|
||
}
|
||
})
|
||
.catch(err => {
|
||
console.error('加载计划数据失败:', err);
|
||
this.$message.error('加载数据失败');
|
||
})
|
||
.finally(() => {
|
||
this.loading = false;
|
||
});
|
||
},
|
||
parseAttachments(json) {
|
||
try {
|
||
const data = JSON.parse(json || '[]');
|
||
return Array.isArray(data) ? data : [];
|
||
} catch {
|
||
return [];
|
||
}
|
||
},
|
||
parseDispatchList(planData) {
|
||
try {
|
||
const sources = [
|
||
planData.waybillList,
|
||
planData.dispatchRows,
|
||
planData.dispatchRecordList,
|
||
planData.dispatchList,
|
||
];
|
||
for (const source of sources) {
|
||
if (Array.isArray(source) && source.length) {
|
||
return source.map((item, index) => ({
|
||
...item,
|
||
id: item.id || `temp-${index}`,
|
||
}));
|
||
}
|
||
}
|
||
return [];
|
||
} catch {
|
||
return [];
|
||
}
|
||
},
|
||
parseGoodsList(json) {
|
||
try {
|
||
const data = JSON.parse(json || '[]');
|
||
return Array.isArray(data) ? data : [];
|
||
} catch {
|
||
return [];
|
||
}
|
||
},
|
||
calculateDispatchedQuantity() {
|
||
return this.dispatchList.reduce((sum, item) => sum + Number(item.quantity || 0), 0);
|
||
},
|
||
formatDateRange(startDate, endDate) {
|
||
const dates = [startDate, endDate].filter(Boolean);
|
||
return dates.length ? dates.join(' ~ ') : '-';
|
||
},
|
||
formatAddress(address) {
|
||
if (!address) return '-';
|
||
const match = address.match(/^(.*?省)?(.*?市)?(.*?区|.*?县)?/);
|
||
return match ? match[0] || address : address;
|
||
},
|
||
formatProvinceCityDistrict(value) {
|
||
const text = String(value || '').trim();
|
||
if (!text) return '-';
|
||
const districtMatch = text.match(/(?:自治县|自治旗|林区|矿区|新区|开发区|区|县|旗)/);
|
||
if (districtMatch) {
|
||
return text.slice(0, districtMatch.index + districtMatch[0].length);
|
||
}
|
||
const cityMatch = text.match(/市/);
|
||
return cityMatch ? text.slice(0, cityMatch.index + 1) : text;
|
||
},
|
||
formatRouteCityDistrict(value) {
|
||
const text = String(value || '').trim();
|
||
if (!text) return '-';
|
||
const provinceMatch = text.match(/^.+?(?:省|自治区|特别行政区)/);
|
||
const cityRegion = provinceMatch ? text.slice(provinceMatch[0].length) : text;
|
||
const cityMatch = cityRegion.match(/^(.+?市)/);
|
||
if (!cityMatch) return this.formatProvinceCityDistrict(text);
|
||
const city = cityMatch[1];
|
||
const remainder = cityRegion.slice(city.length);
|
||
const districtMatch = remainder.match(
|
||
/^(.+?(?:自治县|自治旗|林区|矿区|新区|开发区|区|县|旗){1,2})/
|
||
);
|
||
const district = districtMatch ? districtMatch[1] : '';
|
||
return [city, district].filter(Boolean).join(' ');
|
||
},
|
||
formatDriver(row) {
|
||
const parts = [row.driverName, row.driverPhone].filter(Boolean);
|
||
return parts.length ? parts.join(' / ') : '-';
|
||
},
|
||
formatGoodsInfo(data) {
|
||
const goodsList = this.parseGoodsList(data.goodsJson);
|
||
if (!goodsList.length) {
|
||
return data.cargoName || '-';
|
||
}
|
||
return goodsList
|
||
.map(goods => {
|
||
const parts = [goods.cargoName || goods.goodsName];
|
||
if (goods.quantity) {
|
||
parts.push(`${goods.quantity}${goods.quantityUnit || TRANSPORT_PLAN_QUANTITY_UNIT}`);
|
||
}
|
||
return parts.join(' ');
|
||
})
|
||
.join(';');
|
||
},
|
||
formatCargoInfo(row) {
|
||
const parts = [row.cargoName];
|
||
if (row.specification) parts.push(row.specification);
|
||
if (row.model) parts.push(row.model);
|
||
return parts.filter(Boolean).join(' / ') || '-';
|
||
},
|
||
handleBack() {
|
||
this.$router.back();
|
||
},
|
||
handleAdd() {
|
||
if (!this.canAddDispatch) {
|
||
this.$message.warning('待调度列表货物总量已达到计划总量,不能新增调度明细');
|
||
return;
|
||
}
|
||
this.openPageDispatchItemDialog(-1);
|
||
},
|
||
handleEdit(row, index) {
|
||
this.openPageDispatchItemDialog(index, row);
|
||
},
|
||
openPageDispatchItemDialog(index = -1, row) {
|
||
this.$nextTick(() => {
|
||
const component = this.$refs.transportPlanPageRef;
|
||
if (!component) return;
|
||
component.dispatchRow = this.planData;
|
||
component.dispatchRows = [...this.dispatchList];
|
||
this.bindDispatchItemSaveSync(component);
|
||
if (index >= 0) component.openDispatchItemDialog(index, row);
|
||
else component.openDispatchItemDialog(-1);
|
||
});
|
||
},
|
||
bindDispatchItemSaveSync(component) {
|
||
if (component.__dispatchListSaveSynced) return;
|
||
const originalSave = component.saveDispatchItem;
|
||
component.saveDispatchItem = (...args) => {
|
||
originalSave.apply(component, args);
|
||
if (!component.dispatchItemBox) {
|
||
this.dispatchList = [...(component.dispatchRows || [])];
|
||
}
|
||
};
|
||
component.__dispatchListSaveSynced = true;
|
||
},
|
||
handleDelete(index) {
|
||
this.$confirm('确定删除该调度明细?', '提示', {
|
||
confirmButtonText: '确定',
|
||
cancelButtonText: '取消',
|
||
type: 'warning',
|
||
}).then(() => {
|
||
this.dispatchList.splice(index, 1);
|
||
this.$message.success('删除成功');
|
||
});
|
||
},
|
||
handleSubmit() {
|
||
if (!this.dispatchList.length) {
|
||
this.$message.warning('请先添加调度明细');
|
||
return;
|
||
}
|
||
|
||
for (const [index, row] of this.dispatchList.entries()) {
|
||
if (!row.carrierName) {
|
||
this.$message.warning(`第${index + 1}条调度明细缺少承运商信息`);
|
||
return;
|
||
}
|
||
if (!row.driverName) {
|
||
this.$message.warning(`第${index + 1}条调度明细缺少司机信息`);
|
||
return;
|
||
}
|
||
if (!row.vehicleNo) {
|
||
this.$message.warning(`第${index + 1}条调度明细缺少车牌号`);
|
||
return;
|
||
}
|
||
}
|
||
|
||
this.$confirm(
|
||
`请确认调度信息,将生成 <span style="color: #409eff; font-size: 20px; padding: 0 4px;">${this.dispatchList.length}</span> 条运单,是否继续?`,
|
||
'提示',
|
||
{
|
||
confirmButtonText: '确定',
|
||
cancelButtonText: '取消',
|
||
type: 'warning',
|
||
dangerouslyUseHTMLString: true,
|
||
}
|
||
).then(() => {
|
||
this.submitDispatch();
|
||
});
|
||
},
|
||
submitDispatch() {
|
||
this.saving = true;
|
||
const payload = {
|
||
id: this.planId,
|
||
mode: 'submit',
|
||
waybills: this.dispatchList.map(row => ({
|
||
...row,
|
||
taskEntryMode: row.taskEntryMode || 'simple',
|
||
taskRemark: row.remark || '',
|
||
estimatedStartTime: row.estimatedStartTime || this.planData.planStartDate || '',
|
||
estimatedEndTime: row.estimatedEndTime || this.planData.planEndDate || '',
|
||
goodsJson:
|
||
row.goodsJson ||
|
||
JSON.stringify([
|
||
{
|
||
cargoName: row.cargoName,
|
||
cargoType: row.cargoType,
|
||
quantity: row.quantity,
|
||
quantityUnit: row.quantityUnit,
|
||
specification: row.specification,
|
||
model: row.model,
|
||
packageType: row.packageType,
|
||
brand: row.brand,
|
||
},
|
||
]),
|
||
})),
|
||
};
|
||
|
||
dispatch(payload)
|
||
.then(res => {
|
||
if (res.data?.success) {
|
||
this.$message.success('调度成功,运单已生成');
|
||
this.handleBack();
|
||
} else {
|
||
this.$message.error(res.data?.msg || '调度失败');
|
||
}
|
||
})
|
||
.catch(err => {
|
||
console.error('调度失败:', err);
|
||
this.$message.error('调度失败');
|
||
})
|
||
.finally(() => {
|
||
this.saving = false;
|
||
});
|
||
},
|
||
},
|
||
};
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.transport-plan-dispatch-page {
|
||
height: 100%;
|
||
display: flex;
|
||
flex-direction: column;
|
||
|
||
&__shell {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 16px;
|
||
height: 100%;
|
||
}
|
||
|
||
&__summary {
|
||
:deep(.el-card__body) {
|
||
padding: 18px 22px;
|
||
}
|
||
}
|
||
|
||
&__heading {
|
||
display: flex;
|
||
align-items: center;
|
||
flex-wrap: wrap;
|
||
gap: 12px;
|
||
margin-bottom: 18px;
|
||
|
||
strong {
|
||
font-size: 20px;
|
||
}
|
||
|
||
.detail-status-text {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
height: 28px;
|
||
padding: 0 12px;
|
||
border-radius: 8px;
|
||
font-size: 13px;
|
||
line-height: 28px;
|
||
}
|
||
|
||
.status-text-success,
|
||
.is-dispatching {
|
||
color: #67c23a;
|
||
background: #e1f3d8;
|
||
}
|
||
|
||
.detail-transport-type {
|
||
color: #409eff;
|
||
background: #ecf5ff;
|
||
}
|
||
|
||
.is-danger {
|
||
color: #f56c6c;
|
||
background: #fef0f0;
|
||
}
|
||
|
||
.is-info {
|
||
color: #909399;
|
||
background: #f4f4f5;
|
||
}
|
||
}
|
||
|
||
&__summary-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(4, minmax(120px, 1fr)) minmax(360px, 1.5fr);
|
||
gap: 16px 24px;
|
||
}
|
||
|
||
&__summary-item {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 8px;
|
||
min-width: 0;
|
||
|
||
&.is-goods {
|
||
grid-column: 1 / 5;
|
||
}
|
||
}
|
||
|
||
&__summary-label {
|
||
color: #909399;
|
||
}
|
||
|
||
&__summary-value {
|
||
overflow: hidden;
|
||
color: #303133;
|
||
font-weight: 500;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
|
||
&.is-link {
|
||
color: #409eff;
|
||
}
|
||
|
||
&.is-wrap {
|
||
white-space: normal;
|
||
word-break: break-word;
|
||
}
|
||
}
|
||
|
||
&__route {
|
||
display: grid;
|
||
grid-template-columns: minmax(100px, 1fr) minmax(36px, 0.7fr) minmax(100px, 1fr);
|
||
grid-row: 1 / span 3;
|
||
grid-column: 5;
|
||
align-items: start;
|
||
min-width: 0;
|
||
padding: 4px 0;
|
||
}
|
||
|
||
&__route-item {
|
||
display: flex;
|
||
min-width: 0;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
text-align: center;
|
||
}
|
||
|
||
&__route-marker {
|
||
display: inline-flex;
|
||
width: 36px;
|
||
height: 36px;
|
||
align-items: center;
|
||
justify-content: center;
|
||
color: #fff;
|
||
border-radius: 8px;
|
||
background: #409eff;
|
||
font-size: 18px;
|
||
font-weight: 600;
|
||
|
||
.is-end & {
|
||
background: #67c23a;
|
||
}
|
||
}
|
||
|
||
&__route-line {
|
||
width: 100%;
|
||
height: 6px;
|
||
margin-top: 15px;
|
||
border-radius: 1px;
|
||
background: #e4e7ed;
|
||
}
|
||
|
||
&__route-detail {
|
||
display: flex;
|
||
min-width: 0;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
gap: 5px;
|
||
margin-top: 8px;
|
||
width: 100%;
|
||
}
|
||
|
||
&__route-name {
|
||
max-width: 100%;
|
||
overflow: hidden;
|
||
color: #303133;
|
||
font-size: 18px;
|
||
font-weight: 600;
|
||
line-height: 1.35;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
&__route-addr {
|
||
display: block;
|
||
max-width: 100%;
|
||
overflow: hidden;
|
||
color: #606266;
|
||
font-size: 12px;
|
||
line-height: 1.5;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
&__route-contact {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
justify-content: center;
|
||
gap: 2px 8px;
|
||
max-width: 100%;
|
||
color: #909399;
|
||
font-size: 12px;
|
||
line-height: 1.5;
|
||
}
|
||
|
||
&__attachments {
|
||
grid-column: 1 / 5;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 8px;
|
||
|
||
div {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 16px;
|
||
}
|
||
}
|
||
|
||
&__list-card {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
&__list-summary {
|
||
margin-left: 12px;
|
||
font-size: 14px;
|
||
color: #606266;
|
||
font-weight: normal;
|
||
}
|
||
|
||
&__table {
|
||
flex: 1;
|
||
}
|
||
|
||
&__actions {
|
||
display: flex;
|
||
gap: 8px;
|
||
justify-content: center;
|
||
}
|
||
|
||
&__footer {
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
gap: 12px;
|
||
padding: 16px;
|
||
background: #fff;
|
||
border-radius: 4px;
|
||
}
|
||
|
||
@media (max-width: 1200px) {
|
||
&__summary-grid {
|
||
grid-template-columns: repeat(4, minmax(130px, 1fr));
|
||
}
|
||
|
||
&__summary-item.is-goods,
|
||
&__attachments {
|
||
grid-column: 1 / -1;
|
||
}
|
||
|
||
&__route {
|
||
grid-column: 1 / -1;
|
||
grid-row: auto;
|
||
}
|
||
}
|
||
|
||
@media (max-width: 800px) {
|
||
&__summary-grid {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
&__route {
|
||
grid-template-columns: minmax(0, 1fr);
|
||
gap: 16px;
|
||
}
|
||
|
||
&__route-line {
|
||
width: 10px;
|
||
height: 32px;
|
||
margin: 0 auto;
|
||
}
|
||
|
||
&__summary-item.is-goods,
|
||
&__attachments {
|
||
grid-column: auto;
|
||
}
|
||
}
|
||
}
|
||
</style>
|