fix bug
This commit is contained in:
@@ -0,0 +1,252 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="visible"
|
||||
title="地图选择地址"
|
||||
width="920px"
|
||||
append-to-body
|
||||
@opened="initMap"
|
||||
>
|
||||
<div class="address-map-picker__toolbar">
|
||||
<el-input
|
||||
v-model="keyword"
|
||||
clearable
|
||||
placeholder="输入地址关键词"
|
||||
@keyup.enter="searchKeyword"
|
||||
/>
|
||||
<el-button type="primary" :loading="searching" @click="searchKeyword">搜索</el-button>
|
||||
</div>
|
||||
<div ref="map" class="address-map-picker__map"></div>
|
||||
<div class="address-map-picker__info">{{ status }}</div>
|
||||
<template #footer>
|
||||
<el-button @click="visible = false">取消</el-button>
|
||||
<el-button type="primary" :disabled="!selected.longitude || resolving" @click="confirm">
|
||||
确定
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const AMAP_KEY = '653b7cf105ad7fb8ec9b2f5198ade315';
|
||||
const AMAP_SECURITY_CODE = '5aab65c632e48ebae0d0e28f5b28e21a';
|
||||
let amapLoader;
|
||||
|
||||
export default {
|
||||
props: {
|
||||
modelValue: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
address: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
emits: ['update:modelValue', 'confirm'],
|
||||
data() {
|
||||
return {
|
||||
visible: false,
|
||||
keyword: '',
|
||||
status: '可搜索地址或点击地图选点',
|
||||
searching: false,
|
||||
resolving: false,
|
||||
selected: {},
|
||||
amap: null,
|
||||
marker: null,
|
||||
geocoder: null,
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
modelValue: {
|
||||
immediate: true,
|
||||
handler(value) {
|
||||
this.visible = value;
|
||||
if (value) {
|
||||
this.keyword = this.address || '';
|
||||
this.selected = {};
|
||||
this.status = '可搜索地址或点击地图选点';
|
||||
}
|
||||
},
|
||||
},
|
||||
visible(value) {
|
||||
this.$emit('update:modelValue', value);
|
||||
},
|
||||
},
|
||||
beforeUnmount() {
|
||||
if (this.amap) {
|
||||
this.amap.destroy();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
loadAmap() {
|
||||
if (window.AMap && window.AMap.Map) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
if (!amapLoader) {
|
||||
amapLoader = new Promise((resolve, reject) => {
|
||||
window._AMapSecurityConfig = { securityJsCode: AMAP_SECURITY_CODE };
|
||||
const script = document.createElement('script');
|
||||
script.src = `https://webapi.amap.com/maps?v=2.0&key=${AMAP_KEY}`;
|
||||
script.async = true;
|
||||
script.onload = resolve;
|
||||
script.onerror = () => reject(new Error('高德地图组件加载失败'));
|
||||
document.body.appendChild(script);
|
||||
});
|
||||
}
|
||||
return amapLoader;
|
||||
},
|
||||
initMap() {
|
||||
this.loadAmap()
|
||||
.then(() => {
|
||||
this.$nextTick(() => {
|
||||
if (!this.amap) {
|
||||
this.amap = new window.AMap.Map(this.$refs.map, {
|
||||
center: [116.40769, 39.89945],
|
||||
zoom: 11,
|
||||
});
|
||||
this.amap.on('click', event => this.pickPoint(event.lnglat));
|
||||
} else {
|
||||
this.amap.resize();
|
||||
this.clearMarker();
|
||||
}
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
this.$message.error('高德地图组件加载失败,请稍后重试');
|
||||
this.visible = false;
|
||||
});
|
||||
},
|
||||
ensureGeocoder() {
|
||||
if (this.geocoder) return Promise.resolve(this.geocoder);
|
||||
return new Promise((resolve, reject) => {
|
||||
window.AMap.plugin(['AMap.Geocoder'], () => {
|
||||
try {
|
||||
this.geocoder = new window.AMap.Geocoder();
|
||||
resolve(this.geocoder);
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
runGeocode(action, input) {
|
||||
return this.ensureGeocoder().then(
|
||||
geocoder =>
|
||||
new Promise((resolve, reject) => {
|
||||
const done = (status, result) => {
|
||||
if (status === 'complete' && result) {
|
||||
resolve(result);
|
||||
} else {
|
||||
reject(new Error('高德地图请求失败'));
|
||||
}
|
||||
};
|
||||
if (action === 'location') {
|
||||
geocoder.getLocation(input, done);
|
||||
} else {
|
||||
geocoder.getAddress(input, done);
|
||||
}
|
||||
})
|
||||
);
|
||||
},
|
||||
searchKeyword() {
|
||||
const keyword = String(this.keyword || '').trim();
|
||||
if (!keyword) {
|
||||
this.$message.warning('请输入地址关键词');
|
||||
return;
|
||||
}
|
||||
this.searching = true;
|
||||
this.loadAmap()
|
||||
.then(() => this.runGeocode('location', keyword))
|
||||
.then(result => {
|
||||
const point = result.geocodes?.[0]?.location || result.location;
|
||||
if (!point) {
|
||||
throw new Error('未找到匹配地址');
|
||||
}
|
||||
this.pickPoint(point, keyword);
|
||||
})
|
||||
.catch(() => {
|
||||
this.status = '未找到匹配地址';
|
||||
this.$message.warning('地图搜索无匹配地址');
|
||||
})
|
||||
.finally(() => {
|
||||
this.searching = false;
|
||||
});
|
||||
},
|
||||
pickPoint(point, fallbackAddress = '') {
|
||||
const longitude = typeof point.getLng === 'function' ? point.getLng() : point.lng;
|
||||
const latitude = typeof point.getLat === 'function' ? point.getLat() : point.lat;
|
||||
if (!Number.isFinite(Number(longitude)) || !Number.isFinite(Number(latitude))) {
|
||||
this.$message.warning('选点坐标无效');
|
||||
return;
|
||||
}
|
||||
const lnglat = new window.AMap.LngLat(Number(longitude), Number(latitude));
|
||||
this.renderMarker(lnglat);
|
||||
this.selected = { longitude: Number(longitude), latitude: Number(latitude), address: fallbackAddress };
|
||||
this.status = '正在解析地址...';
|
||||
this.resolving = true;
|
||||
this.runGeocode('address', lnglat)
|
||||
.then(result => {
|
||||
const detailAddress = result.regeocode?.formattedAddress || fallbackAddress;
|
||||
this.selected = { ...this.selected, address: detailAddress };
|
||||
this.keyword = detailAddress || this.keyword;
|
||||
this.status = detailAddress || '已选点,可确认回填';
|
||||
})
|
||||
.catch(() => {
|
||||
this.status = '地址解析失败,请重新选点';
|
||||
this.$message.error('地址解析失败,请重新选点');
|
||||
this.selected = {};
|
||||
this.clearMarker();
|
||||
})
|
||||
.finally(() => {
|
||||
this.resolving = false;
|
||||
});
|
||||
},
|
||||
renderMarker(point) {
|
||||
this.clearMarker();
|
||||
this.marker = new window.AMap.Marker({ position: point });
|
||||
this.marker.setMap(this.amap);
|
||||
this.amap.setCenter(point);
|
||||
},
|
||||
clearMarker() {
|
||||
if (this.marker) {
|
||||
this.marker.setMap(null);
|
||||
this.marker = null;
|
||||
}
|
||||
},
|
||||
confirm() {
|
||||
if (!this.selected.address) {
|
||||
this.$message.warning('请等待地址解析完成后再确认');
|
||||
return;
|
||||
}
|
||||
this.$emit('confirm', this.selected.address);
|
||||
this.visible = false;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.address-map-picker {
|
||||
&__toolbar {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
margin-bottom: 12px;
|
||||
|
||||
.el-input {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
||||
&__map {
|
||||
width: 100%;
|
||||
height: 420px;
|
||||
border: 1px solid #eff1f7;
|
||||
}
|
||||
|
||||
&__info {
|
||||
margin-top: 10px;
|
||||
color: #606266;
|
||||
line-height: 1.6;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -202,6 +202,7 @@ export const option = createCrudOption([
|
||||
label: '单价',
|
||||
prop: 'cargoValue',
|
||||
formslot: true,
|
||||
formatter: row => (String(row.cargoValue) === '-1' ? '' : row.cargoValue),
|
||||
minWidth: 120,
|
||||
rules: [
|
||||
{
|
||||
@@ -277,6 +278,9 @@ export const option = createCrudOption([
|
||||
),
|
||||
]);
|
||||
|
||||
// 搜索栏标签统一加宽,给较长的货物类型字段预留足够展示空间。
|
||||
option.searchLabelWidth = 160;
|
||||
|
||||
export const excelOption = {
|
||||
submitBtn: false,
|
||||
emptyBtn: false,
|
||||
|
||||
@@ -50,6 +50,7 @@ export const option = {
|
||||
border: true,
|
||||
index: true,
|
||||
indexLabel: '序号',
|
||||
indexWidth: 90,
|
||||
viewBtn: true,
|
||||
selection: true,
|
||||
dialogClickModal: false,
|
||||
@@ -128,6 +129,7 @@ export const option = {
|
||||
prop: 'directEconomicLoss',
|
||||
type: 'input',
|
||||
formslot: true,
|
||||
append: '元',
|
||||
minWidth: 140,
|
||||
span: 12,
|
||||
placeholder: '请输入',
|
||||
@@ -138,6 +140,7 @@ export const option = {
|
||||
prop: 'insuranceClaimAmount',
|
||||
type: 'input',
|
||||
formslot: true,
|
||||
append: '元',
|
||||
minWidth: 140,
|
||||
span: 12,
|
||||
placeholder: '请输入',
|
||||
|
||||
@@ -49,6 +49,7 @@ export const option = {
|
||||
border: true,
|
||||
index: true,
|
||||
indexLabel: '序号',
|
||||
indexWidth: 90,
|
||||
viewBtn: true,
|
||||
selection: true,
|
||||
dialogClickModal: false,
|
||||
@@ -145,6 +146,7 @@ export const option = {
|
||||
prop: 'fee',
|
||||
type: 'input',
|
||||
formslot: true,
|
||||
append: '元',
|
||||
minWidth: 100,
|
||||
span: 12,
|
||||
placeholder: '请输入',
|
||||
|
||||
@@ -30,6 +30,7 @@ export const option = {
|
||||
border: true,
|
||||
index: true,
|
||||
indexLabel: '序号',
|
||||
indexWidth: 90,
|
||||
viewBtn: true,
|
||||
selection: true,
|
||||
dialogClickModal: false,
|
||||
|
||||
@@ -39,6 +39,7 @@ export const option = {
|
||||
border: true,
|
||||
index: true,
|
||||
indexLabel: '序号',
|
||||
indexWidth: 90,
|
||||
viewBtn: true,
|
||||
selection: true,
|
||||
dialogClickModal: false,
|
||||
|
||||
@@ -43,6 +43,7 @@ export const option = {
|
||||
border: true,
|
||||
index: true,
|
||||
indexLabel: '序号',
|
||||
indexWidth: 90,
|
||||
viewBtn: true,
|
||||
selection: true,
|
||||
dialogClickModal: false,
|
||||
|
||||
@@ -35,6 +35,7 @@ export const option = {
|
||||
border: true,
|
||||
index: true,
|
||||
indexLabel: '序号',
|
||||
indexWidth: 90,
|
||||
viewBtn: true,
|
||||
selection: true,
|
||||
dialogClickModal: false,
|
||||
@@ -70,6 +71,7 @@ export const option = {
|
||||
prop: 'previousMonthMileage',
|
||||
type: 'input',
|
||||
formslot: true,
|
||||
append: 'km',
|
||||
minWidth: 210,
|
||||
slot: true,
|
||||
rules: [{ validator: validateNonNegative, trigger: 'blur' }],
|
||||
@@ -79,6 +81,7 @@ export const option = {
|
||||
prop: 'currentMonthMileage',
|
||||
type: 'input',
|
||||
formslot: true,
|
||||
append: 'km',
|
||||
minWidth: 210,
|
||||
slot: true,
|
||||
rules: [{ validator: validateNonNegative, trigger: 'blur' }],
|
||||
@@ -88,6 +91,7 @@ export const option = {
|
||||
prop: 'monthlyMileage',
|
||||
type: 'input',
|
||||
formslot: true,
|
||||
append: 'km',
|
||||
minWidth: 170,
|
||||
slot: true,
|
||||
rules: [{ validator: validateNonNegative, trigger: 'blur' }],
|
||||
@@ -97,6 +101,7 @@ export const option = {
|
||||
prop: 'totalMileage',
|
||||
type: 'input',
|
||||
formslot: true,
|
||||
append: 'km',
|
||||
minWidth: 170,
|
||||
slot: true,
|
||||
rules: [{ validator: validateNonNegative, trigger: 'blur' }],
|
||||
|
||||
@@ -36,6 +36,7 @@ export const option = {
|
||||
border: true,
|
||||
index: true,
|
||||
indexLabel: '序号',
|
||||
indexWidth: 90,
|
||||
viewBtn: true,
|
||||
selection: true,
|
||||
dialogClickModal: false,
|
||||
@@ -123,6 +124,7 @@ export const option = {
|
||||
prop: 'unitPrice',
|
||||
type: 'input',
|
||||
formslot: true,
|
||||
append: '元/升',
|
||||
minWidth: 120,
|
||||
rules: [{ validator: validateNonNegative, trigger: 'blur' }],
|
||||
},
|
||||
|
||||
@@ -47,6 +47,7 @@ export const option = {
|
||||
border: true,
|
||||
index: true,
|
||||
indexLabel: '序号',
|
||||
indexWidth: 90,
|
||||
viewBtn: true,
|
||||
selection: true,
|
||||
dialogClickModal: false,
|
||||
|
||||
@@ -40,6 +40,7 @@ export const option = {
|
||||
border: true,
|
||||
index: true,
|
||||
indexLabel: '序号',
|
||||
indexWidth: 90,
|
||||
viewBtn: true,
|
||||
selection: true,
|
||||
dialogClickModal: false,
|
||||
|
||||
@@ -27,6 +27,7 @@ export const option = {
|
||||
border: true,
|
||||
index: true,
|
||||
indexLabel: '序号',
|
||||
indexWidth: 90,
|
||||
viewBtn: true,
|
||||
selection: true,
|
||||
dialogClickModal: false,
|
||||
|
||||
@@ -50,6 +50,7 @@ export const option = {
|
||||
border: true,
|
||||
index: true,
|
||||
indexLabel: '序号',
|
||||
indexWidth: 90,
|
||||
viewBtn: true,
|
||||
selection: true,
|
||||
dialogClickModal: false,
|
||||
@@ -127,6 +128,8 @@ export const option = {
|
||||
{
|
||||
label: '地点',
|
||||
prop: 'location',
|
||||
slot: true,
|
||||
formslot: true,
|
||||
minWidth: 180,
|
||||
overHidden: true,
|
||||
span: 12,
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
@row-del="rowDel"
|
||||
@search-change="searchChange"
|
||||
@search-reset="searchReset"
|
||||
@selection-change="selectionChange"
|
||||
@current-change="currentChange"
|
||||
@size-change="sizeChange"
|
||||
@refresh-change="refreshChange"
|
||||
@@ -40,6 +41,7 @@
|
||||
v-model="form.feeCategory"
|
||||
class="fee-item-form-control"
|
||||
clearable
|
||||
:disabled="dialogType !== 'add'"
|
||||
filterable
|
||||
placeholder="请选择费用类型"
|
||||
@change="handleFeeCategoryChange"
|
||||
@@ -58,6 +60,7 @@
|
||||
:maxlength="feeItemCodeMaxlength"
|
||||
class="fee-item-form-control"
|
||||
clearable
|
||||
:disabled="dialogType !== 'add'"
|
||||
placeholder="请输入费用项代码"
|
||||
@change="handleFeeItemCodeChange"
|
||||
>
|
||||
@@ -114,12 +117,14 @@ export default {
|
||||
data: [],
|
||||
excelBox: false,
|
||||
excelForm: {},
|
||||
dialogType: 'add',
|
||||
feeCategoryOptions: [],
|
||||
page: {
|
||||
pageSize: 10,
|
||||
currentPage: 1,
|
||||
total: 0,
|
||||
},
|
||||
selectionList: [],
|
||||
option: {
|
||||
height: 'auto',
|
||||
calcHeight: 32,
|
||||
@@ -139,7 +144,7 @@ export default {
|
||||
viewBtn: false,
|
||||
delBtn: false,
|
||||
editBtn: false,
|
||||
selection: false,
|
||||
selection: true,
|
||||
dialogClickModal: false,
|
||||
menuWidth: 180,
|
||||
column: [
|
||||
@@ -294,6 +299,9 @@ export default {
|
||||
feeItemCodeMaxlength() {
|
||||
return Math.max(1, 100 - this.feeCategoryPrefix.length);
|
||||
},
|
||||
ids() {
|
||||
return this.selectionList.map(item => item.id).join(',');
|
||||
},
|
||||
permissionList() {
|
||||
return {
|
||||
addBtn: this.validData(this.permission.fee_item_add, false),
|
||||
@@ -418,6 +426,7 @@ export default {
|
||||
});
|
||||
},
|
||||
beforeOpen(done, type) {
|
||||
this.dialogType = type || 'add';
|
||||
if (['edit', 'view'].includes(type)) {
|
||||
getDetail(this.form.id).then(res => {
|
||||
this.form = this.normalizeFormForEdit(res.data.data || {});
|
||||
@@ -439,6 +448,13 @@ export default {
|
||||
this.onLoad(this.page, params);
|
||||
done();
|
||||
},
|
||||
selectionChange(list) {
|
||||
this.selectionList = list;
|
||||
},
|
||||
selectionClear() {
|
||||
this.selectionList = [];
|
||||
this.$refs.crud.toggleSelection();
|
||||
},
|
||||
currentChange(currentPage) {
|
||||
this.page.currentPage = currentPage;
|
||||
},
|
||||
@@ -454,6 +470,7 @@ export default {
|
||||
buildExportParams() {
|
||||
return {
|
||||
...this.query,
|
||||
ids: this.ids,
|
||||
[this.website.tokenHeader]: getToken(),
|
||||
};
|
||||
},
|
||||
@@ -490,6 +507,7 @@ export default {
|
||||
const data = res.data.data;
|
||||
this.page.total = data.total;
|
||||
this.data = data.records;
|
||||
this.selectionClear();
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
|
||||
@@ -250,81 +250,6 @@ 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' });
|
||||
};
|
||||
|
||||
const newLocal = '请选择类型';
|
||||
export default {
|
||||
data() {
|
||||
@@ -1323,9 +1248,6 @@ export default {
|
||||
'港口码头主数据',
|
||||
() => {
|
||||
this.loadPortOptions();
|
||||
},
|
||||
{
|
||||
failDetailDecorator: removeWorkbookColumnsByHeaders,
|
||||
}
|
||||
);
|
||||
},
|
||||
@@ -1339,11 +1261,8 @@ export default {
|
||||
exportBlob('/blade-system/port-terminal/export-port-terminal', this.buildExportParams(), {
|
||||
feedback: true,
|
||||
})
|
||||
.then(async res => {
|
||||
const blob = await removeExcelColumnsByHeaders(res.data, {
|
||||
markRequiredHeaders: true,
|
||||
});
|
||||
downloadXls(blob, `港口码头主数据${this.$dayjs().format('YYYY-MM-DD HH:mm:ss')}.xlsx`);
|
||||
.then(res => {
|
||||
downloadXls(res.data, `港口码头主数据${this.$dayjs().format('YYYY-MM-DD HH:mm:ss')}.xlsx`);
|
||||
})
|
||||
.finally(() => {
|
||||
NProgress.done();
|
||||
@@ -1362,9 +1281,8 @@ export default {
|
||||
`/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');
|
||||
).then(res => {
|
||||
downloadXls(res.data, '港口码头主数据模板.xlsx');
|
||||
});
|
||||
},
|
||||
},
|
||||
|
||||
@@ -689,6 +689,7 @@ export default {
|
||||
feedback: true,
|
||||
}).then(res => {
|
||||
downloadXls(res.data, '行政区划模板.xlsx');
|
||||
this.$message.success('模板下载成功');
|
||||
});
|
||||
},
|
||||
},
|
||||
|
||||
@@ -399,8 +399,17 @@ export default {
|
||||
if (submitRow.cargoValue !== undefined && submitRow.cargoValue !== null) {
|
||||
submitRow.cargoValue = String(submitRow.cargoValue).trim();
|
||||
}
|
||||
if (!submitRow.cargoValue || String(submitRow.cargoValue) === '-1') {
|
||||
submitRow.cargoValue = null;
|
||||
}
|
||||
return submitRow;
|
||||
},
|
||||
normalizeCargoValue(row) {
|
||||
if (row && String(row.cargoValue) === '-1') {
|
||||
row.cargoValue = null;
|
||||
}
|
||||
return row;
|
||||
},
|
||||
validateRow(row) {
|
||||
if (!row.firstCargoTypeName || !row.firstCargoTypeCode) {
|
||||
this.$message.warning('请选择一级货物类型');
|
||||
@@ -539,7 +548,7 @@ export default {
|
||||
}
|
||||
if (['edit', 'view'].includes(type)) {
|
||||
api.getDetail(this.form.id).then(res => {
|
||||
this.form = res.data.data || {};
|
||||
this.form = this.normalizeCargoValue(res.data.data || {});
|
||||
this.ensureCargoTypeOption('firstCargoTypeOptions', {
|
||||
cargoName: this.form.firstCargoTypeName,
|
||||
cargoCode: this.form.firstCargoTypeCode,
|
||||
@@ -593,7 +602,7 @@ export default {
|
||||
.then(res => {
|
||||
const result = res.data.data;
|
||||
this.page.total = result.total;
|
||||
this.data = result.records;
|
||||
this.data = (result.records || []).map(row => this.normalizeCargoValue(row));
|
||||
this.selectionClear();
|
||||
})
|
||||
.finally(() => {
|
||||
@@ -654,6 +663,12 @@ export default {
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.common-cargo-page {
|
||||
// 仅缩短本页面筛选栏中的输入框和下拉框,避免影响表单及其他页面。
|
||||
:deep(.avue-crud__search .el-form-item__content > .el-input),
|
||||
:deep(.avue-crud__search .el-form-item__content > .el-select) {
|
||||
width: 70%;
|
||||
}
|
||||
|
||||
&__value-unit {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2105,7 +2105,7 @@
|
||||
</template>
|
||||
|
||||
<template #menu="{ row, index }">
|
||||
<template>
|
||||
<div class="business-crud-page__row-actions">
|
||||
<el-link type="primary" v-if="showDetailButton(row)" @click="openDetail(row)"
|
||||
>详情</el-link
|
||||
>
|
||||
@@ -2144,7 +2144,7 @@
|
||||
{{ operation.label }}
|
||||
</el-link>
|
||||
<el-link type="danger" v-if="canDelete(row)" @click="rowDel(row)"> 删除 </el-link>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
</component>
|
||||
|
||||
@@ -13281,6 +13281,13 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
&__row-actions {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
:deep(.business-crud-page__full-form-item) {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
|
||||
@@ -1705,6 +1705,10 @@ export default {
|
||||
departureAddress: this.form.arrivalAddress,
|
||||
departureContact: this.form.arrivalContact,
|
||||
departurePhone: this.form.arrivalPhone,
|
||||
departureLongitude: this.form.arrivalLongitude,
|
||||
departureLatitude: this.form.arrivalLatitude,
|
||||
departureRegionCode: this.form.arrivalRegionCode,
|
||||
departureSiteCode: this.form.arrivalSiteCode,
|
||||
transportType: this.form.finalTransportType,
|
||||
},
|
||||
],
|
||||
|
||||
@@ -580,29 +580,205 @@
|
||||
title="合同详情"
|
||||
append-to-body
|
||||
destroy-on-close
|
||||
width="1200px"
|
||||
class="contract-manage-detail-dialog"
|
||||
width="92%"
|
||||
top="4vh"
|
||||
>
|
||||
<div v-loading="detailLoading" class="contract-manage-detail">
|
||||
<section v-for="section in config.detailSections" :key="section.title">
|
||||
<div class="dialog-section-title">{{ section.title }}</div>
|
||||
<el-descriptions :column="3" border>
|
||||
<el-descriptions-item
|
||||
v-for="field in section.fields"
|
||||
:key="field[0]"
|
||||
:label="field[1]"
|
||||
:span="field[2] || 1"
|
||||
>
|
||||
{{ detailValue(field[0]) }}
|
||||
</el-descriptions-item>
|
||||
<div v-loading="detailLoading" class="contract-manage-form contract-manage-detail">
|
||||
<section class="contract-manage-form__section contract-manage-form__section--panel">
|
||||
<div class="dialog-section-title">基本信息</div>
|
||||
<el-descriptions :column="3" class="contract-manage-detail__descriptions">
|
||||
<el-descriptions-item label="签约类型">{{
|
||||
detailValue('signType')
|
||||
}}</el-descriptions-item>
|
||||
<el-descriptions-item label="合同编号">{{
|
||||
detailValue('contractNo')
|
||||
}}</el-descriptions-item>
|
||||
<el-descriptions-item label="合同名称">{{
|
||||
detailValue('contractName')
|
||||
}}</el-descriptions-item>
|
||||
<el-descriptions-item label="合同类型">{{
|
||||
detailValue('contractCategory')
|
||||
}}</el-descriptions-item>
|
||||
<el-descriptions-item label="项目">{{
|
||||
detailValue('projectName')
|
||||
}}</el-descriptions-item>
|
||||
<el-descriptions-item label="甲方">{{ detailValue('partyA') }}</el-descriptions-item>
|
||||
<el-descriptions-item label="乙方">{{ detailValue('partyB') }}</el-descriptions-item>
|
||||
<el-descriptions-item label="合同期限">{{ detailContractPeriod }}</el-descriptions-item>
|
||||
<el-descriptions-item label="所属组织">{{
|
||||
detailValue('organizationName')
|
||||
}}</el-descriptions-item>
|
||||
<el-descriptions-item label="经办人">{{
|
||||
detailValue('handlerUserName')
|
||||
}}</el-descriptions-item>
|
||||
<el-descriptions-item label="签订日期">{{
|
||||
detailValue('signDate')
|
||||
}}</el-descriptions-item>
|
||||
<el-descriptions-item label="结算类型">{{
|
||||
detailValue('settlementMode')
|
||||
}}</el-descriptions-item>
|
||||
<el-descriptions-item label="合同格式">{{
|
||||
detailValue('contractFormat')
|
||||
}}</el-descriptions-item>
|
||||
<el-descriptions-item label="是否需要加盖法人章">{{
|
||||
detailLegalSealText
|
||||
}}</el-descriptions-item>
|
||||
<el-descriptions-item label="一式">{{
|
||||
detailUnitValue('copyCount', '份')
|
||||
}}</el-descriptions-item>
|
||||
<el-descriptions-item label="回款账期">{{
|
||||
detailUnitValue('paymentDays', '天')
|
||||
}}</el-descriptions-item>
|
||||
<el-descriptions-item label="备注" :span="3">{{
|
||||
detailValue('remark')
|
||||
}}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</section>
|
||||
|
||||
<attachment-section
|
||||
title="合同文件"
|
||||
readonly
|
||||
:rows="detailContractFileRows"
|
||||
:preview="previewAttachment"
|
||||
/>
|
||||
|
||||
<section class="contract-manage-form__section contract-manage-form__section--panel">
|
||||
<div class="dialog-section-title">计费信息</div>
|
||||
<el-descriptions :column="3" class="contract-manage-detail__descriptions">
|
||||
<el-descriptions-item label="费用生成模式">{{
|
||||
detailFeeGenerationMode
|
||||
}}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<el-table :data="detailBillingPlanRows" border>
|
||||
<el-table-column type="index" label="序号" width="80" align="center" />
|
||||
<el-table-column prop="planName" label="方案名称" min-width="220" align="center" />
|
||||
<el-table-column label="默认方案" width="140" align="center">
|
||||
<template #default="{ row }">{{ isDefaultBillingPlan(row) ? '是' : '' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="remark"
|
||||
label="备注"
|
||||
min-width="260"
|
||||
align="center"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column label="操作" width="120" align="center" fixed="right">
|
||||
<template #default="{ row, $index }">
|
||||
<el-link type="primary" @click="openDetailBillingPlan(row, $index)"
|
||||
>查看详情</el-link
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</section>
|
||||
|
||||
<section class="contract-manage-form__section contract-manage-form__section--panel">
|
||||
<div class="dialog-section-title">结算单规则</div>
|
||||
<el-tabs v-model="detailSettlementConfigTab">
|
||||
<el-tab-pane label="预结算配置" name="pre" />
|
||||
<el-tab-pane label="正式结算配置" name="formal" />
|
||||
</el-tabs>
|
||||
<el-descriptions :column="3" class="contract-manage-detail__descriptions">
|
||||
<el-descriptions-item label="自动生成结算单">{{
|
||||
Number(detailSettlementRule.autoGenerate) === 1 ? '开启' : '关闭'
|
||||
}}</el-descriptions-item>
|
||||
<template v-if="Number(detailSettlementRule.autoGenerate) === 1">
|
||||
<el-descriptions-item label="账单起始日期">{{
|
||||
displayValue(detailSettlementRule.billStartDate)
|
||||
}}</el-descriptions-item>
|
||||
<el-descriptions-item label="结算类型">{{
|
||||
displayValue(detailSettlementRule.settlementType)
|
||||
}}</el-descriptions-item>
|
||||
<el-descriptions-item
|
||||
v-if="detailSettlementRule.settlementType === '月结'"
|
||||
label="账单周期类型"
|
||||
>{{ displayValue(detailSettlementRule.billCycleType) }}</el-descriptions-item
|
||||
>
|
||||
<el-descriptions-item
|
||||
v-if="
|
||||
detailSettlementRule.settlementType === '月结' &&
|
||||
detailSettlementRule.billCycleType === '固定截单日'
|
||||
"
|
||||
label="账单截单日"
|
||||
>{{
|
||||
detailObjectUnitValue(detailSettlementRule, 'billCutoffDay', '日')
|
||||
}}</el-descriptions-item
|
||||
>
|
||||
<el-descriptions-item
|
||||
v-if="detailSettlementRule.settlementType === '固定天数周期结算'"
|
||||
label="周期天数"
|
||||
>{{
|
||||
detailObjectUnitValue(detailSettlementRule, 'cycleDays', '天')
|
||||
}}</el-descriptions-item
|
||||
>
|
||||
</template>
|
||||
</el-descriptions>
|
||||
</section>
|
||||
|
||||
<section class="contract-manage-form__section contract-manage-form__section--panel">
|
||||
<div class="dialog-section-title">付款比例设置</div>
|
||||
<el-table :data="detailPaymentRatioRows" border>
|
||||
<el-table-column type="index" label="序号" width="80" align="center" />
|
||||
<el-table-column prop="paymentTerm" label="付款笔数" min-width="180" align="center" />
|
||||
<el-table-column label="付款比例上限" min-width="220" align="center">
|
||||
<template #default="{ row }">{{
|
||||
detailObjectUnitValue(row, 'ratioLimit', '%')
|
||||
}}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="remark" label="备注" min-width="220" />
|
||||
</el-table>
|
||||
</section>
|
||||
|
||||
<attachment-section
|
||||
title="其它附件"
|
||||
description
|
||||
readonly
|
||||
:rows="detailAttachmentRows"
|
||||
:preview="previewAttachment"
|
||||
/>
|
||||
|
||||
<section class="contract-manage-form__section contract-manage-form__section--panel">
|
||||
<div class="dialog-section-title">变更记录</div>
|
||||
<el-table :data="detailChangeRecordRows" border>
|
||||
<el-table-column type="index" label="序号" width="70" align="center" />
|
||||
<el-table-column
|
||||
prop="changeDate"
|
||||
label="变更日期"
|
||||
min-width="150"
|
||||
align="center"
|
||||
sortable
|
||||
/>
|
||||
<el-table-column prop="handlerUserName" label="经办人" min-width="140" align="center" />
|
||||
<el-table-column prop="changeType" label="变更类型" min-width="160" align="center" />
|
||||
<el-table-column
|
||||
prop="changeReason"
|
||||
label="变更原因"
|
||||
min-width="240"
|
||||
align="center"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column prop="statusName" label="状态" min-width="140" align="center" />
|
||||
<el-table-column label="操作" width="120" align="center" fixed="right">
|
||||
<template #default="{ row }"
|
||||
><el-link type="primary" @click="openFlow(row)">流程</el-link></template
|
||||
>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</section>
|
||||
</div>
|
||||
<template #footer
|
||||
><el-button type="primary" @click="detailBox = false">关闭</el-button></template
|
||||
>
|
||||
</el-dialog>
|
||||
|
||||
<billing-plan-editor
|
||||
v-model="detailBillingPlanBox"
|
||||
:value="detailBillingPlanForm"
|
||||
:index="detailBillingPlanIndex"
|
||||
readonly
|
||||
/>
|
||||
|
||||
<flow-design
|
||||
v-if="website.design.designMode"
|
||||
is-dialog
|
||||
@@ -743,6 +919,7 @@ const AttachmentSection = defineComponent({
|
||||
title: { type: String, required: true },
|
||||
rows: { type: Array, default: () => [] },
|
||||
description: Boolean,
|
||||
readonly: Boolean,
|
||||
preview: { type: Function, default: null },
|
||||
},
|
||||
emits: ['update:rows'],
|
||||
@@ -797,7 +974,9 @@ const AttachmentSection = defineComponent({
|
||||
const ElTableColumn = resolveComponent('el-table-column');
|
||||
const VehicleAttachmentUpload = resolveComponent('vehicle-attachment-upload');
|
||||
const columns = [
|
||||
h(ElTableColumn, { type: 'selection', width: 55, align: 'center' }),
|
||||
...(!this.readonly
|
||||
? [h(ElTableColumn, { type: 'selection', width: 55, align: 'center' })]
|
||||
: []),
|
||||
h(ElTableColumn, { type: 'index', label: '序号', width: 70, align: 'center' }),
|
||||
h(
|
||||
ElTableColumn,
|
||||
@@ -828,14 +1007,16 @@ const AttachmentSection = defineComponent({
|
||||
{ label: '附件描述', minWidth: 220 },
|
||||
{
|
||||
default: ({ row }) =>
|
||||
h(ElInput, {
|
||||
modelValue: row.description,
|
||||
maxlength: 200,
|
||||
'onUpdate:modelValue': value => {
|
||||
row.description = value;
|
||||
this.update([...this.rows]);
|
||||
},
|
||||
}),
|
||||
this.readonly
|
||||
? row.description || '-'
|
||||
: h(ElInput, {
|
||||
modelValue: row.description,
|
||||
maxlength: 200,
|
||||
'onUpdate:modelValue': value => {
|
||||
row.description = value;
|
||||
this.update([...this.rows]);
|
||||
},
|
||||
}),
|
||||
}
|
||||
)
|
||||
);
|
||||
@@ -855,16 +1036,20 @@ const AttachmentSection = defineComponent({
|
||||
width: 180,
|
||||
align: 'center',
|
||||
sortable: true,
|
||||
}),
|
||||
h(
|
||||
ElTableColumn,
|
||||
{ label: '操作', width: 100, align: 'center', fixed: 'right' },
|
||||
{
|
||||
default: ({ $index }) =>
|
||||
h(ElLink, { type: 'danger', onClick: () => this.remove($index) }, () => '删除'),
|
||||
}
|
||||
)
|
||||
})
|
||||
);
|
||||
if (!this.readonly) {
|
||||
columns.push(
|
||||
h(
|
||||
ElTableColumn,
|
||||
{ label: '操作', width: 100, align: 'center', fixed: 'right' },
|
||||
{
|
||||
default: ({ $index }) =>
|
||||
h(ElLink, { type: 'danger', onClick: () => this.remove($index) }, () => '删除'),
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
return h(
|
||||
'section',
|
||||
{
|
||||
@@ -874,16 +1059,20 @@ const AttachmentSection = defineComponent({
|
||||
h('div', { class: 'dialog-section-title' }, this.title),
|
||||
h('div', { class: 'contract-manage-form__attachment-head' }, [
|
||||
h('div', { class: 'contract-manage-form__attachment-actions' }, [
|
||||
h(VehicleAttachmentUpload, {
|
||||
modelValue: this.rows,
|
||||
fileTypes: this.attachmentFileTypes,
|
||||
maxSize: 500,
|
||||
showTip: false,
|
||||
showFileList: false,
|
||||
buttonText: '上传附件',
|
||||
'onUpdate:modelValue': this.handleChange,
|
||||
onChange: this.handleChange,
|
||||
}),
|
||||
...(!this.readonly
|
||||
? [
|
||||
h(VehicleAttachmentUpload, {
|
||||
modelValue: this.rows,
|
||||
fileTypes: this.attachmentFileTypes,
|
||||
maxSize: 500,
|
||||
showTip: false,
|
||||
showFileList: false,
|
||||
buttonText: '上传附件',
|
||||
'onUpdate:modelValue': this.handleChange,
|
||||
onChange: this.handleChange,
|
||||
}),
|
||||
]
|
||||
: []),
|
||||
h(
|
||||
ElButton,
|
||||
{ type: 'primary', disabled: !this.rows.length, onClick: this.batchDownload },
|
||||
@@ -990,6 +1179,17 @@ export default {
|
||||
detailBox: false,
|
||||
detailLoading: false,
|
||||
detailRow: {},
|
||||
detailContractFileRows: [],
|
||||
detailAttachmentRows: [],
|
||||
detailBillingPlanRows: [],
|
||||
detailBillingPlanBox: false,
|
||||
detailBillingPlanIndex: -1,
|
||||
detailBillingPlanForm: {},
|
||||
detailSettlementConfigTab: 'pre',
|
||||
detailPreSettlementRuleForm: defaultSettlementRule(),
|
||||
detailFormalSettlementRuleForm: defaultSettlementRule(),
|
||||
detailPaymentRatioRows: [],
|
||||
detailChangeRecordRows: [],
|
||||
flowBox: false,
|
||||
flowUrl: '',
|
||||
processInstanceId: '',
|
||||
@@ -1069,6 +1269,27 @@ export default {
|
||||
value: index + 1,
|
||||
}));
|
||||
},
|
||||
detailContractPeriod() {
|
||||
const startDate = this.detailRow.startDate || '-';
|
||||
const endDate = this.detailRow.endDate || '-';
|
||||
return `${startDate} 至 ${endDate}`;
|
||||
},
|
||||
detailLegalSealText() {
|
||||
const value = this.detailRow.legalSealFlag;
|
||||
if (value === undefined || value === null || value === '') return '-';
|
||||
return Number(value) === 1 ? '是' : '否';
|
||||
},
|
||||
detailFeeGenerationMode() {
|
||||
const value =
|
||||
this.detailRow.feeGenerationMode ||
|
||||
(Number(this.detailRow.billingEnabled) === 0 ? 'manual' : 'system');
|
||||
return value === 'manual' ? '手动生成' : '系统生成';
|
||||
},
|
||||
detailSettlementRule() {
|
||||
return this.detailSettlementConfigTab === 'formal'
|
||||
? this.detailFormalSettlementRuleForm
|
||||
: this.detailPreSettlementRuleForm;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
'$route.fullPath'() {
|
||||
@@ -1718,16 +1939,55 @@ export default {
|
||||
openDetail(row) {
|
||||
this.detailBox = true;
|
||||
this.detailLoading = true;
|
||||
this.detailRow = { ...row };
|
||||
this.applyDetailState(row);
|
||||
this.api
|
||||
.getDetail(row.id)
|
||||
.then(res => {
|
||||
this.detailRow = res.data?.data || row;
|
||||
this.applyDetailState(res.data?.data || row);
|
||||
})
|
||||
.finally(() => {
|
||||
this.detailLoading = false;
|
||||
});
|
||||
},
|
||||
applyDetailState(detail = {}) {
|
||||
this.detailRow = { ...detail };
|
||||
this.detailContractFileRows = parseArray(detail.contractFileJson);
|
||||
this.detailAttachmentRows = parseArray(detail.attachmentsJson);
|
||||
this.detailBillingPlanRows = parseArray(detail.billingPlanJson);
|
||||
this.detailPaymentRatioRows = parseArray(detail.paymentRatioJson);
|
||||
this.detailChangeRecordRows = parseArray(detail.changeRecordJson);
|
||||
const payload = parseObject(detail.settlementRuleJson);
|
||||
const legacy = Object.keys(payload).some(
|
||||
key => !['preSettlementConfig', 'formalSettlementConfig'].includes(key)
|
||||
)
|
||||
? payload
|
||||
: {};
|
||||
const preConfig = parseObject(detail.preSettlementConfigJson);
|
||||
const formalConfig = parseObject(detail.formalSettlementConfigJson);
|
||||
this.detailPreSettlementRuleForm = this.normalizeSettlementRule(
|
||||
payload.preSettlementConfig || (Object.keys(preConfig).length ? preConfig : legacy)
|
||||
);
|
||||
this.detailFormalSettlementRuleForm = this.normalizeSettlementRule(
|
||||
payload.formalSettlementConfig || (Object.keys(formalConfig).length ? formalConfig : legacy)
|
||||
);
|
||||
this.detailSettlementConfigTab = 'pre';
|
||||
},
|
||||
openDetailBillingPlan(row, index) {
|
||||
this.detailBillingPlanForm = clone(row);
|
||||
this.detailBillingPlanIndex = index;
|
||||
this.detailBillingPlanBox = true;
|
||||
},
|
||||
displayValue(value) {
|
||||
return value === undefined || value === null || value === '' ? '-' : value;
|
||||
},
|
||||
detailUnitValue(prop, unit) {
|
||||
const value = this.detailRow[prop];
|
||||
return value === undefined || value === null || value === '' ? '-' : `${value}${unit}`;
|
||||
},
|
||||
detailObjectUnitValue(row, prop, unit) {
|
||||
const value = row?.[prop];
|
||||
return value === undefined || value === null || value === '' ? '-' : `${value}${unit}`;
|
||||
},
|
||||
detailValue(prop) {
|
||||
const value = this.detailRow[prop];
|
||||
if (
|
||||
@@ -1743,7 +2003,7 @@ export default {
|
||||
if (prop === 'settlementRuleJson') return value ? '已配置' : '-';
|
||||
if (prop === 'paymentRatioJson') return `${parseArray(value).length}项付款比例`;
|
||||
if (prop === 'feeGenerationMode') return value === 'manual' ? '手动生成' : '系统生成';
|
||||
return value === undefined || value === null || value === '' ? '-' : value;
|
||||
return this.displayValue(value);
|
||||
},
|
||||
handleOperation(operation, row) {
|
||||
if (operation.action === 'startChange') {
|
||||
@@ -2107,8 +2367,28 @@ export default {
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
.contract-manage-detail section + section {
|
||||
margin-top: 20px;
|
||||
.contract-manage-detail {
|
||||
max-height: 74vh;
|
||||
overflow-y: auto;
|
||||
|
||||
&__descriptions {
|
||||
:deep(.el-descriptions__label) {
|
||||
display: inline-block;
|
||||
min-width: 96px;
|
||||
padding-right: 12px;
|
||||
color: #606266;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
:deep(.el-descriptions__content) {
|
||||
color: #303133;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
:deep(.el-descriptions__cell) {
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1200px) {
|
||||
|
||||
@@ -2175,7 +2175,7 @@ export default {
|
||||
if (draftMode) {
|
||||
return true;
|
||||
}
|
||||
if (this.dialogMode === 'add' && this.selectedWaybillRows.length < 2) {
|
||||
if (this.selectedWaybillRows.length < 2) {
|
||||
ElMessage.warning('请至少选择两条待配载运单');
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -797,11 +797,25 @@ export default {
|
||||
result.push(
|
||||
`是否接单:${node.confirmMode === 'no_confirm_accept' ? '无需确认接单' : '是'}`
|
||||
);
|
||||
result.push(
|
||||
`确认接单人(司机):${node.confirmMode === 'yes' && node.confirmDriver ? '是' : '否'}`
|
||||
);
|
||||
return result;
|
||||
}
|
||||
if (node.key === 'return') {
|
||||
if (node.uploadVoucher && node.voucherTypes.length) {
|
||||
result.push(`上传凭证:${node.voucherTypes.join('、')}`);
|
||||
result.push(
|
||||
`是否确认:${node.confirmMode === 'no_confirm_complete' ? '无需确认完成' : '是'}`
|
||||
);
|
||||
result.push(
|
||||
`确认完成(内部人员):${
|
||||
node.confirmMode === 'yes' && node.confirmInternal ? '是' : '否'
|
||||
}`
|
||||
);
|
||||
if (node.supportVoucher) {
|
||||
result.push(`上传凭证:${node.uploadVoucher ? '是' : '否'}`);
|
||||
if (node.uploadVoucher && node.voucherTypes.length) {
|
||||
result.push(`凭证类型:${node.voucherTypes.join('、')}`);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -816,11 +830,17 @@ export default {
|
||||
result.push(`打卡操作:${node.punch ? '是' : '否'}`);
|
||||
result.push(`打卡定位:${node.location ? '是' : '否'}`);
|
||||
}
|
||||
if (node.supportCargo && node.uploadCargo && node.cargoTypes.length) {
|
||||
result.push(`上传货量:${node.cargoTypes.join('、')}`);
|
||||
if (node.supportCargo) {
|
||||
result.push(`上传货量:${node.uploadCargo ? '是' : '否'}`);
|
||||
if (node.uploadCargo && node.cargoTypes.length) {
|
||||
result.push(`上传货量类型:${node.cargoTypes.join('、')}`);
|
||||
}
|
||||
}
|
||||
if (node.supportVoucher && node.uploadVoucher && node.voucherTypes.length) {
|
||||
result.push(`上传凭证:${node.voucherTypes.join('、')}`);
|
||||
if (node.supportVoucher) {
|
||||
result.push(`上传凭证:${node.uploadVoucher ? '是' : '否'}`);
|
||||
if (node.uploadVoucher && node.voucherTypes.length) {
|
||||
result.push(`凭证类型:${node.voucherTypes.join('、')}`);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
},
|
||||
|
||||
@@ -709,18 +709,33 @@ export default {
|
||||
if (!rows.length) return;
|
||||
const first = rows[0];
|
||||
const settlementType = this.initialData.settlementType || first.settlementType || 'payable';
|
||||
const contractId = first.contractId || null;
|
||||
const matchedContract = this.allContracts.find(
|
||||
item =>
|
||||
(first.contractId && String(item.id) === String(first.contractId)) ||
|
||||
(first.contractNo && String(item.contractNo) === String(first.contractNo))
|
||||
);
|
||||
const contractId = first.contractId || matchedContract?.id || null;
|
||||
const projectId = first.projectId || matchedContract?.projectId || null;
|
||||
const projectName = first.projectName || matchedContract?.projectName || '';
|
||||
this.contracts = this.allContracts.filter(
|
||||
item => projectId && String(item.projectId) === String(projectId)
|
||||
);
|
||||
if (projectId && !this.projects.some(item => String(item.id) === String(projectId))) {
|
||||
this.projects.push({ id: projectId, name: projectName });
|
||||
}
|
||||
if (!this.contracts.some(item => String(item.id) === String(contractId))) {
|
||||
this.contracts.push({
|
||||
id: contractId,
|
||||
contractNo: first.contractNo,
|
||||
contractName: first.contractName,
|
||||
projectId: first.projectId,
|
||||
projectName: first.projectName,
|
||||
deptId: first.deptId,
|
||||
deptName: first.deptName,
|
||||
projectId,
|
||||
projectName,
|
||||
deptId: first.deptId || matchedContract?.deptId,
|
||||
deptName: first.deptName || matchedContract?.deptName,
|
||||
payerName: first.payerName,
|
||||
payeeName: first.payeeName,
|
||||
partyA: matchedContract?.partyA,
|
||||
partyB: matchedContract?.partyB,
|
||||
settlementType,
|
||||
});
|
||||
}
|
||||
@@ -729,8 +744,8 @@ export default {
|
||||
contractId,
|
||||
contractNo: first.contractNo || this.form.contractNo,
|
||||
contractName: first.contractName || this.form.contractName,
|
||||
projectId: first.projectId || this.form.projectId,
|
||||
projectName: first.projectName || this.form.projectName,
|
||||
projectId: projectId || this.form.projectId,
|
||||
projectName: projectName || this.form.projectName,
|
||||
deptId: first.deptId || this.form.deptId,
|
||||
deptName: first.deptName || this.form.deptName,
|
||||
payerName: first.payerName || this.form.payerName,
|
||||
@@ -1035,10 +1050,7 @@ export default {
|
||||
return columns.map((column, index) => {
|
||||
if (index === 0) return '合计';
|
||||
if (!sumProps.includes(column.property)) return '';
|
||||
const total = data.reduce(
|
||||
(sum, row) => sum + Number(row[column.property] || 0),
|
||||
0
|
||||
);
|
||||
const total = data.reduce((sum, row) => sum + Number(row[column.property] || 0), 0);
|
||||
return this.formatMoney(total);
|
||||
});
|
||||
},
|
||||
|
||||
@@ -1010,6 +1010,15 @@ export default {
|
||||
this.$message.warning('请至少选择一条结算明细');
|
||||
return;
|
||||
}
|
||||
const invalidManualFeeIndex = this.summaryFees.findIndex(
|
||||
row =>
|
||||
Number(row.manualFlag) === 1 &&
|
||||
(!String(row.feeType || '').trim() || !String(row.feeItem || '').trim())
|
||||
);
|
||||
if (invalidManualFeeIndex >= 0) {
|
||||
this.$message.warning(`请完善结算合计第${invalidManualFeeIndex + 1}行的费用类型和费用项`);
|
||||
return;
|
||||
}
|
||||
const stateKey = shouldSubmit ? 'submitting' : 'saving';
|
||||
this[stateKey] = true;
|
||||
try {
|
||||
@@ -1040,7 +1049,7 @@ export default {
|
||||
sourceDetailIds: this.details.map(row => row.sourceDetailId || row.id),
|
||||
summaryFees: this.summaryFees.map(row => ({
|
||||
id: row.id || undefined,
|
||||
feeType: row.feeType,
|
||||
feeType: row.feeType || '',
|
||||
feeItem: row.feeItem,
|
||||
adjustAmount: Number(row.adjustAmount || 0),
|
||||
remark: row.remark,
|
||||
@@ -1067,7 +1076,7 @@ export default {
|
||||
return this.feeOptions.find(item => item.feeType === feeType)?.feeItems || [];
|
||||
},
|
||||
feeCategoryName(value) {
|
||||
if (value === undefined || value === null || value === '') return '-';
|
||||
if (value === undefined || value === null || value === '') return '';
|
||||
const option = this.feeCategoryOptions.find(
|
||||
item => String(item.dictKey) === String(value) || String(item.dictValue) === String(value)
|
||||
);
|
||||
|
||||
@@ -318,7 +318,7 @@
|
||||
<el-form-item label="转结算类型">
|
||||
<el-radio-group
|
||||
v-model="transferForm.settlementBillType"
|
||||
@change="loadTransferCandidates"
|
||||
@change="handleTransferTypeChange"
|
||||
>
|
||||
<el-radio label="pre">预结算单</el-radio>
|
||||
<el-radio label="formal">正式结算单</el-radio>
|
||||
@@ -343,18 +343,26 @@
|
||||
<el-input v-else v-model="transferQuery[field.prop]" clearable placeholder="请输入" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="loadTransferCandidates">查询</el-button>
|
||||
<el-button type="primary" @click="handleTransferSearch">查询</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<el-table
|
||||
ref="transferTableRef"
|
||||
v-loading="transferDialog.loading"
|
||||
:data="transferRows"
|
||||
row-key="id"
|
||||
border
|
||||
@selection-change="transferSelectionChange"
|
||||
>
|
||||
<el-table-column type="selection" width="52" align="center" />
|
||||
<el-table-column type="index" label="序号" width="70" align="center" />
|
||||
<el-table-column type="selection" width="52" align="center" reserve-selection />
|
||||
<el-table-column
|
||||
type="index"
|
||||
label="序号"
|
||||
width="70"
|
||||
align="center"
|
||||
:index="transferIndexMethod"
|
||||
/>
|
||||
<el-table-column
|
||||
v-for="column in tableColumns.slice(0, 13)"
|
||||
:key="column.prop"
|
||||
@@ -367,6 +375,17 @@
|
||||
<template #default="{ row }">{{ formatColumnValue(row, column) }}</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="settlement-detail-page__pagination">
|
||||
<el-pagination
|
||||
v-model:current-page="transferPage.current"
|
||||
v-model:page-size="transferPage.size"
|
||||
:total="transferPage.total"
|
||||
:page-sizes="[10, 20, 50]"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
@current-change="loadTransferCandidates"
|
||||
@size-change="handleTransferSizeChange"
|
||||
/>
|
||||
</div>
|
||||
<template #footer>
|
||||
<el-button @click="transferDialog.visible = false">取消</el-button>
|
||||
<el-button type="primary" :loading="transferDialog.submitting" @click="submitTransfer">
|
||||
@@ -593,6 +612,7 @@ export default {
|
||||
transferForm: { settlementBillType: 'formal' },
|
||||
transferRows: [],
|
||||
transferSelection: [],
|
||||
transferPage: { current: 1, size: 10, total: 0 },
|
||||
generateDialog: { visible: false, loading: false },
|
||||
generateQuery: {},
|
||||
generateRows: [],
|
||||
@@ -1029,11 +1049,12 @@ export default {
|
||||
this.transferQuery = {};
|
||||
this.transferRows = [];
|
||||
this.transferSelection = [];
|
||||
this.transferPage = { current: 1, size: 10, total: 0 };
|
||||
this.$nextTick(() => this.$refs.transferTableRef?.clearSelection());
|
||||
this.loadTransferCandidates();
|
||||
},
|
||||
async loadTransferCandidates() {
|
||||
this.transferDialog.loading = true;
|
||||
this.transferSelection = [];
|
||||
try {
|
||||
const params = this.buildRequestParams(
|
||||
this.normalizeQuery(
|
||||
@@ -1043,20 +1064,46 @@ export default {
|
||||
'generateEndDate'
|
||||
)
|
||||
);
|
||||
const res = await api.getTransferCandidates(1, 50, {
|
||||
...params,
|
||||
settlementStatus: 'pending',
|
||||
settlementType: this.settlementType || undefined,
|
||||
settlementBillType: this.transferForm.settlementBillType,
|
||||
});
|
||||
const res = await api.getTransferCandidates(
|
||||
this.transferPage.current,
|
||||
this.transferPage.size,
|
||||
{
|
||||
...params,
|
||||
settlementStatus: 'pending',
|
||||
settlementType: this.settlementType || undefined,
|
||||
settlementBillType: this.transferForm.settlementBillType,
|
||||
}
|
||||
);
|
||||
const data = this.unwrapPage(res);
|
||||
this.transferRows = (data.records || [])
|
||||
.filter(row => this.isTransferCandidate(row))
|
||||
.map(this.decorateRow);
|
||||
this.transferPage.total = data.total || 0;
|
||||
} finally {
|
||||
this.transferDialog.loading = false;
|
||||
}
|
||||
},
|
||||
resetTransferSelection() {
|
||||
this.transferSelection = [];
|
||||
this.$nextTick(() => this.$refs.transferTableRef?.clearSelection());
|
||||
},
|
||||
handleTransferSearch() {
|
||||
this.transferPage.current = 1;
|
||||
this.resetTransferSelection();
|
||||
this.loadTransferCandidates();
|
||||
},
|
||||
handleTransferTypeChange() {
|
||||
this.transferPage.current = 1;
|
||||
this.resetTransferSelection();
|
||||
this.loadTransferCandidates();
|
||||
},
|
||||
handleTransferSizeChange() {
|
||||
this.transferPage.current = 1;
|
||||
this.loadTransferCandidates();
|
||||
},
|
||||
transferIndexMethod(index) {
|
||||
return (this.transferPage.current - 1) * this.transferPage.size + index + 1;
|
||||
},
|
||||
isTransferCandidate(row) {
|
||||
const hasValue = value => {
|
||||
if (Array.isArray(value)) return value.length > 0;
|
||||
@@ -1151,16 +1198,38 @@ export default {
|
||||
}
|
||||
},
|
||||
async resolveTransferContractIds(rows) {
|
||||
if (rows.every(item => item.contractId)) return rows;
|
||||
if (rows.every(item => item.contractId && item.projectId)) return rows;
|
||||
const contractId = rows.find(item => item.contractId)?.contractId;
|
||||
const contractNo = rows.find(item => item.contractNo)?.contractNo;
|
||||
const { data } = await getSettlementContractOptions(contractNo);
|
||||
const contracts = data?.data || [];
|
||||
const contract = contracts.find(item => String(item.contractNo) === String(contractNo));
|
||||
if (!contract?.id) {
|
||||
this.$message.warning('未找到所选明细对应的有效合同,无法转结算');
|
||||
const contract = contracts.find(
|
||||
item =>
|
||||
(contractId && String(item.id) === String(contractId)) ||
|
||||
(contractNo && String(item.contractNo) === String(contractNo))
|
||||
);
|
||||
if (!contract?.id || !contract.projectId) {
|
||||
this.$message.warning('未找到所选明细对应的合同或项目信息,无法转结算');
|
||||
return null;
|
||||
}
|
||||
return rows.map(item => ({ ...item, contractId: item.contractId || contract.id }));
|
||||
return rows.map(item => {
|
||||
const settlementType =
|
||||
item.settlementType || this.settlementType || contract.settlementType;
|
||||
return {
|
||||
...item,
|
||||
contractId: item.contractId || contract.id,
|
||||
contractNo: item.contractNo || contract.contractNo,
|
||||
contractName: item.contractName || contract.contractName,
|
||||
projectId: item.projectId || contract.projectId,
|
||||
projectName: item.projectName || contract.projectName,
|
||||
deptId: item.deptId || contract.deptId,
|
||||
deptName: item.deptName || contract.deptName,
|
||||
payerName:
|
||||
item.payerName || (settlementType === 'receivable' ? contract.partyB : contract.partyA),
|
||||
payeeName:
|
||||
item.payeeName || (settlementType === 'receivable' ? contract.partyA : contract.partyB),
|
||||
};
|
||||
});
|
||||
},
|
||||
openGenerateDialog() {
|
||||
this.generateDialog.visible = true;
|
||||
|
||||
@@ -1309,6 +1309,11 @@ export default {
|
||||
},
|
||||
normalizeBirthday(value = '') {
|
||||
const birthday = String(value || '').trim();
|
||||
const compactMatch = birthday.match(/^(\d{4})(\d{2})(\d{2})$/);
|
||||
if (compactMatch) {
|
||||
const [, year, month, day] = compactMatch;
|
||||
return `${year}-${month}-${day}`;
|
||||
}
|
||||
const match = birthday.match(/^(\d{4})[-/.年](\d{1,2})[-/.月](\d{1,2})日?$/);
|
||||
if (!match) return birthday;
|
||||
const [, year, month, day] = match;
|
||||
@@ -1343,6 +1348,10 @@ export default {
|
||||
}
|
||||
const row = {
|
||||
...this.driverForm,
|
||||
birthday: this.normalizeBirthday(this.driverForm.birthday),
|
||||
drivingLicenseStartDate: this.normalizeBirthday(this.driverForm.drivingLicenseStartDate),
|
||||
drivingLicenseEndDate: this.normalizeBirthday(this.driverForm.drivingLicenseEndDate),
|
||||
qualificationEndDate: this.normalizeBirthday(this.driverForm.qualificationEndDate),
|
||||
qualificationNo: this.driverForm.qualificationNo || this.driverForm.idCardNo,
|
||||
posts: this.driverForm.postList.join(','),
|
||||
};
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
placeholder="请输入"
|
||||
@input="value => normalizeDecimalInput('directEconomicLoss', value)"
|
||||
>
|
||||
<template #suffix>元</template>
|
||||
<template #append>元</template>
|
||||
</el-input>
|
||||
</template>
|
||||
<template #insuranceClaimAmountForm>
|
||||
@@ -89,7 +89,7 @@
|
||||
placeholder="请输入"
|
||||
@input="value => normalizeDecimalInput('insuranceClaimAmount', value)"
|
||||
>
|
||||
<template #suffix>元</template>
|
||||
<template #append>元</template>
|
||||
</el-input>
|
||||
</template>
|
||||
<template #attachments="{ row }">
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
placeholder="请输入"
|
||||
@input="value => normalizeDecimalInput('fee', value)"
|
||||
>
|
||||
<template #suffix>元</template>
|
||||
<template #append>元</template>
|
||||
</el-input>
|
||||
</template>
|
||||
<template #attachments="{ row }">
|
||||
|
||||
@@ -634,11 +634,20 @@
|
||||
</el-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="文件名称" min-width="180">
|
||||
<el-table-column label="文件名称" min-width="180" align="left">
|
||||
<template #default="{ row }">
|
||||
<el-link type="primary" :disabled="!row.url" @click="previewQualificationFile(row)">{{
|
||||
row.originalName || row.name || '-'
|
||||
}}</el-link>
|
||||
<div
|
||||
class="qualification-file-name-cell"
|
||||
:title="row.originalName || row.name || '-'"
|
||||
>
|
||||
<span
|
||||
class="qualification-file-name"
|
||||
:class="{ 'is-disabled': !row.url }"
|
||||
@click="row.url && previewQualificationFile(row)"
|
||||
>
|
||||
{{ row.originalName || row.name || '-' }}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="附件描述" min-width="220">
|
||||
@@ -4461,6 +4470,41 @@ export default {
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.qualification-file-name-cell {
|
||||
display: block;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
text-align: left;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.qualification-file-name {
|
||||
display: block;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
vertical-align: middle;
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
color: #606266;
|
||||
transition: color 0.2s ease;
|
||||
|
||||
&:hover {
|
||||
color: #409eff;
|
||||
}
|
||||
|
||||
&.is-disabled {
|
||||
cursor: default;
|
||||
color: #606266;
|
||||
|
||||
&:hover {
|
||||
color: #606266;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.qualification-upload-bar {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto 1fr;
|
||||
|
||||
@@ -70,6 +70,15 @@
|
||||
class="maintenance-plan-page__input"
|
||||
/>
|
||||
</template>
|
||||
<template #address-form>
|
||||
<el-input
|
||||
v-model="form.address"
|
||||
:disabled="boxType === 'view'"
|
||||
readonly
|
||||
placeholder="点击地图选址"
|
||||
@click="openAddressMapPicker"
|
||||
/>
|
||||
</template>
|
||||
<template #mileageForm>
|
||||
<el-input
|
||||
v-model="form.mileage"
|
||||
@@ -140,6 +149,11 @@
|
||||
</template>
|
||||
</avue-form>
|
||||
</el-dialog>
|
||||
<address-map-picker
|
||||
v-model="addressMapPickerVisible"
|
||||
:address="form.address"
|
||||
@confirm="handleAddressMapConfirm"
|
||||
/>
|
||||
</basic-container>
|
||||
</template>
|
||||
|
||||
@@ -154,6 +168,7 @@ import { openImportDialog } from '@/utils/import-excel';
|
||||
import { formatUpdateUserName } from '@/utils/audit';
|
||||
import { getToken } from '@/utils/auth';
|
||||
import { normalizeSearchRangeParams } from '@/utils/search-range';
|
||||
import AddressMapPicker from '@/components/address-map-picker/main.vue';
|
||||
import { mapGetters } from 'vuex';
|
||||
import NProgress from 'nprogress';
|
||||
import 'nprogress/nprogress.css';
|
||||
@@ -163,6 +178,9 @@ const createTimeRangeMap = {
|
||||
};
|
||||
|
||||
export default {
|
||||
components: {
|
||||
AddressMapPicker,
|
||||
},
|
||||
data() {
|
||||
const validateNonNegative = (rule, value, callback) => {
|
||||
if (value === undefined || value === null || value === '') {
|
||||
@@ -178,6 +196,7 @@ export default {
|
||||
query: {},
|
||||
loading: true,
|
||||
excelBox: false,
|
||||
addressMapPickerVisible: false,
|
||||
excelForm: {},
|
||||
page: {
|
||||
pageSize: 10,
|
||||
@@ -203,6 +222,7 @@ export default {
|
||||
border: true,
|
||||
index: true,
|
||||
indexLabel: '序号',
|
||||
indexWidth: 90,
|
||||
viewBtn: true,
|
||||
selection: true,
|
||||
dialogClickModal: false,
|
||||
@@ -315,6 +335,8 @@ export default {
|
||||
{
|
||||
label: '地址',
|
||||
prop: 'address',
|
||||
slot: true,
|
||||
formslot: true,
|
||||
minWidth: 180,
|
||||
overHidden: true,
|
||||
span: 24,
|
||||
@@ -483,6 +505,14 @@ export default {
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
openAddressMapPicker() {
|
||||
if (this.boxType !== 'view') {
|
||||
this.addressMapPickerVisible = true;
|
||||
}
|
||||
},
|
||||
handleAddressMapConfirm(address) {
|
||||
this.form.address = address;
|
||||
},
|
||||
hasPermission(code) {
|
||||
return this.isAdmin || this.validData(this.permission[code], false);
|
||||
},
|
||||
|
||||
@@ -70,6 +70,15 @@
|
||||
class="maintenance-record-page__input"
|
||||
/>
|
||||
</template>
|
||||
<template #address-form>
|
||||
<el-input
|
||||
v-model="form.address"
|
||||
:disabled="boxType === 'view'"
|
||||
readonly
|
||||
placeholder="点击地图选址"
|
||||
@click="openAddressMapPicker"
|
||||
/>
|
||||
</template>
|
||||
<template #costForm>
|
||||
<el-input
|
||||
v-model="form.cost"
|
||||
@@ -126,6 +135,11 @@
|
||||
</template>
|
||||
</avue-form>
|
||||
</el-dialog>
|
||||
<address-map-picker
|
||||
v-model="addressMapPickerVisible"
|
||||
:address="form.address"
|
||||
@confirm="handleAddressMapConfirm"
|
||||
/>
|
||||
</basic-container>
|
||||
</template>
|
||||
|
||||
@@ -140,6 +154,7 @@ import { openImportDialog } from '@/utils/import-excel';
|
||||
import { formatUpdateUserName } from '@/utils/audit';
|
||||
import { getToken } from '@/utils/auth';
|
||||
import { normalizeSearchRangeParams } from '@/utils/search-range';
|
||||
import AddressMapPicker from '@/components/address-map-picker/main.vue';
|
||||
import { mapGetters } from 'vuex';
|
||||
import NProgress from 'nprogress';
|
||||
import 'nprogress/nprogress.css';
|
||||
@@ -149,6 +164,9 @@ const createTimeRangeMap = {
|
||||
};
|
||||
|
||||
export default {
|
||||
components: {
|
||||
AddressMapPicker,
|
||||
},
|
||||
data() {
|
||||
const validateNonNegative = (rule, value, callback) => {
|
||||
if (value === undefined || value === null || value === '') {
|
||||
@@ -164,6 +182,7 @@ export default {
|
||||
query: {},
|
||||
loading: true,
|
||||
excelBox: false,
|
||||
addressMapPickerVisible: false,
|
||||
excelForm: {},
|
||||
isDetailLoading: false,
|
||||
page: {
|
||||
@@ -190,6 +209,7 @@ export default {
|
||||
border: true,
|
||||
index: true,
|
||||
indexLabel: '序号',
|
||||
indexWidth: 90,
|
||||
viewBtn: true,
|
||||
selection: true,
|
||||
dialogClickModal: false,
|
||||
@@ -291,6 +311,8 @@ export default {
|
||||
{
|
||||
label: '地址',
|
||||
prop: 'address',
|
||||
slot: true,
|
||||
formslot: true,
|
||||
minWidth: 180,
|
||||
overHidden: true,
|
||||
span: 24,
|
||||
@@ -478,6 +500,14 @@ export default {
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
openAddressMapPicker() {
|
||||
if (this.boxType !== 'view') {
|
||||
this.addressMapPickerVisible = true;
|
||||
}
|
||||
},
|
||||
handleAddressMapConfirm(address) {
|
||||
this.form.address = address;
|
||||
},
|
||||
hasPermission(code) {
|
||||
return this.isAdmin || this.validData(this.permission[code], false);
|
||||
},
|
||||
|
||||
@@ -90,7 +90,7 @@
|
||||
placeholder="请输入"
|
||||
@input="value => normalizeIntegerInput('previousMonthMileage', value)"
|
||||
>
|
||||
<template #suffix>km</template>
|
||||
<template #append>km</template>
|
||||
</el-input>
|
||||
</template>
|
||||
<template #currentMonthMileageForm>
|
||||
@@ -101,7 +101,7 @@
|
||||
placeholder="请输入"
|
||||
@input="value => normalizeIntegerInput('currentMonthMileage', value)"
|
||||
>
|
||||
<template #suffix>km</template>
|
||||
<template #append>km</template>
|
||||
</el-input>
|
||||
</template>
|
||||
<template #monthlyMileageForm>
|
||||
@@ -112,7 +112,7 @@
|
||||
placeholder="请输入"
|
||||
@input="value => normalizeIntegerInput('monthlyMileage', value)"
|
||||
>
|
||||
<template #suffix>km</template>
|
||||
<template #append>km</template>
|
||||
</el-input>
|
||||
</template>
|
||||
<template #totalMileageForm>
|
||||
@@ -123,7 +123,7 @@
|
||||
placeholder="请输入"
|
||||
@input="value => normalizeIntegerInput('totalMileage', value)"
|
||||
>
|
||||
<template #suffix>km</template>
|
||||
<template #append>km</template>
|
||||
</el-input>
|
||||
</template>
|
||||
<template #totalMileageStart-search="{ row }">
|
||||
|
||||
@@ -87,7 +87,7 @@
|
||||
placeholder="请输入"
|
||||
@input="value => normalizeDecimalInput('unitPrice', value)"
|
||||
>
|
||||
<template #suffix>元</template>
|
||||
<template #append>元/升</template>
|
||||
</el-input>
|
||||
</template>
|
||||
<template #transactionAmountForm>
|
||||
|
||||
@@ -110,6 +110,15 @@
|
||||
@input="value => normalizeIntegerInput('deductPoints', value)"
|
||||
/>
|
||||
</template>
|
||||
<template #location-form>
|
||||
<el-input
|
||||
v-model="form.location"
|
||||
:disabled="boxType === 'view'"
|
||||
readonly
|
||||
placeholder="点击地图选址"
|
||||
@click="openLocationMapPicker"
|
||||
/>
|
||||
</template>
|
||||
<template #processStatus="{ row }">
|
||||
<span :class="row.processStatus === '未处理' ? 'violation-record-page__danger' : ''">
|
||||
{{ row.processStatus }}
|
||||
@@ -152,6 +161,11 @@
|
||||
</template>
|
||||
</avue-form>
|
||||
</el-dialog>
|
||||
<address-map-picker
|
||||
v-model="locationMapPickerVisible"
|
||||
:address="form.location"
|
||||
@confirm="handleLocationMapConfirm"
|
||||
/>
|
||||
</basic-container>
|
||||
</template>
|
||||
|
||||
@@ -167,6 +181,7 @@ import { downloadXls } from '@/utils/util';
|
||||
import { openImportDialog } from '@/utils/import-excel';
|
||||
import { getToken } from '@/utils/auth';
|
||||
import { normalizeSearchRangeParams } from '@/utils/search-range';
|
||||
import AddressMapPicker from '@/components/address-map-picker/main.vue';
|
||||
import { mapGetters } from 'vuex';
|
||||
import { excelOption, option } from '@/option/vehicle/violation-record';
|
||||
import NProgress from 'nprogress';
|
||||
@@ -177,12 +192,16 @@ const createTimeRangeMap = {
|
||||
};
|
||||
|
||||
export default {
|
||||
components: {
|
||||
AddressMapPicker,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {},
|
||||
query: {},
|
||||
loading: true,
|
||||
excelBox: false,
|
||||
locationMapPickerVisible: false,
|
||||
excelForm: {},
|
||||
isDetailLoading: false,
|
||||
option,
|
||||
@@ -242,6 +261,14 @@ export default {
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
openLocationMapPicker() {
|
||||
if (this.boxType !== 'view') {
|
||||
this.locationMapPickerVisible = true;
|
||||
}
|
||||
},
|
||||
handleLocationMapConfirm(address) {
|
||||
this.form.location = address;
|
||||
},
|
||||
hasPermission(code) {
|
||||
return this.isAdmin || this.validData(this.permission[code], false);
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user