cba2ad3b3b
2、调整运单
672 lines
22 KiB
Vue
672 lines
22 KiB
Vue
<template>
|
||
<basic-container class="transport-plan-import-page">
|
||
<div class="transport-plan-import-page__form-wrapper">
|
||
<div class="transport-plan-import-page__title">导入运输计划</div>
|
||
|
||
<el-form
|
||
ref="importFormRef"
|
||
:model="form"
|
||
:rules="rules"
|
||
label-position="right"
|
||
label-width="auto"
|
||
class="transport-plan-import-page__form"
|
||
>
|
||
<el-row :gutter="24">
|
||
<el-col :span="8">
|
||
<el-form-item label="项目" prop="projectId" required>
|
||
<el-select
|
||
v-model="form.projectId"
|
||
placeholder="模糊查询后选择"
|
||
filterable
|
||
clearable
|
||
:loading="projectLoading"
|
||
@visible-change="visible => visible && loadProjectOptions()"
|
||
@change="handleProjectChange"
|
||
>
|
||
<el-option
|
||
v-for="item in projectOptions"
|
||
:key="item.id"
|
||
:label="item.projectName"
|
||
:value="item.id"
|
||
/>
|
||
</el-select>
|
||
</el-form-item>
|
||
</el-col>
|
||
<el-col :span="8">
|
||
<el-form-item label="客户" prop="customerName" required>
|
||
<el-input v-model="form.customerName" disabled placeholder="选择项目后带出" />
|
||
</el-form-item>
|
||
</el-col>
|
||
<el-col :span="8">
|
||
<el-form-item label="客户合同" prop="contractId" required>
|
||
<el-select
|
||
v-model="form.contractId"
|
||
placeholder="选择项目后选择"
|
||
filterable
|
||
clearable
|
||
:loading="contractLoading"
|
||
:disabled="!form.projectId"
|
||
@change="handleContractChange"
|
||
>
|
||
<el-option
|
||
v-for="item in contractOptions"
|
||
:key="item.id"
|
||
:label="item.contractName"
|
||
:value="item.id"
|
||
/>
|
||
</el-select>
|
||
</el-form-item>
|
||
</el-col>
|
||
</el-row>
|
||
<el-form-item
|
||
label="计划明细表"
|
||
prop="file"
|
||
required
|
||
class="transport-plan-import-page__file-item"
|
||
>
|
||
<el-upload
|
||
action="#"
|
||
accept=".xls,.xlsx"
|
||
:auto-upload="false"
|
||
:limit="1"
|
||
:file-list="files"
|
||
:on-change="handleFileChange"
|
||
:on-remove="handleFileRemove"
|
||
>
|
||
<el-button type="primary">添加附件</el-button>
|
||
</el-upload>
|
||
<span class="transport-plan-import-page__file-tip">
|
||
请上传计划明细表,仅支持 Excel 格式
|
||
</span>
|
||
<el-link type="primary" @click="handleTemplateDownload">下载模板</el-link>
|
||
</el-form-item>
|
||
</el-form>
|
||
</div>
|
||
|
||
<section v-if="rows.length" class="transport-plan-import-page__preview">
|
||
<div class="transport-plan-import-page__preview-head">
|
||
<div class="dialog-section-title">数据明细</div>
|
||
<el-button type="danger" plain :disabled="!selection.length" @click="removeSelectedRows">
|
||
批量删除
|
||
</el-button>
|
||
</div>
|
||
<el-tabs v-model="activeTab" type="border-card" class="transport-plan-import-page__tabs">
|
||
<el-tab-pane :label="`计划单数(${rows.length})`" name="all" />
|
||
<el-tab-pane :label="`疑似重复(${duplicateCount})`" name="duplicate" />
|
||
</el-tabs>
|
||
<div class="transport-plan-import-page__table">
|
||
<el-table
|
||
:data="visibleRows"
|
||
border
|
||
row-key="_key"
|
||
empty-text="暂无明细数据"
|
||
@selection-change="handleSelectionChange"
|
||
>
|
||
<el-table-column type="selection" width="52" fixed="left" />
|
||
<el-table-column type="index" label="序号" width="70" fixed="left" />
|
||
<el-table-column label="计划单号" min-width="150">
|
||
<template #default>待生成</template>
|
||
</el-table-column>
|
||
<el-table-column
|
||
v-for="column in previewColumns"
|
||
:key="column.prop"
|
||
:label="column.label"
|
||
:min-width="column.width"
|
||
>
|
||
<template #default="{ row }">
|
||
<el-select
|
||
v-if="isEditingRow(row) && column.prop === 'quantityUnit'"
|
||
v-model="row[column.prop]"
|
||
>
|
||
<el-option
|
||
v-for="item in quantityUnitOptions"
|
||
:key="item"
|
||
:label="item"
|
||
:value="item"
|
||
/>
|
||
</el-select>
|
||
<el-input
|
||
v-else-if="isEditingRow(row)"
|
||
v-model="row[column.prop]"
|
||
:maxlength="column.prop === 'remark' ? 200 : undefined"
|
||
:show-word-limit="column.prop === 'remark'"
|
||
/>
|
||
<span v-else>{{ row[column.prop] || '-' }}</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="操作" width="170" fixed="right">
|
||
<template #default="{ row }">
|
||
<div class="transport-plan-import-page__actions">
|
||
<template v-if="isEditingRow(row)">
|
||
<el-link type="primary" @click="saveRow">保存</el-link>
|
||
<el-link type="primary" @click="cancelEditRow(row)">取消</el-link>
|
||
</template>
|
||
<template v-else>
|
||
<el-link type="primary" @click="editRow(row)">编辑</el-link>
|
||
<el-link type="danger" @click="removeRow(row)">删除</el-link>
|
||
</template>
|
||
</div>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
</div>
|
||
</section>
|
||
|
||
<div class="transport-plan-import-page__footer">
|
||
<el-button :disabled="loading" @click="handleCancel">取消</el-button>
|
||
<el-button type="primary" :loading="loading" @click="handleSubmit">提交</el-button>
|
||
</div>
|
||
</basic-container>
|
||
</template>
|
||
|
||
<script>
|
||
import { exportBlob } from '@/api/common';
|
||
import { getList as getContractList } from '@/api/business/contract-manage';
|
||
import { getList as getProjectList } from '@/api/business/project-apply';
|
||
import { importTransportPlan } from '@/api/business/transport-plan';
|
||
import { config } from '@/option/business/transport-plan';
|
||
import { downloadXls } from '@/utils/util';
|
||
|
||
const importColumns = [
|
||
['计划名称', 'planName'],
|
||
['运输类型', 'transportType'],
|
||
['发货地址', 'departureAddress'],
|
||
['发货联系人', 'departureContact'],
|
||
['发货联系人电话', 'departurePhone'],
|
||
['到货地址', 'arrivalAddress'],
|
||
['收货联系人', 'arrivalContact'],
|
||
['收货联系人电话', 'arrivalPhone'],
|
||
['货物名称', 'cargoName'],
|
||
['货物类型', 'cargoType'],
|
||
['数量', 'quantity'],
|
||
['计量单位', 'quantityUnit'],
|
||
['包装', 'packageType'],
|
||
['规格', 'specification'],
|
||
['型号', 'model'],
|
||
['里程(km)', 'mileage'],
|
||
['计划开始时间', 'planStartDate'],
|
||
['计划结束时间', 'planEndDate'],
|
||
['备注', 'remark'],
|
||
['同一计划标识号', 'planGroupId'],
|
||
];
|
||
|
||
const previewColumns = [
|
||
{ label: '计划名称', prop: 'planName', width: 180 },
|
||
{ label: '运输类型', prop: 'transportType', width: 120 },
|
||
{ label: '发货地址', prop: 'departureAddress', width: 260 },
|
||
{ label: '发货联系人', prop: 'departureContact', width: 120 },
|
||
{ label: '发货联系人电话', prop: 'departurePhone', width: 140 },
|
||
{ label: '到货地址', prop: 'arrivalAddress', width: 260 },
|
||
{ label: '收货联系人', prop: 'arrivalContact', width: 120 },
|
||
{ label: '收货联系人电话', prop: 'arrivalPhone', width: 140 },
|
||
{ label: '货物名称', prop: 'cargoName', width: 140 },
|
||
{ label: '货物类型', prop: 'cargoType', width: 120 },
|
||
{ label: '数量', prop: 'quantity', width: 100 },
|
||
{ label: '计量单位', prop: 'quantityUnit', width: 110 },
|
||
{ label: '包装', prop: 'packageType', width: 100 },
|
||
{ label: '规格', prop: 'specification', width: 120 },
|
||
{ label: '型号', prop: 'model', width: 120 },
|
||
{ label: '里程(km)', prop: 'mileage', width: 120 },
|
||
{ label: '计划开始时间', prop: 'planStartDate', width: 140 },
|
||
{ label: '计划结束时间', prop: 'planEndDate', width: 140 },
|
||
{ label: '备注', prop: 'remark', width: 180 },
|
||
{ label: '同一计划标识号', prop: 'planGroupId', width: 150 },
|
||
];
|
||
|
||
const extractRecords = res => {
|
||
const data = res?.data?.data || res?.data || res;
|
||
if (Array.isArray(data)) return data;
|
||
if (Array.isArray(data?.records)) return data.records;
|
||
if (Array.isArray(data?.data)) return data.data;
|
||
if (Array.isArray(data?.data?.records)) return data.data.records;
|
||
return [];
|
||
};
|
||
|
||
const defaultForm = () => ({
|
||
projectId: '',
|
||
projectName: '',
|
||
customerName: '',
|
||
contractId: '',
|
||
contractName: '',
|
||
file: null,
|
||
});
|
||
|
||
export default {
|
||
name: 'TransportPlanImport',
|
||
data() {
|
||
return {
|
||
form: defaultForm(),
|
||
rules: {
|
||
projectId: [{ required: true, message: '请选择项目', trigger: 'change' }],
|
||
customerName: [{ required: true, message: '请选择项目后带出客户', trigger: 'change' }],
|
||
contractId: [{ required: true, message: '请选择项目后带出客户合同', trigger: 'change' }],
|
||
file: [{ required: true, message: '请上传计划明细表', trigger: 'change' }],
|
||
},
|
||
projectOptions: [],
|
||
projectLoading: false,
|
||
contractOptions: [],
|
||
contractLoading: false,
|
||
files: [],
|
||
sourceFile: null,
|
||
rows: [],
|
||
selection: [],
|
||
activeTab: 'all',
|
||
editingKey: '',
|
||
editSnapshot: null,
|
||
loading: false,
|
||
previewColumns,
|
||
quantityUnitOptions: ['吨', '千克', '立方米', '件', '车', '箱', '托盘'],
|
||
};
|
||
},
|
||
computed: {
|
||
duplicateCount() {
|
||
return this.rows.filter(row => row._duplicate).length;
|
||
},
|
||
visibleRows() {
|
||
return this.activeTab === 'duplicate' ? this.rows.filter(row => row._duplicate) : this.rows;
|
||
},
|
||
},
|
||
created() {
|
||
this.loadProjectOptions();
|
||
},
|
||
methods: {
|
||
loadProjectOptions() {
|
||
if (this.projectLoading) return;
|
||
this.projectLoading = true;
|
||
getProjectList(1, 9999, config.projectQueryParams || {})
|
||
.then(res => {
|
||
this.projectOptions = extractRecords(res);
|
||
})
|
||
.finally(() => {
|
||
this.projectLoading = false;
|
||
});
|
||
},
|
||
handleProjectChange(projectId) {
|
||
const project = this.projectOptions.find(item => String(item.id) === String(projectId));
|
||
this.form.customerName =
|
||
project?.customerName || project?.customerNames || project?.customer || '';
|
||
this.form.projectName = project?.projectName || '';
|
||
this.form.contractId = '';
|
||
this.form.contractName = '';
|
||
this.contractOptions = [];
|
||
if (!projectId) return;
|
||
this.contractLoading = true;
|
||
getContractList(1, 9999, {
|
||
projectId,
|
||
projectName: project?.projectName,
|
||
...(config.contractQueryParams || {}),
|
||
})
|
||
.then(res => {
|
||
this.contractOptions = extractRecords(res);
|
||
const contract = this.contractOptions[0];
|
||
this.form.customerName =
|
||
this.form.customerName || contract?.customerName || contract?.partyA || '';
|
||
this.form.contractId = contract?.id || '';
|
||
this.form.contractName = contract?.contractName || '';
|
||
})
|
||
.finally(() => {
|
||
this.contractLoading = false;
|
||
});
|
||
},
|
||
handleContractChange(contractId) {
|
||
const contract = this.contractOptions.find(item => String(item.id) === String(contractId));
|
||
this.form.contractName = contract?.contractName || '';
|
||
this.form.customerName =
|
||
contract?.customerName || contract?.partyA || this.form.customerName || '';
|
||
},
|
||
async handleFileChange(file, fileList) {
|
||
if (!/\.(xls|xlsx)$/i.test(file.name || '')) {
|
||
this.$message.error('请上传 .xls 或 .xlsx 格式文件');
|
||
this.files = [];
|
||
this.form.file = null;
|
||
return;
|
||
}
|
||
try {
|
||
const XLSX = await import('xlsx');
|
||
const workbook = XLSX.read(await file.raw.arrayBuffer(), {
|
||
type: 'array',
|
||
cellDates: false,
|
||
});
|
||
const worksheet = workbook.Sheets[workbook.SheetNames[0]];
|
||
const values = XLSX.utils.sheet_to_json(worksheet, {
|
||
header: 1,
|
||
defval: '',
|
||
raw: false,
|
||
blankrows: false,
|
||
});
|
||
const headers = values[0] || [];
|
||
const headerMap = headers.reduce((result, label, index) => {
|
||
const normalized = String(label || '')
|
||
.replace(/^\*/, '')
|
||
.trim();
|
||
if (normalized) result[normalized] = index;
|
||
return result;
|
||
}, {});
|
||
const rows = values.slice(1).reduce((result, cells, index) => {
|
||
const row = { _key: `${Date.now()}-${index}-${Math.random().toString(36).slice(2)}` };
|
||
importColumns.forEach(([label, prop]) => {
|
||
row[prop] = String(cells[headerMap[label]] ?? '').trim();
|
||
});
|
||
if (importColumns.some(([, prop]) => row[prop])) result.push(row);
|
||
return result;
|
||
}, []);
|
||
if (!rows.length) {
|
||
this.$message.warning('未读取到计划明细数据');
|
||
this.handleFileRemove();
|
||
return;
|
||
}
|
||
this.files = fileList.slice(-1);
|
||
this.sourceFile = file.raw;
|
||
this.form.file = file.raw;
|
||
this.rows = rows;
|
||
this.markDuplicates();
|
||
this.$refs.importFormRef?.validateField('file');
|
||
this.$message.success(`已读取${rows.length}条计划明细`);
|
||
} catch (error) {
|
||
this.handleFileRemove();
|
||
this.$message.error('计划明细表读取失败,请检查文件格式');
|
||
}
|
||
},
|
||
handleFileRemove() {
|
||
this.files = [];
|
||
this.sourceFile = null;
|
||
this.form.file = null;
|
||
this.rows = [];
|
||
this.selection = [];
|
||
this.editingKey = '';
|
||
this.editSnapshot = null;
|
||
},
|
||
duplicateKey(row) {
|
||
return importColumns.map(([, prop]) => String(row[prop] || '').trim()).join('\u0001');
|
||
},
|
||
markDuplicates() {
|
||
const countMap = this.rows.reduce((result, row) => {
|
||
const key = this.duplicateKey(row);
|
||
result[key] = (result[key] || 0) + 1;
|
||
return result;
|
||
}, {});
|
||
this.rows.forEach(row => {
|
||
row._duplicate = countMap[this.duplicateKey(row)] > 1;
|
||
});
|
||
},
|
||
handleSelectionChange(rows) {
|
||
this.selection = rows;
|
||
},
|
||
isEditingRow(row) {
|
||
return this.editingKey === row._key;
|
||
},
|
||
editRow(row) {
|
||
if (this.editingKey && this.editingKey !== row._key) {
|
||
this.$message.warning('请先保存或取消当前编辑');
|
||
return;
|
||
}
|
||
this.editingKey = row._key;
|
||
this.editSnapshot = { ...row };
|
||
},
|
||
saveRow() {
|
||
this.editingKey = '';
|
||
this.editSnapshot = null;
|
||
this.markDuplicates();
|
||
},
|
||
cancelEditRow(row) {
|
||
Object.assign(row, this.editSnapshot || {});
|
||
this.editingKey = '';
|
||
this.editSnapshot = null;
|
||
this.markDuplicates();
|
||
},
|
||
removeRow(row) {
|
||
this.rows = this.rows.filter(item => item._key !== row._key);
|
||
this.selection = this.selection.filter(item => item._key !== row._key);
|
||
this.markDuplicates();
|
||
},
|
||
removeSelectedRows() {
|
||
const selectedKeys = new Set(this.selection.map(row => row._key));
|
||
this.rows = this.rows.filter(row => !selectedKeys.has(row._key));
|
||
this.selection = [];
|
||
this.markDuplicates();
|
||
},
|
||
validateRows() {
|
||
if (!this.rows.length) {
|
||
this.$message.warning('请保留至少一条计划明细');
|
||
return false;
|
||
}
|
||
const requiredFields = [
|
||
['planName', '计划名称'],
|
||
['transportType', '运输类型'],
|
||
['departureAddress', '发货地址'],
|
||
['arrivalAddress', '到货地址'],
|
||
['cargoType', '货物类型'],
|
||
];
|
||
const isValidDate = value => {
|
||
const match = String(value || '').match(/^(\d{4})-(\d{2})-(\d{2})$/);
|
||
if (!match) return false;
|
||
const [, year, month, day] = match;
|
||
const date = new Date(Number(year), Number(month) - 1, Number(day));
|
||
return (
|
||
date.getFullYear() === Number(year) &&
|
||
date.getMonth() === Number(month) - 1 &&
|
||
date.getDate() === Number(day)
|
||
);
|
||
};
|
||
for (const [index, row] of this.rows.entries()) {
|
||
const emptyField = requiredFields.find(([prop]) => !String(row[prop] || '').trim());
|
||
if (emptyField) {
|
||
this.$message.warning(`第${index + 1}行${emptyField[1]}不能为空`);
|
||
return false;
|
||
}
|
||
if (row.planStartDate && !isValidDate(row.planStartDate)) {
|
||
this.$message.warning(`第${index + 1}行计划开始时间格式必须为 YYYY-MM-DD`);
|
||
return false;
|
||
}
|
||
if (row.planEndDate && !isValidDate(row.planEndDate)) {
|
||
this.$message.warning(`第${index + 1}行计划结束时间格式必须为 YYYY-MM-DD`);
|
||
return false;
|
||
}
|
||
if (row.planStartDate && row.planEndDate && row.planEndDate < row.planStartDate) {
|
||
this.$message.warning(`第${index + 1}行计划结束时间不能早于计划开始时间`);
|
||
return false;
|
||
}
|
||
if (
|
||
row.quantity !== '' &&
|
||
(!Number.isFinite(Number(row.quantity)) || Number(row.quantity) < 0)
|
||
) {
|
||
this.$message.warning(`第${index + 1}行数量必须为非负数`);
|
||
return false;
|
||
}
|
||
if (
|
||
row.mileage !== '' &&
|
||
(!Number.isFinite(Number(row.mileage)) || Number(row.mileage) < 0)
|
||
) {
|
||
this.$message.warning(`第${index + 1}行里程必须为非负数`);
|
||
return false;
|
||
}
|
||
if (String(row.remark || '').length > 200) {
|
||
this.$message.warning(`第${index + 1}行备注不能超过200个字`);
|
||
return false;
|
||
}
|
||
}
|
||
return true;
|
||
},
|
||
async buildImportFile() {
|
||
const XLSX = await import('xlsx');
|
||
const requiredLabels = [
|
||
'计划名称',
|
||
'运输类型',
|
||
'发货地址',
|
||
'到货地址',
|
||
'货物类型',
|
||
];
|
||
const values = [
|
||
importColumns.map(([label]) => (requiredLabels.includes(label) ? `*${label}` : label)),
|
||
...this.rows.map(row => importColumns.map(([, prop]) => String(row[prop] ?? ''))),
|
||
];
|
||
const workbook = XLSX.utils.book_new();
|
||
XLSX.utils.book_append_sheet(workbook, XLSX.utils.aoa_to_sheet(values), '运输计划导入模板');
|
||
const binary = XLSX.write(workbook, { bookType: 'xlsx', type: 'array' });
|
||
const fileName = (this.sourceFile?.name || '运输计划导入模板.xlsx').replace(
|
||
/\.xls$/i,
|
||
'.xlsx'
|
||
);
|
||
return new File([binary], fileName, {
|
||
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||
});
|
||
},
|
||
handleTemplateDownload() {
|
||
exportBlob(config.transportPlanTemplateUrl, {}, { feedback: true }).then(res => {
|
||
downloadXls(res.data, '运输计划导入模板.xlsx');
|
||
});
|
||
},
|
||
async handleSubmit() {
|
||
const valid = await this.$refs.importFormRef?.validate().catch(() => false);
|
||
if (!valid || this.loading || !this.validateRows()) return;
|
||
this.loading = true;
|
||
try {
|
||
const file = await this.buildImportFile();
|
||
const res = await importTransportPlan({ ...this.form, file });
|
||
const contentType = res.headers?.['content-type'] || res.data?.type || '';
|
||
if (
|
||
contentType.includes('application/vnd.ms-excel') ||
|
||
contentType.includes('spreadsheetml')
|
||
) {
|
||
downloadXls(
|
||
res.data,
|
||
`运输计划导入失败明细${this.$dayjs().format('YYYY-MM-DD HH:mm:ss')}.xlsx`
|
||
);
|
||
this.$message.warning('部分数据导入失败,已下载失败明细');
|
||
} else {
|
||
const text = await res.data.text();
|
||
const result = text ? JSON.parse(text) : {};
|
||
if (result.code !== 200) throw new Error(result.msg || '导入失败');
|
||
this.$message.success('导入完成');
|
||
}
|
||
this.$router.push('/business/transport-plan');
|
||
} catch (error) {
|
||
this.$message.error(error.message || '导入失败');
|
||
} finally {
|
||
this.loading = false;
|
||
}
|
||
},
|
||
handleCancel() {
|
||
this.$router.push('/business/transport-plan');
|
||
},
|
||
},
|
||
};
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.transport-plan-import-page {
|
||
min-height: calc(100vh - 112px);
|
||
|
||
&__form-wrapper {
|
||
background: #ffffff;
|
||
border-radius: 8px;
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
&__title {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
padding: 18px 24px;
|
||
border-bottom: 1px solid #eff1f7;
|
||
color: #303133;
|
||
font-size: 18px;
|
||
font-weight: 600;
|
||
|
||
&::before {
|
||
width: 4px;
|
||
height: 18px;
|
||
background: #409eff;
|
||
content: '';
|
||
}
|
||
}
|
||
|
||
&__form {
|
||
padding: 24px 24px 4px;
|
||
|
||
.el-select,
|
||
.el-input {
|
||
width: 100%;
|
||
}
|
||
|
||
:deep(.el-form-item) {
|
||
margin-bottom: 16px;
|
||
}
|
||
}
|
||
|
||
&__file-item {
|
||
margin-top: 12px;
|
||
|
||
:deep(.el-form-item__content) {
|
||
gap: 16px;
|
||
}
|
||
}
|
||
|
||
&__file-tip {
|
||
color: #606266;
|
||
}
|
||
|
||
&__preview {
|
||
margin: 8px 24px 0;
|
||
padding-top: 16px;
|
||
border-top: 1px solid #eff1f7;
|
||
}
|
||
|
||
&__preview-head {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 24px;
|
||
margin-bottom: 12px;
|
||
|
||
.dialog-section-title {
|
||
margin-bottom: 0;
|
||
}
|
||
}
|
||
|
||
&__tabs {
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
&__table {
|
||
overflow-x: auto;
|
||
|
||
:deep(.el-table) {
|
||
min-width: 2400px;
|
||
}
|
||
|
||
:deep(.el-table__cell) {
|
||
border-color: #eff1f7;
|
||
}
|
||
|
||
:deep(.el-table__row:nth-child(even) td) {
|
||
background: #fafafa;
|
||
}
|
||
}
|
||
|
||
&__actions {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 8px;
|
||
}
|
||
|
||
&__footer {
|
||
position: fixed;
|
||
right: 0;
|
||
left: 230px;
|
||
bottom: 0;
|
||
z-index: 10;
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
gap: 12px;
|
||
padding: 12px 24px;
|
||
border-top: 1px solid #eff1f7;
|
||
background: #fff;
|
||
box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.06);
|
||
}
|
||
}
|
||
|
||
:global(.avue--collapse .transport-plan-import-page__footer) {
|
||
left: 60px;
|
||
}
|
||
</style>
|