This commit is contained in:
2026-07-27 17:19:36 +08:00
parent e50d1b8fda
commit 1c7532e0de
132 changed files with 7066 additions and 1241 deletions

View File

@@ -79,15 +79,45 @@
{{ row.status === 1 ? '停用' : '启用' }}
</el-button>
</template>
<template #districtCode-form>
<el-select
v-model="form.districtCode"
clearable
filterable
:loading="districtLoading"
:disabled="!form.cityCode"
:placeholder="form.cityCode ? '请选择区县' : '请先选择城市'"
style="width: 100%"
@change="handleDistrictChange"
>
<el-option
v-for="item in districtOptions"
:key="item.id"
:label="item.title"
:value="item.id"
/>
</el-select>
</template>
<template #longitude-form>
<el-input
v-model="form.longitude"
clearable
placeholder="请输入经度"
@input="handleCoordinateInput('longitude', $event)"
/>
</template>
<template #latitude-form>
<el-input
v-model="form.latitude"
clearable
placeholder="请输入纬度"
@input="handleCoordinateInput('latitude', $event)"
/>
</template>
</avue-crud>
<el-dialog title="空港机场主数据导入" append-to-body v-model="excelBox" width="555px">
<avue-form
:option="excelOption"
v-model="excelForm"
:upload-before="uploadBefore"
:upload-after="uploadAfter"
>
<avue-form :option="excelOption" v-model="excelForm">
<template #excelTemplate>
<el-button type="primary" @click="handleTemplate">
点击下载<i class="el-icon-download el-icon--right"></i>
@@ -104,8 +134,10 @@ import { getLazyTree } from '@/api/base/region';
import { exportBlob } from '@/api/common';
import { mapGetters } from 'vuex';
import { downloadXls } from '@/utils/util';
import { openImportDialog } from '@/utils/import-excel';
import { formatUpdateUserName } from '@/utils/audit';
import { getToken } from '@/utils/auth';
import { getCoordinateValidationMessage, normalizeCoordinateInput } from '@/utils/coordinate';
import NProgress from 'nprogress';
import 'nprogress/nprogress.css';
@@ -128,19 +160,17 @@ export default {
}
};
const validateLongitude = (rule, value, callback) => {
if (value === undefined || value === null || value === '') {
callback();
} else if (Number(value) < -180 || Number(value) > 180) {
callback(new Error('经度范围为 -180 到 180'));
const message = getCoordinateValidationMessage(value, 'longitude');
if (message) {
callback(new Error(message));
} else {
callback();
}
};
const validateLatitude = (rule, value, callback) => {
if (value === undefined || value === null || value === '') {
callback();
} else if (Number(value) < -90 || Number(value) > 90) {
callback(new Error('纬度范围为 -90 到 90'));
const message = getCoordinateValidationMessage(value, 'latitude');
if (message) {
callback(new Error(message));
} else {
callback();
}
@@ -154,6 +184,9 @@ export default {
excelForm: {},
provinceOptions: [],
cityOptions: [],
districtOptions: [],
districtLoading: false,
regionInitializing: false,
page: {
pageSize: 10,
pageSizes: [10, 20, 50, 100],
@@ -165,11 +198,15 @@ export default {
height: 'auto',
calcHeight: 32,
dialogWidth: 980,
labelPosition: 'right',
tip: false,
searchShow: true,
labelWidth: 120,
searchLabelWidth: 120,
searchMenuSpan: 6,
labelWidth: 'auto',
searchLabelWidth: 160,
searchMenuSpan: 24,
searchIcon: true,
searchIndex: 8,
searchMenuPosition: 'right',
border: true,
index: true,
indexLabel: '序号',
@@ -185,8 +222,8 @@ export default {
label: '编码',
prop: 'code',
search: true,
addDisabled: true,
editDisabled: true,
addDisplay: false,
editDisplay: false,
placeholder: '系统自动生成',
searchPlaceholder: '请输入编码',
},
@@ -271,14 +308,35 @@ export default {
editDisplay: false,
},
{
label: '行政区划',
prop: 'regionName',
search: true,
label: '所属区县',
prop: 'districtCode',
type: 'select',
formslot: true,
hide: true,
props: {
label: 'title',
value: 'id',
},
dicData: [],
filterable: true,
rules: [{ required: true, message: '请选择区县', trigger: 'change' }],
change: ({ value }) => this.handleDistrictChange(value),
},
{
label: '所属区县',
prop: 'districtName',
minWidth: 140,
addDisplay: false,
editDisplay: false,
},
{
label: '行政区划编号',
prop: 'regionCode',
minWidth: 160,
overHidden: false,
maxlength: 128,
showWordLimit: true,
rules: [{ max: 128, message: '行政区划不能超过128字', trigger: 'blur' }],
addDisplay: false,
editDisplay: false,
rules: [{ max: 32, message: '行政区划编码不能超过32字', trigger: 'blur' }],
},
{
label: '详细地址',
@@ -295,20 +353,24 @@ export default {
{
label: '经度',
prop: 'longitude',
type: 'number',
precision: 6,
formslot: true,
minWidth: 130,
overHidden: false,
rules: [{ validator: validateLongitude, trigger: 'blur' }],
rules: [
{ required: true, message: '请输入经度', trigger: 'blur' },
{ validator: validateLongitude, trigger: 'blur' },
],
},
{
label: '纬度',
prop: 'latitude',
type: 'number',
precision: 6,
formslot: true,
minWidth: 130,
overHidden: false,
rules: [{ validator: validateLatitude, trigger: 'blur' }],
rules: [
{ required: true, message: '请输入纬度', trigger: 'blur' },
{ validator: validateLatitude, trigger: 'blur' },
],
},
{
label: '数据来源',
@@ -317,6 +379,8 @@ export default {
search: true,
minWidth: 120,
overHidden: false,
addDisplay: false,
editDisplay: false,
dicData: [
{ label: '全部', value: '' },
{ label: '初始导入', value: '初始导入' },
@@ -333,6 +397,8 @@ export default {
dataType: 'number',
minWidth: 110,
overHidden: false,
addDisplay: false,
editDisplay: false,
dicData: [
{ label: '全部', value: '' },
{ label: '启用', value: 1 },
@@ -383,6 +449,7 @@ export default {
],
},
excelOption: {
labelPosition: 'right',
submitBtn: false,
emptyBtn: false,
column: [
@@ -419,7 +486,9 @@ export default {
},
isAdmin() {
const authority = this.userInfo && this.userInfo.authority;
return Array.isArray(authority) ? authority.includes('admin') : String(authority || '').includes('admin');
return Array.isArray(authority)
? authority.includes('admin')
: String(authority || '').includes('admin');
},
ids() {
let ids = [];
@@ -441,7 +510,7 @@ export default {
},
loadProvinceOptions() {
getLazyTree(DEFAULT_COUNTRY_CODE).then(res => {
this.provinceOptions = res.data.data;
this.provinceOptions = (res.data.data || []).map(this.normalizeRegionOption);
this.findColumn('provinceCode').dicData = this.provinceOptions;
});
},
@@ -452,10 +521,60 @@ export default {
return Promise.resolve();
}
return getLazyTree(provinceCode).then(res => {
this.cityOptions = res.data.data;
this.cityOptions = (res.data.data || []).map(this.normalizeRegionOption);
this.findColumn('cityCode').dicData = this.cityOptions;
});
},
loadDistrictOptions(cityCode) {
if (!cityCode) {
this.districtOptions = [];
this.findColumn('districtCode').dicData = [];
return Promise.resolve();
}
this.districtLoading = true;
return getLazyTree(cityCode)
.then(res => {
this.districtOptions = (res.data.data || []).map(this.normalizeRegionOption);
this.findColumn('districtCode').dicData = this.districtOptions;
})
.finally(() => {
this.districtLoading = false;
});
},
normalizeRegionOption(region) {
return {
...region,
id: region.id === undefined || region.id === null ? region.id : String(region.id),
};
},
normalizeRegionForm(row) {
return {
...row,
provinceCode:
row.provinceCode === undefined || row.provinceCode === null
? row.provinceCode
: String(row.provinceCode),
cityCode:
row.cityCode === undefined || row.cityCode === null ? row.cityCode : String(row.cityCode),
districtCode:
row.districtCode === undefined || row.districtCode === null
? row.districtCode
: String(row.districtCode),
};
},
ensureDistrictOption(row) {
if (!row.districtCode || !row.districtName) return;
const exists = this.districtOptions.some(item => item.id === row.districtCode);
if (exists) return;
this.districtOptions = [
...this.districtOptions,
{
id: row.districtCode,
title: row.districtName,
},
];
this.findColumn('districtCode').dicData = this.districtOptions;
},
handleIataChange(value) {
this.form.iataCode = String(value || '')
.toUpperCase()
@@ -472,22 +591,67 @@ export default {
handleProvinceChange(value) {
const province = this.provinceOptions.find(item => item.id === value);
this.form.provinceName = province ? province.title : '';
if (this.regionInitializing) {
this.loadCityOptions(value);
return;
}
this.form.cityCode = undefined;
this.form.cityName = '';
this.form.districtCode = undefined;
this.form.districtName = '';
this.form.regionCode = '';
this.form.regionName = '';
this.loadCityOptions(value);
this.loadDistrictOptions();
},
handleCityChange(value) {
const city = this.cityOptions.find(item => item.id === value);
this.form.cityName = city ? city.title : '';
if (this.regionInitializing) {
this.loadDistrictOptions(value);
return;
}
this.form.districtCode = undefined;
this.form.districtName = '';
this.form.regionCode = '';
this.form.regionName = '';
this.loadDistrictOptions(value);
},
handleDistrictChange(value) {
const district = this.districtOptions.find(item => item.id === value);
this.form.districtName = district ? district.title : '';
this.form.regionCode = value || '';
this.form.regionName = district ? district.title : '';
},
handleCoordinateInput(prop, value) {
this.form[prop] = normalizeCoordinateInput(value);
},
normalizeRow(row) {
row.code = row.iataCode ? `JC-${row.iataCode}` : row.code;
row.regionCode = String(row.regionCode || '').trim();
row.regionName = String(row.regionName || '').trim();
row.districtCode = String(row.districtCode || '').trim();
row.districtName = String(row.districtName || '').trim();
row.detailAddress = String(row.detailAddress || '').trim();
row.longitude = normalizeCoordinateInput(row.longitude);
row.latitude = normalizeCoordinateInput(row.latitude);
if (!row.dataSource) row.dataSource = '手动录入';
if (!row.status) row.status = 1;
return row;
},
validateCoordinateFields(row) {
const longitudeMessage = getCoordinateValidationMessage(row.longitude, 'longitude', true);
if (longitudeMessage) {
this.$message.warning(longitudeMessage);
return false;
}
const latitudeMessage = getCoordinateValidationMessage(row.latitude, 'latitude', true);
if (latitudeMessage) {
this.$message.warning(latitudeMessage);
return false;
}
return true;
},
validateUnique(row) {
const rowId = String(row.id || '');
const hasDuplicate = (params, prop) => {
@@ -519,6 +683,10 @@ export default {
},
rowSave(row, done, loading) {
const submitRow = this.normalizeRow(row);
if (!this.validateCoordinateFields(submitRow)) {
loading();
return;
}
this.validateUnique(submitRow)
.then(() => submit(submitRow))
.then(() => {
@@ -530,6 +698,10 @@ export default {
},
rowUpdate(row, index, done, loading) {
const submitRow = this.normalizeRow(row);
if (!this.validateCoordinateFields(submitRow)) {
loading();
return;
}
this.validateUnique(submitRow)
.then(() => submit(submitRow))
.then(() => {
@@ -584,16 +756,30 @@ export default {
},
beforeOpen(done, type) {
if (['edit', 'view'].includes(type)) {
this.regionInitializing = true;
getDetail(this.form.id).then(res => {
this.form = res.data.data;
this.loadCityOptions(this.form.provinceCode).then(() => done());
const detail = this.normalizeRegionForm(res.data.data || {});
this.loadCityOptions(detail.provinceCode)
.then(() => this.loadDistrictOptions(detail.cityCode))
.then(() => {
this.ensureDistrictOption(detail);
this.form = detail;
done();
this.$nextTick(() => {
window.setTimeout(() => {
this.regionInitializing = false;
}, 0);
});
});
});
return;
}
this.form.code = '';
this.form.dataSource = '手动录入';
this.form.status = 1;
this.loadCityOptions(this.form.provinceCode).then(() => done());
this.loadCityOptions(this.form.provinceCode)
.then(() => this.loadDistrictOptions(this.form.cityCode))
.then(() => done());
},
searchReset() {
this.query = {};
@@ -635,23 +821,7 @@ export default {
});
},
handleImport() {
this.excelBox = true;
},
uploadBefore(file, done) {
const fileName = file && file.name ? file.name.toLowerCase() : '';
if (!/\.(xls|xlsx)$/.test(fileName)) {
this.$message.error('请上传 .xls,.xlsx 标准格式文件');
return false;
}
if (typeof done === 'function') {
done();
}
return true;
},
uploadAfter(res, done) {
this.excelBox = false;
this.onLoad(this.page);
done();
openImportDialog(this, '空港机场主数据');
},
handleExport() {
this.$confirm('是否导出空港机场主数据?', '提示', {