✨ 优化港口地图回填、合同展示与运单导入空值
地图选点回填国家省市区;合同选择显示编号/名称;常用数据组织筛选修正;运单详情将-1费用字段显示为空。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -271,7 +271,12 @@ export default {
|
||||
this.runGeocode('address', lnglat)
|
||||
.then(result => {
|
||||
const detailAddress = result.regeocode?.formattedAddress || fallbackAddress;
|
||||
this.selected = { ...this.selected, address: detailAddress };
|
||||
const region = this.resolveRegionFromGeocode(result);
|
||||
this.selected = {
|
||||
...this.selected,
|
||||
address: detailAddress,
|
||||
...region,
|
||||
};
|
||||
this.keyword = detailAddress || this.keyword;
|
||||
this.status = detailAddress || '已选点,可确认回填';
|
||||
})
|
||||
@@ -285,6 +290,26 @@ export default {
|
||||
this.resolving = false;
|
||||
});
|
||||
},
|
||||
resolveRegionFromGeocode(result = {}) {
|
||||
const component = result.regeocode?.addressComponent || {};
|
||||
const city = Array.isArray(component.city) ? '' : String(component.city || '').trim();
|
||||
const province = String(component.province || '').trim();
|
||||
const district = String(component.district || '').trim();
|
||||
const country = String(component.country || '').trim();
|
||||
const adcode = String(component.adcode || '').trim();
|
||||
return {
|
||||
country,
|
||||
province,
|
||||
city: city || province,
|
||||
district,
|
||||
adcode,
|
||||
regionCode: adcode,
|
||||
provinceName: province,
|
||||
cityName: city || province,
|
||||
districtName: district,
|
||||
countryName: country,
|
||||
};
|
||||
},
|
||||
renderMarker(point) {
|
||||
this.clearMarker();
|
||||
this.marker = new window.AMap.Marker({ position: point });
|
||||
@@ -310,6 +335,16 @@ export default {
|
||||
address: this.selected.address,
|
||||
longitude: this.selected.longitude,
|
||||
latitude: this.selected.latitude,
|
||||
country: this.selected.country || this.selected.countryName || '',
|
||||
province: this.selected.province || this.selected.provinceName || '',
|
||||
city: this.selected.city || this.selected.cityName || '',
|
||||
district: this.selected.district || this.selected.districtName || '',
|
||||
adcode: this.selected.adcode || this.selected.regionCode || '',
|
||||
regionCode: this.selected.regionCode || this.selected.adcode || '',
|
||||
countryName: this.selected.countryName || this.selected.country || '',
|
||||
provinceName: this.selected.provinceName || this.selected.province || '',
|
||||
cityName: this.selected.cityName || this.selected.city || '',
|
||||
districtName: this.selected.districtName || this.selected.district || '',
|
||||
});
|
||||
this.visible = false;
|
||||
},
|
||||
|
||||
@@ -305,6 +305,10 @@ export const createOption = () => ({
|
||||
searchOrder: 3,
|
||||
searchPlaceholder: '请选择',
|
||||
dicData: [],
|
||||
props: {
|
||||
label: 'label',
|
||||
value: 'value',
|
||||
},
|
||||
filterable: true,
|
||||
hide: true,
|
||||
display: false,
|
||||
|
||||
@@ -39,6 +39,7 @@ export const userOption = safe => {
|
||||
prop: 'account',
|
||||
search: true,
|
||||
searchOrder: 2,
|
||||
searchPlaceholder: '支持模糊搜索',
|
||||
display: false,
|
||||
},
|
||||
{
|
||||
@@ -46,6 +47,7 @@ export const userOption = safe => {
|
||||
prop: 'realName',
|
||||
search: true,
|
||||
searchOrder: 4,
|
||||
searchPlaceholder: '支持模糊搜索',
|
||||
display: false,
|
||||
},
|
||||
{
|
||||
@@ -53,6 +55,7 @@ export const userOption = safe => {
|
||||
prop: 'phone',
|
||||
search: true,
|
||||
searchOrder: 3,
|
||||
searchPlaceholder: '支持模糊搜索',
|
||||
display: false,
|
||||
},
|
||||
{ label: '工号', prop: 'code', display: false },
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* 合同下拉/选择展示:合同编号/合同名称
|
||||
*
|
||||
* @param {Object} contract 合同对象
|
||||
* @returns {string}
|
||||
*/
|
||||
export function formatContractOptionLabel(contract = {}) {
|
||||
const contractNo = String(contract?.contractNo ?? '').trim();
|
||||
const contractName = String(contract?.contractName ?? '').trim();
|
||||
if (contractNo && contractName) {
|
||||
return `${contractNo}/${contractName}`;
|
||||
}
|
||||
return contractNo || contractName || '';
|
||||
}
|
||||
@@ -344,15 +344,21 @@ export default {
|
||||
getDeptTree(this.userInfo.tenantId).then(res => {
|
||||
this.deptOptions = this.flattenDept(res.data.data || []);
|
||||
const deptColumn = this.findColumn(this.option.column, 'searchDeptId');
|
||||
deptColumn.dicData = this.deptOptions;
|
||||
if (deptColumn) {
|
||||
deptColumn.dicData = this.deptOptions;
|
||||
}
|
||||
});
|
||||
},
|
||||
flattenDept(tree, level = 0) {
|
||||
const result = [];
|
||||
tree.forEach(item => {
|
||||
// 雪花 ID 必须保持字符串,避免 JS Number 精度丢失导致筛错组织。
|
||||
const id =
|
||||
item.id === undefined || item.id === null || item.id === '' ? '' : String(item.id);
|
||||
if (!id) return;
|
||||
result.push({
|
||||
label: `${' '.repeat(level)}${item.title || item.deptName || item.name}`,
|
||||
value: item.id,
|
||||
value: id,
|
||||
rawLabel: item.title || item.deptName || item.name,
|
||||
});
|
||||
if (item.children && item.children.length) {
|
||||
@@ -361,6 +367,19 @@ export default {
|
||||
});
|
||||
return result;
|
||||
},
|
||||
normalizeListQuery(params = {}) {
|
||||
// 搜索条件优先于缓存的 query,避免旧组织 ID 覆盖用户新选择的组织。
|
||||
const query = { ...this.query, ...params };
|
||||
const rawDeptId = query.deptId ?? query.searchDeptId;
|
||||
delete query.searchDeptId;
|
||||
if (rawDeptId !== undefined && rawDeptId !== null && String(rawDeptId).trim() !== '') {
|
||||
query.deptId = String(rawDeptId).split(',')[0].trim();
|
||||
} else {
|
||||
delete query.deptId;
|
||||
}
|
||||
query.allDept = this.isAdmin ? 1 : 0;
|
||||
return query;
|
||||
},
|
||||
getRecords(res) {
|
||||
const data = res && res.data && res.data.data;
|
||||
if (Array.isArray(data)) return data;
|
||||
@@ -967,13 +986,15 @@ export default {
|
||||
},
|
||||
searchReset() {
|
||||
this.query = {};
|
||||
this.allDept = this.isAdmin ? 1 : 0;
|
||||
this.page.currentPage = 1;
|
||||
this.onLoad(this.page);
|
||||
},
|
||||
searchChange(params, done) {
|
||||
this.query = params;
|
||||
this.query = this.normalizeListQuery(params);
|
||||
this.allDept = this.query.allDept;
|
||||
this.page.currentPage = 1;
|
||||
this.onLoad(this.page, params);
|
||||
this.onLoad(this.page, this.query);
|
||||
done();
|
||||
},
|
||||
selectionChange(list) {
|
||||
@@ -994,7 +1015,10 @@ export default {
|
||||
},
|
||||
onLoad(page, params = {}) {
|
||||
this.loading = true;
|
||||
getList(page.currentPage, page.pageSize, { ...params, ...this.query, allDept: this.allDept })
|
||||
const query = this.normalizeListQuery(params);
|
||||
this.query = query;
|
||||
this.allDept = query.allDept;
|
||||
getList(page.currentPage, page.pageSize, query)
|
||||
.then(res => {
|
||||
const data = res.data.data;
|
||||
this.page.total = data.total;
|
||||
@@ -1027,8 +1051,7 @@ export default {
|
||||
},
|
||||
buildExportParams() {
|
||||
return {
|
||||
...this.query,
|
||||
allDept: this.allDept,
|
||||
...this.normalizeListQuery(this.query),
|
||||
ids: this.ids,
|
||||
[this.website.tokenHeader]: getToken(),
|
||||
};
|
||||
|
||||
@@ -264,7 +264,7 @@ import {
|
||||
changeStatus,
|
||||
getPortSelect,
|
||||
} from '@/api/base/port-terminal';
|
||||
import { getLazyTree } from '@/api/base/region';
|
||||
import { getDetail as getRegionDetail, getLazyTree } from '@/api/base/region';
|
||||
import { exportBlob } from '@/api/common';
|
||||
import { mapGetters } from 'vuex';
|
||||
import { downloadXls } from '@/utils/util';
|
||||
@@ -841,10 +841,60 @@ export default {
|
||||
},
|
||||
handleCountryNameChange(value) {
|
||||
const country = this.countryOptions.find(item => item.title === value);
|
||||
this.setProvinceOptions([]);
|
||||
this.setCityOptions([]);
|
||||
this.setDistrictOptions([]);
|
||||
this.loadProvinceOptions(country ? country.id : '');
|
||||
this.clearSearchCityAndDistrict();
|
||||
// 搜索栏为国家 → 城市 → 区县(无省份),选中国家后需直接加载该国下全部城市
|
||||
this.loadCityOptionsByCountry(country ? country.id : '');
|
||||
},
|
||||
clearSearchCityAndDistrict() {
|
||||
const searchForm = this.$refs.crud && this.$refs.crud.searchForm;
|
||||
if (searchForm) {
|
||||
searchForm.city = undefined;
|
||||
searchForm.districtName = undefined;
|
||||
}
|
||||
if (this.query) {
|
||||
this.query.city = undefined;
|
||||
this.query.districtName = undefined;
|
||||
}
|
||||
},
|
||||
loadCityOptionsByCountry(countryCode) {
|
||||
if (!countryCode) {
|
||||
this.setCityOptions([]);
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
this.cityLoading = true;
|
||||
return this.loadProvinceOptions(countryCode)
|
||||
.then(provinces =>
|
||||
Promise.all((provinces || []).map(province => this.fetchCityOptions(province.id)))
|
||||
)
|
||||
.then(cityGroups => {
|
||||
const cityMap = new Map();
|
||||
cityGroups.flat().forEach(city => {
|
||||
if (city && city.id && !cityMap.has(city.id)) {
|
||||
cityMap.set(city.id, city);
|
||||
}
|
||||
});
|
||||
const cities = Array.from(cityMap.values());
|
||||
this.setCityOptions(cities);
|
||||
return cities;
|
||||
})
|
||||
.finally(() => {
|
||||
this.cityLoading = false;
|
||||
});
|
||||
},
|
||||
fetchCityOptions(provinceCode) {
|
||||
if (!provinceCode) {
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
if (this.cityOptionCache[provinceCode]) {
|
||||
return Promise.resolve(this.cityOptionCache[provinceCode]);
|
||||
}
|
||||
return getLazyTree(provinceCode).then(res => {
|
||||
const options = (res.data.data || []).map(this.normalizeRegionOption);
|
||||
this.cityOptionCache[provinceCode] = options;
|
||||
return options;
|
||||
});
|
||||
},
|
||||
syncCountryName(countryCode) {
|
||||
const country = this.countryOptions.find(item => item.id === countryCode);
|
||||
@@ -925,10 +975,8 @@ export default {
|
||||
return Promise.resolve(this.cityOptionCache[provinceCode]);
|
||||
}
|
||||
this.cityLoading = true;
|
||||
return getLazyTree(provinceCode)
|
||||
.then(res => {
|
||||
const options = (res.data.data || []).map(this.normalizeRegionOption);
|
||||
this.cityOptionCache[provinceCode] = options;
|
||||
return this.fetchCityOptions(provinceCode)
|
||||
.then(options => {
|
||||
this.setCityOptions(options);
|
||||
return options;
|
||||
})
|
||||
@@ -1047,6 +1095,13 @@ export default {
|
||||
handleCityNameChange(value) {
|
||||
const city = this.cityOptions.find(item => item.title === value);
|
||||
this.setDistrictOptions([]);
|
||||
const searchForm = this.$refs.crud && this.$refs.crud.searchForm;
|
||||
if (searchForm) {
|
||||
searchForm.districtName = undefined;
|
||||
}
|
||||
if (this.query) {
|
||||
this.query.districtName = undefined;
|
||||
}
|
||||
this.loadDistrictOptions(city ? city.id : '');
|
||||
},
|
||||
handleDistrictChange(value) {
|
||||
@@ -1071,6 +1126,190 @@ export default {
|
||||
if (selection.latitude !== undefined && selection.latitude !== null && selection.latitude !== '') {
|
||||
this.form.latitude = Number(selection.latitude).toFixed(6);
|
||||
}
|
||||
this.applyMapRegionSelection(selection);
|
||||
},
|
||||
normalizeAmapCityName(city, province) {
|
||||
if (Array.isArray(city)) {
|
||||
return String(province || '').trim();
|
||||
}
|
||||
const cityName = String(city || '').trim();
|
||||
return cityName || String(province || '').trim();
|
||||
},
|
||||
buildRegionLookupCodes(adcode) {
|
||||
const code = String(adcode || '').trim();
|
||||
if (!code) {
|
||||
return [];
|
||||
}
|
||||
const codes = [code];
|
||||
if (/^\d{6}$/.test(code)) {
|
||||
if (code.endsWith('00')) {
|
||||
const cityCode = code.slice(0, 4);
|
||||
if (cityCode && !codes.includes(cityCode)) {
|
||||
codes.push(cityCode);
|
||||
}
|
||||
}
|
||||
if (code.endsWith('0000')) {
|
||||
const provinceCode = code.slice(0, 2);
|
||||
if (provinceCode && !codes.includes(provinceCode)) {
|
||||
codes.push(provinceCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
return codes;
|
||||
},
|
||||
fetchRegionDetailByCodes(codes = []) {
|
||||
const tryNext = index => {
|
||||
if (index >= codes.length) {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
return getRegionDetail(codes[index])
|
||||
.then(res => {
|
||||
const detail = res.data && res.data.data;
|
||||
if (detail && detail.code) {
|
||||
return detail;
|
||||
}
|
||||
return tryNext(index + 1);
|
||||
})
|
||||
.catch(() => tryNext(index + 1));
|
||||
};
|
||||
return tryNext(0);
|
||||
},
|
||||
resolveCountryFromRegionDetail(detail = {}) {
|
||||
const ancestors = String(detail.ancestors || '')
|
||||
.split(',')
|
||||
.map(item => String(item || '').trim())
|
||||
.filter(Boolean);
|
||||
for (let index = 0; index < ancestors.length; index += 1) {
|
||||
const ancestorCode = ancestors[index];
|
||||
if (this.countryOptions.some(item => item.id === ancestorCode)) {
|
||||
return ancestorCode;
|
||||
}
|
||||
}
|
||||
if (
|
||||
detail.parentCode &&
|
||||
Number(detail.regionLevel) === 1 &&
|
||||
this.countryOptions.some(item => item.id === String(detail.parentCode))
|
||||
) {
|
||||
return String(detail.parentCode);
|
||||
}
|
||||
if (/^\d{6}$/.test(String(detail.code || ''))) {
|
||||
return DEFAULT_COUNTRY_CODE;
|
||||
}
|
||||
return '';
|
||||
},
|
||||
applyRegionDetail(detail = {}) {
|
||||
const countryHint = this.resolveCountryFromRegionDetail(detail);
|
||||
return this.resolveCountryCode(countryHint || DEFAULT_COUNTRY_CODE)
|
||||
.then(countryCode => {
|
||||
this.form.countryCode = countryCode;
|
||||
this.syncCountryName(countryCode);
|
||||
return this.loadProvinceOptions(countryCode);
|
||||
})
|
||||
.then(() => {
|
||||
this.form.provinceCode =
|
||||
String(detail.provinceCode || '') || this.resolveProvinceCode(detail.provinceName);
|
||||
const province = this.provinceOptions.find(item => item.id === this.form.provinceCode);
|
||||
this.form.provinceName = province ? province.title : detail.provinceName || '';
|
||||
return this.loadCityOptions(this.form.provinceCode);
|
||||
})
|
||||
.then(() => {
|
||||
this.form.cityCode =
|
||||
String(detail.cityCode || '') ||
|
||||
this.resolveCityCode(detail.cityName, detail.districtCode || detail.code);
|
||||
const city = this.cityOptions.find(item => item.id === this.form.cityCode);
|
||||
this.form.city = city ? city.title : detail.cityName || '';
|
||||
return this.loadDistrictOptions(this.form.cityCode);
|
||||
})
|
||||
.then(() => {
|
||||
this.form.districtCode = this.resolveDistrictCode(
|
||||
detail.districtName || detail.name,
|
||||
detail.districtCode || detail.code
|
||||
);
|
||||
this.handleDistrictChange(this.form.districtCode);
|
||||
});
|
||||
},
|
||||
applyMapRegionByNames(selection = {}) {
|
||||
const provinceName = String(selection.province || selection.provinceName || '').trim();
|
||||
const cityName = this.normalizeAmapCityName(
|
||||
selection.city || selection.cityName,
|
||||
provinceName
|
||||
);
|
||||
const districtName = String(selection.district || selection.districtName || '').trim();
|
||||
const countryName = String(selection.country || selection.countryName || '').trim();
|
||||
const adcode = String(selection.adcode || selection.regionCode || '').trim();
|
||||
const countryPromise = countryName
|
||||
? this.resolveCountryCode(countryName)
|
||||
: Promise.resolve(/^\d{6}$/.test(adcode) ? DEFAULT_COUNTRY_CODE : '');
|
||||
return countryPromise
|
||||
.then(countryCode => {
|
||||
if (!countryCode) {
|
||||
return null;
|
||||
}
|
||||
this.form.countryCode = countryCode;
|
||||
this.syncCountryName(countryCode);
|
||||
return this.loadProvinceOptions(countryCode);
|
||||
})
|
||||
.then(provinces => {
|
||||
if (!provinces) {
|
||||
return null;
|
||||
}
|
||||
this.form.provinceCode = this.resolveProvinceCode(provinceName);
|
||||
const province = this.provinceOptions.find(item => item.id === this.form.provinceCode);
|
||||
this.form.provinceName = province ? province.title : provinceName;
|
||||
if (!this.form.provinceCode) {
|
||||
this.clearCityValue();
|
||||
return null;
|
||||
}
|
||||
return this.loadCityOptions(this.form.provinceCode);
|
||||
})
|
||||
.then(cities => {
|
||||
if (!cities) {
|
||||
return null;
|
||||
}
|
||||
this.form.cityCode = this.resolveCityCode(cityName, adcode);
|
||||
const city = this.cityOptions.find(item => item.id === this.form.cityCode);
|
||||
this.form.city = city ? city.title : cityName;
|
||||
if (!this.form.cityCode) {
|
||||
this.clearDistrictValue();
|
||||
return null;
|
||||
}
|
||||
return this.loadDistrictOptions(this.form.cityCode);
|
||||
})
|
||||
.then(districts => {
|
||||
if (!districts) {
|
||||
return;
|
||||
}
|
||||
this.form.districtCode = this.resolveDistrictCode(districtName, adcode);
|
||||
this.handleDistrictChange(this.form.districtCode);
|
||||
});
|
||||
},
|
||||
applyMapRegionSelection(selection = {}) {
|
||||
if (this.isParentRegionLocked) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
const adcode = String(selection.adcode || selection.regionCode || '').trim();
|
||||
const hasNameHint = Boolean(
|
||||
selection.country ||
|
||||
selection.countryName ||
|
||||
selection.province ||
|
||||
selection.provinceName ||
|
||||
selection.city ||
|
||||
selection.cityName ||
|
||||
selection.district ||
|
||||
selection.districtName
|
||||
);
|
||||
if (!adcode && !hasNameHint) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
const lookupCodes = this.buildRegionLookupCodes(adcode);
|
||||
return this.fetchRegionDetailByCodes(lookupCodes)
|
||||
.then(detail => {
|
||||
if (detail) {
|
||||
return this.applyRegionDetail(detail);
|
||||
}
|
||||
return this.applyMapRegionByNames(selection);
|
||||
})
|
||||
.catch(() => this.applyMapRegionByNames(selection));
|
||||
},
|
||||
resolveCountryCode(country) {
|
||||
if (!country) {
|
||||
@@ -1443,42 +1682,14 @@ export default {
|
||||
</style>
|
||||
|
||||
<style lang="scss">
|
||||
/* 港口码头编辑/新增弹窗:对齐 railway-station 统一风格(灰底 + 白卡表单 + 浮动底栏,padding 24px 与全局弹窗标准一致) */
|
||||
//.port-terminal-edit-dialog {
|
||||
// /* 灰底内容区 */
|
||||
// .el-dialog__body {
|
||||
// background-color: #f2f2f2;
|
||||
// padding: 8px;
|
||||
// }
|
||||
// /* 表单白卡(与全局 .el-dialog .avue-form 一致,padding 24px 对齐 customer-archive / railway-station) */
|
||||
// .avue-form {
|
||||
// background: #fff;
|
||||
// border-radius: 6px;
|
||||
// box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
|
||||
// padding: 24px !important;
|
||||
// margin-bottom: 0;
|
||||
// }
|
||||
// /* 底部按钮区白卡(Avue 弹窗 footer 在 body 内,接续白卡) */
|
||||
// .avue-dialog__footer {
|
||||
// background: #fff;
|
||||
// border-radius: 0 0 6px 6px;
|
||||
// box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
|
||||
// padding: 16px 24px !important;
|
||||
// display: flex;
|
||||
// justify-content: flex-end;
|
||||
// }
|
||||
// /* label 宽度统一 108px(对齐 railway-station,标签对齐更整齐) */
|
||||
// .el-form-item__label {
|
||||
// width: 108px !important;
|
||||
// }
|
||||
// /* 所有 input 文本框、select 下拉控件统一宽度 250px */
|
||||
// .el-input,
|
||||
// .el-select {
|
||||
// width: 250px !important;
|
||||
// }
|
||||
// /* 备注宽度 85% */
|
||||
// .remark-input {
|
||||
// width: 85% !important;
|
||||
// }
|
||||
//}
|
||||
/* 港口码头编辑/新增弹窗:表单项行间距略高于全局默认 */
|
||||
.port-terminal-edit-dialog {
|
||||
.el-form-item,
|
||||
.el-form-item--default.el-form-item,
|
||||
.el-form-item--small.el-form-item,
|
||||
.el-form-item--large.el-form-item,
|
||||
.el-form-item--medium.el-form-item {
|
||||
margin-bottom: 22px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -171,7 +171,12 @@ export default {
|
||||
}
|
||||
};
|
||||
const validateTelegraphCode = (rule, value, callback) => {
|
||||
if (!/^[A-Z]{3}$/.test(String(value || '').toUpperCase())) {
|
||||
const telegraphCode = String(value || '').trim();
|
||||
if (!telegraphCode) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
if (!/^[A-Z]{3}$/.test(telegraphCode.toUpperCase())) {
|
||||
callback(new Error('电报略码格式不正确或已存在'));
|
||||
} else {
|
||||
callback();
|
||||
@@ -273,10 +278,7 @@ export default {
|
||||
prop: 'telegraphCode',
|
||||
minWidth: 100,
|
||||
maxlength: 3,
|
||||
rules: [
|
||||
{ required: true, message: '电报略码格式不正确或已存在', trigger: 'blur' },
|
||||
{ validator: validateTelegraphCode, trigger: 'blur' },
|
||||
],
|
||||
rules: [{ validator: validateTelegraphCode, trigger: 'blur' }],
|
||||
change: ({ value }) => this.handleTelegraphChange(value),
|
||||
blur: ({ value }) => this.handleTelegraphChange(value),
|
||||
},
|
||||
@@ -703,6 +705,7 @@ export default {
|
||||
},
|
||||
normalizeRow(row) {
|
||||
row.code = row.tmisCode ? `TL${row.tmisCode}` : row.code;
|
||||
row.telegraphCode = String(row.telegraphCode || '').trim() || undefined;
|
||||
row.regionCode = String(row.regionCode || '').trim();
|
||||
row.regionName = String(row.regionName || '').trim();
|
||||
row.districtCode = String(row.districtCode || '').trim();
|
||||
@@ -735,14 +738,15 @@ export default {
|
||||
return records.some(item => item[prop] === row[prop] && String(item.id || '') !== rowId);
|
||||
});
|
||||
};
|
||||
return Promise.all([
|
||||
hasDuplicate({ tmisCode: row.tmisCode }, 'tmisCode'),
|
||||
hasDuplicate({ telegraphCode: row.telegraphCode }, 'telegraphCode'),
|
||||
]).then(([tmisExists, telegraphExists]) => {
|
||||
if (tmisExists) {
|
||||
const uniqueChecks = [hasDuplicate({ tmisCode: row.tmisCode }, 'tmisCode')];
|
||||
if (row.telegraphCode) {
|
||||
uniqueChecks.push(hasDuplicate({ telegraphCode: row.telegraphCode }, 'telegraphCode'));
|
||||
}
|
||||
return Promise.all(uniqueChecks).then(results => {
|
||||
if (results[0]) {
|
||||
return Promise.reject(new Error('该TMIS编码已存在'));
|
||||
}
|
||||
if (telegraphExists) {
|
||||
if (results[1]) {
|
||||
return Promise.reject(new Error('电报略码格式不正确或已存在'));
|
||||
}
|
||||
return Promise.resolve();
|
||||
|
||||
@@ -352,7 +352,8 @@ export default {
|
||||
return result;
|
||||
},
|
||||
normalizeListQuery(params = {}) {
|
||||
const query = { ...params, ...this.query };
|
||||
// 搜索条件优先于缓存的 query,避免默认组织 ID 覆盖用户新选择的组织。
|
||||
const query = { ...this.query, ...params };
|
||||
const rawDeptId = query.deptId ?? query.searchDeptId;
|
||||
delete query.searchDeptId;
|
||||
if (rawDeptId !== undefined && rawDeptId !== null && String(rawDeptId).trim() !== '') {
|
||||
|
||||
@@ -415,19 +415,27 @@ export default {
|
||||
});
|
||||
},
|
||||
buildDeptTree(tree) {
|
||||
return tree.map(item => ({
|
||||
label: item.title || item.deptName || item.name,
|
||||
value: item.id,
|
||||
children:
|
||||
item.children && item.children.length ? this.buildDeptTree(item.children) : undefined,
|
||||
}));
|
||||
return tree.map(item => {
|
||||
// 雪花 ID 必须保持字符串,避免 JS Number 精度丢失导致筛错组织。
|
||||
const id =
|
||||
item.id === undefined || item.id === null || item.id === '' ? '' : String(item.id);
|
||||
return {
|
||||
label: item.title || item.deptName || item.name,
|
||||
value: id,
|
||||
children:
|
||||
item.children && item.children.length ? this.buildDeptTree(item.children) : undefined,
|
||||
};
|
||||
}).filter(item => item.value);
|
||||
},
|
||||
flattenDept(tree, level = 0) {
|
||||
const result = [];
|
||||
tree.forEach(item => {
|
||||
const id =
|
||||
item.id === undefined || item.id === null || item.id === '' ? '' : String(item.id);
|
||||
if (!id) return;
|
||||
result.push({
|
||||
label: `${' '.repeat(level)}${item.title || item.deptName || item.name}`,
|
||||
value: item.id,
|
||||
value: id,
|
||||
});
|
||||
if (item.children && item.children.length) {
|
||||
result.push(...this.flattenDept(item.children, level + 1));
|
||||
@@ -445,7 +453,8 @@ export default {
|
||||
);
|
||||
},
|
||||
normalizeListQuery(params = {}) {
|
||||
const query = { ...params, ...this.query };
|
||||
// 搜索条件优先于缓存的 query,避免默认组织 ID 覆盖用户新选择的组织。
|
||||
const query = { ...this.query, ...params };
|
||||
const rawDeptId = query.deptId ?? query.searchDeptId;
|
||||
delete query.searchDeptId;
|
||||
if (rawDeptId !== undefined && rawDeptId !== null && String(rawDeptId).trim() !== '') {
|
||||
|
||||
@@ -215,7 +215,7 @@
|
||||
<el-option
|
||||
v-for="item in contractOptions"
|
||||
:key="item.id"
|
||||
:label="item.contractName"
|
||||
:label="formatContractOptionLabel(item)"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
@@ -3056,7 +3056,7 @@
|
||||
<el-option
|
||||
v-for="item in transportPlanImportContractOptions"
|
||||
:key="item.id"
|
||||
:label="item.contractName"
|
||||
:label="formatContractOptionLabel(item)"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
@@ -5242,6 +5242,7 @@ import { addressTypeOptions } from '@/option/base/common-address';
|
||||
import { packageOptions } from '@/option/business/common';
|
||||
import { formatUpdateUserName } from '@/utils/audit';
|
||||
import { getToken, isAdministrator } from '@/utils/auth';
|
||||
import { formatContractOptionLabel } from '@/utils/contract';
|
||||
import { openImportDialog } from '@/utils/import-excel';
|
||||
import { normalizeMapSearchResults, searchAmapPlaceText } from '@/utils/map-search';
|
||||
import { loadMeasurementUnitOptions } from '@/utils/measurement-unit';
|
||||
@@ -6590,6 +6591,7 @@ export default {
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
formatContractOptionLabel,
|
||||
initStandaloneFormPage() {
|
||||
if (!this.isStandaloneFormPage) return;
|
||||
const mode = this.$route.query.mode === 'edit' ? 'edit' : 'add';
|
||||
|
||||
@@ -317,6 +317,7 @@
|
||||
<script>
|
||||
import * as api from '@/api/business/master-order';
|
||||
import { fetchDriversByCarrierOrganizations } from '@/utils/carrier-org-resource';
|
||||
import { formatContractOptionLabel } from '@/utils/contract';
|
||||
import { loadMeasurementUnitOptions } from '@/utils/measurement-unit';
|
||||
import { isMobile } from '@/utils/validate';
|
||||
|
||||
@@ -904,9 +905,11 @@ export default {
|
||||
},
|
||||
carrierOptionLabel(item) {
|
||||
const duplicateCount = this.carrierOptions.filter(option => option.carrierName === item.carrierName).length;
|
||||
return duplicateCount > 1
|
||||
? `${item.carrierName}(${item.contractName || item.contractId})`
|
||||
: item.carrierName;
|
||||
if (duplicateCount <= 1) {
|
||||
return item.carrierName;
|
||||
}
|
||||
const contractLabel = formatContractOptionLabel(item);
|
||||
return contractLabel ? `${item.carrierName}(${contractLabel})` : item.carrierName;
|
||||
},
|
||||
driverOptionLabel(item) { return item.driverName || item.name || ''; },
|
||||
driverOptionKey(item) { return item.id || item.driverId || this.driverOptionLabel(item) || item.mobile; },
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
><el-option
|
||||
v-for="contract in contracts"
|
||||
:key="contract.id"
|
||||
:label="contract.contractName"
|
||||
:label="formatContractOptionLabel(contract)"
|
||||
:value="contract.id" /></el-select></el-form-item></el-col
|
||||
><el-col :span="6"
|
||||
><el-form-item label="总单号" required
|
||||
@@ -589,6 +589,7 @@ import { getList as getCargoTypeList } from '@/api/base/cargo-type';
|
||||
import { getLazyTree as getRegionLazyTree } from '@/api/base/region';
|
||||
import { getList as getCommonCargoList } from '@/api/business/common-cargo';
|
||||
import { exportBlob, importBlob } from '@/api/common';
|
||||
import { formatContractOptionLabel } from '@/utils/contract';
|
||||
import { downloadFileByUrl, downloadXls } from '@/utils/util';
|
||||
import { OfficeBuilding, Search } from '@element-plus/icons-vue';
|
||||
import { ElImageViewer } from 'element-plus';
|
||||
@@ -784,6 +785,7 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
formatContractOptionLabel,
|
||||
defaultQuantityUnit() {
|
||||
return this.quantityUnitOptions[0] || '吨';
|
||||
},
|
||||
|
||||
@@ -113,7 +113,7 @@
|
||||
<el-option
|
||||
v-for="item in contractOptions"
|
||||
:key="item.id"
|
||||
:label="item.contractName"
|
||||
:label="formatContractOptionLabel(item)"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
@@ -1098,6 +1098,7 @@ import {
|
||||
import { getDictionary as getSystemDictionary } from '@/api/system/dict';
|
||||
import { getDictionary } from '@/api/system/dictbiz';
|
||||
import { packageOptions } from '@/option/business/common';
|
||||
import { formatContractOptionLabel } from '@/utils/contract';
|
||||
import { loadMeasurementUnitOptions } from '@/utils/measurement-unit';
|
||||
import { normalizeMapSearchResults, searchAmapPlaceText } from '@/utils/map-search';
|
||||
import { downloadFileByUrl, downloadXls } from '@/utils/util';
|
||||
@@ -1533,6 +1534,7 @@ export default {
|
||||
if (this.isStandaloneFormPage) this.$nextTick(() => this.initStandaloneFormPage());
|
||||
},
|
||||
methods: {
|
||||
formatContractOptionLabel,
|
||||
loadQuantityUnitOptions() {
|
||||
if (this.quantityUnitLoading) return this.quantityUnitLoadPromise;
|
||||
this.quantityUnitLoading = true;
|
||||
|
||||
@@ -149,7 +149,7 @@
|
||||
<el-option
|
||||
v-for="item in contractOptions"
|
||||
:key="item.id"
|
||||
:label="item.contractName"
|
||||
:label="formatContractOptionLabel(item)"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
@@ -980,7 +980,7 @@
|
||||
<el-option
|
||||
v-for="item in transportPlanImportContractOptions"
|
||||
:key="item.id"
|
||||
:label="item.contractName"
|
||||
:label="formatContractOptionLabel(item)"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
@@ -2741,6 +2741,7 @@ import { addressTypeOptions } from '@/option/base/common-address';
|
||||
import { packageOptions } from '@/option/business/common';
|
||||
import { formatUpdateUserName } from '@/utils/audit';
|
||||
import { getToken, isAdministrator } from '@/utils/auth';
|
||||
import { formatContractOptionLabel } from '@/utils/contract';
|
||||
import { normalizeMapSearchResults, searchAmapPlaceText } from '@/utils/map-search';
|
||||
import { loadMeasurementUnitOptions } from '@/utils/measurement-unit';
|
||||
import { applyTableMenuWidth } from '@/utils/table-menu';
|
||||
@@ -3721,6 +3722,7 @@ export default {
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
formatContractOptionLabel,
|
||||
initStandaloneFormPage() {
|
||||
if (!this.isStandaloneFormPage) return;
|
||||
const mode = this.$route.query.mode === 'edit' ? 'edit' : 'add';
|
||||
|
||||
@@ -374,7 +374,7 @@
|
||||
<el-option
|
||||
v-for="item in contracts"
|
||||
:key="item.id"
|
||||
:label="item.contractName"
|
||||
:label="formatContractOptionLabel(item)"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
@@ -610,6 +610,7 @@ import { getList as getProjectList } from '@/api/business/project-apply';
|
||||
import { getList as getDriverList } from '@/api/transportCapacity/driver';
|
||||
import { getDictionary } from '@/api/system/dictbiz';
|
||||
import * as api from '@/api/business/waybill-manage';
|
||||
import { formatContractOptionLabel } from '@/utils/contract';
|
||||
import { downloadXls } from '@/utils/util';
|
||||
import SectionCard from '@/components/section-card/main.vue';
|
||||
|
||||
@@ -1297,6 +1298,31 @@ const carrierChange = value => {
|
||||
form.carrierName = item.carrierName || '';
|
||||
if (!isSelfOperated.value) form.carrierContractId = item.carrierContractId || '';
|
||||
};
|
||||
const firstNotEmpty = (...values) => values.find(value => String(value ?? '').trim()) ?? '';
|
||||
const OPTIONAL_NUMBER_EMPTY_SENTINELS = [-1];
|
||||
const normalizeOptionalImportNumber = (value, emptySentinels = OPTIONAL_NUMBER_EMPTY_SENTINELS) => {
|
||||
if (!String(value ?? '').trim()) return null;
|
||||
return emptySentinels.some(sentinel => Number(value) === sentinel) ? null : value;
|
||||
};
|
||||
const normalizeImportRow = row => ({
|
||||
...row,
|
||||
mileage: normalizeOptionalImportNumber(
|
||||
firstNotEmpty(row.mileage, row['里程'], row['里程(km)'], row['里程(公里)'])
|
||||
),
|
||||
otherFeeTotal: normalizeOptionalImportNumber(
|
||||
firstNotEmpty(row.otherFeeTotal, row['其他费用合计'])
|
||||
),
|
||||
unitPrice: normalizeOptionalImportNumber(firstNotEmpty(row.unitPrice, row['单价'])),
|
||||
freight: normalizeOptionalImportNumber(firstNotEmpty(row.freight, row['运费'])),
|
||||
freightTotal: normalizeOptionalImportNumber(firstNotEmpty(row.freightTotal, row['运费合计'])),
|
||||
transportType: firstNotEmpty(
|
||||
row.transportType,
|
||||
row['运输类型'],
|
||||
row['*运输类型'],
|
||||
row['运输方式'],
|
||||
row['*运输方式']
|
||||
),
|
||||
});
|
||||
const fileChange = async (file, list) => {
|
||||
if (!projectInfoReady.value) {
|
||||
ElMessage.warning('请先选择项目、客户合同和承运信息,再导入运单明细');
|
||||
@@ -1370,6 +1396,9 @@ const fileChange = async (file, list) => {
|
||||
item[key] ??
|
||||
'';
|
||||
});
|
||||
['mileage', 'unitPrice', 'freight', 'otherFeeTotal', 'freightTotal'].forEach(prop => {
|
||||
row[prop] = normalizeOptionalImportNumber(row[prop]);
|
||||
});
|
||||
row.actualStartDate = normalizeImportDate(row.actualStartDate);
|
||||
row.actualEndDate = normalizeImportDate(row.actualEndDate);
|
||||
row.planStartDate = normalizeImportDate(row.planStartDate);
|
||||
@@ -1656,31 +1685,6 @@ const removeSelectedRows = () => {
|
||||
rowSelection.value = [];
|
||||
refreshDuplicateFlags();
|
||||
};
|
||||
const firstNotEmpty = (...values) => values.find(value => String(value ?? '').trim()) ?? '';
|
||||
const normalizeOptionalImportNumber = (value, emptySentinels = []) => {
|
||||
if (!String(value ?? '').trim()) return null;
|
||||
return emptySentinels.some(sentinel => Number(value) === sentinel) ? null : value;
|
||||
};
|
||||
const normalizeImportRow = row => ({
|
||||
...row,
|
||||
mileage: normalizeOptionalImportNumber(
|
||||
firstNotEmpty(row.mileage, row['里程'], row['里程(km)'], row['里程(公里)']),
|
||||
[-1]
|
||||
),
|
||||
otherFeeTotal: normalizeOptionalImportNumber(
|
||||
firstNotEmpty(row.otherFeeTotal, row['其他费用合计'])
|
||||
),
|
||||
unitPrice: normalizeOptionalImportNumber(firstNotEmpty(row.unitPrice, row['单价'])),
|
||||
freight: normalizeOptionalImportNumber(firstNotEmpty(row.freight, row['运费'])),
|
||||
freightTotal: normalizeOptionalImportNumber(firstNotEmpty(row.freightTotal, row['运费合计'])),
|
||||
transportType: firstNotEmpty(
|
||||
row.transportType,
|
||||
row['运输类型'],
|
||||
row['*运输类型'],
|
||||
row['运输方式'],
|
||||
row['*运输方式']
|
||||
),
|
||||
});
|
||||
const normalizeOptionalPlanId = value => {
|
||||
if (value === undefined || value === null || value === '') return null;
|
||||
return Number(value) === -1 || Number(value) <= 0 ? null : value;
|
||||
|
||||
@@ -212,7 +212,7 @@
|
||||
<el-option
|
||||
v-for="item in contractOptions"
|
||||
:key="item.id"
|
||||
:label="item.contractName"
|
||||
:label="formatContractOptionLabel(item)"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
@@ -3642,6 +3642,7 @@ import { addressTypeOptions } from '@/option/base/common-address';
|
||||
import { packageOptions } from '@/option/business/common';
|
||||
import { formatUpdateUserName } from '@/utils/audit';
|
||||
import { getToken, isAdministrator } from '@/utils/auth';
|
||||
import { formatContractOptionLabel } from '@/utils/contract';
|
||||
import { wgs84ToGcj02 } from '@/utils/coordinate';
|
||||
import { openImportDialog } from '@/utils/import-excel';
|
||||
import { normalizeMapSearchResults, searchAmapPlaceText } from '@/utils/map-search';
|
||||
@@ -4724,6 +4725,7 @@ export default {
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
formatContractOptionLabel,
|
||||
// 页面被 keep-alive 缓存/卸载时调用,关闭本页所有 append-to-body 的弹窗,
|
||||
// 避免 Teleport 出去的 DOM 残留在 body 上盖住后续页面(详见 data 里的说明)。
|
||||
closeInnerDialogs() {
|
||||
@@ -6958,9 +6960,11 @@ export default {
|
||||
applyFormDetail(row) {
|
||||
this.suppressTransportTypeClear = true;
|
||||
this.form = { ...(row || {}) };
|
||||
['quantity', 'mileage', 'unitPrice'].forEach(prop => {
|
||||
if (Number(this.form[prop]) === -1) this.form[prop] = '';
|
||||
});
|
||||
['quantity', 'mileage', 'unitPrice', 'otherFeeTotal', 'freight', 'freightTotal'].forEach(
|
||||
prop => {
|
||||
if (this.isSentinelMinusOne(this.form[prop])) this.form[prop] = '';
|
||||
}
|
||||
);
|
||||
if ([this.form.planId, this.form.planName].some(value => Number(value) === -1)) {
|
||||
this.form.planId = '';
|
||||
this.form.planName = '';
|
||||
@@ -7371,17 +7375,17 @@ export default {
|
||||
this.form.quantityUnit || taskInfo.quantityUnit || goodsInfo.quantityUnit || '吨';
|
||||
const mileage = this.form.mileage || taskInfo.mileage || goodsInfo.mileage || '';
|
||||
this.form.mileage = this.normalizeMileageValue(mileage);
|
||||
this.form.unitPrice = this.form.unitPrice || taskInfo.unitPrice || goodsInfo.unitPrice || '';
|
||||
this.form.unitPrice = this.normalizeOptionalAmount(
|
||||
this.form.unitPrice || taskInfo.unitPrice || goodsInfo.unitPrice || ''
|
||||
);
|
||||
['quantity', 'mileage', 'unitPrice'].forEach(prop => {
|
||||
if (Number(this.form[prop]) === -1) this.form[prop] = '';
|
||||
if (this.isSentinelMinusOne(this.form[prop])) this.form[prop] = '';
|
||||
});
|
||||
this.form.priceUnit =
|
||||
this.form.priceUnit || taskInfo.priceUnit || goodsInfo.priceUnit || '元/吨';
|
||||
this.form.otherFeeTotal =
|
||||
this.form.otherFeeTotal || taskInfo.otherFeeTotal || goodsInfo.otherFeeTotal || '';
|
||||
if (Number(this.form.otherFeeTotal) === -1) {
|
||||
this.form.otherFeeTotal = '';
|
||||
}
|
||||
this.form.otherFeeTotal = this.normalizeOptionalAmount(
|
||||
this.form.otherFeeTotal || taskInfo.otherFeeTotal || goodsInfo.otherFeeTotal || ''
|
||||
);
|
||||
this.form.estimatedStartTime =
|
||||
this.form.estimatedStartTime ||
|
||||
taskInfo.estimatedStartTime ||
|
||||
@@ -7463,7 +7467,7 @@ export default {
|
||||
},
|
||||
taskFullFreightGroupUnitPrice(group = {}) {
|
||||
const prices = (group.rows || [])
|
||||
.map(cargo => String(cargo.unitPrice ?? '').trim())
|
||||
.map(cargo => this.normalizeOptionalAmount(cargo.unitPrice))
|
||||
.filter(Boolean);
|
||||
if (!prices.length || prices.some(price => price !== prices[0])) return '';
|
||||
return prices[0];
|
||||
@@ -7526,10 +7530,21 @@ export default {
|
||||
},
|
||||
formatTaskFullFreightNumber(value) {
|
||||
if (value === undefined || value === null || String(value).trim() === '') return '';
|
||||
const number = Number(value || 0);
|
||||
if (this.isSentinelMinusOne(value)) return '';
|
||||
const number = Number(value);
|
||||
if (!Number.isFinite(number)) return '';
|
||||
return Number(number.toFixed(2)).toString();
|
||||
},
|
||||
isSentinelMinusOne(value) {
|
||||
if (value === undefined || value === null || value === '') return false;
|
||||
return Number(value) === -1 || String(value).trim() === '-1';
|
||||
},
|
||||
normalizeOptionalAmount(value) {
|
||||
if (value === undefined || value === null || value === '' || this.isSentinelMinusOne(value)) {
|
||||
return '';
|
||||
}
|
||||
return value;
|
||||
},
|
||||
handleTaskCarrierTypeChange(value) {
|
||||
const nextValue = value || '承运商';
|
||||
this.form.carrierName = '';
|
||||
@@ -8082,7 +8097,9 @@ export default {
|
||||
}
|
||||
cargo.priceUnit = cargo.priceUnit || this.form.priceUnit || '元/吨';
|
||||
if (this.isBillingFieldEmpty(cargo.freightAmount)) {
|
||||
cargo.freightAmount = freightItems[index]?.freightAmount ?? '';
|
||||
cargo.freightAmount = this.normalizeOptionalAmount(
|
||||
freightItems[index]?.freightAmount ?? ''
|
||||
);
|
||||
}
|
||||
return cargo;
|
||||
});
|
||||
@@ -8274,8 +8291,10 @@ export default {
|
||||
},
|
||||
syncTaskInfoToRow(row) {
|
||||
row.taskEntryMode = row.taskEntryMode || 'simple';
|
||||
['quantity', 'mileage', 'unitPrice'].forEach(prop => {
|
||||
if (this.isBillingFieldEmpty(row[prop]) || Number(row[prop]) === -1) row[prop] = '';
|
||||
['quantity', 'mileage', 'unitPrice', 'otherFeeTotal'].forEach(prop => {
|
||||
if (this.isBillingFieldEmpty(row[prop]) || this.isSentinelMinusOne(row[prop])) {
|
||||
row[prop] = '';
|
||||
}
|
||||
});
|
||||
const taskInfo = {
|
||||
taskEntryMode: row.taskEntryMode,
|
||||
@@ -8300,7 +8319,7 @@ export default {
|
||||
priceUnit: row.priceUnit,
|
||||
taskRemark: row.taskRemark,
|
||||
};
|
||||
if (!this.isBillingFieldEmpty(row.otherFeeTotal) && Number(row.otherFeeTotal) !== -1) {
|
||||
if (!this.isBillingFieldEmpty(row.otherFeeTotal) && !this.isSentinelMinusOne(row.otherFeeTotal)) {
|
||||
taskInfo.otherFeeTotal = row.otherFeeTotal;
|
||||
} else {
|
||||
delete row.otherFeeTotal;
|
||||
@@ -8434,10 +8453,12 @@ export default {
|
||||
cargoName: row.cargoName || row.goodsName || '',
|
||||
packageType: row.packageType || row.package || '',
|
||||
specification: row.specification || row.spec || '',
|
||||
freightAmount: row.freightAmount ?? row.amount ?? row.totalAmount ?? '',
|
||||
freightAmount: this.normalizeOptionalAmount(
|
||||
row.freightAmount ?? row.amount ?? row.totalAmount ?? ''
|
||||
),
|
||||
};
|
||||
['quantity', 'mileage', 'unitPrice'].forEach(prop => {
|
||||
if (Number(cargo[prop]) === -1) cargo[prop] = '';
|
||||
['quantity', 'mileage', 'unitPrice', 'freightAmount'].forEach(prop => {
|
||||
if (this.isSentinelMinusOne(cargo[prop])) cargo[prop] = '';
|
||||
});
|
||||
return cargo;
|
||||
},
|
||||
@@ -8680,7 +8701,12 @@ export default {
|
||||
}
|
||||
},
|
||||
isBillingFieldEmpty(value) {
|
||||
return value === undefined || value === null || String(value).trim() === '';
|
||||
return (
|
||||
value === undefined ||
|
||||
value === null ||
|
||||
String(value).trim() === '' ||
|
||||
this.isSentinelMinusOne(value)
|
||||
);
|
||||
},
|
||||
ensureTransportTypeBeforeAddress() {
|
||||
if (!this.shippingInfoFormEnabled || !this.isBillingFieldEmpty(this.form.transportType)) {
|
||||
|
||||
@@ -1383,7 +1383,11 @@
|
||||
<el-option
|
||||
v-for="item in taskCarrierOptions"
|
||||
:key="item.id || item.carrierName"
|
||||
:label="item.carrierName || item.partyB"
|
||||
:label="
|
||||
dialogForm.carrierType === '承运商'
|
||||
? formatTaskCarrierContractLabel(item)
|
||||
: item.carrierName || item.partyB
|
||||
"
|
||||
:value="
|
||||
dialogForm.carrierType === '承运商'
|
||||
? item.id
|
||||
@@ -1699,6 +1703,7 @@ import { getParentOptions as getCargoTypeOptions } from '@/api/base/cargo-type';
|
||||
import { getList as getCustomerList } from '@/api/vehicle/customer-archive';
|
||||
import { getList as getDriverList } from '@/api/transportCapacity/driver';
|
||||
import { fetchDriversByCarrierOrganizations } from '@/utils/carrier-org-resource';
|
||||
import { formatContractOptionLabel } from '@/utils/contract';
|
||||
import {
|
||||
getList as getProcessConfigList,
|
||||
getDetail as getProcessConfigDetail,
|
||||
@@ -2174,6 +2179,14 @@ export default {
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
formatTaskCarrierContractLabel(item = {}) {
|
||||
const carrierName = item.carrierName || item.partyB || '';
|
||||
const contractLabel = formatContractOptionLabel(item);
|
||||
if (carrierName && contractLabel) {
|
||||
return `${carrierName}(${contractLabel})`;
|
||||
}
|
||||
return carrierName || contractLabel;
|
||||
},
|
||||
syncStandaloneTagTitle() {
|
||||
if (!this.isStandalonePage) return;
|
||||
const title = this.isStandaloneDetailPage ? this.detailPageTitle : this.formPageDefaultTitle;
|
||||
|
||||
@@ -573,7 +573,7 @@
|
||||
type="textarea"
|
||||
:rows="2"
|
||||
placeholder="请输入"
|
||||
maxlength="200"
|
||||
maxlength="1000"
|
||||
show-word-limit
|
||||
/>
|
||||
</el-form-item>
|
||||
@@ -583,7 +583,7 @@
|
||||
type="textarea"
|
||||
:rows="2"
|
||||
placeholder="请输入"
|
||||
maxlength="200"
|
||||
maxlength="1000"
|
||||
show-word-limit
|
||||
/>
|
||||
</el-form-item>
|
||||
@@ -593,7 +593,7 @@
|
||||
type="textarea"
|
||||
:rows="2"
|
||||
placeholder="请输入"
|
||||
maxlength="200"
|
||||
maxlength="1000"
|
||||
show-word-limit
|
||||
/>
|
||||
</el-form-item>
|
||||
@@ -603,7 +603,7 @@
|
||||
type="textarea"
|
||||
:rows="2"
|
||||
placeholder="请输入"
|
||||
maxlength="200"
|
||||
maxlength="1000"
|
||||
show-word-limit
|
||||
/>
|
||||
</el-form-item>
|
||||
@@ -1188,6 +1188,18 @@ export default {
|
||||
changeReason: [
|
||||
{ max: 2000, message: '变更原因不能超过2000个字符', trigger: 'blur' },
|
||||
],
|
||||
projectIntro: [
|
||||
{ max: 1000, message: '项目简介不能超过1000个字符', trigger: 'blur' },
|
||||
],
|
||||
profitRemark: [
|
||||
{ max: 1000, message: '盈利模式及利润测算情况说明不能超过1000个字符', trigger: 'blur' },
|
||||
],
|
||||
riskPoint: [
|
||||
{ max: 1000, message: '项目风险点不能超过1000个字符', trigger: 'blur' },
|
||||
],
|
||||
emergencyPlan: [
|
||||
{ max: 1000, message: '风险防范措施及应急预案不能超过1000个字符', trigger: 'blur' },
|
||||
],
|
||||
},
|
||||
deptOptions: [],
|
||||
businessDeptTreeOptions: [],
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
<el-option
|
||||
v-for="item in contractOptions"
|
||||
:key="item.id"
|
||||
:label="item.contractName"
|
||||
:label="formatContractOptionLabel(item)"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
@@ -165,6 +165,7 @@ import { getList as getContractList } from '@/api/business/contract-manage';
|
||||
import { getList as getProjectList } from '@/api/business/project-apply';
|
||||
import { importTransportPlan, validateTransportPlan } from '@/api/business/transport-plan';
|
||||
import { config } from '@/option/business/transport-plan';
|
||||
import { formatContractOptionLabel } from '@/utils/contract';
|
||||
import { downloadXls } from '@/utils/util';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
@@ -271,6 +272,7 @@ export default {
|
||||
this.loadProjectOptions();
|
||||
},
|
||||
methods: {
|
||||
formatContractOptionLabel,
|
||||
loadProjectOptions() {
|
||||
if (this.projectLoading) return;
|
||||
this.projectLoading = true;
|
||||
|
||||
@@ -100,7 +100,7 @@
|
||||
<el-option
|
||||
v-for="item in contractOptions"
|
||||
:key="item.id"
|
||||
:label="item.contractName || item.contractNo"
|
||||
:label="formatContractOptionLabel(item)"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
@@ -661,6 +661,7 @@ import {
|
||||
getList as getCustomerArchiveList,
|
||||
} from '@/api/vehicle/customer-archive';
|
||||
import { readSettlementTransfer, removeSettlementTransfer } from '@/utils/settlement-transfer';
|
||||
import { formatContractOptionLabel } from '@/utils/contract';
|
||||
import { downloadFileByUrl } from '@/utils/util';
|
||||
import { submitMkApprovalFlow } from '@/utils/mk-approval';
|
||||
import PdfPreview from '@/components/pdf-preview/main.vue';
|
||||
@@ -1021,6 +1022,7 @@ export default {
|
||||
this.initialize();
|
||||
},
|
||||
methods: {
|
||||
formatContractOptionLabel,
|
||||
hasPermission(code) {
|
||||
return this.permission?.[code] !== false;
|
||||
},
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
<el-option
|
||||
v-for="item in contracts"
|
||||
:key="item.id"
|
||||
:label="`${item.contractNo} / ${item.contractName}`"
|
||||
:label="formatContractOptionLabel(item)"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
@@ -980,6 +980,7 @@ import { getDictionary } from '@/api/system/dictbiz';
|
||||
import { h } from 'vue';
|
||||
import { InfoFilled } from '@element-plus/icons-vue';
|
||||
import { mapGetters } from 'vuex';
|
||||
import { formatContractOptionLabel } from '@/utils/contract';
|
||||
import { downloadFileByUrl } from '@/utils/util';
|
||||
import * as XLSX from 'xlsx';
|
||||
|
||||
@@ -1215,6 +1216,7 @@ export default {
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
formatContractOptionLabel,
|
||||
async loadFormalDetail(id) {
|
||||
const response = this.publicMode
|
||||
? await getMkPublicDetail('formal-settlement', id)
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<el-form-item :label="field.label" :prop="field.prop">
|
||||
<el-input
|
||||
v-if="field.type === 'contract'"
|
||||
v-model="form.contractName"
|
||||
:model-value="formatContractOptionLabel(form)"
|
||||
readonly
|
||||
:disabled="!editable || details.length > 0"
|
||||
placeholder="请选择合同"
|
||||
@@ -962,6 +962,7 @@ import {
|
||||
settlementDetailColumns,
|
||||
settlementSummaryColumns,
|
||||
} from '@/option/settlement/preSettlementTable';
|
||||
import { formatContractOptionLabel } from '@/utils/contract';
|
||||
import { downloadFileByUrl } from '@/utils/util';
|
||||
import { submitMkApprovalFlow } from '@/utils/mk-approval';
|
||||
import * as XLSX from 'xlsx';
|
||||
@@ -1265,6 +1266,7 @@ export default {
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
formatContractOptionLabel,
|
||||
hasPermission(code) {
|
||||
return this.isAdmin || this.validData(this.permission?.[code], false);
|
||||
},
|
||||
|
||||
@@ -957,6 +957,7 @@ import { getContractOptions as getSettlementContractOptions } from '@/api/settle
|
||||
import { getList as getCargoTypeList } from '@/api/base/cargo-type';
|
||||
import { exportBlob } from '@/api/common';
|
||||
import { getDictionary } from '@/api/system/dictbiz';
|
||||
import { formatContractOptionLabel } from '@/utils/contract';
|
||||
import { downloadXls } from '@/utils/util';
|
||||
import { createSettlementTransfer } from '@/utils/settlement-transfer';
|
||||
import {
|
||||
@@ -1103,14 +1104,14 @@ export default {
|
||||
const contract = this.contractOptions.find(
|
||||
item => String(item.id) === String(this.generateQuery.contractId)
|
||||
);
|
||||
return contract?.contractName || '';
|
||||
return formatContractOptionLabel(contract);
|
||||
},
|
||||
updateContractName() {
|
||||
const contractId = this.updateFeeForm.contractId;
|
||||
const contract = [...this.updateContractOptions, ...this.contractOptions].find(
|
||||
item => String(item.id) === String(contractId)
|
||||
);
|
||||
return contract?.contractName || '';
|
||||
return formatContractOptionLabel(contract);
|
||||
},
|
||||
generateContractCategory() {
|
||||
return this.settlementType === 'payable' ? '承运商合同' : '客户合同';
|
||||
|
||||
@@ -1292,17 +1292,20 @@ export default {
|
||||
handleExport() {
|
||||
const account = func.toStr(this.search.account);
|
||||
const realName = func.toStr(this.search.realName);
|
||||
const phone = func.toStr(this.search.phone);
|
||||
this.$confirm('是否导出用户数据?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
}).then(() => {
|
||||
NProgress.start();
|
||||
exportBlob(
|
||||
`/blade-system/user/export-user?${
|
||||
this.website.tokenHeader
|
||||
}=${getToken()}&account=${account}&realName=${realName}`
|
||||
).then(res => {
|
||||
const params = new URLSearchParams({
|
||||
[this.website.tokenHeader]: getToken(),
|
||||
});
|
||||
if (account) params.set('account', account);
|
||||
if (realName) params.set('realName', realName);
|
||||
if (phone) params.set('phone', phone);
|
||||
exportBlob(`/blade-system/user/export-user?${params.toString()}`).then(res => {
|
||||
downloadXls(res.data, `用户数据表${this.$dayjs().format('YYYY-MM-DD')}.xlsx`);
|
||||
NProgress.done();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user