1、完善客商模块

2、完善基础数据模块
3、完善规范
This commit is contained in:
2026-08-01 01:23:13 +08:00
parent 6a4c5d02f4
commit 81c98f6ad8
77 changed files with 4883 additions and 711 deletions

View File

@@ -63,7 +63,6 @@
<el-button
type="primary"
text
icon="el-icon-edit"
v-if="hasPermission('airport_master_edit')"
@click="$refs.crud.rowEdit(row, index)"
>
@@ -72,7 +71,6 @@
<el-button
type="primary"
text
:icon="row.status === 1 ? 'el-icon-close' : 'el-icon-check'"
v-if="hasPermission('airport_master_status')"
@click="handleStatus(row)"
>
@@ -142,6 +140,47 @@ import NProgress from 'nprogress';
import 'nprogress/nprogress.css';
const DEFAULT_COUNTRY_CODE = '+86';
const REQUIRED_EXPORT_HEADERS = ['区域层级', '区域编码', '区域名称'];
const getExcelCellText = value => {
if (value === undefined || value === null) return '';
if (typeof value === 'object') {
if (Array.isArray(value.richText)) {
return value.richText.map(item => item.text || '').join('');
}
if (value.text) return value.text;
if (value.result) return value.result;
}
return String(value);
};
const addWorkbookRequiredHeaderMarks = workbook => {
workbook.eachSheet(worksheet => {
const maxHeaderRow = Math.min(worksheet.rowCount || 0, 10);
for (let rowIndex = 1; rowIndex <= maxHeaderRow; rowIndex += 1) {
const row = worksheet.getRow(rowIndex);
let hasRequiredHeader = false;
row.eachCell(cell => {
const text = getExcelCellText(cell.value).trim();
const header = text.replace(/\*+$/g, '').trim();
if (REQUIRED_EXPORT_HEADERS.includes(header)) {
cell.value = `${header}*`;
hasRequiredHeader = true;
}
});
if (hasRequiredHeader) break;
}
});
};
const addExcelRequiredHeaderMarks = async blob => {
const ExcelJS = await import('exceljs');
const workbook = new ExcelJS.Workbook();
await workbook.xlsx.load(await blob.arrayBuffer());
addWorkbookRequiredHeaderMarks(workbook);
const buffer = await workbook.xlsx.writeBuffer();
return new Blob([buffer], { type: 'application/vnd.ms-excel' });
};
export default {
data() {
@@ -830,10 +869,15 @@ export default {
type: 'warning',
}).then(() => {
NProgress.start();
exportBlob('/blade-system/airport-master/export-airport-master', this.buildExportParams())
.then(res => {
exportBlob(
'/blade-system/airport-master/export-airport-master',
this.buildExportParams(),
{ feedback: true }
)
.then(async res => {
const blob = await addExcelRequiredHeaderMarks(res.data);
downloadXls(
res.data,
blob,
`空港机场主数据${this.$dayjs().format('YYYY-MM-DD HH:mm:ss')}.xlsx`
);
})
@@ -851,7 +895,9 @@ export default {
},
handleTemplate() {
exportBlob(
`/blade-system/airport-master/export-template?${this.website.tokenHeader}=${getToken()}`
`/blade-system/airport-master/export-template?${this.website.tokenHeader}=${getToken()}`,
undefined,
{ feedback: true }
).then(res => {
downloadXls(res.data, '空港机场主数据模板.xlsx');
});

View File

@@ -553,7 +553,11 @@ export default {
type: 'warning',
}).then(() => {
NProgress.start();
exportBlob('/blade-system/cargo-type/export-cargo-type', this.buildExportParams())
exportBlob(
'/blade-system/cargo-type/export-cargo-type',
this.buildExportParams(),
{ feedback: true }
)
.then(res => {
downloadXls(res.data, `货物类型${this.$dayjs().format('YYYY-MM-DD HH:mm:ss')}.xlsx`);
})

View File

@@ -57,7 +57,6 @@
<el-button
type="primary"
text
icon="el-icon-view"
v-if="hasPermission('common_address_view')"
@click="$refs.crud.rowView(row, index)"
>
@@ -66,7 +65,6 @@
<el-button
type="primary"
text
icon="el-icon-edit"
v-if="hasPermission('common_address_edit') && !row.readonly"
@click="$refs.crud.rowEdit(row, index)"
>
@@ -75,7 +73,6 @@
<el-button
type="primary"
text
icon="el-icon-delete"
v-if="hasPermission('common_address_delete') && !row.readonly"
@click="rowDel(row)"
>
@@ -914,7 +911,8 @@ export default {
NProgress.start();
exportBlob(
'/blade-transport/common-address/export-common-address',
this.buildExportParams()
this.buildExportParams(),
{ feedback: true }
)
.then(res => {
downloadXls(res.data, `常用地址${this.$dayjs().format('YYYY-MM-DD HH:mm:ss')}.xlsx`);

View File

@@ -71,7 +71,6 @@
<el-button
type="primary"
text
icon="el-icon-edit"
v-if="permission.currency_edit"
@click="$refs.crud.rowEdit(row, index)"
>
@@ -80,7 +79,6 @@
<el-button
type="primary"
text
:icon="row.status === 1 ? 'el-icon-close' : 'el-icon-check'"
v-if="permission.currency_status"
@click="handleStatus(row)"
>
@@ -551,7 +549,7 @@ export default {
type: 'warning',
}).then(() => {
NProgress.start();
exportBlob('/blade-system/currency/export-currency', this.buildExportParams())
exportBlob('/blade-system/currency/export-currency', this.buildExportParams(), { feedback: true })
.then(res => {
downloadXls(res.data, `币种汇率${this.$dayjs().format('YYYY-MM-DD HH:mm:ss')}.xlsx`);
})
@@ -569,7 +567,8 @@ export default {
},
handleTemplate() {
exportBlob(
`/blade-system/currency/export-template?${this.website.tokenHeader}=${getToken()}`
`/blade-system/currency/export-template?${this.website.tokenHeader}=${getToken()}`,
{ feedback: true }
).then(res => {
downloadXls(res.data, '币种汇率模板.xlsx');
});

View File

@@ -39,7 +39,6 @@
<el-button
type="primary"
text
icon="el-icon-edit"
v-if="permission.customer_type_edit"
@click="$refs.crud.rowEdit(row, index)"
>
@@ -48,7 +47,6 @@
<el-button
type="primary"
text
:icon="row.status === 1 ? 'el-icon-close' : 'el-icon-check'"
v-if="permission.customer_type_status"
@click="handleStatus(row)"
>

View File

@@ -39,7 +39,6 @@
<el-button
type="primary"
text
icon="el-icon-edit"
v-if="permission.fee_item_edit"
@click="$refs.crud.rowEdit(row, index)"
>
@@ -48,7 +47,6 @@
<el-button
type="primary"
text
:icon="row.status === 1 ? 'el-icon-close' : 'el-icon-check'"
v-if="permission.fee_item_status"
@click="handleStatus(row)"
>

View File

@@ -116,7 +116,6 @@
<el-button
type="primary"
text
icon="el-icon-edit"
v-if="hasPermission('port_terminal_edit')"
@click="$refs.crud.rowEdit(row, index)"
>
@@ -125,7 +124,6 @@
<el-button
type="primary"
text
:icon="row.status === 1 ? 'el-icon-close' : 'el-icon-check'"
v-if="hasPermission('port_terminal_status')"
@click="handleStatus(row)"
>
@@ -172,6 +170,9 @@
/>
</el-select>
</template>
<template #detailAddress="{ row }">
<span class="port-terminal-page__detail-address">{{ row.detailAddress || '-' }}</span>
</template>
<template #longitude-form>
<el-input
v-model="form.longitude"
@@ -229,6 +230,74 @@ import NProgress from 'nprogress';
import 'nprogress/nprogress.css';
const DEFAULT_COUNTRY_CODE = '+86';
const EXCLUDED_EXCEL_HEADERS = ['数据来源', '启停状态'];
const REQUIRED_EXPORT_HEADERS = ['港口码头名称', '港口/码头名称', '类型', '国家', '城市', '经度', '纬度'];
const getExcelCellText = value => {
if (value === undefined || value === null) return '';
if (typeof value === 'object') {
if (Array.isArray(value.richText)) {
return value.richText.map(item => item.text || '').join('');
}
if (value.text) return value.text;
if (value.result) return value.result;
}
return String(value);
};
const removeWorkbookColumnsByHeaders = workbook => {
workbook.eachSheet(worksheet => {
const maxHeaderRow = Math.min(worksheet.rowCount || 0, 10);
for (let rowIndex = 1; rowIndex <= maxHeaderRow; rowIndex += 1) {
const row = worksheet.getRow(rowIndex);
const indexes = [];
row.eachCell((cell, colNumber) => {
const text = getExcelCellText(cell.value).trim();
if (EXCLUDED_EXCEL_HEADERS.includes(text)) {
indexes.push(colNumber);
}
});
if (indexes.length) {
indexes
.sort((a, b) => b - a)
.forEach(colNumber => worksheet.spliceColumns(colNumber, 1));
break;
}
}
});
};
const addWorkbookRequiredHeaderMarks = workbook => {
workbook.eachSheet(worksheet => {
const maxHeaderRow = Math.min(worksheet.rowCount || 0, 10);
for (let rowIndex = 1; rowIndex <= maxHeaderRow; rowIndex += 1) {
const row = worksheet.getRow(rowIndex);
let hasRequiredHeader = false;
row.eachCell(cell => {
const text = getExcelCellText(cell.value).trim();
const header = text.replace(/\*+$/g, '').trim();
if (REQUIRED_EXPORT_HEADERS.includes(header)) {
cell.value = `${header}*`;
hasRequiredHeader = true;
}
});
if (hasRequiredHeader) break;
}
});
};
const removeExcelColumnsByHeaders = async (blob, options = {}) => {
const { markRequiredHeaders = false } = options;
const ExcelJS = await import('exceljs');
const workbook = new ExcelJS.Workbook();
await workbook.xlsx.load(await blob.arrayBuffer());
removeWorkbookColumnsByHeaders(workbook);
if (markRequiredHeaders) {
addWorkbookRequiredHeaderMarks(workbook);
}
const buffer = await workbook.xlsx.writeBuffer();
return new Blob([buffer], { type: 'application/vnd.ms-excel' });
};
export default {
data() {
@@ -466,6 +535,7 @@ export default {
label: '详细地址',
prop: 'detailAddress',
type: 'textarea',
slot: true,
minRows: 3,
span: 24,
minWidth: 220,
@@ -1184,9 +1254,16 @@ export default {
});
},
handleImport() {
openImportDialog(this, '港口码头主数据', () => {
this.loadPortOptions();
});
openImportDialog(
this,
'港口码头主数据',
() => {
this.loadPortOptions();
},
{
failDetailDecorator: removeWorkbookColumnsByHeaders,
}
);
},
handleExport() {
this.$confirm('是否导出港口码头主数据?', '提示', {
@@ -1195,10 +1272,17 @@ export default {
type: 'warning',
}).then(() => {
NProgress.start();
exportBlob('/blade-system/port-terminal/export-port-terminal', this.buildExportParams())
.then(res => {
exportBlob(
'/blade-system/port-terminal/export-port-terminal',
this.buildExportParams(),
{ feedback: true }
)
.then(async res => {
const blob = await removeExcelColumnsByHeaders(res.data, {
markRequiredHeaders: true,
});
downloadXls(
res.data,
blob,
`港口码头主数据${this.$dayjs().format('YYYY-MM-DD HH:mm:ss')}.xlsx`
);
})
@@ -1216,11 +1300,24 @@ export default {
},
handleTemplate() {
exportBlob(
`/blade-system/port-terminal/export-template?${this.website.tokenHeader}=${getToken()}`
).then(res => {
downloadXls(res.data, '港口码头主数据模板.xlsx');
`/blade-system/port-terminal/export-template?${this.website.tokenHeader}=${getToken()}`,
undefined,
{ feedback: true }
).then(async res => {
const blob = await removeExcelColumnsByHeaders(res.data);
downloadXls(blob, '港口码头主数据模板.xlsx');
});
},
},
};
</script>
<style lang="scss" scoped>
.port-terminal-page__detail-address {
display: block;
white-space: normal;
word-break: break-all;
line-height: 20px;
padding: 4px 0;
}
</style>

View File

@@ -63,7 +63,6 @@
<el-button
type="primary"
text
icon="el-icon-edit"
v-if="hasPermission('railway_station_edit')"
@click="$refs.crud.rowEdit(row, index)"
>
@@ -72,7 +71,6 @@
<el-button
type="primary"
text
:icon="row.status === 1 ? 'el-icon-close' : 'el-icon-check'"
v-if="hasPermission('railway_station_status')"
@click="handleStatus(row)"
>
@@ -154,7 +152,15 @@ export default {
};
const validateTelegraphCode = (rule, value, callback) => {
if (!/^[A-Z]{3}$/.test(String(value || '').toUpperCase())) {
callback(new Error('电报码为3位大写字母'));
callback(new Error('电报码格式不正确或已存在'));
} else {
callback();
}
};
const validateStationName = (rule, value, callback) => {
const name = String(value || '').trim();
if (!name || name.length > 50) {
callback(new Error('请输入车站名称'));
} else {
callback();
}
@@ -162,7 +168,7 @@ export default {
const validateLongitude = (rule, value, callback) => {
const message = getCoordinateValidationMessage(value, 'longitude');
if (message) {
callback(new Error(message));
callback(new Error('经度范围不正确'));
} else {
callback();
}
@@ -170,7 +176,7 @@ export default {
const validateLatitude = (rule, value, callback) => {
const message = getCoordinateValidationMessage(value, 'latitude');
if (message) {
callback(new Error(message));
callback(new Error('纬度范围不正确'));
} else {
callback();
}
@@ -245,7 +251,7 @@ export default {
minWidth: 100,
maxlength: 3,
rules: [
{ required: true, message: '请输入电报码', trigger: 'blur' },
{ required: true, message: '电报码格式不正确或已存在', trigger: 'blur' },
{ validator: validateTelegraphCode, trigger: 'blur' },
],
change: ({ value }) => this.handleTelegraphChange(value),
@@ -255,8 +261,9 @@ export default {
label: '车站名称',
prop: 'name',
minWidth: 120,
maxlength: 50,
search: true,
rules: [{ required: true, message: '请输入车站名称', trigger: 'blur' }],
rules: [{ validator: validateStationName, trigger: 'blur' }],
},
// {
// label: '所属铁路线路',
@@ -357,10 +364,7 @@ export default {
formslot: true,
minWidth: 130,
overHidden: false,
rules: [
{ required: true, message: '请输入经度', trigger: 'blur' },
{ validator: validateLongitude, trigger: 'blur' },
],
rules: [{ validator: validateLongitude, trigger: 'blur' }],
},
{
label: '纬度',
@@ -368,10 +372,7 @@ export default {
formslot: true,
minWidth: 130,
overHidden: false,
rules: [
{ required: true, message: '请输入纬度', trigger: 'blur' },
{ validator: validateLatitude, trigger: 'blur' },
],
rules: [{ validator: validateLatitude, trigger: 'blur' }],
},
{
label: '数据来源',
@@ -653,14 +654,14 @@ export default {
return row;
},
validateCoordinateFields(row) {
const longitudeMessage = getCoordinateValidationMessage(row.longitude, 'longitude', true);
const longitudeMessage = getCoordinateValidationMessage(row.longitude, 'longitude');
if (longitudeMessage) {
this.$message.warning(longitudeMessage);
this.$message.warning('经度范围不正确');
return false;
}
const latitudeMessage = getCoordinateValidationMessage(row.latitude, 'latitude', true);
const latitudeMessage = getCoordinateValidationMessage(row.latitude, 'latitude');
if (latitudeMessage) {
this.$message.warning(latitudeMessage);
this.$message.warning('纬度范围不正确');
return false;
}
return true;
@@ -681,13 +682,13 @@ export default {
return Promise.reject(new Error('该TMIS编码已存在'));
}
if (telegraphExists) {
return Promise.reject(new Error('电报码已存在'));
return Promise.reject(new Error('电报码格式不正确或已存在'));
}
return Promise.resolve();
});
},
handleSubmitError(error, loading) {
const uniqueMessages = ['该TMIS编码已存在', '电报码已存在'];
const uniqueMessages = ['该TMIS编码已存在', '电报码格式不正确或已存在'];
if (uniqueMessages.includes(error.message)) {
this.$message.warning(error.message);
}
@@ -846,7 +847,11 @@ export default {
type: 'warning',
}).then(() => {
NProgress.start();
exportBlob('/blade-system/railway-station/export-railway-station', this.buildExportParams())
exportBlob(
'/blade-system/railway-station/export-railway-station',
this.buildExportParams(),
{ feedback: true }
)
.then(res => {
downloadXls(
res.data,
@@ -867,7 +872,9 @@ export default {
},
handleTemplate() {
exportBlob(
`/blade-system/railway-station/export-template?${this.website.tokenHeader}=${getToken()}`
`/blade-system/railway-station/export-template?${this.website.tokenHeader}=${getToken()}`,
undefined,
{ feedback: true }
).then(res => {
downloadXls(res.data, '铁路车站主数据模板.xlsx');
});

View File

@@ -625,7 +625,8 @@ export default {
}).then(() => {
NProgress.start();
exportBlob(
`/blade-system/region/export-region?${this.website.tokenHeader}=${getToken()}`
`/blade-system/region/export-region?${this.website.tokenHeader}=${getToken()}`,
{ feedback: true }
).then(res => {
downloadXls(res.data, `行政区划数据${this.$dayjs().format('YYYY-MM-DD HH:mm:ss')}.xlsx`);
NProgress.done();
@@ -634,7 +635,8 @@ export default {
},
handleTemplate() {
exportBlob(
`/blade-system/region/export-template?${this.website.tokenHeader}=${getToken()}`
`/blade-system/region/export-template?${this.website.tokenHeader}=${getToken()}`,
{ feedback: true }
).then(res => {
downloadXls(res.data, '行政区划模板.xlsx');
});