带出甲乙方数据,下载权限控制
This commit is contained in:
@@ -1,598 +0,0 @@
|
|||||||
<template>
|
|
||||||
<a-modal
|
|
||||||
v-model:visible="visible"
|
|
||||||
centered
|
|
||||||
title="公路运输产品新增"
|
|
||||||
width="800px"
|
|
||||||
@cancel="handleCancel"
|
|
||||||
@ok="handleOk"
|
|
||||||
>
|
|
||||||
<a-form
|
|
||||||
ref="formRef"
|
|
||||||
:model="formState"
|
|
||||||
:label-col="{ span: 8 }"
|
|
||||||
:wrapper-col="{ span: 16 }"
|
|
||||||
:rules="rules"
|
|
||||||
>
|
|
||||||
<a-row :gutter="16">
|
|
||||||
<a-col :span="12">
|
|
||||||
<a-form-item label="短驳类型" name="busType">
|
|
||||||
<a-select
|
|
||||||
v-model:value="formState.busType"
|
|
||||||
placeholder="请选择短驳类型"
|
|
||||||
allow-clear
|
|
||||||
>
|
|
||||||
<a-select-option value="集装箱">集装箱</a-select-option>
|
|
||||||
<a-select-option value="散杂货">散杂货</a-select-option>
|
|
||||||
</a-select>
|
|
||||||
</a-form-item>
|
|
||||||
</a-col>
|
|
||||||
<a-col :span="12">
|
|
||||||
<a-form-item label="计价方式" name="priceType">
|
|
||||||
<a-select
|
|
||||||
v-model:value="formState.priceType"
|
|
||||||
placeholder="请选择计价方式"
|
|
||||||
allow-clear
|
|
||||||
>
|
|
||||||
<a-select-option value="1">一口价</a-select-option>
|
|
||||||
<a-select-option value="2">阶梯价</a-select-option>
|
|
||||||
</a-select>
|
|
||||||
</a-form-item>
|
|
||||||
</a-col>
|
|
||||||
|
|
||||||
<!-- 一口价时显示起运地类型和目的地类型 -->
|
|
||||||
<template v-if="formState.priceType === '1'">
|
|
||||||
<!-- 起运地类型(前端UI控制字段) -->
|
|
||||||
<a-col :span="12">
|
|
||||||
<a-form-item label="起运地类型" name="fromLocUIType">
|
|
||||||
<a-select
|
|
||||||
v-model:value="formState.fromLocUIType"
|
|
||||||
placeholder="请选择起运地类型"
|
|
||||||
allow-clear
|
|
||||||
@change="handleFromLocTypeChange"
|
|
||||||
>
|
|
||||||
<a-select-option value="railway">铁路场站</a-select-option>
|
|
||||||
<a-select-option value="dock">码头</a-select-option>
|
|
||||||
<a-select-option value="door">门点地址</a-select-option>
|
|
||||||
</a-select>
|
|
||||||
</a-form-item>
|
|
||||||
</a-col>
|
|
||||||
|
|
||||||
<!-- 目的地类型(前端UI控制字段) -->
|
|
||||||
<a-col :span="12">
|
|
||||||
<a-form-item label="目的地类型" name="toLocUIType">
|
|
||||||
<a-select
|
|
||||||
v-model:value="formState.toLocUIType"
|
|
||||||
placeholder="请选择目的地类型"
|
|
||||||
allow-clear
|
|
||||||
@change="handleToLocTypeChange"
|
|
||||||
>
|
|
||||||
<a-select-option value="railway">铁路场站</a-select-option>
|
|
||||||
<a-select-option value="dock">码头</a-select-option>
|
|
||||||
<a-select-option value="door">门点地址</a-select-option>
|
|
||||||
</a-select>
|
|
||||||
</a-form-item>
|
|
||||||
</a-col>
|
|
||||||
|
|
||||||
<!-- 起运地 -->
|
|
||||||
<a-col :span="12">
|
|
||||||
<a-form-item label="起运地" name="fromLoc">
|
|
||||||
<a-form-item-rest>
|
|
||||||
<div style="display: flex; align-items: center">
|
|
||||||
<!-- 铁路场站或码头:使用下拉选择 -->
|
|
||||||
<a-select
|
|
||||||
v-if="formState.fromLocUIType === 'railway' || formState.fromLocUIType === 'dock'"
|
|
||||||
v-model:value="formState.fromLoc"
|
|
||||||
:placeholder="formState.fromLocUIType === 'railway' ? '请选择铁路场站' : '请选择码头'"
|
|
||||||
allow-clear
|
|
||||||
show-search
|
|
||||||
:filter-option="filterOption"
|
|
||||||
@change="handleFromStationSelect"
|
|
||||||
>
|
|
||||||
<a-select-option
|
|
||||||
v-for="item in fromStationOptions"
|
|
||||||
:key="item.value"
|
|
||||||
:value="item.value"
|
|
||||||
>
|
|
||||||
{{ item.label }}
|
|
||||||
</a-select-option>
|
|
||||||
</a-select>
|
|
||||||
|
|
||||||
<!-- 门点地址:使用搜索选择 -->
|
|
||||||
<a-select
|
|
||||||
v-else
|
|
||||||
v-model:value="formState.fromLoc"
|
|
||||||
show-search
|
|
||||||
placeholder="请输入地点"
|
|
||||||
:filter-option="false"
|
|
||||||
@search="handleLocationSearch"
|
|
||||||
@select="handleRealSelect"
|
|
||||||
@dropdownVisibleChange="handleDropdownHide"
|
|
||||||
>
|
|
||||||
<a-select-option
|
|
||||||
v-for="item in locationOptions"
|
|
||||||
:key="item.uid"
|
|
||||||
:value="item.title"
|
|
||||||
:data="item"
|
|
||||||
>
|
|
||||||
<div>{{ item.title }}</div>
|
|
||||||
</a-select-option>
|
|
||||||
</a-select>
|
|
||||||
|
|
||||||
<!-- 只有门点地址才显示定位按钮 -->
|
|
||||||
<a-button
|
|
||||||
v-if="formState.fromLocUIType === 'door'"
|
|
||||||
@click="handleSelectCoordinates('from')"
|
|
||||||
type="primary"
|
|
||||||
shape="circle"
|
|
||||||
size="small"
|
|
||||||
style="margin-left: 8px"
|
|
||||||
>
|
|
||||||
<template #icon>
|
|
||||||
<EnvironmentOutlined />
|
|
||||||
</template>
|
|
||||||
</a-button>
|
|
||||||
</div>
|
|
||||||
</a-form-item-rest>
|
|
||||||
</a-form-item>
|
|
||||||
</a-col>
|
|
||||||
|
|
||||||
<!-- 目的地 -->
|
|
||||||
<a-col :span="12">
|
|
||||||
<a-form-item label="目的地" name="toLoc">
|
|
||||||
<a-form-item-rest>
|
|
||||||
<div style="display: flex; align-items: center">
|
|
||||||
<!-- 铁路场站或码头:使用下拉选择 -->
|
|
||||||
<a-select
|
|
||||||
v-if="formState.toLocUIType === 'railway' || formState.toLocUIType === 'dock'"
|
|
||||||
v-model:value="formState.toLoc"
|
|
||||||
:placeholder="formState.toLocUIType === 'railway' ? '请选择铁路场站' : '请选择码头'"
|
|
||||||
allow-clear
|
|
||||||
show-search
|
|
||||||
:filter-option="filterOption"
|
|
||||||
@change="handleToStationSelect"
|
|
||||||
>
|
|
||||||
<a-select-option
|
|
||||||
v-for="item in toStationOptions"
|
|
||||||
:key="item.value"
|
|
||||||
:value="item.value"
|
|
||||||
>
|
|
||||||
{{ item.label }}
|
|
||||||
</a-select-option>
|
|
||||||
</a-select>
|
|
||||||
|
|
||||||
<!-- 门点地址:使用下拉选择 -->
|
|
||||||
<a-select
|
|
||||||
v-else
|
|
||||||
v-model:value="formState.toLoc"
|
|
||||||
placeholder="请选择目的地"
|
|
||||||
allow-clear
|
|
||||||
show-search
|
|
||||||
:filter-option="filterOption"
|
|
||||||
@change="handleDoorToChange"
|
|
||||||
>
|
|
||||||
<a-select-option
|
|
||||||
v-for="item in stationOptions"
|
|
||||||
:key="item.value"
|
|
||||||
:value="item.value"
|
|
||||||
>
|
|
||||||
{{ item.label }}
|
|
||||||
</a-select-option>
|
|
||||||
</a-select>
|
|
||||||
|
|
||||||
<!-- 只有门点地址才显示定位按钮 -->
|
|
||||||
<a-button
|
|
||||||
v-if="formState.toLocUIType === 'door'"
|
|
||||||
@click="handleSelectCoordinates('to')"
|
|
||||||
type="primary"
|
|
||||||
shape="circle"
|
|
||||||
size="small"
|
|
||||||
style="margin-left: 8px"
|
|
||||||
>
|
|
||||||
<template #icon>
|
|
||||||
<EnvironmentOutlined />
|
|
||||||
</template>
|
|
||||||
</a-button>
|
|
||||||
</div>
|
|
||||||
</a-form-item-rest>
|
|
||||||
</a-form-item>
|
|
||||||
</a-col>
|
|
||||||
|
|
||||||
<!-- 价格 -->
|
|
||||||
<a-col :span="12">
|
|
||||||
<a-form-item label="价格(元)" name="basePrice">
|
|
||||||
<a-form-item-rest>
|
|
||||||
<div style="display: flex; align-items: center">
|
|
||||||
<a-input-number
|
|
||||||
style="flex: 1; margin-right: 10px"
|
|
||||||
v-model:value="formState.basePrice"
|
|
||||||
placeholder="请输入运价"
|
|
||||||
/>
|
|
||||||
<a-input disabled value="元" style="width: 100px" placeholder="单位" />
|
|
||||||
</div>
|
|
||||||
</a-form-item-rest>
|
|
||||||
</a-form-item>
|
|
||||||
</a-col>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<a-col :span="12">
|
|
||||||
<a-form-item label="运价备注" name="priceRemark">
|
|
||||||
<a-input
|
|
||||||
style="width: 100%"
|
|
||||||
v-model:value="formState.priceRemark"
|
|
||||||
placeholder="请输入运价备注"
|
|
||||||
/>
|
|
||||||
</a-form-item>
|
|
||||||
</a-col>
|
|
||||||
|
|
||||||
<a-col :span="12">
|
|
||||||
<a-form-item label="预计时长" name="estTime">
|
|
||||||
<a-form-item-rest>
|
|
||||||
<div style="display: flex; align-items: center">
|
|
||||||
<a-input-number
|
|
||||||
style="flex: 1; margin-right: 10px"
|
|
||||||
v-model:value="formState.estTime"
|
|
||||||
type="number"
|
|
||||||
min="0"
|
|
||||||
placeholder="请输入预计时长"
|
|
||||||
/>
|
|
||||||
<a-select
|
|
||||||
v-model:value="formState.estTimeUnit"
|
|
||||||
style="width: 100px"
|
|
||||||
placeholder="单位"
|
|
||||||
>
|
|
||||||
<a-select-option value="D">天</a-select-option>
|
|
||||||
<a-select-option value="H">小时</a-select-option>
|
|
||||||
</a-select>
|
|
||||||
</div>
|
|
||||||
</a-form-item-rest>
|
|
||||||
</a-form-item>
|
|
||||||
</a-col>
|
|
||||||
|
|
||||||
<a-col :span="12">
|
|
||||||
<a-form-item label="揽货备注" name="cargoRemark">
|
|
||||||
<a-input v-model:value="formState.cargoRemark" placeholder="请输入揽货备注" />
|
|
||||||
</a-form-item>
|
|
||||||
</a-col>
|
|
||||||
|
|
||||||
<gridientComp
|
|
||||||
v-if="formState.priceType === '2'"
|
|
||||||
v-model:modelValue="formState.elementTieredPriceList"
|
|
||||||
/>
|
|
||||||
</a-row>
|
|
||||||
</a-form>
|
|
||||||
|
|
||||||
<locationSelect ref="locationSelectRef" @location-selected="changeLocation" />
|
|
||||||
</a-modal>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { ref, reactive, nextTick, watch } from 'vue';
|
|
||||||
import { FormInstance, message } from 'ant-design-vue';
|
|
||||||
import locationSelect from '../../../commonComponents/locationSelect.vue';
|
|
||||||
import { addTruckInfo, editTruckInfo, getTruckInfoById, getBaiduPlace } from '@/api/qcwl';
|
|
||||||
import * as commonApi from '@/api/common';
|
|
||||||
import type { RuleObject } from 'ant-design-vue/lib/form/interface';
|
|
||||||
import { noLoginlistStation } from '@/api/sysOrgRelation';
|
|
||||||
import { commonMixin } from '@/mixins/commonMixin';
|
|
||||||
import gridientComp from './gridientComp.vue';
|
|
||||||
|
|
||||||
const { filterOption } = commonMixin();
|
|
||||||
|
|
||||||
interface StationOption {
|
|
||||||
label: string;
|
|
||||||
value: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const emit = defineEmits(['refresh']);
|
|
||||||
|
|
||||||
const formRef = ref<FormInstance>();
|
|
||||||
const locationSelectRef = ref();
|
|
||||||
const visible = ref(false);
|
|
||||||
|
|
||||||
// 起运地站点选项(铁路场站/码头)
|
|
||||||
const fromStationOptions = ref<StationOption[]>([]);
|
|
||||||
// 目的地站点选项(铁路场站/码头)
|
|
||||||
const toStationOptions = ref<StationOption[]>([]);
|
|
||||||
// 门点地址选项
|
|
||||||
const stationOptions = ref<StationOption[]>([]);
|
|
||||||
|
|
||||||
// 位置搜索选项
|
|
||||||
const locationOptions = ref<any[]>([]);
|
|
||||||
let realInputValue = '';
|
|
||||||
|
|
||||||
// 当前操作的坐标类型(用于定位回调)
|
|
||||||
let currentCoordType: 'from' | 'to' = 'from';
|
|
||||||
|
|
||||||
const formState = reactive<any>({
|
|
||||||
id: undefined,
|
|
||||||
busType: '集装箱',
|
|
||||||
// 后端接口字段(保持不变)
|
|
||||||
fromLocType: 'city',
|
|
||||||
toLocType: 'railway',
|
|
||||||
// 前端UI控制字段(不提交给后端)
|
|
||||||
fromLocUIType: 'door',
|
|
||||||
toLocUIType: 'door',
|
|
||||||
fromLoc: undefined,
|
|
||||||
toLoc: undefined,
|
|
||||||
basePrice: undefined,
|
|
||||||
priceRemark: undefined,
|
|
||||||
estTime: undefined,
|
|
||||||
estTimeUnit: 'D',
|
|
||||||
cargoRemark: undefined,
|
|
||||||
fromLocPosition: '',
|
|
||||||
toLocPosition: '',
|
|
||||||
priceType: '1',
|
|
||||||
elementTieredPriceList: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
const rules: Record<string, RuleObject | RuleObject[]> = {
|
|
||||||
busType: [{ required: true, message: '请选择短驳类型' }],
|
|
||||||
fromLocUIType: [{ required: true, message: '请选择起运地类型' }],
|
|
||||||
toLocUIType: [{ required: true, message: '请选择目的地类型' }],
|
|
||||||
fromLoc: [{ required: true, message: '请选择起运地' }],
|
|
||||||
toLoc: [{ required: true, message: '请选择目的地' }],
|
|
||||||
basePrice: [{ required: true, message: '请输入运价' }],
|
|
||||||
estTime: [{ required: true, message: '请输入预计时长' }],
|
|
||||||
estTimeUnit: [{ required: true, message: '请选择预计时长单位' }],
|
|
||||||
priceType: [{ required: true, message: '请选择计价方式' }],
|
|
||||||
};
|
|
||||||
|
|
||||||
const showModal = (row?: any) => {
|
|
||||||
// 初始化站点选项
|
|
||||||
initStationOptions();
|
|
||||||
// 初始化门点地址选项
|
|
||||||
initDoorStationOptions();
|
|
||||||
// 清空位置搜索
|
|
||||||
locationOptions.value = [];
|
|
||||||
|
|
||||||
if (row && row.id) {
|
|
||||||
getTruckInfoById(row.id).then((res) => {
|
|
||||||
// 从后端获取数据,UI类型默认设置为door
|
|
||||||
Object.assign(formState, {
|
|
||||||
...res.result,
|
|
||||||
fromLocUIType: 'door',
|
|
||||||
toLocUIType: 'door',
|
|
||||||
});
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
Object.assign(formState, {
|
|
||||||
id: undefined,
|
|
||||||
busType: '集装箱',
|
|
||||||
fromLocType: 'city',
|
|
||||||
toLocType: 'railway',
|
|
||||||
fromLocUIType: 'door',
|
|
||||||
toLocUIType: 'door',
|
|
||||||
fromLoc: undefined,
|
|
||||||
toLoc: undefined,
|
|
||||||
basePrice: undefined,
|
|
||||||
priceRemark: undefined,
|
|
||||||
estTime: undefined,
|
|
||||||
estTimeUnit: 'D',
|
|
||||||
cargoRemark: undefined,
|
|
||||||
fromLocPosition: '',
|
|
||||||
toLocPosition: '',
|
|
||||||
priceType: '1',
|
|
||||||
elementTieredPriceList: [],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
visible.value = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
// 初始化站点选项(铁路场站和码头)- 占位数据
|
|
||||||
const initStationOptions = () => {
|
|
||||||
// 铁路场站占位数据(待接口对接)
|
|
||||||
const railwayStations = [
|
|
||||||
{ label: '上海铁路场站', value: 'shanghai_railway' },
|
|
||||||
{ label: '北京铁路场站', value: 'beijing_railway' },
|
|
||||||
{ label: '广州铁路场站', value: 'guangzhou_railway' },
|
|
||||||
{ label: '深圳铁路场站', value: 'shenzhen_railway' },
|
|
||||||
{ label: '成都铁路场站', value: 'chengdu_railway' },
|
|
||||||
{ label: '武汉铁路场站', value: 'wuhan_railway' },
|
|
||||||
];
|
|
||||||
|
|
||||||
// 码头占位数据(待接口对接)
|
|
||||||
const dockStations = [
|
|
||||||
{ label: '上海港码头', value: 'shanghai_dock' },
|
|
||||||
{ label: '宁波港码头', value: 'ningbo_dock' },
|
|
||||||
{ label: '深圳港码头', value: 'shenzhen_dock' },
|
|
||||||
{ label: '广州港码头', value: 'guangzhou_dock' },
|
|
||||||
{ label: '青岛港码头', value: 'qingdao_dock' },
|
|
||||||
{ label: '天津港码头', value: 'tianjin_dock' },
|
|
||||||
];
|
|
||||||
|
|
||||||
// 合并所有站点供选择(实际使用时可区分铁路和码头)
|
|
||||||
fromStationOptions.value = [...railwayStations, ...dockStations];
|
|
||||||
toStationOptions.value = [...railwayStations, ...dockStations];
|
|
||||||
};
|
|
||||||
|
|
||||||
// 初始化门点地址选项
|
|
||||||
const initDoorStationOptions = () => {
|
|
||||||
noLoginlistStation({}).then((res) => {
|
|
||||||
if (res.code !== '0000') {
|
|
||||||
return Promise.reject(res);
|
|
||||||
}
|
|
||||||
stationOptions.value = res.result.map((item: any) => ({
|
|
||||||
label: item,
|
|
||||||
value: item,
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// 起运地类型变更
|
|
||||||
const handleFromLocTypeChange = (val: string) => {
|
|
||||||
formState.fromLoc = undefined;
|
|
||||||
formState.fromLocPosition = '';
|
|
||||||
// 如果不是门点地址,清空搜索选项
|
|
||||||
if (val !== 'door') {
|
|
||||||
locationOptions.value = [];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 目的地类型变更
|
|
||||||
const handleToLocTypeChange = (val: string) => {
|
|
||||||
formState.toLoc = undefined;
|
|
||||||
formState.toLocPosition = '';
|
|
||||||
};
|
|
||||||
|
|
||||||
// 起运地铁路/码头选择
|
|
||||||
const handleFromStationSelect = (val: string) => {
|
|
||||||
// 从站点列表中查找对应的经纬度
|
|
||||||
const found = fromStationOptions.value.find((item) => item.value === val);
|
|
||||||
if (found) {
|
|
||||||
// TODO: 从后端获取对应站点的经纬度,目前使用示例坐标
|
|
||||||
formState.fromLocPosition = '121.4737,31.2304';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 目的地铁路/码头选择
|
|
||||||
const handleToStationSelect = (val: string) => {
|
|
||||||
const found = toStationOptions.value.find((item) => item.value === val);
|
|
||||||
if (found) {
|
|
||||||
// TODO: 从后端获取对应站点的经纬度,目前使用示例坐标
|
|
||||||
formState.toLocPosition = '121.4737,31.2304';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 起运地门点地址搜索选择
|
|
||||||
const handleRealSelect = (selectedTitle: string, option: any) => {
|
|
||||||
const selectedItem = option.data;
|
|
||||||
formState.fromLocPosition = `${selectedItem.point.lng},${selectedItem.point.lat}`;
|
|
||||||
};
|
|
||||||
|
|
||||||
// 起运地搜索
|
|
||||||
const handleLocationSearch = async (value: string) => {
|
|
||||||
realInputValue = value;
|
|
||||||
if (!value.trim()) {
|
|
||||||
locationOptions.value = [];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
getBaiduPlace(value).then((res) => {
|
|
||||||
locationOptions.value = res.result.results.map((item: any) => ({
|
|
||||||
title: item.name,
|
|
||||||
point: { lat: item.location.lat, lng: item.location.lng },
|
|
||||||
uid: item.uid,
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
console.error('搜索失败:', error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 起运地下拉隐藏
|
|
||||||
const handleDropdownHide = (visible: boolean) => {
|
|
||||||
if (!visible) {
|
|
||||||
nextTick(() => {
|
|
||||||
formState.fromLoc = realInputValue;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 目的地门点地址选择
|
|
||||||
const handleDoorToChange = (val: string) => {
|
|
||||||
if (val) {
|
|
||||||
// TODO: 根据实际数据获取经纬度
|
|
||||||
formState.toLocPosition = '121.4737,31.2304';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 选择坐标(起运地或目的地)
|
|
||||||
const handleSelectCoordinates = (type: 'from' | 'to') => {
|
|
||||||
currentCoordType = type;
|
|
||||||
locationSelectRef.value.showModal(formState);
|
|
||||||
};
|
|
||||||
|
|
||||||
// 坐标选择回调
|
|
||||||
const changeLocation = (data: { lng: number; lat: number }) => {
|
|
||||||
const position = `${data.lng},${data.lat}`;
|
|
||||||
if (currentCoordType === 'from') {
|
|
||||||
formState.fromLocPosition = position;
|
|
||||||
} else {
|
|
||||||
formState.toLocPosition = position;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleCancel = () => {
|
|
||||||
visible.value = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
// 提交前处理:将UI类型映射到后端字段
|
|
||||||
const prepareSubmitData = () => {
|
|
||||||
const submitData = { ...formState };
|
|
||||||
|
|
||||||
// 根据UI类型设置后端字段(如果需要映射)
|
|
||||||
// 注意:fromLocType 和 toLocType 保持后端支持的值
|
|
||||||
// 如果 UI 类型是 railway,可以设置 fromLocType = 'railway' 等
|
|
||||||
// 但根据你的说明,后端不支持其他值,所以保持原样
|
|
||||||
|
|
||||||
// 删除前端UI控制字段(不提交给后端)
|
|
||||||
delete submitData.fromLocUIType;
|
|
||||||
delete submitData.toLocUIType;
|
|
||||||
|
|
||||||
return submitData;
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleOk = async () => {
|
|
||||||
// 阶梯价校验
|
|
||||||
if (formState.priceType === '2') {
|
|
||||||
if (!formState.elementTieredPriceList || formState.elementTieredPriceList.length === 0) {
|
|
||||||
message.error('请设置梯度价格');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const invalidRows = formState.elementTieredPriceList
|
|
||||||
.map((item: any, index: number) => ({
|
|
||||||
index: index + 1,
|
|
||||||
hasError: !item.distance || !item.price,
|
|
||||||
}))
|
|
||||||
.filter((item: any) => item.hasError);
|
|
||||||
if (invalidRows.length > 0) {
|
|
||||||
message.error(`第 ${invalidRows.map((r: any) => r.index).join(', ')} 行的距离或价格未填写`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 一口价校验
|
|
||||||
if (formState.priceType === '1') {
|
|
||||||
if (!formState.fromLocPosition) {
|
|
||||||
message.error('请选择起运地经纬度');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!formState.toLocPosition) {
|
|
||||||
message.error('请选择目的地经纬度');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
await formRef.value?.validateFields();
|
|
||||||
|
|
||||||
const submitData = prepareSubmitData();
|
|
||||||
|
|
||||||
if (formState.id) {
|
|
||||||
editTruckInfo(submitData).then((res) => {
|
|
||||||
if (res.code === '0000') {
|
|
||||||
message.success('更新成功');
|
|
||||||
emit('refresh');
|
|
||||||
visible.value = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
addTruckInfo(submitData).then((res) => {
|
|
||||||
if (res.code === '0000') {
|
|
||||||
message.success('新增成功');
|
|
||||||
emit('refresh');
|
|
||||||
visible.value = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.log('验证失败:', error);
|
|
||||||
message.error('请检查表单数据');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
defineExpose({ showModal });
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped></style>
|
|
||||||
@@ -1,727 +0,0 @@
|
|||||||
<template>
|
|
||||||
<a-modal
|
|
||||||
v-model:visible="visible"
|
|
||||||
centered
|
|
||||||
title="公路运输产品新增"
|
|
||||||
width="800px"
|
|
||||||
@cancel="handleCancel"
|
|
||||||
@ok="handleOk"
|
|
||||||
>
|
|
||||||
<a-form
|
|
||||||
ref="formRef"
|
|
||||||
:model="formState"
|
|
||||||
:label-col="{ span: 8 }"
|
|
||||||
:wrapper-col="{ span: 16 }"
|
|
||||||
:rules="rules"
|
|
||||||
>
|
|
||||||
<a-row :gutter="16">
|
|
||||||
<a-col :span="12">
|
|
||||||
<a-form-item label="短驳类型" name="busType">
|
|
||||||
<a-select
|
|
||||||
v-model:value="formState.busType"
|
|
||||||
placeholder="请选择短驳类型"
|
|
||||||
allow-clear
|
|
||||||
>
|
|
||||||
<a-select-option value="集装箱">集装箱</a-select-option>
|
|
||||||
<a-select-option value="散杂货">散杂货</a-select-option>
|
|
||||||
</a-select>
|
|
||||||
</a-form-item>
|
|
||||||
</a-col>
|
|
||||||
<a-col :span="12">
|
|
||||||
<a-form-item label="计价方式" name="priceType">
|
|
||||||
<a-select
|
|
||||||
v-model:value="formState.priceType"
|
|
||||||
placeholder="请选择计价方式"
|
|
||||||
allow-clear
|
|
||||||
>
|
|
||||||
<a-select-option value="1">一口价</a-select-option>
|
|
||||||
<a-select-option value="2">阶梯价</a-select-option>
|
|
||||||
</a-select>
|
|
||||||
</a-form-item>
|
|
||||||
</a-col>
|
|
||||||
|
|
||||||
<!-- 一口价时显示起运地类型和目的地类型 -->
|
|
||||||
<template v-if="formState.priceType === '1'">
|
|
||||||
<!-- 起运地类型(前端UI控制字段) -->
|
|
||||||
<a-col :span="12">
|
|
||||||
<a-form-item label="起运地类型" name="fromLocUIType">
|
|
||||||
<a-select
|
|
||||||
v-model:value="formState.fromLocUIType"
|
|
||||||
placeholder="请选择起运地类型"
|
|
||||||
allow-clear
|
|
||||||
@change="handleFromLocTypeChange"
|
|
||||||
>
|
|
||||||
<a-select-option value="railway">铁路场站</a-select-option>
|
|
||||||
<a-select-option value="dock">码头</a-select-option>
|
|
||||||
<a-select-option value="door">门点地址</a-select-option>
|
|
||||||
</a-select>
|
|
||||||
</a-form-item>
|
|
||||||
</a-col>
|
|
||||||
|
|
||||||
<!-- 目的地类型(前端UI控制字段) -->
|
|
||||||
<a-col :span="12">
|
|
||||||
<a-form-item label="目的地类型" name="toLocUIType">
|
|
||||||
<a-select
|
|
||||||
v-model:value="formState.toLocUIType"
|
|
||||||
placeholder="请选择目的地类型"
|
|
||||||
allow-clear
|
|
||||||
@change="handleToLocTypeChange"
|
|
||||||
>
|
|
||||||
<a-select-option value="railway">铁路场站</a-select-option>
|
|
||||||
<a-select-option value="dock">码头</a-select-option>
|
|
||||||
<a-select-option value="door">门点地址</a-select-option>
|
|
||||||
</a-select>
|
|
||||||
</a-form-item>
|
|
||||||
</a-col>
|
|
||||||
|
|
||||||
<!-- 起运地 -->
|
|
||||||
<a-col :span="12">
|
|
||||||
<a-form-item label="起运地" name="fromLoc">
|
|
||||||
<a-form-item-rest>
|
|
||||||
<div style="display: flex; align-items: center">
|
|
||||||
<!-- 铁路场站 -->
|
|
||||||
<a-select
|
|
||||||
v-if="formState.fromLocUIType === 'railway'"
|
|
||||||
v-model:value="formState.fromLoc"
|
|
||||||
placeholder="请选择铁路场站"
|
|
||||||
allow-clear
|
|
||||||
show-search
|
|
||||||
:filter-option="filterOption"
|
|
||||||
@change="handleFromStationSelect"
|
|
||||||
>
|
|
||||||
<a-select-option
|
|
||||||
v-for="item in fromRailwayOptions"
|
|
||||||
:key="item.value"
|
|
||||||
:value="item.value"
|
|
||||||
>
|
|
||||||
{{ item.label }}
|
|
||||||
</a-select-option>
|
|
||||||
</a-select>
|
|
||||||
|
|
||||||
<!-- 码头 -->
|
|
||||||
<a-select
|
|
||||||
v-else-if="formState.fromLocUIType === 'dock'"
|
|
||||||
v-model:value="formState.fromLoc"
|
|
||||||
placeholder="请选择码头"
|
|
||||||
allow-clear
|
|
||||||
show-search
|
|
||||||
:filter-option="filterOption"
|
|
||||||
@change="handleFromStationSelect"
|
|
||||||
>
|
|
||||||
<a-select-option
|
|
||||||
v-for="item in fromDockOptions"
|
|
||||||
:key="item.value"
|
|
||||||
:value="item.value"
|
|
||||||
>
|
|
||||||
{{ item.label }}
|
|
||||||
</a-select-option>
|
|
||||||
</a-select>
|
|
||||||
|
|
||||||
<!-- 门点地址:百度地图搜索 -->
|
|
||||||
<a-select
|
|
||||||
v-else
|
|
||||||
v-model:value="formState.fromLoc"
|
|
||||||
show-search
|
|
||||||
placeholder="请输入地点"
|
|
||||||
:filter-option="false"
|
|
||||||
@search="handleFromLocationSearch"
|
|
||||||
@select="handleFromRealSelect"
|
|
||||||
@dropdownVisibleChange="handleFromDropdownHide"
|
|
||||||
>
|
|
||||||
<a-select-option
|
|
||||||
v-for="item in fromLocationOptions"
|
|
||||||
:key="item.uid"
|
|
||||||
:value="item.title"
|
|
||||||
:data="item"
|
|
||||||
>
|
|
||||||
<div>{{ item.title }}</div>
|
|
||||||
</a-select-option>
|
|
||||||
</a-select>
|
|
||||||
|
|
||||||
<!-- 只有门点地址才显示定位按钮 -->
|
|
||||||
<a-button
|
|
||||||
v-if="formState.fromLocUIType === 'door'"
|
|
||||||
@click="handleSelectCoordinates('from')"
|
|
||||||
type="primary"
|
|
||||||
shape="circle"
|
|
||||||
size="small"
|
|
||||||
style="margin-left: 8px"
|
|
||||||
>
|
|
||||||
<template #icon>
|
|
||||||
<EnvironmentOutlined />
|
|
||||||
</template>
|
|
||||||
</a-button>
|
|
||||||
</div>
|
|
||||||
</a-form-item-rest>
|
|
||||||
</a-form-item>
|
|
||||||
</a-col>
|
|
||||||
|
|
||||||
<!-- 目的地 -->
|
|
||||||
<a-col :span="12">
|
|
||||||
<a-form-item label="目的地" name="toLoc">
|
|
||||||
<a-form-item-rest>
|
|
||||||
<div style="display: flex; align-items: center">
|
|
||||||
<!-- 铁路场站 -->
|
|
||||||
<a-select
|
|
||||||
v-if="formState.toLocUIType === 'railway'"
|
|
||||||
v-model:value="formState.toLoc"
|
|
||||||
placeholder="请选择铁路场站"
|
|
||||||
allow-clear
|
|
||||||
show-search
|
|
||||||
:filter-option="filterOption"
|
|
||||||
@change="handleToStationSelect"
|
|
||||||
>
|
|
||||||
<a-select-option
|
|
||||||
v-for="item in toRailwayOptions"
|
|
||||||
:key="item.value"
|
|
||||||
:value="item.value"
|
|
||||||
>
|
|
||||||
{{ item.label }}
|
|
||||||
</a-select-option>
|
|
||||||
</a-select>
|
|
||||||
|
|
||||||
<!-- 码头 -->
|
|
||||||
<a-select
|
|
||||||
v-else-if="formState.toLocUIType === 'dock'"
|
|
||||||
v-model:value="formState.toLoc"
|
|
||||||
placeholder="请选择码头"
|
|
||||||
allow-clear
|
|
||||||
show-search
|
|
||||||
:filter-option="filterOption"
|
|
||||||
@change="handleToStationSelect"
|
|
||||||
>
|
|
||||||
<a-select-option
|
|
||||||
v-for="item in toDockOptions"
|
|
||||||
:key="item.value"
|
|
||||||
:value="item.value"
|
|
||||||
>
|
|
||||||
{{ item.label }}
|
|
||||||
</a-select-option>
|
|
||||||
</a-select>
|
|
||||||
|
|
||||||
<!-- 门点地址:百度地图搜索 -->
|
|
||||||
<a-select
|
|
||||||
v-else
|
|
||||||
v-model:value="formState.toLoc"
|
|
||||||
show-search
|
|
||||||
placeholder="请输入地点"
|
|
||||||
:filter-option="false"
|
|
||||||
@search="handleToLocationSearch"
|
|
||||||
@select="handleToRealSelect"
|
|
||||||
@dropdownVisibleChange="handleToDropdownHide"
|
|
||||||
>
|
|
||||||
<a-select-option
|
|
||||||
v-for="item in toLocationOptions"
|
|
||||||
:key="item.uid"
|
|
||||||
:value="item.title"
|
|
||||||
:data="item"
|
|
||||||
>
|
|
||||||
<div>{{ item.title }}</div>
|
|
||||||
</a-select-option>
|
|
||||||
</a-select>
|
|
||||||
|
|
||||||
<!-- 只有门点地址才显示定位按钮 -->
|
|
||||||
<a-button
|
|
||||||
v-if="formState.toLocUIType === 'door'"
|
|
||||||
@click="handleSelectCoordinates('to')"
|
|
||||||
type="primary"
|
|
||||||
shape="circle"
|
|
||||||
size="small"
|
|
||||||
style="margin-left: 8px"
|
|
||||||
>
|
|
||||||
<template #icon>
|
|
||||||
<EnvironmentOutlined />
|
|
||||||
</template>
|
|
||||||
</a-button>
|
|
||||||
</div>
|
|
||||||
</a-form-item-rest>
|
|
||||||
</a-form-item>
|
|
||||||
</a-col>
|
|
||||||
|
|
||||||
<!-- 价格 -->
|
|
||||||
<a-col :span="12">
|
|
||||||
<a-form-item label="价格(元)" name="basePrice">
|
|
||||||
<a-form-item-rest>
|
|
||||||
<div style="display: flex; align-items: center">
|
|
||||||
<a-input-number
|
|
||||||
style="flex: 1; margin-right: 10px"
|
|
||||||
v-model:value="formState.basePrice"
|
|
||||||
placeholder="请输入运价"
|
|
||||||
/>
|
|
||||||
<a-input disabled value="元" style="width: 100px" placeholder="单位" />
|
|
||||||
</div>
|
|
||||||
</a-form-item-rest>
|
|
||||||
</a-form-item>
|
|
||||||
</a-col>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<a-col :span="12">
|
|
||||||
<a-form-item label="运价备注" name="priceRemark">
|
|
||||||
<a-input
|
|
||||||
style="width: 100%"
|
|
||||||
v-model:value="formState.priceRemark"
|
|
||||||
placeholder="请输入运价备注"
|
|
||||||
/>
|
|
||||||
</a-form-item>
|
|
||||||
</a-col>
|
|
||||||
|
|
||||||
<a-col :span="12">
|
|
||||||
<a-form-item label="预计时长" name="estTime">
|
|
||||||
<a-form-item-rest>
|
|
||||||
<div style="display: flex; align-items: center">
|
|
||||||
<a-input-number
|
|
||||||
style="flex: 1; margin-right: 10px"
|
|
||||||
v-model:value="formState.estTime"
|
|
||||||
type="number"
|
|
||||||
min="0"
|
|
||||||
placeholder="请输入预计时长"
|
|
||||||
/>
|
|
||||||
<a-select
|
|
||||||
v-model:value="formState.estTimeUnit"
|
|
||||||
style="width: 100px"
|
|
||||||
placeholder="单位"
|
|
||||||
>
|
|
||||||
<a-select-option value="D">天</a-select-option>
|
|
||||||
<a-select-option value="H">小时</a-select-option>
|
|
||||||
</a-select>
|
|
||||||
</div>
|
|
||||||
</a-form-item-rest>
|
|
||||||
</a-form-item>
|
|
||||||
</a-col>
|
|
||||||
|
|
||||||
<a-col :span="12">
|
|
||||||
<a-form-item label="揽货备注" name="cargoRemark">
|
|
||||||
<a-input v-model:value="formState.cargoRemark" placeholder="请输入揽货备注" />
|
|
||||||
</a-form-item>
|
|
||||||
</a-col>
|
|
||||||
|
|
||||||
<gridientComp
|
|
||||||
v-if="formState.priceType === '2'"
|
|
||||||
v-model:modelValue="formState.elementTieredPriceList"
|
|
||||||
/>
|
|
||||||
</a-row>
|
|
||||||
</a-form>
|
|
||||||
|
|
||||||
<locationSelect ref="locationSelectRef" @location-selected="changeLocation" />
|
|
||||||
</a-modal>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { ref, reactive, nextTick } from 'vue';
|
|
||||||
import { FormInstance, message } from 'ant-design-vue';
|
|
||||||
import locationSelect from '../../../commonComponents/locationSelect.vue';
|
|
||||||
import { addTruckInfo, editTruckInfo, getTruckInfoById, getBaiduPlace } from '@/api/qcwl';
|
|
||||||
import * as commonApi from '@/api/common';
|
|
||||||
import type { RuleObject } from 'ant-design-vue/lib/form/interface';
|
|
||||||
import { noLoginlistStation } from '@/api/sysOrgRelation';
|
|
||||||
import { commonMixin } from '@/mixins/commonMixin';
|
|
||||||
import gridientComp from './gridientComp.vue';
|
|
||||||
|
|
||||||
const { filterOption } = commonMixin();
|
|
||||||
|
|
||||||
interface StationOption {
|
|
||||||
label: string;
|
|
||||||
value: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface LocationItem {
|
|
||||||
title: string;
|
|
||||||
point: { lat: number; lng: number };
|
|
||||||
uid: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const emit = defineEmits(['refresh']);
|
|
||||||
|
|
||||||
const formRef = ref<FormInstance>();
|
|
||||||
const locationSelectRef = ref();
|
|
||||||
const visible = ref(false);
|
|
||||||
|
|
||||||
// ==================== 数据源定义 ====================
|
|
||||||
|
|
||||||
// 起运地 - 铁路场站选项
|
|
||||||
const fromRailwayOptions = ref<StationOption[]>([]);
|
|
||||||
// 起运地 - 码头选项
|
|
||||||
const fromDockOptions = ref<StationOption[]>([]);
|
|
||||||
// 目的地 - 铁路场站选项
|
|
||||||
const toRailwayOptions = ref<StationOption[]>([]);
|
|
||||||
// 目的地 - 码头选项
|
|
||||||
const toDockOptions = ref<StationOption[]>([]);
|
|
||||||
|
|
||||||
// 起运地 - 百度地图搜索选项(门点地址专用)
|
|
||||||
const fromLocationOptions = ref<LocationItem[]>([]);
|
|
||||||
// 目的地 - 百度地图搜索选项(门点地址专用)
|
|
||||||
const toLocationOptions = ref<LocationItem[]>([]);
|
|
||||||
|
|
||||||
// 起运地搜索暂存值
|
|
||||||
let fromRealInputValue = '';
|
|
||||||
// 目的地搜索暂存值
|
|
||||||
let toRealInputValue = '';
|
|
||||||
|
|
||||||
// 当前操作的坐标类型(用于定位回调)
|
|
||||||
let currentCoordType: 'from' | 'to' = 'from';
|
|
||||||
|
|
||||||
// ==================== 表单数据 ====================
|
|
||||||
|
|
||||||
const formState = reactive<any>({
|
|
||||||
id: undefined,
|
|
||||||
busType: '集装箱',
|
|
||||||
// 后端接口字段(保持不变)
|
|
||||||
fromLocType: 'city',
|
|
||||||
toLocType: 'railway',
|
|
||||||
// 前端UI控制字段(不提交给后端)
|
|
||||||
fromLocUIType: 'door',
|
|
||||||
toLocUIType: 'door',
|
|
||||||
fromLoc: undefined,
|
|
||||||
toLoc: undefined,
|
|
||||||
basePrice: undefined,
|
|
||||||
priceRemark: undefined,
|
|
||||||
estTime: undefined,
|
|
||||||
estTimeUnit: 'D',
|
|
||||||
cargoRemark: undefined,
|
|
||||||
fromLocPosition: '',
|
|
||||||
toLocPosition: '',
|
|
||||||
priceType: '1',
|
|
||||||
elementTieredPriceList: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
// ==================== 校验规则 ====================
|
|
||||||
|
|
||||||
const rules: Record<string, RuleObject | RuleObject[]> = {
|
|
||||||
busType: [{ required: true, message: '请选择短驳类型' }],
|
|
||||||
fromLocUIType: [{ required: true, message: '请选择起运地类型' }],
|
|
||||||
toLocUIType: [{ required: true, message: '请选择目的地类型' }],
|
|
||||||
fromLoc: [{ required: true, message: '请选择起运地' }],
|
|
||||||
toLoc: [{ required: true, message: '请选择目的地' }],
|
|
||||||
basePrice: [{ required: true, message: '请输入运价' }],
|
|
||||||
estTime: [{ required: true, message: '请输入预计时长' }],
|
|
||||||
estTimeUnit: [{ required: true, message: '请选择预计时长单位' }],
|
|
||||||
priceType: [{ required: true, message: '请选择计价方式' }],
|
|
||||||
};
|
|
||||||
|
|
||||||
// ==================== 数据加载函数 ====================
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 加载铁路场站列表
|
|
||||||
*/
|
|
||||||
const loadRailwayStationList = () => {
|
|
||||||
// 接口不存在时使用占位数据
|
|
||||||
const railwayPlaceholder = [
|
|
||||||
{ label: '上海铁路场站', value: 'shanghai_railway' },
|
|
||||||
{ label: '北京铁路场站', value: 'beijing_railway' },
|
|
||||||
{ label: '广州铁路场站', value: 'guangzhou_railway' },
|
|
||||||
{ label: '深圳铁路场站', value: 'shenzhen_railway' },
|
|
||||||
{ label: '成都铁路场站', value: 'chengdu_railway' },
|
|
||||||
{ label: '武汉铁路场站', value: 'wuhan_railway' },
|
|
||||||
{ label: '郑州铁路场站', value: 'zhengzhou_railway' },
|
|
||||||
{ label: '西安铁路场站', value: 'xian_railway' },
|
|
||||||
];
|
|
||||||
fromRailwayOptions.value = railwayPlaceholder;
|
|
||||||
toRailwayOptions.value = railwayPlaceholder;
|
|
||||||
|
|
||||||
// 如果接口已存在,使用下面的代码替换上面
|
|
||||||
/*
|
|
||||||
noLoginlistStation({ type: 'railway' }).then((res) => {
|
|
||||||
if (res.code !== '0000') {
|
|
||||||
return Promise.reject(res);
|
|
||||||
}
|
|
||||||
const list = res.result.map((item: any) => ({
|
|
||||||
label: item,
|
|
||||||
value: item,
|
|
||||||
}));
|
|
||||||
fromRailwayOptions.value = list;
|
|
||||||
toRailwayOptions.value = list;
|
|
||||||
});
|
|
||||||
*/
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 加载码头列表
|
|
||||||
*/
|
|
||||||
const loadDockStationList = () => {
|
|
||||||
// 接口不存在时使用占位数据
|
|
||||||
const dockPlaceholder = [
|
|
||||||
{ label: '上海港码头', value: 'shanghai_dock' },
|
|
||||||
{ label: '宁波港码头', value: 'ningbo_dock' },
|
|
||||||
{ label: '深圳港码头', value: 'shenzhen_dock' },
|
|
||||||
{ label: '广州港码头', value: 'guangzhou_dock' },
|
|
||||||
{ label: '青岛港码头', value: 'qingdao_dock' },
|
|
||||||
{ label: '天津港码头', value: 'tianjin_dock' },
|
|
||||||
{ label: '大连港码头', value: 'dalian_dock' },
|
|
||||||
{ label: '厦门港码头', value: 'xiamen_dock' },
|
|
||||||
];
|
|
||||||
fromDockOptions.value = dockPlaceholder;
|
|
||||||
toDockOptions.value = dockPlaceholder;
|
|
||||||
|
|
||||||
// 如果接口已存在,使用下面的代码替换上面
|
|
||||||
/*
|
|
||||||
noLoginlistStation({ type: 'dock' }).then((res) => {
|
|
||||||
if (res.code !== '0000') {
|
|
||||||
return Promise.reject(res);
|
|
||||||
}
|
|
||||||
const list = res.result.map((item: any) => ({
|
|
||||||
label: item,
|
|
||||||
value: item,
|
|
||||||
}));
|
|
||||||
fromDockOptions.value = list;
|
|
||||||
toDockOptions.value = list;
|
|
||||||
});
|
|
||||||
*/
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 初始化所有下拉数据
|
|
||||||
*/
|
|
||||||
const initAllOptions = () => {
|
|
||||||
loadRailwayStationList();
|
|
||||||
loadDockStationList();
|
|
||||||
// 清空百度地图搜索选项
|
|
||||||
fromLocationOptions.value = [];
|
|
||||||
toLocationOptions.value = [];
|
|
||||||
};
|
|
||||||
|
|
||||||
// ==================== UI 交互函数 ====================
|
|
||||||
|
|
||||||
const showModal = (row?: any) => {
|
|
||||||
initAllOptions();
|
|
||||||
|
|
||||||
if (row && row.id) {
|
|
||||||
getTruckInfoById(row.id).then((res) => {
|
|
||||||
Object.assign(formState, {
|
|
||||||
...res.result,
|
|
||||||
fromLocUIType: 'door',
|
|
||||||
toLocUIType: 'door',
|
|
||||||
});
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
Object.assign(formState, {
|
|
||||||
id: undefined,
|
|
||||||
busType: '集装箱',
|
|
||||||
fromLocType: 'city',
|
|
||||||
toLocType: 'railway',
|
|
||||||
fromLocUIType: 'door',
|
|
||||||
toLocUIType: 'door',
|
|
||||||
fromLoc: undefined,
|
|
||||||
toLoc: undefined,
|
|
||||||
basePrice: undefined,
|
|
||||||
priceRemark: undefined,
|
|
||||||
estTime: undefined,
|
|
||||||
estTimeUnit: 'D',
|
|
||||||
cargoRemark: undefined,
|
|
||||||
fromLocPosition: '',
|
|
||||||
toLocPosition: '',
|
|
||||||
priceType: '1',
|
|
||||||
elementTieredPriceList: [],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
visible.value = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
// 起运地类型变更
|
|
||||||
const handleFromLocTypeChange = (val: string) => {
|
|
||||||
formState.fromLoc = undefined;
|
|
||||||
formState.fromLocPosition = '';
|
|
||||||
if (val !== 'door') {
|
|
||||||
fromLocationOptions.value = [];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 目的地类型变更
|
|
||||||
const handleToLocTypeChange = (val: string) => {
|
|
||||||
formState.toLoc = undefined;
|
|
||||||
formState.toLocPosition = '';
|
|
||||||
if (val !== 'door') {
|
|
||||||
toLocationOptions.value = [];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// ==================== 起运地 - 铁路/码头选择 ====================
|
|
||||||
|
|
||||||
const handleFromStationSelect = (val: string) => {
|
|
||||||
let found: StationOption | undefined;
|
|
||||||
if (formState.fromLocUIType === 'railway') {
|
|
||||||
found = fromRailwayOptions.value.find((item) => item.value === val);
|
|
||||||
} else if (formState.fromLocUIType === 'dock') {
|
|
||||||
found = fromDockOptions.value.find((item) => item.value === val);
|
|
||||||
}
|
|
||||||
if (found) {
|
|
||||||
// TODO: 从后端获取对应站点的经纬度,目前使用示例坐标
|
|
||||||
formState.fromLocPosition = '121.4737,31.2304';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// ==================== 目的地 - 铁路/码头选择 ====================
|
|
||||||
|
|
||||||
const handleToStationSelect = (val: string) => {
|
|
||||||
let found: StationOption | undefined;
|
|
||||||
if (formState.toLocUIType === 'railway') {
|
|
||||||
found = toRailwayOptions.value.find((item) => item.value === val);
|
|
||||||
} else if (formState.toLocUIType === 'dock') {
|
|
||||||
found = toDockOptions.value.find((item) => item.value === val);
|
|
||||||
}
|
|
||||||
if (found) {
|
|
||||||
// TODO: 从后端获取对应站点的经纬度,目前使用示例坐标
|
|
||||||
formState.toLocPosition = '121.4737,31.2304';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// ==================== 起运地 - 门点地址(百度地图搜索) ====================
|
|
||||||
|
|
||||||
const handleFromLocationSearch = async (value: string) => {
|
|
||||||
fromRealInputValue = value;
|
|
||||||
if (!value.trim()) {
|
|
||||||
fromLocationOptions.value = [];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
getBaiduPlace(value).then((res) => {
|
|
||||||
fromLocationOptions.value = res.result.results.map((item: any) => ({
|
|
||||||
title: item.name,
|
|
||||||
point: { lat: item.location.lat, lng: item.location.lng },
|
|
||||||
uid: item.uid,
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
console.error('搜索失败:', error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleFromRealSelect = (selectedTitle: string, option: any) => {
|
|
||||||
const selectedItem = option.data;
|
|
||||||
formState.fromLocPosition = `${selectedItem.point.lng},${selectedItem.point.lat}`;
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleFromDropdownHide = (visible: boolean) => {
|
|
||||||
if (!visible) {
|
|
||||||
nextTick(() => {
|
|
||||||
formState.fromLoc = fromRealInputValue;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// ==================== 目的地 - 门点地址(百度地图搜索) ====================
|
|
||||||
|
|
||||||
const handleToLocationSearch = async (value: string) => {
|
|
||||||
toRealInputValue = value;
|
|
||||||
if (!value.trim()) {
|
|
||||||
toLocationOptions.value = [];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
getBaiduPlace(value).then((res) => {
|
|
||||||
toLocationOptions.value = res.result.results.map((item: any) => ({
|
|
||||||
title: item.name,
|
|
||||||
point: { lat: item.location.lat, lng: item.location.lng },
|
|
||||||
uid: item.uid,
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
console.error('搜索失败:', error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleToRealSelect = (selectedTitle: string, option: any) => {
|
|
||||||
const selectedItem = option.data;
|
|
||||||
formState.toLocPosition = `${selectedItem.point.lng},${selectedItem.point.lat}`;
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleToDropdownHide = (visible: boolean) => {
|
|
||||||
if (!visible) {
|
|
||||||
nextTick(() => {
|
|
||||||
formState.toLoc = toRealInputValue;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// ==================== 定位按钮 ====================
|
|
||||||
|
|
||||||
const handleSelectCoordinates = (type: 'from' | 'to') => {
|
|
||||||
currentCoordType = type;
|
|
||||||
locationSelectRef.value.showModal(formState);
|
|
||||||
};
|
|
||||||
|
|
||||||
const changeLocation = (data: { lng: number; lat: number }) => {
|
|
||||||
const position = `${data.lng},${data.lat}`;
|
|
||||||
if (currentCoordType === 'from') {
|
|
||||||
formState.fromLocPosition = position;
|
|
||||||
} else {
|
|
||||||
formState.toLocPosition = position;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// ==================== 提交逻辑 ====================
|
|
||||||
|
|
||||||
const handleCancel = () => {
|
|
||||||
visible.value = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
const prepareSubmitData = () => {
|
|
||||||
const submitData = { ...formState };
|
|
||||||
// 删除前端UI控制字段
|
|
||||||
delete submitData.fromLocUIType;
|
|
||||||
delete submitData.toLocUIType;
|
|
||||||
return submitData;
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleOk = async () => {
|
|
||||||
// 阶梯价校验
|
|
||||||
if (formState.priceType === '2') {
|
|
||||||
if (!formState.elementTieredPriceList || formState.elementTieredPriceList.length === 0) {
|
|
||||||
message.error('请设置梯度价格');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const invalidRows = formState.elementTieredPriceList
|
|
||||||
.map((item: any, index: number) => ({
|
|
||||||
index: index + 1,
|
|
||||||
hasError: !item.distance || !item.price,
|
|
||||||
}))
|
|
||||||
.filter((item: any) => item.hasError);
|
|
||||||
if (invalidRows.length > 0) {
|
|
||||||
message.error(`第 ${invalidRows.map((r: any) => r.index).join(', ')} 行的距离或价格未填写`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 一口价校验
|
|
||||||
if (formState.priceType === '1') {
|
|
||||||
if (!formState.fromLocPosition) {
|
|
||||||
message.error('请选择起运地经纬度');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!formState.toLocPosition) {
|
|
||||||
message.error('请选择目的地经纬度');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
await formRef.value?.validateFields();
|
|
||||||
|
|
||||||
const submitData = prepareSubmitData();
|
|
||||||
|
|
||||||
if (formState.id) {
|
|
||||||
editTruckInfo(submitData).then((res) => {
|
|
||||||
if (res.code === '0000') {
|
|
||||||
message.success('更新成功');
|
|
||||||
emit('refresh');
|
|
||||||
visible.value = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
addTruckInfo(submitData).then((res) => {
|
|
||||||
if (res.code === '0000') {
|
|
||||||
message.success('新增成功');
|
|
||||||
emit('refresh');
|
|
||||||
visible.value = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.log('验证失败:', error);
|
|
||||||
message.error('请检查表单数据');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
defineExpose({ showModal });
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped></style>
|
|
||||||
@@ -1090,21 +1090,24 @@ function splitFilesByCategory(source = {}) {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
contractBodyFileName:
|
contractBodyFileName:
|
||||||
getFileNameFromDetail(source, "body") || bodyFile.fileName || "",
|
source.contractBodyFileName ||
|
||||||
|
bodyFile.fileName ||
|
||||||
|
getFileNameFromDetail(source, "body") ||
|
||||||
|
"",
|
||||||
contractBodyFilePath:
|
contractBodyFilePath:
|
||||||
source.contractBodyFilePath ||
|
source.contractBodyFilePath ||
|
||||||
source.contractTextFilePath ||
|
|
||||||
bodyFile.filePath ||
|
bodyFile.filePath ||
|
||||||
|
source.contractTextFilePath ||
|
||||||
"",
|
"",
|
||||||
contractBodyFileType:
|
contractBodyFileType:
|
||||||
source.contractBodyFileType ||
|
source.contractBodyFileType ||
|
||||||
source.contractTextFileType ||
|
|
||||||
bodyFile.fileType ||
|
bodyFile.fileType ||
|
||||||
|
source.contractTextFileType ||
|
||||||
"",
|
"",
|
||||||
contractBodyFileSize:
|
contractBodyFileSize:
|
||||||
source.contractBodyFileSize ??
|
source.contractBodyFileSize ??
|
||||||
source.contractTextFileSize ??
|
|
||||||
bodyFile.fileSize ??
|
bodyFile.fileSize ??
|
||||||
|
source.contractTextFileSize ??
|
||||||
null,
|
null,
|
||||||
otherAttachmentList: source.otherAttachmentList?.length
|
otherAttachmentList: source.otherAttachmentList?.length
|
||||||
? source.otherAttachmentList.map(normalizeFileItem)
|
? source.otherAttachmentList.map(normalizeFileItem)
|
||||||
@@ -1181,6 +1184,9 @@ function createEmptyParty(roleCode, index = 0) {
|
|||||||
oppositeId: "",
|
oppositeId: "",
|
||||||
companyName: "",
|
companyName: "",
|
||||||
companyType: "",
|
companyType: "",
|
||||||
|
companyNature: "",
|
||||||
|
orgNature: "",
|
||||||
|
orgNatureLevel: "",
|
||||||
oppositeCharacter: "",
|
oppositeCharacter: "",
|
||||||
oppCharacter: "",
|
oppCharacter: "",
|
||||||
contactName: "",
|
contactName: "",
|
||||||
@@ -1190,6 +1196,8 @@ function createEmptyParty(roleCode, index = 0) {
|
|||||||
registeredAddress: "",
|
registeredAddress: "",
|
||||||
legalRepresentative: "",
|
legalRepresentative: "",
|
||||||
creditCode: "",
|
creditCode: "",
|
||||||
|
registeredCapitalText: "",
|
||||||
|
countryName: "",
|
||||||
naturalPersonIdType: "",
|
naturalPersonIdType: "",
|
||||||
naturalPersonIdNumber: "",
|
naturalPersonIdNumber: "",
|
||||||
isGroupInternal: false,
|
isGroupInternal: false,
|
||||||
@@ -1731,6 +1739,9 @@ function mapPartnerToParty(raw = {}, roleKey, companyName) {
|
|||||||
oppositeId: raw.oppositeId || "",
|
oppositeId: raw.oppositeId || "",
|
||||||
companyName: raw.customerNameC || companyName || "",
|
companyName: raw.customerNameC || companyName || "",
|
||||||
companyType: getRelativeTypeLabel(raw.relativeType),
|
companyType: getRelativeTypeLabel(raw.relativeType),
|
||||||
|
companyNature: raw.oppositeCharacter || "",
|
||||||
|
orgNature: raw.natureOfEnterpriseOrg || "",
|
||||||
|
orgNatureLevel: raw.natureOfEnterpriseOrgLev || "",
|
||||||
oppositeCharacter: raw.oppositeCharacter || "",
|
oppositeCharacter: raw.oppositeCharacter || "",
|
||||||
oppCharacter: raw.oppositeCharacter || "",
|
oppCharacter: raw.oppositeCharacter || "",
|
||||||
creditCode: raw.customerTaxno || "",
|
creditCode: raw.customerTaxno || "",
|
||||||
@@ -1740,6 +1751,8 @@ function mapPartnerToParty(raw = {}, roleKey, companyName) {
|
|||||||
contactPhone: firstContact.contactPhone || raw.officephone || "",
|
contactPhone: firstContact.contactPhone || raw.officephone || "",
|
||||||
contactEmail: firstContact.email || raw.emailAddress || "",
|
contactEmail: firstContact.email || raw.emailAddress || "",
|
||||||
contactAddress: firstContact.postalAddress || raw.customerAddress || "",
|
contactAddress: firstContact.postalAddress || raw.customerAddress || "",
|
||||||
|
registeredCapitalText: raw.regCapital || raw.registeredCapital || "",
|
||||||
|
countryName: raw.countryName || raw.country || "",
|
||||||
naturalPersonIdType: raw.certificateType || "",
|
naturalPersonIdType: raw.certificateType || "",
|
||||||
naturalPersonIdNumber: raw.certificateNum || "",
|
naturalPersonIdNumber: raw.certificateNum || "",
|
||||||
isGroupInternal: raw.groupFlag === "Y" || raw.isJtn === "1",
|
isGroupInternal: raw.groupFlag === "Y" || raw.isJtn === "1",
|
||||||
@@ -1754,12 +1767,19 @@ function mapOrgNodeToParty(raw = {}) {
|
|||||||
...createEmptyParty(PARTY_ROLE_OUR),
|
...createEmptyParty(PARTY_ROLE_OUR),
|
||||||
subjectCode: raw.orgId == null ? "" : String(raw.orgId),
|
subjectCode: raw.orgId == null ? "" : String(raw.orgId),
|
||||||
companyName: raw.orgName || "",
|
companyName: raw.orgName || "",
|
||||||
|
companyNature: raw.companyNature || "1",
|
||||||
|
orgNature: raw.orgNature || "QY",
|
||||||
|
orgNatureLevel: raw.orgNatureLevel || "",
|
||||||
contactPhone: raw.contactPhone || "",
|
contactPhone: raw.contactPhone || "",
|
||||||
contactEmail: raw.contactEmail || "",
|
contactEmail: raw.contactEmail || "",
|
||||||
contactAddress: raw.contactAddress || "",
|
contactAddress: raw.contactAddress || "",
|
||||||
registeredAddress: raw.registeredAddress || "",
|
registeredAddress: raw.registeredAddress || "",
|
||||||
legalRepresentative: raw.legalRepresentative || "",
|
legalRepresentative: raw.legalRepresentative || "",
|
||||||
creditCode: raw.creditCode || "",
|
creditCode: raw.creditCode || "",
|
||||||
|
registeredCapitalText: raw.regCapital || raw.registeredCapital || "",
|
||||||
|
countryName: raw.countryName || raw.country || "",
|
||||||
|
isGroupInternal: true,
|
||||||
|
isHongKongMacaoTaiwan: false,
|
||||||
roleCode: PARTY_ROLE_OUR,
|
roleCode: PARTY_ROLE_OUR,
|
||||||
roleName: "我方",
|
roleName: "我方",
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -220,6 +220,7 @@ import {
|
|||||||
} from "../../shared/templateFieldDict.js";
|
} from "../../shared/templateFieldDict.js";
|
||||||
import { renderTemplateDocxBlob } from "../../shared/templateDocxRenderer.js";
|
import { renderTemplateDocxBlob } from "../../shared/templateDocxRenderer.js";
|
||||||
import { buildTemplateLaunchFieldList } from "../../shared/templateVariableConfig.js";
|
import { buildTemplateLaunchFieldList } from "../../shared/templateVariableConfig.js";
|
||||||
|
import { buildOurPartyAutoFillValues } from "../../shared/templateAutoFillMappings.js";
|
||||||
import TemplateRichTextEditor from "./TemplateRichTextEditor.vue";
|
import TemplateRichTextEditor from "./TemplateRichTextEditor.vue";
|
||||||
import {
|
import {
|
||||||
extraAmountFieldOptions,
|
extraAmountFieldOptions,
|
||||||
@@ -317,6 +318,21 @@ function createParty(roleCode = PARTY_ROLE_OPPOSITE, index = 0) {
|
|||||||
: `相对方${index + 1}`,
|
: `相对方${index + 1}`,
|
||||||
subjectCode: "",
|
subjectCode: "",
|
||||||
companyName: "",
|
companyName: "",
|
||||||
|
companyType: "",
|
||||||
|
companyNature: "",
|
||||||
|
orgNature: "",
|
||||||
|
orgNatureLevel: "",
|
||||||
|
isGroupInternal: false,
|
||||||
|
isHongKongMacaoTaiwan: false,
|
||||||
|
creditCode: "",
|
||||||
|
registeredAddress: "",
|
||||||
|
legalRepresentative: "",
|
||||||
|
registeredCapitalText: "",
|
||||||
|
contactName: "",
|
||||||
|
contactPhone: "",
|
||||||
|
contactEmail: "",
|
||||||
|
contactAddress: "",
|
||||||
|
countryName: "",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -335,6 +351,9 @@ function mapLaunchPartyToFormParty(item = {}) {
|
|||||||
oppositeId: item.oppositeId || "",
|
oppositeId: item.oppositeId || "",
|
||||||
companyName: item.companyName || "",
|
companyName: item.companyName || "",
|
||||||
companyType: item.companyType || "",
|
companyType: item.companyType || "",
|
||||||
|
companyNature: item.companyNature || item.oppositeCharacter || "",
|
||||||
|
orgNature: item.orgNature || item.natureOfEnterpriseOrg || "",
|
||||||
|
orgNatureLevel: item.orgNatureLevel || item.natureOfEnterpriseOrgLev || "",
|
||||||
oppCharacter: item.oppositeCharacter || "",
|
oppCharacter: item.oppositeCharacter || "",
|
||||||
contactName: item.contactName || "",
|
contactName: item.contactName || "",
|
||||||
contactPhone: item.contactPhone || "",
|
contactPhone: item.contactPhone || "",
|
||||||
@@ -343,6 +362,9 @@ function mapLaunchPartyToFormParty(item = {}) {
|
|||||||
registeredAddress: item.registeredAddress || "",
|
registeredAddress: item.registeredAddress || "",
|
||||||
legalRepresentative: item.legalRepresentative || "",
|
legalRepresentative: item.legalRepresentative || "",
|
||||||
creditCode: item.creditCode || "",
|
creditCode: item.creditCode || "",
|
||||||
|
registeredCapitalText:
|
||||||
|
item.registeredCapitalText || item.regCapital || item.registeredCapital || "",
|
||||||
|
countryName: item.countryName || item.country || "",
|
||||||
bankName: item.bankName || "",
|
bankName: item.bankName || "",
|
||||||
bankAccount: item.bankAccount || "",
|
bankAccount: item.bankAccount || "",
|
||||||
naturalPersonIdType: item.naturalPersonIdType || "",
|
naturalPersonIdType: item.naturalPersonIdType || "",
|
||||||
@@ -1257,6 +1279,16 @@ function prefillFromMainFields(rawSource) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let changed = false;
|
let changed = false;
|
||||||
|
const ourPartyAutoFillValues = buildOurPartyAutoFillValues(contractDetailState.value);
|
||||||
|
Object.entries(ourPartyAutoFillValues).forEach(([key, value]) => {
|
||||||
|
if (!keysToFill.has(key)) return;
|
||||||
|
if (values[key] !== undefined && values[key] !== null && values[key] !== "") return;
|
||||||
|
if (value !== undefined && value !== null && value !== "") {
|
||||||
|
values[key] = String(value);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
keysToFill.forEach(key => {
|
keysToFill.forEach(key => {
|
||||||
if (values[key] !== undefined && values[key] !== null && values[key] !== "") return;
|
if (values[key] !== undefined && values[key] !== null && values[key] !== "") return;
|
||||||
// 1. 先尝试从当前合同详情直接取(同名字段)
|
// 1. 先尝试从当前合同详情直接取(同名字段)
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
:title="modalTitle"
|
:title="modalTitle"
|
||||||
width="96%"
|
width="96%"
|
||||||
:footer="null"
|
:footer="null"
|
||||||
|
centered
|
||||||
:mask-closable="false"
|
:mask-closable="false"
|
||||||
:destroy-on-close="false"
|
:destroy-on-close="false"
|
||||||
wrap-class-name="seal-position-config-wrap"
|
wrap-class-name="seal-position-config-wrap"
|
||||||
@@ -80,6 +81,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="config-pane">
|
<div class="config-pane">
|
||||||
|
<div class="config-pane-scroll">
|
||||||
<div class="side-card">
|
<div class="side-card">
|
||||||
<div class="side-card-title">合同信息</div>
|
<div class="side-card-title">合同信息</div>
|
||||||
<div class="meta-item">
|
<div class="meta-item">
|
||||||
@@ -177,8 +179,13 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="side-card side-card-grow">
|
<div class="side-card side-card-grow">
|
||||||
<div class="side-card-title">签章位列表</div>
|
<div class="side-card-title">签章位列表({{ sortedPositions.length }})</div>
|
||||||
<div class="position-list">
|
<div class="position-list">
|
||||||
|
<a-empty
|
||||||
|
v-if="!sortedPositions.length"
|
||||||
|
class="position-list-empty"
|
||||||
|
description="暂无签章位,请先点击左侧“添加签章位”"
|
||||||
|
/>
|
||||||
<div
|
<div
|
||||||
v-for="box in sortedPositions"
|
v-for="box in sortedPositions"
|
||||||
:key="box.localId"
|
:key="box.localId"
|
||||||
@@ -198,6 +205,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="footer-actions">
|
<div class="footer-actions">
|
||||||
<a-space>
|
<a-space>
|
||||||
@@ -702,14 +710,23 @@ defineExpose({ showModal })
|
|||||||
flex: 0 0 380px;
|
flex: 0 0 380px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 12px;
|
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
overflow-y: auto;
|
overflow: hidden;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
background: linear-gradient(180deg, #fbfdff 0%, #f5f8fc 100%);
|
background: linear-gradient(180deg, #fbfdff 0%, #f5f8fc 100%);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.config-pane-scroll {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
min-height: 0;
|
||||||
|
overflow-y: auto;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
padding-right: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
.side-card {
|
.side-card {
|
||||||
border-radius: 16px;
|
border-radius: 16px;
|
||||||
border: 1px solid #e2e8f0;
|
border: 1px solid #e2e8f0;
|
||||||
@@ -719,7 +736,7 @@ defineExpose({ showModal })
|
|||||||
|
|
||||||
.side-card-grow {
|
.side-card-grow {
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
min-height: 0;
|
min-height: 220px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
@@ -766,11 +783,14 @@ defineExpose({ showModal })
|
|||||||
|
|
||||||
.position-list {
|
.position-list {
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
min-height: 0;
|
min-height: 160px;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
|
padding: 4px;
|
||||||
|
border-radius: 12px;
|
||||||
|
background: #ffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.position-list-item {
|
.position-list-item {
|
||||||
@@ -781,7 +801,9 @@ defineExpose({ showModal })
|
|||||||
padding: 12px;
|
padding: 12px;
|
||||||
border: 1px solid #dbe4f0;
|
border: 1px solid #dbe4f0;
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
|
background: #ffffff;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
flex-shrink: 0;
|
||||||
transition: all 0.2s ease;
|
transition: all 0.2s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -803,11 +825,16 @@ defineExpose({ showModal })
|
|||||||
color: #64748b;
|
color: #64748b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.position-list-empty {
|
||||||
|
margin: auto 0;
|
||||||
|
padding: 24px 0;
|
||||||
|
}
|
||||||
|
|
||||||
.footer-actions {
|
.footer-actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
position: sticky;
|
flex: 0 0 auto;
|
||||||
bottom: 0;
|
margin-top: 12px;
|
||||||
padding-top: 12px;
|
padding-top: 12px;
|
||||||
padding-bottom: 4px;
|
padding-bottom: 4px;
|
||||||
background: linear-gradient(180deg, rgba(245, 248, 252, 0) 0%, rgba(245, 248, 252, 0.96) 24%, rgba(245, 248, 252, 1) 100%);
|
background: linear-gradient(180deg, rgba(245, 248, 252, 0) 0%, rgba(245, 248, 252, 0.96) 24%, rgba(245, 248, 252, 1) 100%);
|
||||||
|
|||||||
@@ -155,6 +155,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<a-space>
|
<a-space>
|
||||||
|
<a-tooltip title="查看甲方信息自动带出规则">
|
||||||
|
<a-button size="small" @click="autoFillGuideVisible = true">
|
||||||
|
<InfoCircleOutlined />
|
||||||
|
甲方带出说明
|
||||||
|
</a-button>
|
||||||
|
</a-tooltip>
|
||||||
<a-button @click="handleDownloadVariableGuide">
|
<a-button @click="handleDownloadVariableGuide">
|
||||||
<DownloadOutlined />
|
<DownloadOutlined />
|
||||||
下载变量说明
|
下载变量说明
|
||||||
@@ -324,6 +330,43 @@
|
|||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
</a-modal>
|
</a-modal>
|
||||||
|
|
||||||
|
<a-modal
|
||||||
|
v-model:open="autoFillGuideVisible"
|
||||||
|
title="甲方自动带出变量"
|
||||||
|
width="760px"
|
||||||
|
:footer="null"
|
||||||
|
>
|
||||||
|
<div class="auto-fill-guide">
|
||||||
|
<a-alert
|
||||||
|
type="info"
|
||||||
|
show-icon
|
||||||
|
message="使用规则"
|
||||||
|
description="模板中写入下列中文变量后,合同发起选择甲方并进入合同正文配置时,系统会从甲方信息自动填入。只有一个甲方时会填“甲方名称”这类变量;多个甲方时使用“甲方1名称”“甲方名称列表”。"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div class="guide-section">
|
||||||
|
<h4>单甲方变量</h4>
|
||||||
|
<div class="guide-tag-list">
|
||||||
|
<a-tag v-for="name in ourPartySingleVariables" :key="name">{{ name }}</a-tag>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="guide-section">
|
||||||
|
<h4>多甲方变量(支持甲方1到甲方{{ OUR_PARTY_AUTO_FILL_MAX_COUNT }})</h4>
|
||||||
|
<div class="guide-tag-list">
|
||||||
|
<a-tag v-for="name in ourPartyIndexedVariables" :key="name">{{ name }}</a-tag>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="guide-section">
|
||||||
|
<h4>汇总变量</h4>
|
||||||
|
<div class="guide-tag-list">
|
||||||
|
<a-tag v-for="name in ourPartyListVariables" :key="name">{{ name }}</a-tag>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a-modal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
@@ -334,6 +377,7 @@ import {
|
|||||||
DeleteOutlined,
|
DeleteOutlined,
|
||||||
DownloadOutlined,
|
DownloadOutlined,
|
||||||
FileWordOutlined,
|
FileWordOutlined,
|
||||||
|
InfoCircleOutlined,
|
||||||
PlusOutlined,
|
PlusOutlined,
|
||||||
ReloadOutlined,
|
ReloadOutlined,
|
||||||
} from '@ant-design/icons-vue'
|
} from '@ant-design/icons-vue'
|
||||||
@@ -358,6 +402,13 @@ import {
|
|||||||
normalizeTemplateVariableMapping,
|
normalizeTemplateVariableMapping,
|
||||||
TEMPLATE_FIELD_TYPE_OPTIONS,
|
TEMPLATE_FIELD_TYPE_OPTIONS,
|
||||||
} from '../../shared/templateVariableConfig.js'
|
} from '../../shared/templateVariableConfig.js'
|
||||||
|
import {
|
||||||
|
getOurPartyAutoFillFieldOptions,
|
||||||
|
getOurPartyAutoFillIndexedVariableNames,
|
||||||
|
getOurPartyAutoFillListVariableNames,
|
||||||
|
getOurPartyAutoFillSingleVariableNames,
|
||||||
|
OUR_PARTY_AUTO_FILL_MAX_COUNT,
|
||||||
|
} from '../../shared/templateAutoFillMappings.js'
|
||||||
import {
|
import {
|
||||||
loadDictTypeOptions,
|
loadDictTypeOptions,
|
||||||
buildDictTypeSelectOptions,
|
buildDictTypeSelectOptions,
|
||||||
@@ -388,6 +439,7 @@ const templateArrayBuffer = ref(null)
|
|||||||
const templateUploadList = ref([])
|
const templateUploadList = ref([])
|
||||||
const variableMappings = ref([])
|
const variableMappings = ref([])
|
||||||
const detectedVariableKeys = ref([])
|
const detectedVariableKeys = ref([])
|
||||||
|
const autoFillGuideVisible = ref(false)
|
||||||
const orgTreeData = ref([])
|
const orgTreeData = ref([])
|
||||||
const SHOW_PARENT = 'SHOW_PARENT'
|
const SHOW_PARENT = 'SHOW_PARENT'
|
||||||
const templateFieldList = ref([])
|
const templateFieldList = ref([])
|
||||||
@@ -400,14 +452,22 @@ const templateFieldLabelMap = computed(() =>
|
|||||||
)
|
)
|
||||||
|
|
||||||
const templateFieldAutoOptions = computed(() =>
|
const templateFieldAutoOptions = computed(() =>
|
||||||
(templateFieldList.value || []).map((item) => ({
|
[
|
||||||
value: item.value,
|
...(templateFieldList.value || []).map((item) => ({
|
||||||
label: `${item.label}(${item.value})`,
|
value: item.value,
|
||||||
})),
|
label: `${item.label}(${item.value})`,
|
||||||
|
})),
|
||||||
|
...getOurPartyAutoFillFieldOptions(),
|
||||||
|
].filter((item, index, list) =>
|
||||||
|
item.value && list.findIndex((option) => option.value === item.value) === index,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
const fieldTypeOptions = TEMPLATE_FIELD_TYPE_OPTIONS
|
const fieldTypeOptions = TEMPLATE_FIELD_TYPE_OPTIONS
|
||||||
const dictTypePresetOptions = ref([])
|
const dictTypePresetOptions = ref([])
|
||||||
|
const ourPartySingleVariables = getOurPartyAutoFillSingleVariableNames()
|
||||||
|
const ourPartyIndexedVariables = getOurPartyAutoFillIndexedVariableNames()
|
||||||
|
const ourPartyListVariables = getOurPartyAutoFillListVariableNames()
|
||||||
|
|
||||||
const formRules = {
|
const formRules = {
|
||||||
templateName: [{ required: true, message: '请输入范本名称', trigger: 'blur' }],
|
templateName: [{ required: true, message: '请输入范本名称', trigger: 'blur' }],
|
||||||
@@ -895,6 +955,10 @@ function buildVariableGuideText() {
|
|||||||
...templateFieldList.value.map(
|
...templateFieldList.value.map(
|
||||||
(item) => `- ${item.label}: ${item.value}`,
|
(item) => `- ${item.label}: ${item.value}`,
|
||||||
),
|
),
|
||||||
|
'',
|
||||||
|
'甲方自动带出变量:',
|
||||||
|
'说明:单甲方变量仅在只有一个甲方时自动填;多甲方请使用甲方1/甲方2变量或列表变量。',
|
||||||
|
...getOurPartyAutoFillFieldOptions().map((item) => `- ${item.value}`),
|
||||||
]
|
]
|
||||||
|
|
||||||
return lines.join('\r\n')
|
return lines.join('\r\n')
|
||||||
@@ -1068,6 +1132,27 @@ defineExpose({
|
|||||||
margin-bottom: 6px;
|
margin-bottom: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.auto-fill-guide {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16px;
|
||||||
|
max-height: 68vh;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.guide-section h4 {
|
||||||
|
margin: 0 0 8px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #0f172a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.guide-tag-list {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 8px 4px;
|
||||||
|
}
|
||||||
|
|
||||||
.panel-header p {
|
.panel-header p {
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
color: #64748b;
|
color: #64748b;
|
||||||
|
|||||||
@@ -0,0 +1,293 @@
|
|||||||
|
const LIST_SEPARATOR = ";";
|
||||||
|
|
||||||
|
export const OUR_PARTY_AUTO_FILL_MAX_COUNT = 5;
|
||||||
|
|
||||||
|
const RELATIVE_TYPE_LABELS = {
|
||||||
|
client: "客户",
|
||||||
|
supplier: "供应商",
|
||||||
|
Partner: "合作伙伴",
|
||||||
|
clientAndSup: "客户及供应商",
|
||||||
|
other: "其他",
|
||||||
|
};
|
||||||
|
|
||||||
|
const OPPOSITE_CHARACTER_LABELS = {
|
||||||
|
1: "境内组织",
|
||||||
|
2: "境内个人",
|
||||||
|
3: "境外组织",
|
||||||
|
4: "境外个人",
|
||||||
|
};
|
||||||
|
|
||||||
|
const ORG_NATURE_LABELS = {
|
||||||
|
ZF: "政府",
|
||||||
|
ZY: "政府",
|
||||||
|
QY: "企业",
|
||||||
|
QT: "其他组织",
|
||||||
|
};
|
||||||
|
|
||||||
|
const ORG_NATURE_LEVEL_LABELS = {
|
||||||
|
GNQY: "国有企业",
|
||||||
|
MYQY: "民营企业",
|
||||||
|
WZQY: "外资企业",
|
||||||
|
HZQY: "合资企业",
|
||||||
|
GYQZHKGQY: "国有全资和控股企业",
|
||||||
|
QT: "其他",
|
||||||
|
};
|
||||||
|
|
||||||
|
const ID_TYPE_LABELS = {
|
||||||
|
idCard: "身份证",
|
||||||
|
passport: "护照",
|
||||||
|
other: "其他",
|
||||||
|
};
|
||||||
|
|
||||||
|
function normalizeText(value) {
|
||||||
|
if (value === null || value === undefined) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
if (typeof value === "boolean") {
|
||||||
|
return value ? "是" : "否";
|
||||||
|
}
|
||||||
|
return String(value).trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
function pickLabel(value, labelMap) {
|
||||||
|
const text = normalizeText(value);
|
||||||
|
if (!text) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return labelMap[text] || text;
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatBoolean(value) {
|
||||||
|
if (value === true || value === "true" || value === "1" || value === "Y" || value === "是") {
|
||||||
|
return "是";
|
||||||
|
}
|
||||||
|
if (value === false || value === "false" || value === "0" || value === "N" || value === "否") {
|
||||||
|
return "否";
|
||||||
|
}
|
||||||
|
return normalizeText(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatMoneyLike(value) {
|
||||||
|
const text = normalizeText(value);
|
||||||
|
if (!text) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const OUR_PARTY_AUTO_FILL_FIELD_MAPPINGS = [
|
||||||
|
{
|
||||||
|
label: "甲方名称",
|
||||||
|
suffixes: ["名称", "公司名称"],
|
||||||
|
sourceKeys: ["companyName"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "甲方主体编码",
|
||||||
|
suffixes: ["主体编码", "组织编码"],
|
||||||
|
sourceKeys: ["subjectCode"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "甲方公司类型",
|
||||||
|
suffixes: ["公司类型"],
|
||||||
|
sourceKeys: ["companyType", "relativeType"],
|
||||||
|
formatter: (value) => pickLabel(value, RELATIVE_TYPE_LABELS),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "甲方公司性质",
|
||||||
|
suffixes: ["公司性质"],
|
||||||
|
sourceKeys: ["companyNature", "oppositeCharacter", "oppCharacter"],
|
||||||
|
formatter: (value) => pickLabel(value, OPPOSITE_CHARACTER_LABELS),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "甲方组织性质",
|
||||||
|
suffixes: ["组织性质"],
|
||||||
|
sourceKeys: ["orgNature", "natureOfEnterpriseOrg"],
|
||||||
|
formatter: (value) => pickLabel(value, ORG_NATURE_LABELS),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "甲方组织性质企业二级",
|
||||||
|
suffixes: ["组织性质企业二级"],
|
||||||
|
sourceKeys: ["orgNatureLevel", "natureOfEnterpriseOrgLev"],
|
||||||
|
formatter: (value) => pickLabel(value, ORG_NATURE_LEVEL_LABELS),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "甲方是否涉港澳台",
|
||||||
|
suffixes: ["是否涉港澳台"],
|
||||||
|
sourceKeys: ["isHongKongMacaoTaiwan", "isSgat", "gatFlag"],
|
||||||
|
formatter: formatBoolean,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "甲方是否集团内",
|
||||||
|
suffixes: ["是否集团内"],
|
||||||
|
sourceKeys: ["isGroupInternal", "isJtn", "groupFlag"],
|
||||||
|
formatter: formatBoolean,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "甲方统一社会信用代码",
|
||||||
|
suffixes: ["统一社会信用代码", "信用代码"],
|
||||||
|
sourceKeys: ["creditCode", "customerTaxno"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "甲方法定代表人或负责人",
|
||||||
|
suffixes: ["法定代表人或负责人", "法定代表人", "负责人"],
|
||||||
|
sourceKeys: ["legalRepresentative", "legalPersonName"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "甲方注册地址",
|
||||||
|
suffixes: ["注册地址", "地址"],
|
||||||
|
sourceKeys: ["registeredAddress", "customerRegaddr"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "甲方注册资本",
|
||||||
|
suffixes: ["注册资本"],
|
||||||
|
sourceKeys: ["registeredCapitalText", "regCapital", "registeredCapital"],
|
||||||
|
formatter: formatMoneyLike,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "甲方联系人",
|
||||||
|
suffixes: ["联系人"],
|
||||||
|
sourceKeys: ["contactName"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "甲方联系电话",
|
||||||
|
suffixes: ["联系电话", "电话"],
|
||||||
|
sourceKeys: ["contactPhone", "officephone"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "甲方通讯地址",
|
||||||
|
suffixes: ["通讯地址", "联系地址"],
|
||||||
|
sourceKeys: ["contactAddress", "customerAddress"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "甲方电子邮箱",
|
||||||
|
suffixes: ["电子邮箱", "邮箱"],
|
||||||
|
sourceKeys: ["contactEmail", "emailAddress"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "甲方国家",
|
||||||
|
suffixes: ["国家"],
|
||||||
|
sourceKeys: ["countryName", "country"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "甲方自然人证件类型",
|
||||||
|
suffixes: ["自然人证件类型"],
|
||||||
|
sourceKeys: ["naturalPersonIdType", "certificateType"],
|
||||||
|
formatter: (value) => pickLabel(value, ID_TYPE_LABELS),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "甲方自然人证件号码",
|
||||||
|
suffixes: ["自然人证件号码"],
|
||||||
|
sourceKeys: ["naturalPersonIdNumber", "certificateNum"],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
function getPrimarySuffix(mapping) {
|
||||||
|
return mapping.suffixes?.[0] || "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildVariableName(prefix, suffix) {
|
||||||
|
return `${prefix}${suffix}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPartyList(source = {}) {
|
||||||
|
const partyState = source.partyState || source;
|
||||||
|
if (Array.isArray(partyState.ourPartyList)) {
|
||||||
|
return partyState.ourPartyList.filter((party) => normalizeText(party?.companyName || party?.subjectCode));
|
||||||
|
}
|
||||||
|
if (Array.isArray(source.partyList)) {
|
||||||
|
return source.partyList.filter((party) => String(party?.roleCode || "").toUpperCase() === "OUR");
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPartyValue(party = {}, mapping = {}) {
|
||||||
|
for (const key of mapping.sourceKeys || []) {
|
||||||
|
const rawValue = party[key];
|
||||||
|
const value = mapping.formatter ? mapping.formatter(rawValue, party) : normalizeText(rawValue);
|
||||||
|
if (value) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getOurPartyAutoFillSingleVariableNames() {
|
||||||
|
return OUR_PARTY_AUTO_FILL_FIELD_MAPPINGS.flatMap((mapping) =>
|
||||||
|
(mapping.suffixes || []).map((suffix) => buildVariableName("甲方", suffix)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getOurPartyAutoFillIndexedVariableNames(maxCount = OUR_PARTY_AUTO_FILL_MAX_COUNT) {
|
||||||
|
const names = [];
|
||||||
|
for (let index = 1; index <= maxCount; index += 1) {
|
||||||
|
OUR_PARTY_AUTO_FILL_FIELD_MAPPINGS.forEach((mapping) => {
|
||||||
|
(mapping.suffixes || []).forEach((suffix) => {
|
||||||
|
names.push(buildVariableName(`甲方${index}`, suffix));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return names;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getOurPartyAutoFillListVariableNames() {
|
||||||
|
return OUR_PARTY_AUTO_FILL_FIELD_MAPPINGS.map((mapping) =>
|
||||||
|
buildVariableName("甲方", `${getPrimarySuffix(mapping)}列表`),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getOurPartyAutoFillVariableNames() {
|
||||||
|
return [
|
||||||
|
...getOurPartyAutoFillSingleVariableNames(),
|
||||||
|
...getOurPartyAutoFillIndexedVariableNames(),
|
||||||
|
...getOurPartyAutoFillListVariableNames(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getOurPartyAutoFillFieldOptions() {
|
||||||
|
return getOurPartyAutoFillVariableNames().map((name) => ({
|
||||||
|
label: `${name}(甲方自动带出)`,
|
||||||
|
value: name,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildOurPartyAutoFillValues(source = {}) {
|
||||||
|
const parties = getPartyList(source);
|
||||||
|
const values = {};
|
||||||
|
|
||||||
|
parties.slice(0, OUR_PARTY_AUTO_FILL_MAX_COUNT).forEach((party, index) => {
|
||||||
|
const prefix = `甲方${index + 1}`;
|
||||||
|
OUR_PARTY_AUTO_FILL_FIELD_MAPPINGS.forEach((mapping) => {
|
||||||
|
const value = getPartyValue(party, mapping);
|
||||||
|
if (!value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
(mapping.suffixes || []).forEach((suffix) => {
|
||||||
|
values[buildVariableName(prefix, suffix)] = value;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
OUR_PARTY_AUTO_FILL_FIELD_MAPPINGS.forEach((mapping) => {
|
||||||
|
const listValue = parties
|
||||||
|
.map((party) => getPartyValue(party, mapping))
|
||||||
|
.filter(Boolean)
|
||||||
|
.join(LIST_SEPARATOR);
|
||||||
|
if (listValue) {
|
||||||
|
values[buildVariableName("甲方", `${getPrimarySuffix(mapping)}列表`)] = listValue;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (parties.length === 1) {
|
||||||
|
OUR_PARTY_AUTO_FILL_FIELD_MAPPINGS.forEach((mapping) => {
|
||||||
|
const value = getPartyValue(parties[0], mapping);
|
||||||
|
if (!value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
(mapping.suffixes || []).forEach((suffix) => {
|
||||||
|
values[buildVariableName("甲方", suffix)] = value;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return values;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user