feat: 船货修改功能

main
sankeyangshu 2024-12-10 15:48:11 +08:00
parent 016f8ce306
commit b072ce9879
17 changed files with 899 additions and 59 deletions

View File

@ -37,9 +37,9 @@
</template>
</el-upload>
</el-form-item>
<el-form-item label="数据覆盖 :">
<!-- <el-form-item label="数据覆盖 :">
<el-switch v-model="isCover" />
</el-form-item>
</el-form-item> -->
</el-form>
</el-dialog>
</template>
@ -79,6 +79,8 @@ const acceptParams = (params: ExcelParameterProps) => {
dialogVisible.value = true;
};
const emits = defineEmits(['endFileUpload']);
//
const uploadExcel = async (param: UploadRequestOptions) => {
let excelFormData = new FormData();
@ -87,6 +89,7 @@ const uploadExcel = async (param: UploadRequestOptions) => {
await parameter.value.importApi!(excelFormData);
parameter.value.getTableList && parameter.value.getTableList();
dialogVisible.value = false;
emits('endFileUpload');
};
/**

View File

@ -0,0 +1,75 @@
<template>
<el-select
v-model="valueContent"
:placeholder="placeholder"
style="width: 100%"
clearable
filterable
remote
reserve-keyword
remote-show-suffix
:remote-method="onRemoteData"
:loading="selectLoading"
:disabled="disabled"
value-key="id"
>
<el-option v-for="item in optionList" :key="item.id" :label="item.text" :value="item" />
</el-select>
</template>
<script lang="ts" setup>
import { computed, ref } from 'vue';
import { useRequest } from 'vue-hooks-plus';
import { dictionaryListType } from '@/types';
interface SelectType {
value: string | number | dictionaryListType;
placeholder?: string;
disabled?: boolean;
api?: (params: any) => Promise<any>;
}
//
const props = withDefaults(defineProps<SelectType>(), {
value: '',
placeholder: '请选择',
disabled: false,
});
//
const emit = defineEmits<{
(event: 'update:value', value: string | number | dictionaryListType): void;
}>();
const valueContent = computed({
get() {
return props.value;
},
set(val: string | number | dictionaryListType) {
emit('update:value', val);
},
});
// loading
const selectLoading = ref(false);
//
const optionList = ref<dictionaryListType[]>([]);
const { runAsync } = useRequest(props.api!, {
debounceWait: 500,
onSuccess: (list) => {
optionList.value = list.data;
},
});
//
const onRemoteData = async (query: string) => {
selectLoading.value = true;
const { data } = await runAsync({ q: query });
selectLoading.value = false;
optionList.value = data;
};
</script>
<style lang="scss" scoped></style>

View File

@ -1,5 +1,14 @@
import { PageRowsType } from '.';
/**
*
*/
export interface CreateUserType {
id: number;
name: string;
phone: string;
}
/**
*
*/
@ -7,6 +16,7 @@ export interface BoatInfoType {
id: number;
createBy: number;
createDate: string;
createUser: CreateUserType;
updateBy: number;
updateDate: string;
version: number;
@ -201,6 +211,8 @@ export interface ShipType {
seaworthiness: string;
regular: string;
status: string;
layer: number;
fragment: number;
}
/**

View File

@ -48,11 +48,11 @@
<div class="info">
<div class="info-item">
<div class="info-title">发布单位</div>
<div class="info-text">{{ userInfo.enterpriseName }}</div>
<div class="info-text">{{ dialogProps.enterprise?.name }}</div>
</div>
<div class="info-item">
<div class="info-title">发布人</div>
<div class="info-text">{{ userInfo.username }}</div>
<div class="info-text">{{ dialogProps.createUser?.name }}</div>
</div>
<div class="info-item">
<div class="info-title">发布时间</div>
@ -64,7 +64,7 @@
</div>
<div class="info-item">
<div class="info-title">联系电话</div>
<div class="info-text">暂无</div>
<div class="info-text">{{ dialogProps.createUser?.phone }}</div>
</div>
</div>
<div class="footer">
@ -76,9 +76,7 @@
</template>
<script lang="ts" setup>
import { storeToRefs } from 'pinia';
import { ref } from 'vue';
import { useUserStore } from '@/store/modules/user';
import { BoatInfoType } from '@/types/boatInfo';
// dialog
@ -95,10 +93,6 @@ const isShowDialog = (params: BoatInfoType) => {
//
defineExpose({ isShowDialog });
//
const userState = useUserStore();
const { userInfo } = storeToRefs(userState);
</script>
<style lang="scss" scoped>
@ -149,7 +143,6 @@ const { userInfo } = storeToRefs(userState);
.info {
box-sizing: border-box;
width: 238px;
height: 180px;
padding: 15px 20px;
margin-bottom: 10px;
font-family: 'Arial Normal', Arial;

View File

@ -11,7 +11,7 @@
<div class="card-title">请选择船名</div>
<div class="card-text">
<RemoteSelect
v-model:value="searchTableForm.scheduleId"
v-model:value="searchTableForm.scheduleData"
:api="postSaleShipListAPI"
placeholder=""
/>
@ -24,10 +24,10 @@
</el-form>
</div>
<div class="deck">
<div class="deck" v-if="deskShipData?.layer > 0 && searchTableForm.scheduleData?.id">
<div
class="deck-btn"
v-for="item in 12"
v-for="item in deskShipData?.layer"
:class="{ 'deck-btn-active': item === currentDesk }"
:key="item"
@click="onClickOpenDeck(item)"
@ -62,9 +62,9 @@
<div class="right-table">
<el-table v-loading="tableLoading" :data="tableData" style="width: 100%" height="400px">
<el-table-column type="index" label="No." width="50" />
<el-table-column prop="billNo" label="积载编号" align="center" width="160" />
<el-table-column prop="cabin" label="舱段" align="center" width="80" />
<el-table-column prop="billNo" label="贸易类型" align="center" width="160" />
<el-table-column prop="billNo" label="提单号" align="center" width="160" />
<el-table-column label="货名/品牌/型号" align="center" width="200">
<template #default="scope">
<div class="goods-name">
@ -77,21 +77,40 @@
<el-table-column prop="spareNum" label="件杂货" align="center" width="100" />
<el-table-column prop="weight" label="重量 (kg)" align="center" width="100" />
<el-table-column prop="volume" label="体积 (m3)" align="center" width="100" />
<!-- TODO:港口没有 -->
<el-table-column prop="consigner" label="发货人" align="center" width="180" />
<el-table-column prop="consignee" label="收货人" align="center" width="180" />
</el-table>
</div>
<div class="right-map">
<div class="map-content">
<div>
<div style="height: 30px"></div>
<div class="triangle-right"></div>
</div>
<div class="map-deck" v-for="item in deskShipData?.fragment" :key="item">
<div class="map-deck-title">{{ item }}舱段</div>
<div class="map-deck-item">
<div class="item-wrap"><span>No</span>WOW240001</div>
<div class="item-wrap"><span>沃尔沃XC90</span>20</div>
<div class="item-wrap"><span>位置</span>RORO-1-1-1-1</div>
</div>
</div>
</div>
<div class="map-bottom">船舶舱层数据映射关系图 - 此图根据舱单数据生成仅供参考</div>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { ElMessage, ElMessageBox } from 'element-plus';
import { reactive, ref } from 'vue';
import { reactive, ref, watch } from 'vue';
import { postSaleShipListAPI } from '@/api/Boat/info';
import { getManifestFileExportAPI, getManifestListAPI } from '@/api/Manifest';
import RemoteSelect from '@/components/RemoteSelect/index.vue';
import { postShipGetAPI } from '@/api/Ship';
import RemoteSelect from '@/components/RemoteSelect/select.vue';
import { dictionaryListType } from '@/types';
import { ShipType } from '@/types/boatInfo';
import { ManifestType } from '@/types/manifest';
const emits = defineEmits(['ReturnRouter', 'CurrentNav']);
@ -107,15 +126,18 @@ const tableData = ref<ManifestType[]>([]);
//
const searchTableForm = reactive({
scheduleId: '',
scheduleData: {} as dictionaryListType,
});
//
const tableLoading = ref(false);
//
const deskShipData = ref<ShipType>();
//
const onClickSearch = async () => {
if (searchTableForm.scheduleId === '') {
if (!searchTableForm.scheduleData?.id) {
ElMessage({
message: '请选择船名',
type: 'warning',
@ -124,8 +146,13 @@ const onClickSearch = async () => {
}
tableLoading.value = true;
//
const { data: deckData } = await postShipGetAPI({ id: searchTableForm.scheduleData.extra2 });
deskShipData.value = deckData;
const { data } = await getManifestListAPI({
scheduleId: searchTableForm.scheduleId,
scheduleId: searchTableForm.scheduleData.id,
});
tableData.value = data;
@ -135,13 +162,25 @@ const onClickSearch = async () => {
//
const currentDesk = ref(0);
watch(
() => searchTableForm.scheduleData?.id,
(newValue) => {
if (!newValue) {
currentDesk.value = 0;
deskShipData.value = undefined;
}
}
);
//
const onClickOpenDeck = async (item: number) => {
// ID
if (searchTableForm.scheduleId) {
if (searchTableForm.scheduleData.id) {
if (currentDesk.value === item) return;
currentDesk.value = item;
const { data } = await getManifestListAPI({
scheduleId: searchTableForm.scheduleId,
scheduleId: searchTableForm.scheduleData.id,
desk: item,
});
tableData.value = data;
@ -391,6 +430,68 @@ const onClickReturn = () => {
padding: 0 16px;
margin-top: 20px;
}
.right-map {
box-sizing: border-box;
width: 100%;
height: 374px;
padding: 16px;
margin-top: 20px;
background-color: rgb(51 51 51 / 100%);
border-radius: 13px;
.map-content {
display: flex;
flex-direction: row-reverse;
width: 100%;
.triangle-right {
width: 0;
height: 0;
border-top: 135px solid transparent;
border-bottom: 135px solid transparent;
border-left: 217px solid #f2f2f2;
}
.map-deck {
width: 258px;
height: 300px;
margin-right: 3px;
overflow: hidden;
.map-deck-title {
height: 30px;
font-weight: 700;
line-height: 30px;
color: #f2f2f2;
text-align: center;
}
.map-deck-item {
display: flex;
flex-direction: column;
justify-content: center;
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
.item-wrap {
font-size: 13px;
font-style: normal;
line-height: 18px;
color: #333;
span {
font-weight: 700;
color: #000;
}
}
}
}
}
.map-bottom {
width: 100%;
height: 17px;
margin-top: 10px;
font-size: 15px;
font-weight: 400;
color: #0ff;
text-align: center;
}
}
}
}
</style>

View File

@ -21,7 +21,7 @@ defineProps({
<style lang="scss" scoped>
.chart {
width: 280px;
width: 300px;
height: 200px;
}
</style>

View File

@ -154,6 +154,9 @@ const outImportVoyages = ref({
textStyle: {
color: '#fff',
},
formatter: function (name: string) {
return name.length > 3 ? name.substr(0, 3) + '...' : name;
},
},
series: [
{
@ -198,6 +201,9 @@ const outExportVoyages = ref({
textStyle: {
color: '#fff',
},
formatter: function (name: string) {
return name.length > 3 ? name.substr(0, 3) + '...' : name;
},
},
series: [
{
@ -242,6 +248,9 @@ const inTotalVoyages = ref({
textStyle: {
color: '#fff',
},
formatter: function (name: string) {
return name.length > 3 ? name.substr(0, 3) + '...' : name;
},
},
series: [
{
@ -286,6 +295,9 @@ const inYearVoyages = ref({
textStyle: {
color: '#fff',
},
formatter: function (name: string) {
return name.length > 3 ? name.substr(0, 3) + '...' : name;
},
},
series: [
{
@ -330,6 +342,9 @@ const outImportCargos = ref({
textStyle: {
color: '#fff',
},
formatter: function (name: string) {
return name.length > 3 ? name.substr(0, 3) + '...' : name;
},
},
series: [
{
@ -371,6 +386,10 @@ const outExportCargos = ref({
orient: 'vertical',
left: 'left',
top: 'middle',
itemWidth: 20,
formatter: function (name: string) {
return name.length > 3 ? name.substr(0, 3) + '...' : name;
},
textStyle: {
color: '#fff',
},
@ -418,6 +437,9 @@ const inTotalCargos = ref({
textStyle: {
color: '#fff',
},
formatter: function (name: string) {
return name.length > 3 ? name.substr(0, 3) + '...' : name;
},
},
series: [
{
@ -462,6 +484,9 @@ const inYearCargos = ref({
textStyle: {
color: '#fff',
},
formatter: function (name: string) {
return name.length > 3 ? name.substr(0, 3) + '...' : name;
},
},
series: [
{
@ -588,7 +613,7 @@ onMounted(async () => {
.charts {
display: flex;
flex-direction: column;
margin-right: 50px;
margin-right: 10px;
}
}
.home-footer {

View File

@ -15,6 +15,7 @@
v-for="item in noticeList"
:key="item.id"
class="list-item"
:class="{ 'list-item-active': currentNotice === item.id }"
@click="onClickOpenDialog(item)"
>
<div class="item-icon"></div>
@ -51,9 +52,6 @@ const onClickReturn = () => {
const noticeList = ref<NoticeType[]>([]);
const noticeViewData = ref<NoticeType>();
//
const isShowNotice = ref(false);
// -
const currentPage = ref(1);
@ -82,10 +80,13 @@ const noticeListLoad = async () => {
await getNoticeList();
};
//
const currentNotice = ref(0);
const onClickOpenDialog = async (row: NoticeType) => {
currentNotice.value = row.id;
const { data } = await noticeGetAPI({ id: row.id });
noticeViewData.value = data;
isShowNotice.value = true;
};
</script>
@ -154,6 +155,14 @@ const onClickOpenDialog = async (row: NoticeType) => {
font-size: 14px;
}
}
.list-item:hover {
color: #333;
background-color: #ffffc9;
}
.list-item-active {
color: #333;
background-color: #ffffc9;
}
}
.content {
position: relative;

View File

@ -0,0 +1,485 @@
<template>
<el-dialog v-model="dialogVisible" width="802px" style="padding: 0" :show-close="false">
<template #header>
<div class="header">船期信息详情</div>
</template>
<div class="content">
<div class="content-left">
<div class="right-info">
<el-form :model="form" :rules="formRules" ref="ruleFormRef" label-width="auto">
<div class="item">
<div class="title">起运港</div>
<div class="text">
<el-form-item prop="loadPortId">
<el-input
v-model="dialogProps.row.loadWharf!.name"
style="width: 170px"
disabled
/>
</el-form-item>
</div>
</div>
<div class="item">
<div class="title">目的港:</div>
<div class="text">
<el-form-item prop="dischargePortId">
<RemoteSelect
v-model:value="form.dischargePortId"
placeholder="请输入目的港"
:api="postPortListAPI"
style="width: 170px"
/>
</el-form-item>
</div>
</div>
<div class="item">
<div class="title">卸货码头:</div>
<div class="text">
<el-form-item prop="dischargeWharfId">
<RemoteSelect
v-model:value="form.dischargeWharfId"
placeholder="请输入卸货码头"
style="width: 170px"
:api="() => postWharfListAPI({ ref: form.dischargePortId })"
:disabled="!form.dischargePortId"
/>
</el-form-item>
</div>
</div>
<div class="item">
<div class="title">船名:</div>
<div class="text">
<el-form-item prop="shipId">
<RemoteSelect
v-model:value="form.shipId"
placeholder="请输入船名"
style="width: 170px"
:api="postShipListAPI"
/>
</el-form-item>
</div>
</div>
<div class="item">
<div class="title">航次:</div>
<div class="text">
<el-form-item prop="voyage">
<el-input v-model="form.voyage" placeholder="请输入航次" style="width: 170px" />
</el-form-item>
</div>
</div>
<!-- <div class="item">
<div class="title">航线:</div>
<div class="text">
<el-form-item prop="shipRouteId">
<RemoteSelect
v-model:value="form.shipRouteId"
placeholder="请选择航线"
:api="postRouteListAPI"
style="width: 170px"
/>
</el-form-item>
</div>
</div> -->
<div class="item">
<div class="title">计划装载数量:</div>
<div class="text">
<el-form-item required>
<div class="form-item">
<el-form-item prop="carNumPlan" style="width: 100%">
<el-input
v-model="form.carNumPlan"
placeholder="商品车数量"
style="width: 75px"
/>
</el-form-item>
<div style="margin: 0 8px; text-align: center">/</div>
<el-form-item prop="spareNumPlan" style="width: 100%">
<el-input
v-model="form.spareNumPlan"
placeholder="件杂货数量"
style="width: 75px"
/>
</el-form-item>
</div>
</el-form-item>
</div>
</div>
<div class="item">
<div class="title">实际装载数量:</div>
<div class="text">
<el-form-item required>
<el-form-item prop="carNumActual">
<el-input
v-model="form.carNumActual"
placeholder="商品车数量"
style="width: 75px"
/>
</el-form-item>
<div style="margin: 0 8px; text-align: center">/</div>
<el-form-item prop="spareNumActual">
<el-input
v-model="form.spareNumActual"
placeholder="件杂货数量"
style="width: 75px"
/>
</el-form-item>
</el-form-item>
</div>
</div>
<div class="item">
<div class="title">计划离港时间:</div>
<div class="text">
<el-form-item prop="departureDatePlan">
<el-date-picker
v-model="form.departureDatePlan"
type="datetime"
placeholder="请选择计划离港时间"
style="width: 170px"
/>
</el-form-item>
</div>
</div>
<div class="item">
<div class="title">实际离港时间:</div>
<div class="text">
<el-form-item>
<el-date-picker
v-model="form.departureDateActual"
type="datetime"
placeholder="请选择实际离港时间"
style="width: 170px"
/>
</el-form-item>
</div>
</div>
<div class="item">
<div class="title">当前状态:</div>
<div class="text">
<el-form-item prop="shipStatus">
<el-select
v-model="form.shipStatus"
placeholder="请选择船舶状态"
style="width: 170px"
>
<el-option label="有计划" value="有计划" />
<el-option label="已靠港" value="已靠港" />
<el-option label="作业中" value="作业中" />
<el-option label="已离港" value="已离港" />
</el-select>
</el-form-item>
</div>
</div>
<div class="item">
<div class="title">贸易类型:</div>
<div class="text">
<el-form-item prop="tradeType">
<el-select
v-model="form.tradeType"
placeholder="请选择贸易类型"
style="width: 170px"
>
<el-option label="外贸进口" value="外贸进口" />
<el-option label="外贸出口" value="外贸出口" />
<el-option label="内贸" value="内贸" />
</el-select>
</el-form-item>
</div>
</div>
</el-form>
</div>
<div class="footer">
<div class="btn" @click="onClickConfirm(ruleFormRef)"></div>
<div class="btn-del" @click="onClickDelete"></div>
</div>
</div>
<div class="content-right">
<div class="info">
<div class="info-item">
<div class="info-title">发布单位</div>
<div class="info-text">{{ dialogProps.row.enterprise?.name }}</div>
</div>
<div class="info-item">
<div class="info-title">发布人</div>
<div class="info-text">{{ dialogProps.row.createUser?.name }}</div>
</div>
<div class="info-item">
<div class="info-title">发布时间</div>
<div class="info-text">{{ dialogProps.row.createDate }}</div>
</div>
<div class="info-item">
<div class="info-title">更新时间</div>
<div class="info-text">{{ dialogProps.row.updateDate }}</div>
</div>
<div class="info-item">
<div class="info-title">联系电话</div>
<div class="info-text">{{ dialogProps.row.createUser?.phone }}</div>
</div>
</div>
</div>
</div>
</el-dialog>
</template>
<script lang="ts" setup>
import { ElMessage, ElMessageBox, FormInstance, FormRules } from 'element-plus';
import { nextTick, reactive, ref, watch } from 'vue';
// import { postRouteListAPI } from '@/api/BoatRoute';
import { postPortListAPI } from '@/api/Port';
import { postShipListAPI } from '@/api/Ship';
import { postWharfListAPI } from '@/api/Wharf';
import RemoteSelect from '@/components/RemoteSelect/index.vue';
import { BoatInfoType } from '@/types/boatInfo';
interface DialogPropsType {
row: Partial<BoatInfoType>;
isView: boolean;
api?: (params: any) => Promise<any>;
delApi?: (params: any) => Promise<any>;
getTableList?: () => void;
}
// dialog
const dialogVisible = ref(false);
//
const dialogProps = ref<DialogPropsType>({
isView: false,
row: {},
});
//
const form = reactive<any>({
id: '',
enterpriseId: '',
loadPortId: '',
loadWharfId: '',
shipRouteId: '',
dischargePortId: '',
dischargeWharfId: '',
shipId: '',
voyage: '',
carNumPlan: '',
spareNumPlan: '',
carNumActual: '',
spareNumActual: '',
departureDatePlan: '',
departureDateActual: '',
shipStatus: '',
tradeType: '',
});
//
watch(
() => form.dischargePortId ?? '',
(newValue, oldValue) => {
if (newValue !== oldValue) {
form.dischargeWharfId = '';
}
}
);
//
const initForm = (params: BoatInfoType) => {
form.id = params.id;
form.enterpriseId = params.enterpriseId;
form.loadPortId = params.loadPortId;
form.loadWharfId = params.loadWharfId;
form.shipRouteId = params.shipRouteId;
form.shipId = params.shipId;
form.voyage = params.voyage;
form.dischargePortId = params.dischargePortId;
form.dischargeWharfId = params.dischargeWharfId;
form.carNumPlan = params.carNumPlan;
form.spareNumPlan = params.spareNumPlan;
form.carNumActual = params.carNumActual;
form.spareNumActual = params.spareNumActual;
form.departureDatePlan = params.departureDatePlan;
form.departureDateActual = params.departureDateActual;
form.shipStatus = params.shipStatus;
form.tradeType = params.tradeType;
};
// dialog/
const isShowDialog = (params: DialogPropsType) => {
nextTick(() => {
dialogProps.value = params;
initForm(params.row as BoatInfoType);
});
dialogVisible.value = true;
};
//
defineExpose({ isShowDialog });
//
const formRules = reactive<FormRules>({
shipId: [{ required: true, message: '请输入船ID', trigger: 'blur' }],
voyage: [{ required: true, message: '请输入航次', trigger: 'blur' }],
dischargeWharfId: [{ required: true, message: '请输入卸货码头', trigger: 'blur' }],
carNumPlan: [{ required: true, message: '请输入计划商品车数量', trigger: 'blur' }],
spareNumPlan: [{ required: true, message: '请输入计划件杂货数量', trigger: 'blur' }],
carNumActual: [{ required: true, message: '请输入实际商品车数量', trigger: 'blur' }],
spareNumActual: [{ required: true, message: '请输入实际件杂货数量', trigger: 'blur' }],
departureDatePlan: [{ required: true, message: '请选择计划离港时间', trigger: 'change' }],
shipStatus: [{ required: true, message: '请选择船舶状态', trigger: 'change' }],
dischargePortId: [{ required: true, message: '请输入卸货港口', trigger: 'blur' }],
});
//
const ruleFormRef = ref<FormInstance>();
// /
const onClickConfirm = (formEl: FormInstance | undefined) => {
if (!formEl) return;
formEl.validate(async (valid) => {
if (!valid) return;
try {
await dialogProps.value.api!(form);
ElMessage({
message: `编辑成功`,
type: 'success',
});
dialogProps.value.getTableList!();
} finally {
dialogVisible.value = false;
}
});
};
const emit = defineEmits<{
endManifestDetail: [];
}>();
//
const onClickDelete = () => {
ElMessageBox.confirm(`你确定要删除船货信息吗?`, '温馨提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
draggable: true,
})
.then(async () => {
await dialogProps.value.delApi!([form.id]);
//
emit('endManifestDetail');
dialogVisible.value = false;
ElMessage({
message: '删除成功',
type: 'success',
});
})
.catch(() => {
console.log('用户点击了取消');
});
};
</script>
<style lang="scss" scoped>
.header {
width: 100%;
height: 50px;
font-size: 18px;
line-height: 50px;
color: #fff;
text-align: center;
background-color: #a30014;
}
.content {
box-sizing: border-box;
display: flex;
justify-content: space-between;
width: 100%;
padding: 30px 60px;
.content-left {
width: 319px;
.right-info {
width: 100%;
font-weight: 400;
color: #333;
.item {
display: flex;
width: 100%;
font-size: 18px;
.title {
width: 147px;
}
.text {
flex: 1;
color: #027db4;
.form-item {
display: flex;
flex-direction: row;
}
}
}
}
.footer {
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: flex-end;
width: 100%;
padding: 40px 0 0;
background-color: #fff;
.btn {
width: 120px;
height: 55px;
font-size: 18px;
line-height: 55px;
color: #fff;
text-align: center;
background-color: rgb(109 0 14 / 100%);
border-radius: 5px;
box-shadow: 5px 5px 5px rgb(0 0 0 / 34.9%);
}
.btn-del {
width: 120px;
height: 55px;
margin-left: 20px;
font-size: 18px;
line-height: 55px;
color: #fff;
text-align: center;
background-color: rgb(0 0 0 / 100%);
border-radius: 5px;
box-shadow: 5px 5px 5px rgb(0 0 0 / 34.9%);
}
}
}
.content-right {
display: flex;
flex-direction: column;
justify-content: space-between;
width: 238px;
height: 342px;
.info {
box-sizing: border-box;
width: 238px;
padding: 15px 20px;
margin-bottom: 10px;
font-family: 'Arial Normal', Arial;
font-size: 15px;
font-style: normal;
font-weight: 400;
line-height: 30px;
color: #333;
background-color: rgb(242 242 242 / 100%);
border-radius: 7px;
.info-item {
display: flex;
width: 100%;
line-height: 30px;
.info-title {
width: 75px;
}
.info-text {
flex: 1;
color: #027db4;
}
}
}
}
}
</style>

View File

@ -1,5 +1,11 @@
<template>
<el-form class="form" ref="ruleFormRef" :rules="formRules" :model="boatForm">
<el-form
class="form"
ref="ruleFormRef"
:rules="formRules"
:model="boatForm"
require-asterisk-position="right"
>
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="船名" prop="shipId">
@ -180,7 +186,7 @@
</div>
</el-form>
<ImportFile ref="importFileRef" />
<ImportFile ref="importFileRef" @endFileUpload="endFileUpload" />
</template>
<script lang="ts" setup>
@ -310,8 +316,13 @@ interface propsType {
const emit = defineEmits<{
updateBoatID: [value: propsType];
endManifestDetail: [];
}>();
const endFileUpload = () => {
emit('endManifestDetail');
};
//
const onClickConfirm = (formEl: FormInstance | undefined) => {
if (!formEl) return;

View File

@ -1,6 +1,6 @@
<template>
<div class="historyTable">
<el-table :data="historyData">
<el-table :data="boatInfoTable" @row-dblclick="onClickEditHistoryTable">
<el-table-column prop="ship.name" label="船名" align="center" />
<el-table-column prop="voyage" label="航次" align="center" />
<el-table-column label="装货港 / 装货码头" align="center">
@ -19,8 +19,20 @@
</el-table-column>
<el-table-column prop="carNumActual" label="商品车数量" align="center" />
<el-table-column prop="spareNumActual" label="件杂货数量" align="center" />
<el-table-column prop="departureDatePlan" label="计划离港时间" align="center" />
<el-table-column prop="departureDateActual" label="实际离港时间" align="center" />
<el-table-column label="计划离港时间" align="center">
<template #default="scope">
<div class="goods-name">
{{ handleTableData(scope.row?.departureDatePlan) }}
</div>
</template>
</el-table-column>
<el-table-column label="实际离港时间" align="center">
<template #default="scope">
<div class="goods-name">
{{ handleTableData(scope.row?.departureDateActual) }}
</div>
</template>
</el-table-column>
<el-table-column prop="shipStatus" label="当前状态" align="center" />
</el-table>
@ -97,6 +109,7 @@
</el-table>
</div>
<BoatInfoDialog ref="boatInfoDialogRef" @endManifestDetail="endManifestDetail" />
<ManifestDialog ref="manifestDialogRef" />
<ManifestDetailDialog ref="manifestDetailDialogRef" />
</div>
@ -106,10 +119,20 @@
import dayjs from 'dayjs';
import { ElMessage } from 'element-plus';
import { onMounted, ref } from 'vue';
import { getManifestListAPI, postManifestSaveAPI } from '@/api/Manifest';
import { getManifestDetailListAPI, postManifestDetailSaveAPI } from '@/api/Manifest/detail';
import {
getSailScheduleDeleteAPI,
getSailScheduleGetAPI,
getSailScheduleSaveAPI,
} from '@/api/Boat/info';
import { getManifestListAPI, postManifestDeleteAPI, postManifestSaveAPI } from '@/api/Manifest';
import {
getManifestDetailListAPI,
postManifestDetailDeleteAPI,
postManifestDetailSaveAPI,
} from '@/api/Manifest/detail';
import { BoatInfoType } from '@/types/boatInfo';
import { ManifestDetailType, ManifestType } from '@/types/manifest';
import BoatInfoDialog from './BoatInfoDialog.vue';
import ManifestDetailDialog from './ManifestDetailDialog.vue';
import ManifestDialog from './ManifestDialog.vue';
@ -118,6 +141,31 @@ const props = defineProps<{
historyData: BoatInfoType[];
}>();
const handleTableData = (item: string) => {
return dayjs(item).format('YYYY-MM-DD HH:mm');
};
const boatInfoTable = ref<BoatInfoType[]>([]);
//
const getBoatInfoTable = async () => {
const { data } = await getSailScheduleGetAPI({ id: props.historyData[0].id });
boatInfoTable.value = [data];
};
const boatInfoDialogRef = ref<InstanceType<typeof BoatInfoDialog> | null>(null);
const onClickEditHistoryTable = (row: BoatInfoType) => {
const params = {
isView: false,
row: { ...row },
api: getSailScheduleSaveAPI,
delApi: getSailScheduleDeleteAPI,
getTableList: getBoatInfoTable,
};
boatInfoDialogRef.value?.isShowDialog(params);
};
//
const manifestTable = ref<ManifestType[]>([]);
@ -137,6 +185,7 @@ const onClickEditManifest = (row: ManifestType) => {
isView: false,
row: { ...row },
api: postManifestSaveAPI,
delApi: postManifestDeleteAPI,
getTableList: getManifestTable,
};
manifestDialogRef.value?.isShowDialog(params);
@ -158,6 +207,7 @@ interface addManifestDetailType {
const emit = defineEmits<{
addManifest: [value: propsType];
addManifestDetail: [value: addManifestDetailType];
endManifestDetail: [];
}>();
//
@ -173,6 +223,7 @@ const onClickAddManifest = () => {
};
onMounted(async () => {
await getBoatInfoTable();
await getManifestTable();
});
@ -208,6 +259,7 @@ const onClickEditManifestDetail = (row: ManifestDetailType) => {
isView: false,
row: { ...row },
api: postManifestDetailSaveAPI,
delApi: postManifestDetailDeleteAPI,
getTableList: resetManifestDetailTable,
};
manifestDetailDialogRef.value?.isShowDialog(params);
@ -248,6 +300,10 @@ const onClickAddManifestDetail = () => {
});
}
};
const endManifestDetail = () => {
emit('endManifestDetail');
};
</script>
<style lang="scss" scoped>

View File

@ -51,6 +51,7 @@
<template #footer>
<div class="footer">
<el-button @click="onClickDelete" type="danger">删除</el-button>
<el-button @click="dialogVisible = false">取消</el-button>
<el-button v-show="!dialogProps.isView" type="primary" @click="onClickConfirm(ruleFormRef)">
确认
@ -61,7 +62,7 @@
</template>
<script lang="ts" setup>
import { ElMessage, FormInstance, FormRules } from 'element-plus';
import { ElMessage, ElMessageBox, FormInstance, FormRules } from 'element-plus';
import { reactive, ref, watch } from 'vue';
import { postVehicleListAPI } from '@/api/Vehicle';
import { postVehicleDetailListAPI } from '@/api/Vehicle/detail';
@ -72,6 +73,7 @@ interface DialogPropsType {
row: Partial<ManifestDetailType>;
isView: boolean;
api?: (params: any) => Promise<any>;
delApi?: (params: any) => Promise<any>;
getTableList?: () => void;
}
@ -98,6 +100,7 @@ const form = reactive<any>({
damageDesc: '',
bamm: '',
lrmm: '',
id: '',
});
//
@ -112,6 +115,7 @@ watch(
//
const initForm = (params: ManifestDetailType) => {
form.id = params.id;
form.manifestId = params.manifestId;
form.vehicleTypeId = params.vehicleTypeId;
form.vehicleTypeDetailId = params.vehicleTypeDetailId;
@ -164,6 +168,29 @@ const onClickConfirm = (formEl: FormInstance | undefined) => {
}
});
};
//
const onClickDelete = () => {
ElMessageBox.confirm(`你确定要删除舱单明细吗?`, '温馨提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
draggable: true,
})
.then(async () => {
await dialogProps.value.delApi!([form.id]);
//
dialogProps.value.getTableList!();
dialogVisible.value = false;
ElMessage({
message: '删除成功',
type: 'success',
});
})
.catch(() => {
console.log('用户点击了取消');
});
};
</script>
<style lang="scss" scoped></style>

View File

@ -1,5 +1,11 @@
<template>
<el-form class="form" ref="ruleFormRef" :rules="formRules" :model="form">
<el-form
class="form"
ref="ruleFormRef"
:rules="formRules"
:model="form"
require-asterisk-position="right"
>
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="提单号">
@ -128,7 +134,7 @@
</div>
</el-form>
<ImportFile ref="importFileRef" />
<ImportFile ref="importFileRef" @endFileUpload="endFileUpload" />
</template>
<script lang="ts" setup>
@ -252,17 +258,6 @@ const onClickUpload = () => {
importFileRef.value?.acceptParams(params);
};
// interface emitsType {
// scheduleId: string;
// voyage: string;
// loadPortId: string;
// dischargePortId: string;
// }
// const emit = defineEmits<{
// updateBoatID: [value: emitsType];
// }>();
//
const onClickAddSubmit = (formEl: FormInstance | undefined) => {
if (!formEl) return;
@ -281,6 +276,10 @@ const onClickAddSubmit = (formEl: FormInstance | undefined) => {
const emits = defineEmits(['endManifestDetail']);
const endFileUpload = () => {
emits('endManifestDetail');
};
//
const onClickConfirm = (formEl: FormInstance | undefined) => {
if (!formEl) return;

View File

@ -59,6 +59,7 @@
<template #footer>
<div class="footer">
<el-button @click="onClickDelete" type="danger">删除</el-button>
<el-button @click="dialogVisible = false">取消</el-button>
<el-button v-show="!dialogProps.isView" type="primary" @click="onClickConfirm(ruleFormRef)">
确认
@ -69,7 +70,7 @@
</template>
<script lang="ts" setup>
import { ElMessage, FormInstance, FormRules } from 'element-plus';
import { ElMessage, ElMessageBox, FormInstance, FormRules } from 'element-plus';
import { reactive, ref } from 'vue';
import { postBrandListAPI } from '@/api/Brand';
import RemoteSelect from '@/components/RemoteSelect/index.vue';
@ -79,6 +80,7 @@ interface DialogPropsType {
row: Partial<ManifestType>;
isView: boolean;
api?: (params: any) => Promise<any>;
delApi?: (params: any) => Promise<any>;
getTableList?: () => void;
}
@ -107,10 +109,12 @@ const form = reactive<any>({
consigner: '',
consignee: '',
goodsStatus: '',
id: '',
});
//
const initForm = (params: ManifestType) => {
form.id = params.id;
form.scheduleId = params.scheduleId;
form.deck = params.deck;
form.cabin = params.cabin;
@ -172,6 +176,29 @@ const onClickConfirm = (formEl: FormInstance | undefined) => {
}
});
};
//
const onClickDelete = () => {
ElMessageBox.confirm(`你确定要删除舱单吗?`, '温馨提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
draggable: true,
})
.then(async () => {
await dialogProps.value.delApi!([form.id]);
//
dialogProps.value.getTableList!();
dialogVisible.value = false;
ElMessage({
message: '删除成功',
type: 'success',
});
})
.catch(() => {
console.log('用户点击了取消');
});
};
</script>
<style lang="scss" scoped></style>

View File

@ -1,5 +1,11 @@
<template>
<el-form class="form" ref="ruleFormRef" :rules="formRules" :model="form">
<el-form
class="form"
ref="ruleFormRef"
:rules="formRules"
:model="form"
require-asterisk-position="right"
>
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="船名" prop="voyage">
@ -83,11 +89,11 @@
<el-form-item label="商品车/件杂货" required>
<div class="form-item">
<el-form-item prop="carNum">
<el-input v-model="form.carNum" placeholder="数量" style="width: 70px" />
<el-input v-model="form.carNum" placeholder="数量" style="width: 60px" />
</el-form-item>
<div style="margin: 0 10px; text-align: center">/</div>
<div style="margin: 0 3px; text-align: center">/</div>
<el-form-item prop="spareNum">
<el-input v-model="form.spareNum" placeholder="数量" style="width: 70px" />
<el-input v-model="form.spareNum" placeholder="数量" style="width: 60px" />
</el-form-item>
</div>
</el-form-item>
@ -138,7 +144,7 @@
</div>
</el-form>
<ImportFile ref="importFileRef" />
<ImportFile ref="importFileRef" @endFileUpload="endFileUpload" />
</template>
<script lang="ts" setup>
@ -286,8 +292,13 @@ interface emitsType {
const emit = defineEmits<{
updateBoatID: [value: emitsType];
endManifestDetail: [];
}>();
const endFileUpload = () => {
emit('endManifestDetail');
};
//
const onClickAddSubmit = (formEl: FormInstance | undefined) => {
if (!formEl) return;

View File

@ -13,12 +13,17 @@
<div class="left-title">{{ currentTitle[currentActive - 1] }}</div>
</div>
<div class="content-right">
<BoatInfoSend @updateBoatID="onUpdateBoatID" v-if="currentActive === 1" />
<BoatInfoSend
@updateBoatID="onUpdateBoatID"
@endManifestDetail="endManifestDetail"
v-if="currentActive === 1"
/>
<ManifestSend
:scheduleId="manifestProps?.scheduleId"
:voyage="manifestProps?.voyage"
:dischargePortId="manifestProps?.dischargePortId"
@updateBoatID="onUpdateManifest"
@endManifestDetail="endManifestDetail"
v-if="currentActive === 2"
/>
<ManifestDetailSend

View File

@ -17,6 +17,7 @@
:historyData="historyData!"
@addManifest="onClickAddManifest"
@addManifestDetail="onClickAddManifestDetail"
@endManifestDetail="onClickEndManifestDetail"
/>
<Send
ref="sendRef"