Browse Source

船运结算

fanzherong_v 18 hours ago
parent
commit
b6b9fed14c
36 changed files with 3709 additions and 30 deletions
  1. 12 0
      snowy-admin-web/src/api/biz/bizSettleApi.js
  2. 4 4
      snowy-admin-web/src/views/biz/bizsettle/form.vue
  3. 1 0
      snowy-admin-web/src/views/biz/bizsettle/index.vue
  4. 304 0
      snowy-admin-web/src/views/biz/bizsettleload/detail.vue
  5. 234 0
      snowy-admin-web/src/views/biz/bizsettleload/form.vue
  6. 345 0
      snowy-admin-web/src/views/biz/bizsettleload/index.vue
  7. 312 0
      snowy-admin-web/src/views/biz/bizsettleload/orderItem.vue
  8. 66 0
      snowy-admin-web/src/views/biz/bizsettleload/reviewadmin.vue
  9. 66 0
      snowy-admin-web/src/views/biz/bizsettleload/reviewfinance.vue
  10. 162 0
      snowy-admin-web/src/views/biz/bizsettleload/uploadFile.vue
  11. 195 0
      snowy-admin-web/src/views/biz/bizsettleload/uploadVoucher.vue
  12. 304 0
      snowy-admin-web/src/views/biz/bizsettleship/detail.vue
  13. 235 0
      snowy-admin-web/src/views/biz/bizsettleship/form.vue
  14. 345 0
      snowy-admin-web/src/views/biz/bizsettleship/index.vue
  15. 311 0
      snowy-admin-web/src/views/biz/bizsettleship/orderItem.vue
  16. 66 0
      snowy-admin-web/src/views/biz/bizsettleship/reviewadmin.vue
  17. 66 0
      snowy-admin-web/src/views/biz/bizsettleship/reviewfinance.vue
  18. 162 0
      snowy-admin-web/src/views/biz/bizsettleship/uploadFile.vue
  19. 195 0
      snowy-admin-web/src/views/biz/bizsettleship/uploadVoucher.vue
  20. 6 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizloadappoint/entity/BizLoadAppoint.java
  21. 2 1
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizloadappoint/mapper/mapping/BizLoadAppointMapper.xml
  22. 1 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizloadappoint/param/BizLoadAppointPageParam.java
  23. 42 14
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizloadappoint/service/impl/BizLoadAppointServiceImpl.java
  24. 12 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizloadarrive/entity/BizLoadArrive.java
  25. 5 1
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizloadarrive/mapper/mapping/BizLoadArriveMapper.xml
  26. 2 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizloadarrive/param/BizLoadArrivePageParam.java
  27. 7 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizloadarrive/service/BizLoadArriveService.java
  28. 18 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizloadarrive/service/impl/BizLoadArriveServiceImpl.java
  29. 3 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizservicecustomer/entity/BizServiceCustomerAccount.java
  30. 57 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizsettle/controller/BizSettleController.java
  31. 4 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizsettle/entity/BizSettle.java
  32. 3 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizsettle/param/BizSettleAddParam.java
  33. 3 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizsettle/param/BizSettleEditParam.java
  34. 23 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizsettle/service/BizSettleService.java
  35. 134 8
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizsettle/service/impl/BizSettleServiceImpl.java
  36. 2 2
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizsupplier/service/impl/BizSupplierServiceImpl.java

+ 12 - 0
snowy-admin-web/src/api/biz/bizSettleApi.js

@@ -17,10 +17,18 @@ export default {
 	bizSettleSubmitForm(data, edit = false) {
 		return request(edit ? 'edit' : 'add', data)
 	},
+	//船运结算
+	bizSettleShipSubmit(data,edit  = false){
+		return request(edit ? 'editShipSettle' : 'addShipSettle', data)
+	},
 	// 删除运费结算
 	bizSettleDelete(data) {
 		return request('delete', data)
 	},
+	//删除船运结算
+	deleteArrive(data){
+		return request('deleteArrive',data)
+	},
 	// 获取运费结算详情
 	bizSettleDetail(data) {
 		return request('detail', data, 'get')
@@ -29,6 +37,10 @@ export default {
 	detailOrder(data){
 		return request('detailOrder',data,'get')
 	},
+	//编辑获取船运明细
+	detailArrive(data){
+		return request('detailArrive',data,'get')
+	},
 	// 提交数据
 	submit(data){
 		return request('submit',data)

+ 4 - 4
snowy-admin-web/src/views/biz/bizsettle/form.vue

@@ -1,6 +1,6 @@
 <template>
 	<xn-form-container
-		:title="formData.id ? '编辑运结算' : '增加运结算'"
+		:title="formData.id ? '编辑运结算' : '增加运结算'"
 		:width="width"
 		v-model:open="open"
 		:destroy-on-close="true"
@@ -23,9 +23,9 @@
 					<td>货品名称</td>
 					<td>货品编码</td>
 					<td>供应商名称</td>
-					<td>订单重量</td>
-					<td>托运重量</td>
-					<td>运费单价</td>
+					<td>订单重量(吨)</td>
+					<td>托运重量(吨)</td>
+					<td>运费单价(元)</td>
 					<td>操作</td>
 				</tr>
 				<tr v-for="(order, index) in formData.orderList">

+ 1 - 0
snowy-admin-web/src/views/biz/bizsettle/index.vue

@@ -259,6 +259,7 @@
 			searchFormParam.endCreateTime = searchFormParam.createTime[1]
 			delete searchFormParam.createTime
 		}
+		searchFormParam.settleType = '1'
 		return bizSettleApi.bizSettlePage(Object.assign(parameter, searchFormParam)).then((data) => {
 			return data
 		})

+ 304 - 0
snowy-admin-web/src/views/biz/bizsettleload/detail.vue

@@ -0,0 +1,304 @@
+<template>
+	<xn-form-container title="详情" :width="1100" :visible="visible" :destroy-on-close="true" @close="onClose">
+		<a-form ref="formRef" :model="formData" :label-col="labelCol4" :wrapper-col="wrapperCol20">
+			<a-divider dashed style="border-color: gray">结算单</a-divider>
+			<a-descriptions :column="4" size="middle" bordered class="mb-2" :label-style="labelStyle" :contentStyle="contentStyle">
+				<a-descriptions-item label="结算单号" :span="2">{{ formData.settleNo }}</a-descriptions-item>
+				<a-descriptions-item label="订单类型" :span="2">
+					<a-tag
+						:color="
+							formData.settleType === '1'
+								? 'orange'
+								: formData.settleType === '2'
+								  ? 'green'
+								  : 'purple'
+						"
+					>
+						{{ $TOOL.dictTypeData('settle_type', formData.settleType) }}
+					</a-tag>
+				</a-descriptions-item>
+				<a-descriptions-item label="结算金额(元)" :span="2">{{ formData.settleAccount }}</a-descriptions-item>
+				<a-descriptions-item label="状态" :span="2">
+					<a-tag
+						:color="
+							formData.settleStatus === '1'
+								? 'red'
+								: formData.settleStatus === '2'
+								  ? 'green'
+								 : formData.settleStatus === '3'
+								  ? '#f50'
+								  : formData.settleStatus === '4'
+								  ? 'processing'
+								  : formData.settleStatus === '5'
+								  ? 'processing'
+								  : formData.settleStatus === '6'
+								  ? 'cyan'
+								  : 'purple'
+						"
+					>
+						{{ $TOOL.dictTypeData('settle_status', formData.settleStatus) }}
+					</a-tag>
+				</a-descriptions-item>
+
+				<a-descriptions-item label="发票信息" :span="4">
+					<p v-for="(item, index) in fileUploadInvoice" :key="index">
+						<a @click="downloadMaterial(item.url)" target="_blank">{{ item.name }}</a>
+					</p>
+				</a-descriptions-item>
+				<a-descriptions-item label="结算凭证" :span="4">
+					<p v-for="(item, index) in fileUploadVoucher" :key="index">
+						<a @click="downloadMaterial(item.url)" target="_blank">{{ item.name }}</a>
+					</p>
+				</a-descriptions-item>
+			</a-descriptions>
+
+			<a-divider dashed style="border-color: gray">结算明细</a-divider>
+
+			<table class="table">
+				<tr>
+					<td>订单编号</td>
+					<td>客户名称</td>
+					<td>货品名称</td>
+					<td>货品编码</td>
+					<td>供应商名称</td>
+					<td>订单重量</td>
+					<td>实际托运重量</td>
+					<td>运费单价</td>
+<!--					<td>操作</td>-->
+				</tr>
+				<tr v-for="(order, index) in formData.orderList">
+					<td>
+						<a-tooltip :title="order.orderNumber">
+							{{ order.orderNumber }}
+						</a-tooltip>
+					</td>
+					<td>
+						<a-tooltip :title="order.customerName">
+							{{ order.customerName }}
+						</a-tooltip>
+					</td>
+					<td>
+						<a-tooltip :title="order.goodsName">
+							{{ order.goodsName }}
+						</a-tooltip>
+					</td>
+					<td>
+						<a-tooltip :title="order.goodsCode">
+							{{ order.goodsCode }}
+						</a-tooltip>
+					</td>
+					<td>
+						<a-tooltip :title="order.supplierName">
+							{{ order.supplierName }}
+						</a-tooltip>
+					</td>
+					<td>
+						<a-tooltip :title="order.orderWeight">
+							{{ order.orderWeight }}
+						</a-tooltip>
+					</td>
+					<td>
+						<a-tooltip :title="order.orderWeight">
+							{{ order.orderType == '1'? order.shippingWeight:order.netWeight }}
+						</a-tooltip>
+					</td>
+					<td>
+						<a-tooltip :title="order.freightPrice">
+							{{ order.freightPrice }}
+						</a-tooltip>
+					</td>
+<!--					<td>
+						<a-button
+							danger
+							size="small"
+							type="link"
+							@click="deleteCount(index)"
+
+						>
+							<delete-outlined />
+						</a-button>
+					</td>-->
+				</tr>
+<!--				<tr v-if="formData.orderList.length>0">
+					<th colspan="1">合计</th>
+					<td colspan="8">
+						{{amountTotal}}
+					</td>
+				</tr>-->
+			</table>
+
+			<a-divider dashed style="border-color: gray" v-if="auditDataSource.length > 0">审核记录</a-divider>
+			<a-table
+				:dataSource="auditDataSource"
+				:columns="auditDataColumns"
+				:pagination="false"
+				:bordered="true"
+				v-if="auditDataSource.length > 0"
+			>
+				<template #bodyCell="{ column, record }">
+					<template v-if="column.dataIndex === 'status'">
+						<a-tag :color="record.status === '1' ? 'green' : 'red'">{{
+								$TOOL.dictTypeData('examine_status', record.status)
+							}}</a-tag>
+					</template>
+				</template>
+			</a-table>
+		</a-form>
+	</xn-form-container>
+</template>
+
+<script setup name="recordDoubleForm">
+	import { cloneDeep } from 'lodash-es'
+	import bizSettleApi from "@/api/biz/bizSettleApi";
+	import sysConfig from "@/config";
+	import bizAuditLogApi from "@/api/biz/bizAuditLogApi";
+
+
+	const auditDataSource = ref([])
+
+	// 默认是关闭状态
+	const visible = ref(false)
+	const formData = ref({})
+	const table = ref()
+	const resultJson = ref()
+
+	const labelStyle = {
+		width: '20%'
+	}
+	const contentStyle = {
+		width: '30%'
+	}
+
+	const labelCol4 = ref({span: 4, style: 'width: 26%; line-height: 20px; white-space: normal',})
+	const labelCol8 = ref({span: 8, style: 'width: 26%; line-height: 20px; white-space: normal',})
+	const wrapperCol20 = ref({span: 20})
+
+	const fileUploadInvoice = ref([])
+	const fileUploadVoucher = ref([])
+
+	// 打开抽屉
+	const onOpen = (record) => {
+		visible.value = true
+		//getRecordDoubleDetail(record)
+		if(record){
+			/*let recordData = cloneDeep(record)
+			formData.value = Object.assign({}, recordData)*/
+			bizSettleApi.detailOrder({id:record.id}).then((res)=>{
+				formData.value = res
+
+				if (formData.value.fileInvoicePath) {
+					for (var i = 0; i < formData.value.fileInvoicePath.split(',').length; i++) {
+						fileUploadInvoice.value.push({
+							url: sysConfig.PREVIEW_PATH + formData.value.fileInvoicePath.split(',')[i],
+							name: formData.value.fileInvoiceName.split(',')[i]
+						})
+					}
+				}
+
+				if (formData.value.fileVoucherPath) {
+					for (var i = 0; i < formData.value.fileVoucherPath.split(',').length; i++) {
+						fileUploadVoucher.value.push({
+							url: sysConfig.PREVIEW_PATH + formData.value.fileVoucherPath.split(',')[i],
+							name: formData.value.fileVoucherName.split(',')[i]
+						})
+					}
+
+				}
+
+
+				// 获取审核记录
+				bizAuditLogApi.getList({ type: 'YFJS', dataId: formData.value.id }).then((res) => {
+					auditDataSource.value = res
+				})
+			})
+		}
+
+	}
+	const getRecordDoubleDetail = (record) => {
+		const param = {
+			id: record.id
+		}
+		tbRecordDoubleApi.recordDoubleDetailPic(param).then((data) => {
+			Object.assign(record, data)
+			formData.value = record
+		})
+	}
+
+	const downloadMaterial = (url) => {
+		window.open( url)
+		/*console.log('previewFile:' + JSON.stringify(file))
+		const viewFile = cloneDeep(file)
+		var imgList = []
+		for (let i = 0; i < fileUploadInvoice.value.length; i++) {
+			var img = {}
+			img.url = fileUploadInvoice.value[i].url
+			img.name = fileUploadInvoice.value[i].name
+			imgList.push(img)
+		}
+		commFilePreviewRef.value.previewFileCommon(viewFile, imgList)*/
+	}
+
+
+	const auditDataColumns = [
+		{
+			title: '审核时间',
+			dataIndex: 'createTime',
+			width: 200,
+			align: 'center'
+		},
+		{
+			title: '审核人',
+			dataIndex: 'createUserName',
+			width: 150,
+			align: 'center'
+		},
+		{
+			title: '状态',
+			dataIndex: 'status',
+			width: 200,
+			align: 'center'
+		},
+		{
+			title: '审核意见',
+			dataIndex: 'remark',
+			align: 'center'
+		}
+	]
+
+	// 关闭抽屉
+	const onClose = () => {
+		resultJson.value = ''
+		visible.value = false
+		fileUploadInvoice.value = []
+		fileUploadVoucher.value = []
+	}
+	// 调用这个函数将子组件的一些数据和方法暴露出去
+	defineExpose({
+		onOpen
+	})
+</script>
+
+<style scoped>
+	.imgDiv ::v-deep .ant-image {
+		margin-left: 20px;
+		margin-top: 10px;
+	}
+	.imgDiv ::v-deep .ant-image-mask-info {
+		margin-left: 20px;
+		margin-top: 10px;
+	}
+
+	table {
+		margin-top: 10px;
+		text-align: center;
+		width: 100%;
+	}
+
+	table td {
+		border: 1px solid #f0f2f5;
+		padding: 10px 0;
+	}
+	tr:hover {
+		background-color: #f5f5f5;
+	}
+</style>

+ 234 - 0
snowy-admin-web/src/views/biz/bizsettleload/form.vue

@@ -0,0 +1,234 @@
+<template>
+	<xn-form-container
+		:title="formData.id ? '编辑起卸结算' : '增加起卸结算'"
+		:width="width"
+		v-model:open="open"
+		:destroy-on-close="true"
+		@close="onClose"
+	>
+		<a-form ref="formRef" :model="formData" :rules="formRules" :label-col="labelCol" :wrapper-col="wrapperCol">
+			<a-form-item label="结算类型:" name="settleType" v-show="isShow">
+				<a-input v-model:value="formData.settleType" placeholder="请输入结算类型" allow-clear />
+			</a-form-item>
+			<a-form-item label="结算金额:" name="settleAccount" v-show="isShow">
+				<a-input v-model:value="formData.settleAccount" placeholder="请输入结算金额" allow-clear />
+			</a-form-item>
+			<a-tooltip title="点击添加起卸订单">
+				<a-button size="small" @click="itemRef.showModal('checkbox', 'orderItem')"> 选择起卸订单 </a-button>
+			</a-tooltip>
+			<table class="table">
+				<tr>
+					<td>订单编号</td>
+					<td>客户名称</td>
+					<td>货品名称</td>
+					<td>货品编码</td>
+					<td>供应商名称</td>
+					<td>订单重量(吨)</td>
+					<td>起卸重量(吨)</td>
+					<td>起卸单价(元)</td>
+					<td>操作</td>
+				</tr>
+				<tr v-for="(order, index) in formData.orderList">
+					<td>
+						<a-tooltip :title="order.loadNumber">
+							{{ order.loadNumber }}
+						</a-tooltip>
+					</td>
+					<td>
+						<a-tooltip :title="order.customerName">
+							{{ order.customerName }}
+						</a-tooltip>
+					</td>
+					<td>
+						<a-tooltip :title="order.goodsName">
+							{{ order.goodsName }}
+						</a-tooltip>
+					</td>
+					<td>
+						<a-tooltip :title="order.goodsCode">
+							{{ order.goodsCode }}
+						</a-tooltip>
+					</td>
+					<td>
+						<a-tooltip :title="order.supplierName">
+							{{ order.supplierName }}
+						</a-tooltip>
+					</td>
+					<td>
+						<a-tooltip :title="order.orderWeight">
+							{{ order.orderWeight }}
+						</a-tooltip>
+					</td>
+					<td>
+						<a-tooltip :title="order.fillWeight">
+							{{ order.fillWeight }}
+						</a-tooltip>
+					</td>
+					<td>
+						<a-tooltip :title="order.loadPrice">
+							{{ order.loadPrice }}
+						</a-tooltip>
+					</td>
+					<td>
+						<a-button
+							danger
+							size="small"
+							type="link"
+							@click="deleteCount(index)"
+
+						>
+							<delete-outlined />
+						</a-button>
+					</td>
+				</tr>
+				<tr v-if="formData.orderList.length>0">
+					<th colspan="1">合计</th>
+					<td colspan="8">
+						{{amountTotal}}
+					</td>
+				</tr>
+			</table>
+		</a-form>
+		<template #footer>
+			<a-button style="margin-right: 8px" @click="onClose">关闭</a-button>
+			<a-button type="primary" @click="onSubmit" :loading="submitLoading">保存</a-button>
+		</template>
+
+		<OrderItem ref="itemRef" @orderItemCallBack="orderItemCallBack" />
+	</xn-form-container>
+</template>
+
+<script setup name="bizSettleForm">
+	import { cloneDeep } from 'lodash-es'
+	import { required } from '@/utils/formRules'
+	import { message, Modal } from 'ant-design-vue'
+	import { ExclamationCircleOutlined } from '@ant-design/icons-vue'
+	import { createVNode } from 'vue'
+	import bizSettleApi from '@/api/biz/bizSettleApi'
+	import OrderItem from './orderItem.vue'
+
+	// 抽屉状态
+	const open = ref(false)
+	const emit = defineEmits({ successful: null })
+	const formRef = ref()
+	const itemRef = ref()
+	const amountTotal = ref()
+	const isShow = ref(false)
+	// 表单数据
+	const formData = ref({orderList:[]})
+	const submitLoading = ref(false)
+	const width = ref('calc(70%)')
+	const labelCol = ref({ span: 3 })
+	const wrapperCol = ref({ span: 21 })
+
+	// 打开抽屉
+	const onOpen = (record) => {
+		open.value = true
+		if (record) {
+			//let recordData = cloneDeep(record)
+			//formData.value = Object.assign({}, recordData)
+			bizSettleApi.detailOrder({id:record.id}).then((res)=>{
+				formData.value = res
+				amountTotal.value = 0
+				formData.value.orderList.forEach((item) => {
+					amountTotal.value = (amountTotal.value + (item.fillWeight*item.loadPrice)).toFixed(2)
+				})
+				formData.value.settleAccount = amountTotal.value
+			})
+		}
+	}
+	// 关闭抽屉
+	const onClose = () => {
+		formRef.value.resetFields()
+		formData.value = {orderList:[]}
+		open.value = false
+	}
+
+	//删除明细
+	const deleteCount = (index) =>{
+		formData.value.orderList.splice(index, 1)
+		amountTotal.value = 0
+		formData.value.orderList.forEach((item) => {
+			amountTotal.value = (amountTotal.value + (item.fillWeight*item.loadPrice)).toFixed(2)
+		})
+		formData.value.settleAccount = amountTotal.value
+	}
+
+	// 默认要校验的
+	const formRules = {
+	}
+	// 验证并提交数据
+	const onSubmit = () => {
+		formRef.value
+			.validate()
+			.then(() => {
+
+				//校验物料明细的字段
+				let orderList = formData.value.orderList
+				if (!orderList || orderList.length < 1) {
+					message.error('物流订单明细信息不能为空')
+					return
+				}
+
+				submitLoading.value = true
+				const formDataParam = cloneDeep(formData.value)
+				bizSettleApi
+					.bizSettleSubmitForm(formDataParam, formDataParam.id)
+					.then(() => {
+						onClose()
+						emit('successful')
+					})
+					.finally(() => {
+						submitLoading.value = false
+					})
+			})
+			.catch(() => {})
+	}
+
+	const orderItemCallBack = (value) => {
+		if (value && value.length > 0) {
+			console.log('---this.value--->' + JSON.stringify(value))
+			if (formData.value.orderList && formData.value.orderList.length > 0) {
+				let map = new Map()
+				const array = ref([])
+				formData.value.orderList = formData.value.orderList.concat(value)
+				formData.value.orderList.forEach((item) => {
+					if (!map.has(item.id)) {
+						map.set(item.id, item)
+						array.value = array.value.concat(item)
+					}
+				})
+				formData.value.orderList = array.value
+			} else {
+				formData.value.orderList = value
+			}
+			amountTotal.value = 0
+			formData.value.orderList.forEach((item) => {
+				amountTotal.value = amountTotal.value + Number((item.fillWeight*item.loadPrice).toFixed(2))
+			})
+
+			formData.value.settleType = '3'
+			formData.value.settleAccount = amountTotal.value
+		}
+	}
+	// 抛出函数
+	defineExpose({
+		onOpen
+	})
+</script>
+
+<style scoped>
+table {
+	margin-top: 10px;
+	text-align: center;
+	width: 100%;
+}
+
+table td {
+	border: 1px solid #f0f2f5;
+	padding: 10px 0;
+}
+tr:hover {
+	background-color: #f5f5f5;
+}
+</style>

+ 345 - 0
snowy-admin-web/src/views/biz/bizsettleload/index.vue

@@ -0,0 +1,345 @@
+<template>
+	<a-card :bordered="false" style="margin-bottom: 10px" class="mb-2">
+		<a-form ref="searchFormRef" name="advanced_search" :model="searchFormState" class="ant-advanced-search-form">
+			<a-row :gutter="24">
+				<a-col :span="6">
+					<a-form-item label="结算单号" name="settleNo">
+						<a-input v-model:value="searchFormState.settleNo" placeholder="结算单号查询" />
+					</a-form-item>
+				</a-col>
+				<a-col :span="6">
+					<a-form-item label="结算类型" name="settleType">
+						<a-select v-model:value="searchFormState.settleType" placeholder="结算类型查询"
+								  :options="settleTypeList"
+						> </a-select>
+					</a-form-item>
+				</a-col>
+				<a-col :span="6">
+					<a-form-item label="创建时间" name="createTime">
+						<a-range-picker
+							v-model:value="searchFormState.createTime"
+							value-format="YYYY-MM-DD"
+						/>
+					</a-form-item>
+				</a-col>
+				<template v-if="advanced">
+
+					<a-col :span="6">
+						<a-form-item label="状态" name="settleStatus">
+							<a-select v-model:value="searchFormState.settleStatus" placeholder="状态查询"
+									  :options="settleStatusList"
+							> </a-select>
+						</a-form-item>
+					</a-col>
+				</template>
+				<a-col :span="6">
+					<a-button type="primary" @click="tableRef.refresh()">查询</a-button>
+					<a-button style="margin: 0 8px" @click="reset">重置</a-button>
+					<a @click="toggleAdvanced" style="margin-left: 8px">
+						{{ advanced ? '收起' : '展开' }}
+						<component :is="advanced ? 'up-outlined' : 'down-outlined'" />
+					</a>
+				</a-col>
+			</a-row>
+		</a-form>
+	</a-card>
+	<a-card :bordered="false">
+		<s-table
+			ref="tableRef"
+			:columns="columns"
+			:data="loadData"
+			bordered
+			:row-key="(record) => record.id"
+		>
+			<template #operator class="table-operator">
+				<a-space>
+					<a-button type="primary" @click="formRef.onOpen()" v-if="hasPerm('bizSettleAdd')">
+						<template #icon><plus-outlined /></template>
+						新增
+					</a-button>
+				</a-space>
+			</template>
+			<template #bodyCell="{ column, record }">
+				<template v-if="column.dataIndex === 'settleType'">
+					<a-tag
+						:color="
+							record.settleType === '1'
+								? 'orange'
+								: record.settleType === '2'
+								  ? 'green'
+								  : 'purple'
+						"
+					>
+						{{ $TOOL.dictTypeData('settle_type', record.settleType) }}
+					</a-tag>
+				</template>
+				<template v-if="column.dataIndex === 'settleStatus'">
+					<a-tag
+						:color="
+							record.settleStatus === '1'
+								? 'red'
+								: record.settleStatus === '2'
+								  ? 'green'
+								 : record.settleStatus === '3'
+								  ? '#f50'
+								  : record.settleStatus === '4'
+								  ? 'processing'
+								  : record.settleStatus === '5'
+								  ? 'processing'
+								  : record.settleStatus === '6'
+								  ? 'cyan'
+								  : 'purple'
+						"
+					>
+						{{ $TOOL.dictTypeData('settle_status', record.settleStatus) }}
+					</a-tag>
+				</template>
+				<template v-if="column.dataIndex === 'action'">
+<!--					<a-space>
+						<a @click="formRef.onOpen(record)" v-if="hasPerm('bizSettleEdit')">编辑</a>
+						<a-divider type="vertical" v-if="hasPerm(['bizSettleEdit', 'bizSettleDelete'], 'and')" />
+						<a style="color:red" size="small" type="link" @click="deleteConfig(record)">删除</a>
+					</a-space>-->
+					<a size="small" type="link" @click="detailRef.onOpen(record)" >详情</a>
+
+					<a-divider type="vertical" v-if="(hasPerm('bizSettleSubmit') && record.settleStatus == '1') ||
+						(hasPerm('bizSettleAdminAudit') && record.settleStatus == '2') ||
+						(hasPerm('bizSettleFinanceAudit') && record.settleStatus == '4') ||
+						(hasPerm('bizSettleEdit') && (record.settleStatus == '1' || record.settleStatus == '3')) ||
+						(hasPerm('bizSettleUploadInvoice') && (record.settleStatus == '5')) ||
+						(hasPerm('bizSettleUploadVoucher') && (record.settleStatus == '6')) ||
+						(hasPerm('bizSettleDelete') && record.settleStatus !='7')"/>
+
+					<a-dropdown v-if="(hasPerm('bizSettleSubmit') && record.settleStatus == '1') ||
+						(hasPerm('bizSettleAdminAudit') && record.settleStatus == '2') ||
+						(hasPerm('bizSettleFinanceAudit') && record.settleStatus == '4') ||
+						(hasPerm('bizSettleEdit') && (record.settleStatus == '1' ||  record.settleStatus == '3')) ||
+						(hasPerm('bizSettleUploadInvoice') && (record.settleStatus == '5')) ||
+						(hasPerm('bizSettleUploadVoucher') && (record.settleStatus == '6')) ||
+						(hasPerm('bizSettleDelete') && record.settleStatus !='7' )">
+						<a class="ant-dropdown-link">
+							更多
+							<DownOutlined />
+						</a>
+
+						<template #overlay>
+							<a-menu>
+								<a-menu-item v-if="hasPerm('bizSettleSubmit') && record.settleStatus == '1'">
+									<a style="color:blue" @click="onSubmit(record)" >提交</a>
+								</a-menu-item>
+								<!--管理员审核-->
+								<a-menu-item v-if="hasPerm('bizSettleAdminAudit') && record.settleStatus == '2'">
+									<a style="color:blue" @click="adminReviewRef.showModal(record.id)" >审核</a>
+								</a-menu-item>
+								<!--财务审核-->
+								<a-menu-item v-if="hasPerm('bizSettleFinanceAudit') && record.settleStatus == '4'">
+									<a style="color:blue" @click="financeReviewRef.showModal(record.id)" >审核</a>
+								</a-menu-item>
+								<a-menu-item v-if="hasPerm('bizSettleEdit') && (record.settleStatus == '1' || record.settleStatus == '3')">
+									<a @click="formRef.onOpen(record)" >编辑</a>
+								</a-menu-item>
+								<a-menu-item v-if="hasPerm('bizSettleUploadInvoice') && (record.settleStatus == '5')">
+									<a style="color:green" @click="uploadFileRef.onOpen(record)" >上传发票</a>
+								</a-menu-item>
+								<a-menu-item v-if="hasPerm('bizSettleUploadVoucher') && (record.settleStatus == '6')">
+									<a style="color:green" @click="uploadVoucherRef.onOpen(record)" >结款凭证</a>
+								</a-menu-item>
+								<a-menu-item v-if="hasPerm('bizSettleDelete') && record.settleStatus !='7'">
+									<a style="color:red" size="small" type="link" @click="deleteConfig(record)">删除</a>
+								</a-menu-item>
+							</a-menu>
+						</template>
+					</a-dropdown>
+				</template>
+			</template>
+		</s-table>
+	</a-card>
+	<Form ref="formRef" @successful="tableRef.refresh()" />
+	<Detail ref="detailRef" @successful="tableRef.refresh()" />
+	<ReviewAdmin ref="adminReviewRef" @successful="tableRef.refresh(true)" />
+	<ReviewFinance ref="financeReviewRef" @successful="tableRef.refresh(true)" />
+	<UploadFileRef ref="uploadFileRef" @successful="tableRef.refresh()" />
+	<UploadVoucherRef ref="uploadVoucherRef" @successful="tableRef.refresh()" />
+</template>
+
+<script setup name="bizsettle">
+	import { cloneDeep } from 'lodash-es'
+	import Form from './form.vue'
+	import bizSettleApi from '@/api/biz/bizSettleApi'
+	import {ExclamationCircleOutlined} from '@ant-design/icons-vue';
+	import {Modal} from 'ant-design-vue';
+	import {createVNode} from 'vue';
+	import ReviewAdmin from "./reviewadmin.vue";
+	import ReviewFinance from './reviewfinance.vue'
+	import UploadFileRef from './uploadFile.vue'
+	import UploadVoucherRef from './uploadVoucher.vue'
+	import Detail from './detail.vue'
+	import tool from '@/utils/tool'
+
+
+	const settleStatusList = tool.dictList('settle_status')
+	const settleTypeList = tool.dictList('settle_type')
+	const detailRef = ref()
+	const uploadVoucherRef = ref()
+	const uploadFileRef = ref()
+	const financeReviewRef = ref()
+	const adminReviewRef = ref()
+	const submitLoading = ref(false)
+	const tableRef = ref()
+	const formRef = ref()
+	const toolConfig = { refresh: true, height: true, columnSetting: true, striped: false }
+
+	//查询数据
+	const searchFormState = ref({})
+	const searchFormRef = ref()
+
+	// 查询区域显示更多控制
+	const advanced = ref(false)
+	const toggleAdvanced = () => {
+		advanced.value = !advanced.value
+	}
+
+
+	const columns = [
+		{
+			title: '结算单号',
+			dataIndex: 'settleNo',
+			align:'center',
+		},
+		{
+			title: '结算类型',
+			dataIndex: 'settleType',
+			align:'center',
+		},
+		{
+			title: '结算金额(元)',
+			dataIndex: 'settleAccount',
+			align:'center',
+		},
+		{
+			title: '创建日期',
+			dataIndex: 'createTime',
+			align:'center',
+		},
+		{
+			title: '状态',
+			dataIndex: 'settleStatus',
+			align:'center',
+		}
+	]
+	// 操作栏通过权限判断是否显示
+	columns.push({
+		title: '操作',
+		dataIndex: 'action',
+		align: 'center',
+		width: 150
+	})
+
+	const selectedRowKeys = ref([])
+	// 列表选择配置
+	const options = {
+		// columns数字类型字段加入 needTotal: true 可以勾选自动算账
+		alert: {
+			show: true,
+			clear: () => {
+				selectedRowKeys.value = ref([])
+			}
+		},
+		rowSelection: {
+			onChange: (selectedRowKey, selectedRows) => {
+				selectedRowKeys.value = selectedRowKey
+			}
+		}
+	}
+	const loadData = (parameter) => {
+		const searchFormParam = cloneDeep(searchFormState.value)
+		// grossTime范围查询条件重载
+		if (searchFormParam.createTime) {
+			searchFormParam.startCreateTime = searchFormParam.createTime[0]
+			searchFormParam.endCreateTime = searchFormParam.createTime[1]
+			delete searchFormParam.createTime
+		}
+		searchFormParam.settleType = '3'
+		return bizSettleApi.bizSettlePage(Object.assign(parameter, searchFormParam)).then((data) => {
+			return data
+		})
+	}
+	// 重置
+	const reset = () => {
+		searchFormRef.value.resetFields()
+		tableRef.value.refresh(true)
+	}
+	// 删除
+	const deleteBizSettle = (record) => {
+		let params = [
+			{
+				id: record.id
+			}
+		]
+		bizSettleApi.bizSettleDelete(params).then(() => {
+			tableRef.value.refresh(true)
+		})
+	}
+
+	//提交
+	const onSubmit = (record) => {
+
+		Modal.confirm({
+			title: '确定提交该数据吗?',
+			icon: createVNode(ExclamationCircleOutlined),
+			content: '',
+			onOk() {
+				submitLoading.value = true
+				let params =
+					{
+						id: record.id
+					}
+
+
+				bizSettleApi
+					.submit(params)
+					.then(() => {
+						tableRef.value.refresh(true)
+					})
+					.finally(() => {
+						submitLoading.value = false
+					})
+			},
+			onCancel() {}
+		})
+	}
+
+	// 删除
+	const deleteConfig = (record) => {
+
+		Modal.confirm({
+			title: '确定删除该数据吗?',
+			icon: createVNode(ExclamationCircleOutlined),
+			content: '',
+			onOk() {
+				submitLoading.value = true
+				let params = [
+					{
+						id: record.id
+					}
+				]
+
+				bizSettleApi
+					.bizSettleDelete(params)
+					.then(() => {
+						tableRef.value.refresh(true)
+					})
+					.finally(() => {
+						submitLoading.value = false
+					})
+			},
+			onCancel() {}
+		})
+	}
+	// 批量删除
+	const deleteBatchBizSettle = (params) => {
+		bizSettleApi.bizSettleDelete(params).then(() => {
+			tableRef.value.clearRefreshSelected()
+		})
+	}
+</script>

+ 312 - 0
snowy-admin-web/src/views/biz/bizsettleload/orderItem.vue

@@ -0,0 +1,312 @@
+<template>
+	<a-modal
+		ref="modalRef"
+		v-model:visible="visible"
+		width="1350px"
+		:body-style="{
+			height: 'calc(100vh - 200px)',
+			overflow: 'auto'
+		}"
+		centered
+		:destoryOnClose="true"
+		:afterClose="handleAfterClose"
+		@ok="handleOk"
+	>
+		<a-row>
+			<a-col :span="23" style="margin-left:20px;">
+				<a-spin :spinning="submitLoading">
+					<a-form ref="searchFormRef" :model="searchFormState" class="ant-advanced-search-form" name="advanced_search" style="margin-top:20px;margin-left:20px;">
+						<a-row :gutter="24">
+							<a-col :span="6">
+								<a-form-item label="订单编号" name="orderNumber">
+									<a-input v-model:value="searchFormState.orderNumber" placeholder="订单编号查询" />
+								</a-form-item>
+							</a-col>
+							<a-col :span="6">
+								<a-form-item label="客户名称" name="customerName">
+									<a-input v-model:value="searchFormState.customerName" placeholder="客户名称查询" />
+								</a-form-item>
+							</a-col>
+							<a-col :span="6">
+								<a-form-item label="货品名称" name="goodsName">
+									<a-input v-model:value="searchFormState.goodsName" placeholder="货品名称查询" />
+								</a-form-item>
+							</a-col>
+							<a-col :span="6">
+								<a-button type="primary" @click="table.refresh(true)">查询</a-button>
+								<a-button style="margin: 0 8px" @click="reset">重置</a-button>
+							</a-col>
+						</a-row>
+					</a-form>
+					<s-table
+						ref="table"
+						:alert="options.alert.show"
+						:columns="columns"
+						:data="loadData"
+						:rowKey="(record) => record.id"
+						:row-selection="options.rowSelection"
+						bordered
+						sticky
+					>
+					</s-table>
+				</a-spin>
+			</a-col>
+		</a-row>
+		<template #title>
+			<div ref="modalTitleRef" style="width: 100%; cursor: move">选择物流订单</div>
+		</template>
+		<template #modalRender="{ originVNode }">
+			<div :style="transformStyle">
+				<component :is="originVNode" />
+			</div>
+		</template>
+	</a-modal>
+</template>
+<script name="orderItem" setup>
+	import { computed, watch, watchEffect } from 'vue'
+	import { useDraggable } from '@vueuse/core'
+	import { Empty, message } from 'ant-design-vue'
+	import bizOrderApi from "@/api/biz/bizOrderApi";
+	import bizLoadAppointApi from "@/api/biz/bizLoadAppointApi";
+
+	// 默认展开的节点
+	let defaultExpandedKeys = ref([])
+	const treeData = ref([])
+	// 替换treeNode 中 title,key,children
+	const treeFieldNames = { children: 'children', title: 'name', key: 'id' }
+	const cardLoading = ref(true)
+
+	const submitLoading = ref(false)
+	let searchFormState = reactive({})
+	const searchFormRef = ref()
+	const table = ref()
+	const storeDatas = ref([])
+
+	const toolConfig = { refresh: true, height: true, columnSetting: true, striped: false }
+	const columns = [
+		{
+			title: '订单编号',
+			width: 100,
+			dataIndex: 'loadNumber',
+			ellipsis: true,
+			align:'center'
+		},
+		{
+			title: '客户名称',
+			width: 100,
+			dataIndex: 'customerName',
+			ellipsis: true,
+			align:'center'
+		},
+		{
+			title: '货品名称',
+			width: 90,
+			dataIndex: 'goodsName',
+			ellipsis: true,
+			align:'center'
+		},
+		{
+			title: '货品编码',
+			width: 80,
+			dataIndex: 'goodsCode',
+			ellipsis: true,
+			align:'center'
+		},
+		{
+			title: '供应商名称',
+			width: 100,
+			dataIndex: 'supplierName',
+			align:'center'
+		},
+		{
+			title: '订单重量(吨)',
+			width: 80,
+			dataIndex: 'orderWeight',
+			ellipsis: true,
+			align:'center'
+		},
+		/*{
+			title: '过磅重量(吨)',
+			width: 80,
+			dataIndex: 'netWeight',
+			ellipsis: true
+		},*/
+		{
+			title: '起卸重量(吨)',
+			width: 80,
+			dataIndex: 'fillWeight',
+			ellipsis: true,
+			align:'center'
+		},
+		{
+			title: '起卸单价(元/吨)',
+			width: 80,
+			dataIndex: 'loadPrice',
+			ellipsis: true,
+			align:'center'
+		}
+	]
+
+	const selectedRowKeys = ref([])
+	const selectedRecords = ref([])
+	const selectedCallBack = ref('bom')
+	// 列表选择配置
+	const options = {
+		// columns数字类型字段加入 needTotal: true 可以勾选自动算账
+		alert: {
+			show: true,
+			clear: () => {
+				selectedRowKeys.value = ref([])
+				selectedRecords.value = ref([])
+			}
+		},
+		rowSelection: {
+			onChange: (selectedRowKey, selectedRows) => {
+				selectedRowKeys.value = selectedRowKey
+				selectedRecords.value = selectedRows
+			}
+		}
+	}
+
+	const loadData = (parameter) => {
+		const searchFormParam = JSON.parse(JSON.stringify(searchFormState))
+		searchFormParam.status = '13'
+		searchFormParam.loadCostSettle = '1'
+		return bizLoadAppointApi.bizLoadAppointPage(Object.assign(parameter, searchFormParam)).then((data) => {
+			return data
+		})
+	}
+
+	// 仓库下拉框
+	/*baseStoreApi.baseStoreSelector().then((res) => {
+		storeDatas.value = res
+	})
+
+	// 加载左侧的树
+	baseItemKindApi.baseItemKindTree().then((res) => {
+		cardLoading.value = false
+		if (res !== null) {
+			treeData.value = [
+				{
+					id: '',
+					pId: '-1',
+					name: '全部分类',
+					children: res
+				}
+			]
+			// 默认展开2级
+			treeData.value.forEach((item) => {
+				// 因为0的顶级
+				if (item.pId === '-1') {
+					defaultExpandedKeys.value.push(item.id)
+					// 取到下级ID
+					if (item.children) {
+						item.children.forEach((items) => {
+							defaultExpandedKeys.value.push(items.id)
+						})
+					}
+				}
+			})
+		}
+	})*/
+	// 点击树查询
+	const treeSelect = (selectedKeys) => {
+		if (selectedKeys.length > 0) {
+			searchFormState.kindId = selectedKeys.toString()
+		} else {
+			delete searchFormState.kindId
+		}
+		table.value.refresh(true)
+	}
+	// 重置
+	const reset = () => {
+		searchFormRef.value.resetFields()
+		table.value.refresh(true)
+	}
+
+	const visible = ref(false)
+	const modalTitleRef = ref(null)
+	const showModal = (selectType, callBackType) => {
+		console.log("111")
+		options.rowSelection.type = selectType === 'radio' ? 'radio' : 'checkbox'
+		selectedCallBack.value = callBackType
+		visible.value = true
+		table.value.refresh(true)
+	}
+	const { x, y, isDragging } = useDraggable(modalTitleRef)
+
+	const emit = defineEmits(['bomItemCallBack', 'bomCallBack'])
+
+	const handleOk = (e) => {
+		if (selectedRecords.value && selectedRecords.value.length > 0) {
+			if (selectedCallBack.value === 'orderItem') {
+				emit('orderItemCallBack', JSON.parse(JSON.stringify(selectedRecords.value)))
+			}
+			visible.value = false
+			selectedRowKeys.value = []
+			selectedRecords.value = []
+			table.value.clearSelected()
+		} else {
+			message.error('物流订单不能为空!')
+		}
+	}
+	const startX = ref(0)
+	const startY = ref(0)
+	const startedDrag = ref(false)
+	const transformX = ref(0)
+	const transformY = ref(0)
+	const preTransformX = ref(0)
+	const preTransformY = ref(0)
+	const dragRect = ref({
+		left: 0,
+		right: 0,
+		top: 0,
+		bottom: 0
+	})
+	watch([x, y], () => {
+		if (!startedDrag.value) {
+			startX.value = x.value
+			startY.value = y.value
+			const bodyRect = document.body.getBoundingClientRect()
+			const titleRect = modalTitleRef.value.getBoundingClientRect()
+			dragRect.value.right = bodyRect.width - titleRect.width
+			dragRect.value.bottom = bodyRect.height - titleRect.height
+			preTransformX.value = transformX.value
+			preTransformY.value = transformY.value
+		}
+		startedDrag.value = true
+	})
+	watch(isDragging, () => {
+		if (!isDragging) {
+			startedDrag.value = false
+		}
+	})
+	watchEffect(() => {
+		if (startedDrag.value) {
+			transformX.value =
+				preTransformX.value + Math.min(Math.max(dragRect.value.left, x.value), dragRect.value.right) - startX.value
+			transformY.value =
+				preTransformY.value + Math.min(Math.max(dragRect.value.top, y.value), dragRect.value.bottom) - startY.value
+		}
+	})
+	const transformStyle = computed(() => {
+		return {
+			transform: `translate(${transformX.value}px, ${transformY.value}px)`
+		}
+	})
+
+	const handleAfterClose = () => {
+		console.log('handleAfterClose')
+		searchFormState = reactive({})
+	}
+	// 抛出函数
+	defineExpose({
+		showModal
+	})
+</script>
+
+<style lang="less" scoped>
+	.cardImp {
+		margin-right: 10px;
+	}
+</style>

+ 66 - 0
snowy-admin-web/src/views/biz/bizsettleload/reviewadmin.vue

@@ -0,0 +1,66 @@
+<template>
+    <a-modal v-model:visible="visible" title="审核">
+
+        <a-form ref="formRef" :label-col="labelCol" :model="formData" layout="horizontal">
+            <a-form-item v-show="false">
+                <a-input v-model:value="formData.id"></a-input>
+            </a-form-item>
+            <a-form-item
+                    label="审核备注"
+                    name="auditingRemark"
+            >
+                <a-textarea v-model:value="formData.settleReason" placeholder="请输入审核备注"
+                            :auto-size="{ minRows: 3, maxRows: 5 }"/>
+            </a-form-item>
+        </a-form>
+        <template #footer>
+            <a-spin :spinning="submitLoading">
+                <a-button style="margin-right: 8px" @click="onsubmit(false)" type="primary" danger>审核驳回</a-button>
+                <a-button type="primary" @click="onsubmit(true)">审核通过</a-button>
+            </a-spin>
+        </template>
+    </a-modal>
+</template>
+<script setup>
+import {message} from 'ant-design-vue';
+import bizSettleApi from '@/api/biz/bizSettleApi'
+
+
+const emit = defineEmits({successful: null})
+const visible = ref(false);
+const submitLoading = ref(false)
+const labelCol = ref({span: 4})
+// 表单数据
+const formData = ref({})
+const showModal = (id) => {
+    formData.value.id = id
+    visible.value = true;
+};
+const onClose = () => {
+    formData.value = {}
+    visible.value = false
+};
+const onsubmit = (flag) => {
+    if (flag === false) {
+        if (!formData.value.settleReason) {
+            message.error('审核驳回时,备注信息不能为空')
+            return
+        }
+    }
+    submitLoading.value = true
+	formData.value.auditFlag = flag
+	bizSettleApi.auditAdmin(formData.value).then(() => {
+        onClose()
+        emit('successful', null)
+    }).finally(() => {
+        submitLoading.value = false
+    })
+}
+// 抛出函数
+defineExpose({
+    showModal
+})
+</script>
+<style scoped>
+
+</style>

+ 66 - 0
snowy-admin-web/src/views/biz/bizsettleload/reviewfinance.vue

@@ -0,0 +1,66 @@
+<template>
+    <a-modal v-model:visible="visible" title="审核">
+
+        <a-form ref="formRef" :label-col="labelCol" :model="formData" layout="horizontal">
+            <a-form-item v-show="false">
+                <a-input v-model:value="formData.id"></a-input>
+            </a-form-item>
+            <a-form-item
+                    label="审核备注"
+                    name="auditingRemark"
+            >
+                <a-textarea v-model:value="formData.settleReason" placeholder="请输入审核备注"
+                            :auto-size="{ minRows: 3, maxRows: 5 }"/>
+            </a-form-item>
+        </a-form>
+        <template #footer>
+            <a-spin :spinning="submitLoading">
+                <a-button style="margin-right: 8px" @click="onsubmit(false)" type="primary" danger>审核驳回</a-button>
+                <a-button type="primary" @click="onsubmit(true)">审核通过</a-button>
+            </a-spin>
+        </template>
+    </a-modal>
+</template>
+<script setup>
+import {message} from 'ant-design-vue';
+import bizSettleApi from '@/api/biz/bizSettleApi'
+
+
+const emit = defineEmits({successful: null})
+const visible = ref(false);
+const submitLoading = ref(false)
+const labelCol = ref({span: 4})
+// 表单数据
+const formData = ref({})
+const showModal = (id) => {
+    formData.value.id = id
+    visible.value = true;
+};
+const onClose = () => {
+    formData.value = {}
+    visible.value = false
+};
+const onsubmit = (flag) => {
+    if (flag === false) {
+        if (!formData.value.settleReason) {
+            message.error('审核驳回时,备注信息不能为空')
+            return
+        }
+    }
+    submitLoading.value = true
+	formData.value.auditFlag = flag
+	bizSettleApi.auditFinance(formData.value).then(() => {
+        onClose()
+        emit('successful', null)
+    }).finally(() => {
+        submitLoading.value = false
+    })
+}
+// 抛出函数
+defineExpose({
+    showModal
+})
+</script>
+<style scoped>
+
+</style>

+ 162 - 0
snowy-admin-web/src/views/biz/bizsettleload/uploadFile.vue

@@ -0,0 +1,162 @@
+<template>
+	<xn-form-container
+		:title="formData.id ? '上传发票' : '上传发票'"
+		:width="700"
+		v-model:open="open"
+		:destroy-on-close="true"
+		@close="onClose"
+	>
+		<a-form ref="formRef" :model="formData" :rules="formRules" :wrapper-col="wrapperCol" :label-col="labelCol">
+			<a-form-item label="上传发票:" name="filePathList" :rules="[{ required: true, message: '请上传发票' }]">
+				<a-upload
+					v-model:file-list="fileList"
+					class="avatar-uploader"
+					list-type="picture"
+					:show-upload-list="true"
+					:custom-request="customRequest"
+					:remove="file => removeOtherFile(file,index)"
+					:before-upload="beforeUpload"
+					accept="image/png, image/jpeg, image/jpg"
+
+				>
+					<a-button>
+						<upload-outlined></upload-outlined>
+						upload
+					</a-button>
+				</a-upload>
+			</a-form-item>
+		</a-form>
+		<template #footer>
+			<a-button style="margin-right: 8px" @click="onClose">关闭</a-button>
+			<a-button type="primary" @click="onSubmit" :loading="submitLoading">保存</a-button>
+		</template>
+	</xn-form-container>
+</template>
+
+<script setup name="bizRecordForm">
+	import { cloneDeep } from 'lodash-es'
+	import { required } from '@/utils/formRules'
+	import bizSettleApi from "@/api/biz/bizSettleApi";
+	import fileApi from '@/api/dev/fileApi'
+	import sysConfig from "@/config";
+	import {message, Modal, Upload } from 'ant-design-vue';
+	// 抽屉状态
+	const open = ref(false)
+	const emit = defineEmits({ successful: null })
+	const formRef = ref()
+	// 表单数据
+	const formData = ref({filePathList:[],fileNameList:[]})
+	const submitLoading = ref(false)
+
+	//设置表单样式
+	const labelCol = ref({ span: 5})
+	const wrapperCol = ref({ span: 16})
+
+	const fileList = ref([])
+
+	// 打开抽屉
+	const onOpen = (record) => {
+		open.value = true
+		if (record) {
+			let recordData = cloneDeep(record)
+			formData.value = Object.assign({}, recordData)
+			formData.value.filePathList = []
+			formData.value.fileNameList = []
+			fileList.value = []
+			if (formData.value.fileInvoicePath) {
+				for (var i = 0; i < formData.value.fileInvoicePath.split(',').length; i++) {
+					fileList.value.push({
+						url: sysConfig.PREVIEW_PATH + formData.value.fileInvoicePath.split(',')[i],
+						name: formData.value.fileInvoiceName.split(',')[i]
+					})
+
+					formData.value.filePathList.push(formData.value.fileInvoicePath.split(',')[i])
+					formData.value.fileNameList.push(formData.value.fileInvoiceName.split(',')[i])
+				}
+			}
+		}
+	}
+	// 关闭抽屉
+	const onClose = () => {
+		formRef.value.resetFields()
+		formData.value = {}
+		formData.value.fileNameList = []
+		formData.value.filePathList = []
+		fileList.value = []
+		open.value = false
+	}
+	// 默认要校验的
+	const formRules = {
+	}
+	// 验证并提交数据
+	const onSubmit = () => {
+		formRef.value
+			.validate()
+			.then(() => {
+
+				if (
+					formData.value.filePathList == [] ||
+					formData.value.filePathList == '' ||
+					formData.value.filePathList == null
+				) {
+					message.warn('请上传发票')
+					return
+				}
+
+				submitLoading.value = true
+				const formDataParam = cloneDeep(formData.value)
+				console.log("formData:"+formDataParam.filePahList)
+				bizSettleApi
+					.uploadInvoice(formDataParam)
+					.then(() => {
+						onClose()
+						emit('successful')
+					})
+					.finally(() => {
+						submitLoading.value = false
+					})
+			})
+			.catch(() => {})
+	}
+
+	const customRequest = (data) => {
+		console.log("data:"+JSON.stringify(data.file.name))
+		//保存图片
+		const fileData = new FormData()
+		fileData.append('file', data.file)
+		fileApi
+			.uploadImgMap(fileData)
+			.then((result) => {
+				formData.value.filePathList.push(result.imageFile)
+				formData.value.fileNameList.push(data.file.name)
+			}).finally(()=>{
+			data.onSuccess()
+		})
+
+	}
+
+	//文件删除
+	const removeOtherFile = (file) => {
+		fileList.value.forEach((item,index)=>{
+			console.log(item.name+"======="+file.name)
+			if(item.name === file.name){
+
+				fileList.value.splice(index, 1);
+				formData.value.filePathList.splice(index,1)
+				formData.value.fileNameList.splice(index,1)
+			}
+		})
+	}
+
+	const beforeUpload = (file) => {
+		const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png'
+		if (!isJpgOrPng) {
+			message.error('请上传JPG/PNG格式的图片!')
+		}
+		return isJpgOrPng || Upload.LIST_IGNORE
+	}
+	// 抛出函数
+	defineExpose({
+		onOpen
+	})
+</script>

+ 195 - 0
snowy-admin-web/src/views/biz/bizsettleload/uploadVoucher.vue

@@ -0,0 +1,195 @@
+<template>
+	<xn-form-container
+		:title="formData.id ? '上传结款凭证' : '上传结款凭证'"
+		:width="700"
+		v-model:open="open"
+		:destroy-on-close="true"
+		@close="onClose"
+	>
+		<a-form ref="formRef" :model="formData" :rules="formRules" :wrapper-col="wrapperCol" :label-col="labelCol">
+			<a-form-item label="发票信息:" >
+				<p v-for="(item, index) in fileUploadInvoice" :key="index" style="margin-top:5px;">
+					<a @click="downloadMaterial(item.url)" target="_blank">{{ item.name }}</a>
+				</p>
+			</a-form-item>
+			<a-form-item label="上传结款凭证:" name="filePathList" :rules="[{ required: true, message: '请上传结款凭证' }]">
+				<a-upload
+					v-model:file-list="fileList"
+					class="avatar-uploader"
+					list-type="picture"
+					:show-upload-list="true"
+					:custom-request="customRequest"
+					:remove="file => removeOtherFile(file,index)"
+					:before-upload="beforeUpload"
+					accept="image/png, image/jpeg, image/jpg"
+
+				>
+					<a-button>
+						<upload-outlined></upload-outlined>
+						upload
+					</a-button>
+				</a-upload>
+			</a-form-item>
+			<a-form-item label="驳回备注:" name="settleReason">
+				<a-textarea
+					v-model:value="formData.settleReason"
+					placeholder="请输入驳回备注"
+					:maxlength="200"
+					show-count
+				/>
+			</a-form-item>
+		</a-form>
+		<template #footer>
+			<a-button style="margin-right: 8px" @click="onClose">关闭</a-button>
+			<a-button style="margin-right: 8px" @click="reject" type="primary" danger>驳回</a-button>
+			<a-button type="primary" @click="onSubmit" :loading="submitLoading">保存</a-button>
+		</template>
+	</xn-form-container>
+</template>
+
+<script setup name="bizRecordForm">
+	import { cloneDeep } from 'lodash-es'
+	import { required } from '@/utils/formRules'
+	import bizSettleApi from "@/api/biz/bizSettleApi";
+	import fileApi from '@/api/dev/fileApi'
+	import sysConfig from "@/config";
+	import {message, Modal, Upload } from 'ant-design-vue';
+	// 抽屉状态
+	const open = ref(false)
+	const emit = defineEmits({ successful: null })
+	const formRef = ref()
+	// 表单数据
+	const formData = ref({filePathList:[],fileNameList:[]})
+	const submitLoading = ref(false)
+
+	//设置表单样式
+	const labelCol = ref({ span: 5})
+	const wrapperCol = ref({ span: 16})
+
+	const fileList = ref([])
+	const fileUploadInvoice = ref([])
+
+	// 打开抽屉
+	const onOpen = (record) => {
+		open.value = true
+		if (record) {
+			let recordData = cloneDeep(record)
+			formData.value = Object.assign({}, recordData)
+			formData.value.filePathList = []
+			formData.value.fileNameList = []
+			fileList.value = []
+			if (formData.value.fileInvoicePath) {
+				for (var i = 0; i < formData.value.fileInvoicePath.split(',').length; i++) {
+					fileUploadInvoice.value.push({
+						url: sysConfig.PREVIEW_PATH + formData.value.fileInvoicePath.split(',')[i],
+						name: formData.value.fileInvoiceName.split(',')[i]
+					})
+				}
+			}
+		}
+	}
+	// 关闭抽屉
+	const onClose = () => {
+		formRef.value.resetFields()
+		formData.value = {}
+		formData.value.fileNameList = []
+		formData.value.filePathList = []
+		fileList.value = []
+		open.value = false
+		fileUploadInvoice.value = []
+	}
+
+	const downloadMaterial = (url) => {
+		window.open( url)
+	}
+
+	// 默认要校验的
+	const formRules = {
+	}
+	// 验证并提交数据
+	const onSubmit = () => {
+		formRef.value
+			.validate()
+			.then(() => {
+
+				if (
+					formData.value.filePathList == [] ||
+					formData.value.filePathList == '' ||
+					formData.value.filePathList == null
+				) {
+					message.warn('请上传发票')
+					return
+				}
+
+				submitLoading.value = true
+				const formDataParam = cloneDeep(formData.value)
+				console.log("formData:"+formDataParam.filePahList)
+				bizSettleApi
+					.uploadVoucher(formDataParam)
+					.then(() => {
+						onClose()
+						emit('successful')
+					})
+					.finally(() => {
+						submitLoading.value = false
+					})
+			})
+			.catch(() => {})
+	}
+
+	const reject = () => {
+		if(formData.value.settleReason== '' || formData.value.settleReason==null){
+			message.error('驳回时,备注信息不能为空')
+			return
+		}
+		submitLoading.value = true
+		const formDataParam = cloneDeep(formData.value)
+		bizSettleApi.auditReject(formDataParam).then((res)=>{
+			onClose()
+			emit('successful')
+		}).finally(() => {
+			submitLoading.value = false
+		})
+	}
+
+	const customRequest = (data) => {
+		console.log("data:"+JSON.stringify(data.file.name))
+		//保存图片
+		const fileData = new FormData()
+		fileData.append('file', data.file)
+		fileApi
+			.uploadImgMap(fileData)
+			.then((result) => {
+				formData.value.filePathList.push(result.imageFile)
+				formData.value.fileNameList.push(data.file.name)
+			}).finally(()=>{
+			data.onSuccess()
+		})
+
+	}
+
+	//文件删除
+	const removeOtherFile = (file) => {
+		fileList.value.forEach((item,index)=>{
+			console.log(item.name+"======="+file.name)
+			if(item.name === file.name){
+
+				fileList.value.splice(index, 1);
+				formData.value.filePathList.splice(index,1)
+				formData.value.fileNameList.splice(index,1)
+			}
+		})
+	}
+
+	const beforeUpload = (file) => {
+		const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png'
+		if (!isJpgOrPng) {
+			message.error('请上传JPG/PNG格式的图片!')
+		}
+		return isJpgOrPng || Upload.LIST_IGNORE
+	}
+	// 抛出函数
+	defineExpose({
+		onOpen
+	})
+</script>

+ 304 - 0
snowy-admin-web/src/views/biz/bizsettleship/detail.vue

@@ -0,0 +1,304 @@
+<template>
+	<xn-form-container title="详情" :width="1100" :visible="visible" :destroy-on-close="true" @close="onClose">
+		<a-form ref="formRef" :model="formData" :label-col="labelCol4" :wrapper-col="wrapperCol20">
+			<a-divider dashed style="border-color: gray">结算单</a-divider>
+			<a-descriptions :column="4" size="middle" bordered class="mb-2" :label-style="labelStyle" :contentStyle="contentStyle">
+				<a-descriptions-item label="结算单号" :span="2">{{ formData.settleNo }}</a-descriptions-item>
+				<a-descriptions-item label="订单类型" :span="2">
+					<a-tag
+						:color="
+							formData.settleType === '1'
+								? 'orange'
+								: formData.settleType === '2'
+								  ? 'green'
+								  : 'purple'
+						"
+					>
+						{{ $TOOL.dictTypeData('settle_type', formData.settleType) }}
+					</a-tag>
+				</a-descriptions-item>
+				<a-descriptions-item label="结算金额(元)" :span="2">{{ formData.settleAccount }}</a-descriptions-item>
+				<a-descriptions-item label="状态" :span="2">
+					<a-tag
+						:color="
+							formData.settleStatus === '1'
+								? 'red'
+								: formData.settleStatus === '2'
+								  ? 'green'
+								 : formData.settleStatus === '3'
+								  ? '#f50'
+								  : formData.settleStatus === '4'
+								  ? 'processing'
+								  : formData.settleStatus === '5'
+								  ? 'processing'
+								  : formData.settleStatus === '6'
+								  ? 'cyan'
+								  : 'purple'
+						"
+					>
+						{{ $TOOL.dictTypeData('settle_status', formData.settleStatus) }}
+					</a-tag>
+				</a-descriptions-item>
+
+				<a-descriptions-item label="发票信息" :span="4">
+					<p v-for="(item, index) in fileUploadInvoice" :key="index">
+						<a @click="downloadMaterial(item.url)" target="_blank">{{ item.name }}</a>
+					</p>
+				</a-descriptions-item>
+				<a-descriptions-item label="结算凭证" :span="4">
+					<p v-for="(item, index) in fileUploadVoucher" :key="index">
+						<a @click="downloadMaterial(item.url)" target="_blank">{{ item.name }}</a>
+					</p>
+				</a-descriptions-item>
+			</a-descriptions>
+
+			<a-divider dashed style="border-color: gray">结算明细</a-divider>
+
+			<table class="table">
+				<tr>
+					<td>订单编号</td>
+					<td>客户名称</td>
+					<td>货品名称</td>
+					<td>货品编码</td>
+					<td>供应商名称</td>
+					<td>订单重量(吨)</td>
+					<td>报港重量(吨)</td>
+					<td>运费单价(元)</td>
+<!--					<td>操作</td>-->
+				</tr>
+				<tr v-for="(order, index) in formData.arriveList">
+					<td>
+						<a-tooltip :title="order.loadNumber">
+							{{ order.loadNumber }}
+						</a-tooltip>
+					</td>
+					<td>
+						<a-tooltip :title="order.customerName">
+							{{ order.customerName }}
+						</a-tooltip>
+					</td>
+					<td>
+						<a-tooltip :title="order.goodsName">
+							{{ order.goodsName }}
+						</a-tooltip>
+					</td>
+					<td>
+						<a-tooltip :title="order.goodsCode">
+							{{ order.goodsCode }}
+						</a-tooltip>
+					</td>
+					<td>
+						<a-tooltip :title="order.supplierName">
+							{{ order.supplierName }}
+						</a-tooltip>
+					</td>
+					<td>
+						<a-tooltip :title="order.orderWeight">
+							{{ order.orderWeight }}
+						</a-tooltip>
+					</td>
+					<td>
+						<a-tooltip :title="order.arriveNumber">
+							{{ order.arriveNumber }}
+						</a-tooltip>
+					</td>
+					<td>
+						<a-tooltip :title="order.freightPrice">
+							{{ order.freightPrice }}
+						</a-tooltip>
+					</td>
+<!--					<td>
+						<a-button
+							danger
+							size="small"
+							type="link"
+							@click="deleteCount(index)"
+
+						>
+							<delete-outlined />
+						</a-button>
+					</td>-->
+				</tr>
+<!--				<tr v-if="formData.orderList.length>0">
+					<th colspan="1">合计</th>
+					<td colspan="8">
+						{{amountTotal}}
+					</td>
+				</tr>-->
+			</table>
+
+			<a-divider dashed style="border-color: gray" v-if="auditDataSource.length > 0">审核记录</a-divider>
+			<a-table
+				:dataSource="auditDataSource"
+				:columns="auditDataColumns"
+				:pagination="false"
+				:bordered="true"
+				v-if="auditDataSource.length > 0"
+			>
+				<template #bodyCell="{ column, record }">
+					<template v-if="column.dataIndex === 'status'">
+						<a-tag :color="record.status === '1' ? 'green' : 'red'">{{
+								$TOOL.dictTypeData('examine_status', record.status)
+							}}</a-tag>
+					</template>
+				</template>
+			</a-table>
+		</a-form>
+	</xn-form-container>
+</template>
+
+<script setup name="recordDoubleForm">
+	import { cloneDeep } from 'lodash-es'
+	import bizSettleApi from "@/api/biz/bizSettleApi";
+	import sysConfig from "@/config";
+	import bizAuditLogApi from "@/api/biz/bizAuditLogApi";
+
+
+	const auditDataSource = ref([])
+
+	// 默认是关闭状态
+	const visible = ref(false)
+	const formData = ref({})
+	const table = ref()
+	const resultJson = ref()
+
+	const labelStyle = {
+		width: '20%'
+	}
+	const contentStyle = {
+		width: '30%'
+	}
+
+	const labelCol4 = ref({span: 4, style: 'width: 26%; line-height: 20px; white-space: normal',})
+	const labelCol8 = ref({span: 8, style: 'width: 26%; line-height: 20px; white-space: normal',})
+	const wrapperCol20 = ref({span: 20})
+
+	const fileUploadInvoice = ref([])
+	const fileUploadVoucher = ref([])
+
+	// 打开抽屉
+	const onOpen = (record) => {
+		visible.value = true
+		//getRecordDoubleDetail(record)
+		if(record){
+			/*let recordData = cloneDeep(record)
+			formData.value = Object.assign({}, recordData)*/
+			bizSettleApi.detailArrive({id:record.id}).then((res)=>{
+				formData.value = res
+
+				if (formData.value.fileInvoicePath) {
+					for (var i = 0; i < formData.value.fileInvoicePath.split(',').length; i++) {
+						fileUploadInvoice.value.push({
+							url: sysConfig.PREVIEW_PATH + formData.value.fileInvoicePath.split(',')[i],
+							name: formData.value.fileInvoiceName.split(',')[i]
+						})
+					}
+				}
+
+				if (formData.value.fileVoucherPath) {
+					for (var i = 0; i < formData.value.fileVoucherPath.split(',').length; i++) {
+						fileUploadVoucher.value.push({
+							url: sysConfig.PREVIEW_PATH + formData.value.fileVoucherPath.split(',')[i],
+							name: formData.value.fileVoucherName.split(',')[i]
+						})
+					}
+
+				}
+
+
+				// 获取审核记录
+				bizAuditLogApi.getList({ type: 'YFJS', dataId: formData.value.id }).then((res) => {
+					auditDataSource.value = res
+				})
+			})
+		}
+
+	}
+	const getRecordDoubleDetail = (record) => {
+		const param = {
+			id: record.id
+		}
+		tbRecordDoubleApi.recordDoubleDetailPic(param).then((data) => {
+			Object.assign(record, data)
+			formData.value = record
+		})
+	}
+
+	const downloadMaterial = (url) => {
+		window.open( url)
+		/*console.log('previewFile:' + JSON.stringify(file))
+		const viewFile = cloneDeep(file)
+		var imgList = []
+		for (let i = 0; i < fileUploadInvoice.value.length; i++) {
+			var img = {}
+			img.url = fileUploadInvoice.value[i].url
+			img.name = fileUploadInvoice.value[i].name
+			imgList.push(img)
+		}
+		commFilePreviewRef.value.previewFileCommon(viewFile, imgList)*/
+	}
+
+
+	const auditDataColumns = [
+		{
+			title: '审核时间',
+			dataIndex: 'createTime',
+			width: 200,
+			align: 'center'
+		},
+		{
+			title: '审核人',
+			dataIndex: 'createUserName',
+			width: 150,
+			align: 'center'
+		},
+		{
+			title: '状态',
+			dataIndex: 'status',
+			width: 200,
+			align: 'center'
+		},
+		{
+			title: '审核意见',
+			dataIndex: 'remark',
+			align: 'center'
+		}
+	]
+
+	// 关闭抽屉
+	const onClose = () => {
+		resultJson.value = ''
+		visible.value = false
+		fileUploadInvoice.value = []
+		fileUploadVoucher.value = []
+	}
+	// 调用这个函数将子组件的一些数据和方法暴露出去
+	defineExpose({
+		onOpen
+	})
+</script>
+
+<style scoped>
+	.imgDiv ::v-deep .ant-image {
+		margin-left: 20px;
+		margin-top: 10px;
+	}
+	.imgDiv ::v-deep .ant-image-mask-info {
+		margin-left: 20px;
+		margin-top: 10px;
+	}
+
+	table {
+		margin-top: 10px;
+		text-align: center;
+		width: 100%;
+	}
+
+	table td {
+		border: 1px solid #f0f2f5;
+		padding: 10px 0;
+	}
+	tr:hover {
+		background-color: #f5f5f5;
+	}
+</style>

+ 235 - 0
snowy-admin-web/src/views/biz/bizsettleship/form.vue

@@ -0,0 +1,235 @@
+<template>
+	<xn-form-container
+		:title="formData.id ? '编辑船运结算' : '增加船运结算'"
+		:width="width"
+		v-model:open="open"
+		:destroy-on-close="true"
+		@close="onClose"
+	>
+		<a-form ref="formRef" :model="formData" :rules="formRules" :label-col="labelCol" :wrapper-col="wrapperCol">
+			<a-form-item label="结算类型:" name="settleType" v-show="isShow">
+				<a-input v-model:value="formData.settleType" placeholder="请输入结算类型" allow-clear />
+			</a-form-item>
+			<a-form-item label="结算金额:" name="settleAccount" v-show="isShow">
+				<a-input v-model:value="formData.settleAccount" placeholder="请输入结算金额" allow-clear />
+			</a-form-item>
+			<a-tooltip title="点击添加报港预约">
+				<a-button size="small" @click="itemRef.showModal('radio', 'orderItem')"> 选择报港预约 </a-button>
+			</a-tooltip>
+			<table class="table">
+				<tr>
+					<td>订单编号</td>
+					<td>客户名称</td>
+					<td>货品名称</td>
+					<td>货品编码</td>
+					<td>供应商名称</td>
+					<td>订单重量(吨)</td>
+					<td>报港重量(吨)</td>
+					<td>运费单价(元)</td>
+					<td>操作</td>
+				</tr>
+				<tr v-for="(order, index) in formData.arriveList">
+					<td>
+						<a-tooltip :title="order.loadNumber">
+							{{ order.loadNumber }}
+						</a-tooltip>
+					</td>
+					<td>
+						<a-tooltip :title="order.customerName">
+							{{ order.customerName }}
+						</a-tooltip>
+					</td>
+					<td>
+						<a-tooltip :title="order.goodsName">
+							{{ order.goodsName }}
+						</a-tooltip>
+					</td>
+					<td>
+						<a-tooltip :title="order.goodsCode">
+							{{ order.goodsCode }}
+						</a-tooltip>
+					</td>
+					<td>
+						<a-tooltip :title="order.supplierName">
+							{{ order.supplierName }}
+						</a-tooltip>
+					</td>
+					<td>
+						<a-tooltip :title="order.orderWeight">
+							{{ order.orderWeight }}
+						</a-tooltip>
+					</td>
+					<td>
+						<a-tooltip :title="order.arriveNumber">
+							{{ order.arriveNumber }}
+						</a-tooltip>
+					</td>
+					<td>
+						<a-tooltip :title="order.freightPrice">
+							{{ order.freightPrice }}
+						</a-tooltip>
+					</td>
+					<td>
+						<a-button
+							danger
+							size="small"
+							type="link"
+							@click="deleteCount(index)"
+
+						>
+							<delete-outlined />
+						</a-button>
+					</td>
+				</tr>
+				<tr v-if="formData.arriveList.length>0">
+					<th colspan="1">合计</th>
+					<td colspan="8">
+						{{amountTotal}}
+					</td>
+				</tr>
+			</table>
+		</a-form>
+		<template #footer>
+			<a-button style="margin-right: 8px" @click="onClose">关闭</a-button>
+			<a-button type="primary" @click="onSubmit" :loading="submitLoading">保存</a-button>
+		</template>
+
+		<OrderItem ref="itemRef" @orderItemCallBack="orderItemCallBack" />
+	</xn-form-container>
+</template>
+
+<script setup name="bizSettleForm">
+	import { cloneDeep } from 'lodash-es'
+	import { required } from '@/utils/formRules'
+	import { message, Modal } from 'ant-design-vue'
+	import { ExclamationCircleOutlined } from '@ant-design/icons-vue'
+	import { createVNode } from 'vue'
+	import bizSettleApi from '@/api/biz/bizSettleApi'
+	import OrderItem from './orderItem.vue'
+
+	// 抽屉状态
+	const open = ref(false)
+	const emit = defineEmits({ successful: null })
+	const formRef = ref()
+	const itemRef = ref()
+	const amountTotal = ref()
+	const isShow = ref(false)
+	// 表单数据
+	const formData = ref({arriveList:[]})
+	const submitLoading = ref(false)
+	const width = ref('calc(70%)')
+	const labelCol = ref({ span: 3 })
+	const wrapperCol = ref({ span: 21 })
+
+	// 打开抽屉
+	const onOpen = (record) => {
+		open.value = true
+		if (record) {
+			//let recordData = cloneDeep(record)
+			//formData.value = Object.assign({}, recordData)
+			bizSettleApi.detailArrive({id:record.id}).then((res)=>{
+				formData.value = res
+				amountTotal.value = 0
+				formData.value.arriveList.forEach((item) => {
+					amountTotal.value = (amountTotal.value + (item.arriveNumber*item.freightPrice)).toFixed(2)
+				})
+				formData.value.settleAccount = amountTotal.value
+			})
+		}
+	}
+	// 关闭抽屉
+	const onClose = () => {
+		formRef.value.resetFields()
+		formData.value = {arriveList:[]}
+		open.value = false
+	}
+
+	//删除明细
+	const deleteCount = (index) =>{
+		formData.value.arriveList.splice(index, 1)
+		amountTotal.value = 0
+		formData.value.arriveList.forEach((item) => {
+			amountTotal.value = (amountTotal.value + (item.arriveNumber*item.freightPrice)).toFixed(2)
+		})
+		formData.value.settleAccount = amountTotal.value
+	}
+
+	// 默认要校验的
+	const formRules = {
+	}
+	// 验证并提交数据
+	const onSubmit = () => {
+		formRef.value
+			.validate()
+			.then(() => {
+
+				//校验物料明细的字段
+				let arriveList = formData.value.arriveList
+				if (!arriveList || arriveList.length < 1) {
+					message.error('报港预约明细信息不能为空')
+					return
+				}
+
+				submitLoading.value = true
+				const formDataParam = cloneDeep(formData.value)
+				bizSettleApi
+					.bizSettleShipSubmit(formDataParam, formDataParam.id)
+					.then(() => {
+						onClose()
+						emit('successful')
+					})
+					.finally(() => {
+						submitLoading.value = false
+					})
+			})
+			.catch(() => {})
+	}
+
+	const orderItemCallBack = (value) => {
+		if (value && value.length > 0) {
+			formData.value.arriveList = []
+			console.log('---this.value--->' + JSON.stringify(value))
+			if (formData.value.arriveList && formData.value.arriveList.length > 0) {
+				let map = new Map()
+				const array = ref([])
+				formData.value.arriveList = formData.value.arriveList.concat(value)
+				formData.value.arriveList.forEach((item) => {
+					if (!map.has(item.id)) {
+						map.set(item.id, item)
+						array.value = array.value.concat(item)
+					}
+				})
+				formData.value.arriveList = array.value
+			} else {
+				formData.value.arriveList = value
+			}
+			amountTotal.value = 0
+			formData.value.arriveList.forEach((item) => {
+				amountTotal.value = (amountTotal.value + (item.arriveNumber*item.freightPrice)).toFixed(2)
+			})
+
+			formData.value.settleType = '2'
+			formData.value.settleAccount = amountTotal.value
+		}
+	}
+	// 抛出函数
+	defineExpose({
+		onOpen
+	})
+</script>
+
+<style scoped>
+table {
+	margin-top: 10px;
+	text-align: center;
+	width: 100%;
+}
+
+table td {
+	border: 1px solid #f0f2f5;
+	padding: 10px 0;
+}
+tr:hover {
+	background-color: #f5f5f5;
+}
+</style>

+ 345 - 0
snowy-admin-web/src/views/biz/bizsettleship/index.vue

@@ -0,0 +1,345 @@
+<template>
+	<a-card :bordered="false" style="margin-bottom: 10px" class="mb-2">
+		<a-form ref="searchFormRef" name="advanced_search" :model="searchFormState" class="ant-advanced-search-form">
+			<a-row :gutter="24">
+				<a-col :span="6">
+					<a-form-item label="结算单号" name="settleNo">
+						<a-input v-model:value="searchFormState.settleNo" placeholder="结算单号查询" />
+					</a-form-item>
+				</a-col>
+				<a-col :span="6">
+					<a-form-item label="结算类型" name="settleType">
+						<a-select v-model:value="searchFormState.settleType" placeholder="结算类型查询"
+								  :options="settleTypeList"
+						> </a-select>
+					</a-form-item>
+				</a-col>
+				<a-col :span="6">
+					<a-form-item label="创建时间" name="createTime">
+						<a-range-picker
+							v-model:value="searchFormState.createTime"
+							value-format="YYYY-MM-DD"
+						/>
+					</a-form-item>
+				</a-col>
+				<template v-if="advanced">
+
+					<a-col :span="6">
+						<a-form-item label="状态" name="settleStatus">
+							<a-select v-model:value="searchFormState.settleStatus" placeholder="状态查询"
+									  :options="settleStatusList"
+							> </a-select>
+						</a-form-item>
+					</a-col>
+				</template>
+				<a-col :span="6">
+					<a-button type="primary" @click="tableRef.refresh()">查询</a-button>
+					<a-button style="margin: 0 8px" @click="reset">重置</a-button>
+					<a @click="toggleAdvanced" style="margin-left: 8px">
+						{{ advanced ? '收起' : '展开' }}
+						<component :is="advanced ? 'up-outlined' : 'down-outlined'" />
+					</a>
+				</a-col>
+			</a-row>
+		</a-form>
+	</a-card>
+	<a-card :bordered="false">
+		<s-table
+			ref="tableRef"
+			:columns="columns"
+			:data="loadData"
+			bordered
+			:row-key="(record) => record.id"
+		>
+			<template #operator class="table-operator">
+				<a-space>
+					<a-button type="primary" @click="formRef.onOpen()" v-if="hasPerm('bizSettleShipAdd')">
+						<template #icon><plus-outlined /></template>
+						新增
+					</a-button>
+				</a-space>
+			</template>
+			<template #bodyCell="{ column, record }">
+				<template v-if="column.dataIndex === 'settleType'">
+					<a-tag
+						:color="
+							record.settleType === '1'
+								? 'orange'
+								: record.settleType === '2'
+								  ? 'green'
+								  : 'purple'
+						"
+					>
+						{{ $TOOL.dictTypeData('settle_type', record.settleType) }}
+					</a-tag>
+				</template>
+				<template v-if="column.dataIndex === 'settleStatus'">
+					<a-tag
+						:color="
+							record.settleStatus === '1'
+								? 'red'
+								: record.settleStatus === '2'
+								  ? 'green'
+								 : record.settleStatus === '3'
+								  ? '#f50'
+								  : record.settleStatus === '4'
+								  ? 'processing'
+								  : record.settleStatus === '5'
+								  ? 'processing'
+								  : record.settleStatus === '6'
+								  ? 'cyan'
+								  : 'purple'
+						"
+					>
+						{{ $TOOL.dictTypeData('settle_status', record.settleStatus) }}
+					</a-tag>
+				</template>
+				<template v-if="column.dataIndex === 'action'">
+<!--					<a-space>
+						<a @click="formRef.onOpen(record)" v-if="hasPerm('bizSettleEdit')">编辑</a>
+						<a-divider type="vertical" v-if="hasPerm(['bizSettleEdit', 'bizSettleDelete'], 'and')" />
+						<a style="color:red" size="small" type="link" @click="deleteConfig(record)">删除</a>
+					</a-space>-->
+					<a size="small" type="link" @click="detailRef.onOpen(record)" >详情</a>
+
+					<a-divider type="vertical" v-if="(hasPerm('bizSettleShipSubmit') && record.settleStatus == '1') ||
+						(hasPerm('bizSettleShipAdminAudit') && record.settleStatus == '2') ||
+						(hasPerm('bizSettleShipFinanceAudit') && record.settleStatus == '4') ||
+						(hasPerm('bizSettleShipEdit') && (record.settleStatus == '1' || record.settleStatus == '3')) ||
+						(hasPerm('bizSettleShipUploadInvoice') && (record.settleStatus == '5')) ||
+						(hasPerm('bizSettleShipUploadVoucher') && (record.settleStatus == '6')) ||
+						(hasPerm('bizSettleShipDelete') && record.settleStatus !='7')"/>
+
+					<a-dropdown v-if="(hasPerm('bizSettleShipSubmit') && record.settleStatus == '1') ||
+						(hasPerm('bizSettleShipFinanceAudit') && record.settleStatus == '2') ||
+						(hasPerm('bizSettleFinanceAudit') && record.settleStatus == '4') ||
+						(hasPerm('bizSettleShipEdit') && (record.settleStatus == '1' ||  record.settleStatus == '3')) ||
+						(hasPerm('bizSettleShipUploadInvoice') && (record.settleStatus == '5')) ||
+						(hasPerm('bizSettleShipUploadVoucher') && (record.settleStatus == '6')) ||
+						(hasPerm('bizSettleShipDelete') && record.settleStatus !='7' )">
+						<a class="ant-dropdown-link">
+							更多
+							<DownOutlined />
+						</a>
+
+						<template #overlay>
+							<a-menu>
+								<a-menu-item v-if="hasPerm('bizSettleShipSubmit') && record.settleStatus == '1'">
+									<a style="color:blue" @click="onSubmit(record)" >提交</a>
+								</a-menu-item>
+								<!--管理员审核-->
+								<a-menu-item v-if="hasPerm('bizSettleShipAdminAudit') && record.settleStatus == '2'">
+									<a style="color:blue" @click="adminReviewRef.showModal(record.id)" >审核</a>
+								</a-menu-item>
+								<!--财务审核-->
+								<a-menu-item v-if="hasPerm('bizSettleShipFinanceAudit') && record.settleStatus == '4'">
+									<a style="color:blue" @click="financeReviewRef.showModal(record.id)" >审核</a>
+								</a-menu-item>
+								<a-menu-item v-if="hasPerm('bizSettleShipEdit') && (record.settleStatus == '1' || record.settleStatus == '3')">
+									<a @click="formRef.onOpen(record)" >编辑</a>
+								</a-menu-item>
+								<a-menu-item v-if="hasPerm('bizSettleShipUploadInvoice') && (record.settleStatus == '5')">
+									<a style="color:green" @click="uploadFileRef.onOpen(record)" >上传发票</a>
+								</a-menu-item>
+								<a-menu-item v-if="hasPerm('bizSettleShipUploadVoucher') && (record.settleStatus == '6')">
+									<a style="color:green" @click="uploadVoucherRef.onOpen(record)" >结款凭证</a>
+								</a-menu-item>
+								<a-menu-item v-if="hasPerm('bizSettleShipDelete') && record.settleStatus !='7'">
+									<a style="color:red" size="small" type="link" @click="deleteConfig(record)">删除</a>
+								</a-menu-item>
+							</a-menu>
+						</template>
+					</a-dropdown>
+				</template>
+			</template>
+		</s-table>
+	</a-card>
+	<Form ref="formRef" @successful="tableRef.refresh()" />
+	<Detail ref="detailRef" @successful="tableRef.refresh()" />
+	<ReviewAdmin ref="adminReviewRef" @successful="tableRef.refresh(true)" />
+	<ReviewFinance ref="financeReviewRef" @successful="tableRef.refresh(true)" />
+	<UploadFileRef ref="uploadFileRef" @successful="tableRef.refresh()" />
+	<UploadVoucherRef ref="uploadVoucherRef" @successful="tableRef.refresh()" />
+</template>
+
+<script setup name="bizsettle">
+	import { cloneDeep } from 'lodash-es'
+	import Form from './form.vue'
+	import bizSettleApi from '@/api/biz/bizSettleApi'
+	import {ExclamationCircleOutlined} from '@ant-design/icons-vue';
+	import {Modal} from 'ant-design-vue';
+	import {createVNode} from 'vue';
+	import ReviewAdmin from "./reviewadmin.vue";
+	import ReviewFinance from './reviewfinance.vue'
+	import UploadFileRef from './uploadFile.vue'
+	import UploadVoucherRef from './uploadVoucher.vue'
+	import Detail from './detail.vue'
+	import tool from '@/utils/tool'
+
+
+	const settleStatusList = tool.dictList('settle_status')
+	const settleTypeList = tool.dictList('settle_type')
+	const detailRef = ref()
+	const uploadVoucherRef = ref()
+	const uploadFileRef = ref()
+	const financeReviewRef = ref()
+	const adminReviewRef = ref()
+	const submitLoading = ref(false)
+	const tableRef = ref()
+	const formRef = ref()
+	const toolConfig = { refresh: true, height: true, columnSetting: true, striped: false }
+
+	//查询数据
+	const searchFormState = ref({})
+	const searchFormRef = ref()
+
+	// 查询区域显示更多控制
+	const advanced = ref(false)
+	const toggleAdvanced = () => {
+		advanced.value = !advanced.value
+	}
+
+
+	const columns = [
+		{
+			title: '结算单号',
+			dataIndex: 'settleNo',
+			align:'center',
+		},
+		{
+			title: '结算类型',
+			dataIndex: 'settleType',
+			align:'center',
+		},
+		{
+			title: '结算金额(元)',
+			dataIndex: 'settleAccount',
+			align:'center',
+		},
+		{
+			title: '创建日期',
+			dataIndex: 'createTime',
+			align:'center',
+		},
+		{
+			title: '状态',
+			dataIndex: 'settleStatus',
+			align:'center',
+		}
+	]
+	// 操作栏通过权限判断是否显示
+	columns.push({
+		title: '操作',
+		dataIndex: 'action',
+		align: 'center',
+		width: 150
+	})
+
+	const selectedRowKeys = ref([])
+	// 列表选择配置
+	const options = {
+		// columns数字类型字段加入 needTotal: true 可以勾选自动算账
+		alert: {
+			show: true,
+			clear: () => {
+				selectedRowKeys.value = ref([])
+			}
+		},
+		rowSelection: {
+			onChange: (selectedRowKey, selectedRows) => {
+				selectedRowKeys.value = selectedRowKey
+			}
+		}
+	}
+	const loadData = (parameter) => {
+		const searchFormParam = cloneDeep(searchFormState.value)
+		// grossTime范围查询条件重载
+		if (searchFormParam.createTime) {
+			searchFormParam.startCreateTime = searchFormParam.createTime[0]
+			searchFormParam.endCreateTime = searchFormParam.createTime[1]
+			delete searchFormParam.createTime
+		}
+		searchFormParam.settleType = '2'
+		return bizSettleApi.bizSettlePage(Object.assign(parameter, searchFormParam)).then((data) => {
+			return data
+		})
+	}
+	// 重置
+	const reset = () => {
+		searchFormRef.value.resetFields()
+		tableRef.value.refresh(true)
+	}
+	// 删除
+	const deleteBizSettle = (record) => {
+		let params = [
+			{
+				id: record.id
+			}
+		]
+		bizSettleApi.bizSettleDelete(params).then(() => {
+			tableRef.value.refresh(true)
+		})
+	}
+
+	//提交
+	const onSubmit = (record) => {
+
+		Modal.confirm({
+			title: '确定提交该数据吗?',
+			icon: createVNode(ExclamationCircleOutlined),
+			content: '',
+			onOk() {
+				submitLoading.value = true
+				let params =
+					{
+						id: record.id
+					}
+
+
+				bizSettleApi
+					.submit(params)
+					.then(() => {
+						tableRef.value.refresh(true)
+					})
+					.finally(() => {
+						submitLoading.value = false
+					})
+			},
+			onCancel() {}
+		})
+	}
+
+	// 删除
+	const deleteConfig = (record) => {
+
+		Modal.confirm({
+			title: '确定删除该数据吗?',
+			icon: createVNode(ExclamationCircleOutlined),
+			content: '',
+			onOk() {
+				submitLoading.value = true
+				let params = [
+					{
+						id: record.id
+					}
+				]
+
+				bizSettleApi
+					.deleteArrive(params)
+					.then(() => {
+						tableRef.value.refresh(true)
+					})
+					.finally(() => {
+						submitLoading.value = false
+					})
+			},
+			onCancel() {}
+		})
+	}
+	// 批量删除
+	const deleteBatchBizSettle = (params) => {
+		bizSettleApi.bizSettleDelete(params).then(() => {
+			tableRef.value.clearRefreshSelected()
+		})
+	}
+</script>

+ 311 - 0
snowy-admin-web/src/views/biz/bizsettleship/orderItem.vue

@@ -0,0 +1,311 @@
+<template>
+	<a-modal
+		ref="modalRef"
+		v-model:visible="visible"
+		width="1350px"
+		:body-style="{
+			height: 'calc(100vh - 200px)',
+			overflow: 'auto'
+		}"
+		centered
+		:destoryOnClose="true"
+		:afterClose="handleAfterClose"
+		@ok="handleOk"
+	>
+		<a-row>
+			<a-col :span="23" style="margin-left:20px;">
+				<a-spin :spinning="submitLoading">
+					<a-form ref="searchFormRef" :model="searchFormState" class="ant-advanced-search-form" name="advanced_search" style="margin-top:20px;margin-left:20px;">
+						<a-row :gutter="24">
+							<a-col :span="6">
+								<a-form-item label="订单编号" name="loadNumber">
+									<a-input v-model:value="searchFormState.loadNumber" placeholder="订单编号查询" />
+								</a-form-item>
+							</a-col>
+							<a-col :span="6">
+								<a-form-item label="客户名称" name="customerName">
+									<a-input v-model:value="searchFormState.customerName" placeholder="客户名称查询" />
+								</a-form-item>
+							</a-col>
+							<a-col :span="6">
+								<a-form-item label="货品名称" name="goodsName">
+									<a-input v-model:value="searchFormState.goodsName" placeholder="货品名称查询" />
+								</a-form-item>
+							</a-col>
+							<a-col :span="6">
+								<a-button type="primary" @click="table.refresh(true)">查询</a-button>
+								<a-button style="margin: 0 8px" @click="reset">重置</a-button>
+							</a-col>
+						</a-row>
+					</a-form>
+					<s-table
+						ref="table"
+						:alert="options.alert.show"
+						:columns="columns"
+						:data="loadData"
+						:rowKey="(record) => record.id"
+						:row-selection="options.rowSelection"
+						bordered
+						sticky
+					>
+					</s-table>
+				</a-spin>
+			</a-col>
+		</a-row>
+		<template #title>
+			<div ref="modalTitleRef" style="width: 100%; cursor: move">选择报港预约</div>
+		</template>
+		<template #modalRender="{ originVNode }">
+			<div :style="transformStyle">
+				<component :is="originVNode" />
+			</div>
+		</template>
+	</a-modal>
+</template>
+<script name="orderItem" setup>
+	import { computed, watch, watchEffect } from 'vue'
+	import { useDraggable } from '@vueuse/core'
+	import { Empty, message } from 'ant-design-vue'
+	import bizOrderApi from "@/api/biz/bizOrderApi";
+	import bizLoadArriveApi from "@/api/biz/bizLoadArriveApi";
+
+	// 默认展开的节点
+	let defaultExpandedKeys = ref([])
+	const treeData = ref([])
+	// 替换treeNode 中 title,key,children
+	const treeFieldNames = { children: 'children', title: 'name', key: 'id' }
+	const cardLoading = ref(true)
+
+	const submitLoading = ref(false)
+	let searchFormState = reactive({})
+	const searchFormRef = ref()
+	const table = ref()
+	const storeDatas = ref([])
+
+	const toolConfig = { refresh: true, height: true, columnSetting: true, striped: false }
+	const columns = [
+		{
+			title: '订单编号',
+			width: 100,
+			dataIndex: 'loadNumber',
+			ellipsis: true,
+			align:'center'
+		},
+		{
+			title: '客户名称',
+			width: 100,
+			dataIndex: 'customerName',
+			ellipsis: true,
+			align:'center'
+		},
+		{
+			title: '货品名称',
+			width: 90,
+			dataIndex: 'goodsName',
+			ellipsis: true,
+			align:'center'
+		},
+		{
+			title: '货品编码',
+			width: 80,
+			dataIndex: 'goodsCode',
+			ellipsis: true,
+			align:'center'
+		},
+		{
+			title: '供应商名称',
+			width: 100,
+			dataIndex: 'supplierName',
+			align:'center'
+		},
+		{
+			title: '订单重量(吨)',
+			width: 80,
+			dataIndex: 'orderWeight',
+			ellipsis: true,
+			align:'center'
+		},
+		/*{
+			title: '过磅重量(吨)',
+			width: 80,
+			dataIndex: 'netWeight',
+			ellipsis: true
+		},*/
+		{
+			title: '报港重量(吨)',
+			width: 80,
+			dataIndex: 'arriveNumber',
+			ellipsis: true,
+			align:'center'
+		},
+		{
+			title: '运费单价(元/吨)',
+			width: 80,
+			dataIndex: 'freightPrice',
+			ellipsis: true,
+			align:'center'
+		}
+	]
+
+	const selectedRowKeys = ref([])
+	const selectedRecords = ref([])
+	const selectedCallBack = ref('bom')
+	// 列表选择配置
+	const options = {
+		// columns数字类型字段加入 needTotal: true 可以勾选自动算账
+		alert: {
+			show: true,
+			clear: () => {
+				selectedRowKeys.value = ref([])
+				selectedRecords.value = ref([])
+			}
+		},
+		rowSelection: {
+			onChange: (selectedRowKey, selectedRows) => {
+				selectedRowKeys.value = selectedRowKey
+				selectedRecords.value = selectedRows
+			}
+		}
+	}
+
+	const loadData = (parameter) => {
+		const searchFormParam = JSON.parse(JSON.stringify(searchFormState))
+		searchFormParam.status = '4'
+		return bizLoadArriveApi.bizLoadArrivePage(Object.assign(parameter, searchFormParam)).then((data) => {
+			return data
+		})
+	}
+
+	// 仓库下拉框
+	/*baseStoreApi.baseStoreSelector().then((res) => {
+		storeDatas.value = res
+	})
+
+	// 加载左侧的树
+	baseItemKindApi.baseItemKindTree().then((res) => {
+		cardLoading.value = false
+		if (res !== null) {
+			treeData.value = [
+				{
+					id: '',
+					pId: '-1',
+					name: '全部分类',
+					children: res
+				}
+			]
+			// 默认展开2级
+			treeData.value.forEach((item) => {
+				// 因为0的顶级
+				if (item.pId === '-1') {
+					defaultExpandedKeys.value.push(item.id)
+					// 取到下级ID
+					if (item.children) {
+						item.children.forEach((items) => {
+							defaultExpandedKeys.value.push(items.id)
+						})
+					}
+				}
+			})
+		}
+	})*/
+	// 点击树查询
+	const treeSelect = (selectedKeys) => {
+		if (selectedKeys.length > 0) {
+			searchFormState.kindId = selectedKeys.toString()
+		} else {
+			delete searchFormState.kindId
+		}
+		table.value.refresh(true)
+	}
+	// 重置
+	const reset = () => {
+		searchFormRef.value.resetFields()
+		table.value.refresh(true)
+	}
+
+	const visible = ref(false)
+	const modalTitleRef = ref(null)
+	const showModal = (selectType, callBackType) => {
+		console.log("111")
+		options.rowSelection.type = selectType === 'radio' ? 'radio' : 'checkbox'
+		selectedCallBack.value = callBackType
+		visible.value = true
+		table.value.refresh(true)
+	}
+	const { x, y, isDragging } = useDraggable(modalTitleRef)
+
+	const emit = defineEmits(['bomItemCallBack', 'bomCallBack'])
+
+	const handleOk = (e) => {
+		if (selectedRecords.value && selectedRecords.value.length > 0) {
+			if (selectedCallBack.value === 'orderItem') {
+				emit('orderItemCallBack', JSON.parse(JSON.stringify(selectedRecords.value)))
+			}
+			visible.value = false
+			selectedRowKeys.value = []
+			selectedRecords.value = []
+			table.value.clearSelected()
+		} else {
+			message.error('报港预约不能为空!')
+		}
+	}
+	const startX = ref(0)
+	const startY = ref(0)
+	const startedDrag = ref(false)
+	const transformX = ref(0)
+	const transformY = ref(0)
+	const preTransformX = ref(0)
+	const preTransformY = ref(0)
+	const dragRect = ref({
+		left: 0,
+		right: 0,
+		top: 0,
+		bottom: 0
+	})
+	watch([x, y], () => {
+		if (!startedDrag.value) {
+			startX.value = x.value
+			startY.value = y.value
+			const bodyRect = document.body.getBoundingClientRect()
+			const titleRect = modalTitleRef.value.getBoundingClientRect()
+			dragRect.value.right = bodyRect.width - titleRect.width
+			dragRect.value.bottom = bodyRect.height - titleRect.height
+			preTransformX.value = transformX.value
+			preTransformY.value = transformY.value
+		}
+		startedDrag.value = true
+	})
+	watch(isDragging, () => {
+		if (!isDragging) {
+			startedDrag.value = false
+		}
+	})
+	watchEffect(() => {
+		if (startedDrag.value) {
+			transformX.value =
+				preTransformX.value + Math.min(Math.max(dragRect.value.left, x.value), dragRect.value.right) - startX.value
+			transformY.value =
+				preTransformY.value + Math.min(Math.max(dragRect.value.top, y.value), dragRect.value.bottom) - startY.value
+		}
+	})
+	const transformStyle = computed(() => {
+		return {
+			transform: `translate(${transformX.value}px, ${transformY.value}px)`
+		}
+	})
+
+	const handleAfterClose = () => {
+		console.log('handleAfterClose')
+		searchFormState = reactive({})
+	}
+	// 抛出函数
+	defineExpose({
+		showModal
+	})
+</script>
+
+<style lang="less" scoped>
+	.cardImp {
+		margin-right: 10px;
+	}
+</style>

+ 66 - 0
snowy-admin-web/src/views/biz/bizsettleship/reviewadmin.vue

@@ -0,0 +1,66 @@
+<template>
+    <a-modal v-model:visible="visible" title="审核">
+
+        <a-form ref="formRef" :label-col="labelCol" :model="formData" layout="horizontal">
+            <a-form-item v-show="false">
+                <a-input v-model:value="formData.id"></a-input>
+            </a-form-item>
+            <a-form-item
+                    label="审核备注"
+                    name="auditingRemark"
+            >
+                <a-textarea v-model:value="formData.settleReason" placeholder="请输入审核备注"
+                            :auto-size="{ minRows: 3, maxRows: 5 }"/>
+            </a-form-item>
+        </a-form>
+        <template #footer>
+            <a-spin :spinning="submitLoading">
+                <a-button style="margin-right: 8px" @click="onsubmit(false)" type="primary" danger>审核驳回</a-button>
+                <a-button type="primary" @click="onsubmit(true)">审核通过</a-button>
+            </a-spin>
+        </template>
+    </a-modal>
+</template>
+<script setup>
+import {message} from 'ant-design-vue';
+import bizSettleApi from '@/api/biz/bizSettleApi'
+
+
+const emit = defineEmits({successful: null})
+const visible = ref(false);
+const submitLoading = ref(false)
+const labelCol = ref({span: 4})
+// 表单数据
+const formData = ref({})
+const showModal = (id) => {
+    formData.value.id = id
+    visible.value = true;
+};
+const onClose = () => {
+    formData.value = {}
+    visible.value = false
+};
+const onsubmit = (flag) => {
+    if (flag === false) {
+        if (!formData.value.settleReason) {
+            message.error('审核驳回时,备注信息不能为空')
+            return
+        }
+    }
+    submitLoading.value = true
+	formData.value.auditFlag = flag
+	bizSettleApi.auditAdmin(formData.value).then(() => {
+        onClose()
+        emit('successful', null)
+    }).finally(() => {
+        submitLoading.value = false
+    })
+}
+// 抛出函数
+defineExpose({
+    showModal
+})
+</script>
+<style scoped>
+
+</style>

+ 66 - 0
snowy-admin-web/src/views/biz/bizsettleship/reviewfinance.vue

@@ -0,0 +1,66 @@
+<template>
+    <a-modal v-model:visible="visible" title="审核">
+
+        <a-form ref="formRef" :label-col="labelCol" :model="formData" layout="horizontal">
+            <a-form-item v-show="false">
+                <a-input v-model:value="formData.id"></a-input>
+            </a-form-item>
+            <a-form-item
+                    label="审核备注"
+                    name="auditingRemark"
+            >
+                <a-textarea v-model:value="formData.settleReason" placeholder="请输入审核备注"
+                            :auto-size="{ minRows: 3, maxRows: 5 }"/>
+            </a-form-item>
+        </a-form>
+        <template #footer>
+            <a-spin :spinning="submitLoading">
+                <a-button style="margin-right: 8px" @click="onsubmit(false)" type="primary" danger>审核驳回</a-button>
+                <a-button type="primary" @click="onsubmit(true)">审核通过</a-button>
+            </a-spin>
+        </template>
+    </a-modal>
+</template>
+<script setup>
+import {message} from 'ant-design-vue';
+import bizSettleApi from '@/api/biz/bizSettleApi'
+
+
+const emit = defineEmits({successful: null})
+const visible = ref(false);
+const submitLoading = ref(false)
+const labelCol = ref({span: 4})
+// 表单数据
+const formData = ref({})
+const showModal = (id) => {
+    formData.value.id = id
+    visible.value = true;
+};
+const onClose = () => {
+    formData.value = {}
+    visible.value = false
+};
+const onsubmit = (flag) => {
+    if (flag === false) {
+        if (!formData.value.settleReason) {
+            message.error('审核驳回时,备注信息不能为空')
+            return
+        }
+    }
+    submitLoading.value = true
+	formData.value.auditFlag = flag
+	bizSettleApi.auditFinance(formData.value).then(() => {
+        onClose()
+        emit('successful', null)
+    }).finally(() => {
+        submitLoading.value = false
+    })
+}
+// 抛出函数
+defineExpose({
+    showModal
+})
+</script>
+<style scoped>
+
+</style>

+ 162 - 0
snowy-admin-web/src/views/biz/bizsettleship/uploadFile.vue

@@ -0,0 +1,162 @@
+<template>
+	<xn-form-container
+		:title="formData.id ? '上传发票' : '上传发票'"
+		:width="700"
+		v-model:open="open"
+		:destroy-on-close="true"
+		@close="onClose"
+	>
+		<a-form ref="formRef" :model="formData" :rules="formRules" :wrapper-col="wrapperCol" :label-col="labelCol">
+			<a-form-item label="上传发票:" name="filePathList" :rules="[{ required: true, message: '请上传发票' }]">
+				<a-upload
+					v-model:file-list="fileList"
+					class="avatar-uploader"
+					list-type="picture"
+					:show-upload-list="true"
+					:custom-request="customRequest"
+					:remove="file => removeOtherFile(file,index)"
+					:before-upload="beforeUpload"
+					accept="image/png, image/jpeg, image/jpg"
+
+				>
+					<a-button>
+						<upload-outlined></upload-outlined>
+						upload
+					</a-button>
+				</a-upload>
+			</a-form-item>
+		</a-form>
+		<template #footer>
+			<a-button style="margin-right: 8px" @click="onClose">关闭</a-button>
+			<a-button type="primary" @click="onSubmit" :loading="submitLoading">保存</a-button>
+		</template>
+	</xn-form-container>
+</template>
+
+<script setup name="bizRecordForm">
+	import { cloneDeep } from 'lodash-es'
+	import { required } from '@/utils/formRules'
+	import bizSettleApi from "@/api/biz/bizSettleApi";
+	import fileApi from '@/api/dev/fileApi'
+	import sysConfig from "@/config";
+	import {message, Modal, Upload } from 'ant-design-vue';
+	// 抽屉状态
+	const open = ref(false)
+	const emit = defineEmits({ successful: null })
+	const formRef = ref()
+	// 表单数据
+	const formData = ref({filePathList:[],fileNameList:[]})
+	const submitLoading = ref(false)
+
+	//设置表单样式
+	const labelCol = ref({ span: 5})
+	const wrapperCol = ref({ span: 16})
+
+	const fileList = ref([])
+
+	// 打开抽屉
+	const onOpen = (record) => {
+		open.value = true
+		if (record) {
+			let recordData = cloneDeep(record)
+			formData.value = Object.assign({}, recordData)
+			formData.value.filePathList = []
+			formData.value.fileNameList = []
+			fileList.value = []
+			if (formData.value.fileInvoicePath) {
+				for (var i = 0; i < formData.value.fileInvoicePath.split(',').length; i++) {
+					fileList.value.push({
+						url: sysConfig.PREVIEW_PATH + formData.value.fileInvoicePath.split(',')[i],
+						name: formData.value.fileInvoiceName.split(',')[i]
+					})
+
+					formData.value.filePathList.push(formData.value.fileInvoicePath.split(',')[i])
+					formData.value.fileNameList.push(formData.value.fileInvoiceName.split(',')[i])
+				}
+			}
+		}
+	}
+	// 关闭抽屉
+	const onClose = () => {
+		formRef.value.resetFields()
+		formData.value = {}
+		formData.value.fileNameList = []
+		formData.value.filePathList = []
+		fileList.value = []
+		open.value = false
+	}
+	// 默认要校验的
+	const formRules = {
+	}
+	// 验证并提交数据
+	const onSubmit = () => {
+		formRef.value
+			.validate()
+			.then(() => {
+
+				if (
+					formData.value.filePathList == [] ||
+					formData.value.filePathList == '' ||
+					formData.value.filePathList == null
+				) {
+					message.warn('请上传发票')
+					return
+				}
+
+				submitLoading.value = true
+				const formDataParam = cloneDeep(formData.value)
+				console.log("formData:"+formDataParam.filePahList)
+				bizSettleApi
+					.uploadInvoice(formDataParam)
+					.then(() => {
+						onClose()
+						emit('successful')
+					})
+					.finally(() => {
+						submitLoading.value = false
+					})
+			})
+			.catch(() => {})
+	}
+
+	const customRequest = (data) => {
+		console.log("data:"+JSON.stringify(data.file.name))
+		//保存图片
+		const fileData = new FormData()
+		fileData.append('file', data.file)
+		fileApi
+			.uploadImgMap(fileData)
+			.then((result) => {
+				formData.value.filePathList.push(result.imageFile)
+				formData.value.fileNameList.push(data.file.name)
+			}).finally(()=>{
+			data.onSuccess()
+		})
+
+	}
+
+	//文件删除
+	const removeOtherFile = (file) => {
+		fileList.value.forEach((item,index)=>{
+			console.log(item.name+"======="+file.name)
+			if(item.name === file.name){
+
+				fileList.value.splice(index, 1);
+				formData.value.filePathList.splice(index,1)
+				formData.value.fileNameList.splice(index,1)
+			}
+		})
+	}
+
+	const beforeUpload = (file) => {
+		const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png'
+		if (!isJpgOrPng) {
+			message.error('请上传JPG/PNG格式的图片!')
+		}
+		return isJpgOrPng || Upload.LIST_IGNORE
+	}
+	// 抛出函数
+	defineExpose({
+		onOpen
+	})
+</script>

+ 195 - 0
snowy-admin-web/src/views/biz/bizsettleship/uploadVoucher.vue

@@ -0,0 +1,195 @@
+<template>
+	<xn-form-container
+		:title="formData.id ? '上传结款凭证' : '上传结款凭证'"
+		:width="700"
+		v-model:open="open"
+		:destroy-on-close="true"
+		@close="onClose"
+	>
+		<a-form ref="formRef" :model="formData" :rules="formRules" :wrapper-col="wrapperCol" :label-col="labelCol">
+			<a-form-item label="发票信息:" >
+				<p v-for="(item, index) in fileUploadInvoice" :key="index" style="margin-top:5px;">
+					<a @click="downloadMaterial(item.url)" target="_blank">{{ item.name }}</a>
+				</p>
+			</a-form-item>
+			<a-form-item label="上传结款凭证:" name="filePathList" :rules="[{ required: true, message: '请上传结款凭证' }]">
+				<a-upload
+					v-model:file-list="fileList"
+					class="avatar-uploader"
+					list-type="picture"
+					:show-upload-list="true"
+					:custom-request="customRequest"
+					:remove="file => removeOtherFile(file,index)"
+					:before-upload="beforeUpload"
+					accept="image/png, image/jpeg, image/jpg"
+
+				>
+					<a-button>
+						<upload-outlined></upload-outlined>
+						upload
+					</a-button>
+				</a-upload>
+			</a-form-item>
+			<a-form-item label="驳回备注:" name="settleReason">
+				<a-textarea
+					v-model:value="formData.settleReason"
+					placeholder="请输入驳回备注"
+					:maxlength="200"
+					show-count
+				/>
+			</a-form-item>
+		</a-form>
+		<template #footer>
+			<a-button style="margin-right: 8px" @click="onClose">关闭</a-button>
+			<a-button style="margin-right: 8px" @click="reject" type="primary" danger>驳回</a-button>
+			<a-button type="primary" @click="onSubmit" :loading="submitLoading">保存</a-button>
+		</template>
+	</xn-form-container>
+</template>
+
+<script setup name="bizRecordForm">
+	import { cloneDeep } from 'lodash-es'
+	import { required } from '@/utils/formRules'
+	import bizSettleApi from "@/api/biz/bizSettleApi";
+	import fileApi from '@/api/dev/fileApi'
+	import sysConfig from "@/config";
+	import {message, Modal, Upload } from 'ant-design-vue';
+	// 抽屉状态
+	const open = ref(false)
+	const emit = defineEmits({ successful: null })
+	const formRef = ref()
+	// 表单数据
+	const formData = ref({filePathList:[],fileNameList:[]})
+	const submitLoading = ref(false)
+
+	//设置表单样式
+	const labelCol = ref({ span: 5})
+	const wrapperCol = ref({ span: 16})
+
+	const fileList = ref([])
+	const fileUploadInvoice = ref([])
+
+	// 打开抽屉
+	const onOpen = (record) => {
+		open.value = true
+		if (record) {
+			let recordData = cloneDeep(record)
+			formData.value = Object.assign({}, recordData)
+			formData.value.filePathList = []
+			formData.value.fileNameList = []
+			fileList.value = []
+			if (formData.value.fileInvoicePath) {
+				for (var i = 0; i < formData.value.fileInvoicePath.split(',').length; i++) {
+					fileUploadInvoice.value.push({
+						url: sysConfig.PREVIEW_PATH + formData.value.fileInvoicePath.split(',')[i],
+						name: formData.value.fileInvoiceName.split(',')[i]
+					})
+				}
+			}
+		}
+	}
+	// 关闭抽屉
+	const onClose = () => {
+		formRef.value.resetFields()
+		formData.value = {}
+		formData.value.fileNameList = []
+		formData.value.filePathList = []
+		fileList.value = []
+		open.value = false
+		fileUploadInvoice.value = []
+	}
+
+	const downloadMaterial = (url) => {
+		window.open( url)
+	}
+
+	// 默认要校验的
+	const formRules = {
+	}
+	// 验证并提交数据
+	const onSubmit = () => {
+		formRef.value
+			.validate()
+			.then(() => {
+
+				if (
+					formData.value.filePathList == [] ||
+					formData.value.filePathList == '' ||
+					formData.value.filePathList == null
+				) {
+					message.warn('请上传发票')
+					return
+				}
+
+				submitLoading.value = true
+				const formDataParam = cloneDeep(formData.value)
+				console.log("formData:"+formDataParam.filePahList)
+				bizSettleApi
+					.uploadVoucher(formDataParam)
+					.then(() => {
+						onClose()
+						emit('successful')
+					})
+					.finally(() => {
+						submitLoading.value = false
+					})
+			})
+			.catch(() => {})
+	}
+
+	const reject = () => {
+		if(formData.value.settleReason== '' || formData.value.settleReason==null){
+			message.error('驳回时,备注信息不能为空')
+			return
+		}
+		submitLoading.value = true
+		const formDataParam = cloneDeep(formData.value)
+		bizSettleApi.auditReject(formDataParam).then((res)=>{
+			onClose()
+			emit('successful')
+		}).finally(() => {
+			submitLoading.value = false
+		})
+	}
+
+	const customRequest = (data) => {
+		console.log("data:"+JSON.stringify(data.file.name))
+		//保存图片
+		const fileData = new FormData()
+		fileData.append('file', data.file)
+		fileApi
+			.uploadImgMap(fileData)
+			.then((result) => {
+				formData.value.filePathList.push(result.imageFile)
+				formData.value.fileNameList.push(data.file.name)
+			}).finally(()=>{
+			data.onSuccess()
+		})
+
+	}
+
+	//文件删除
+	const removeOtherFile = (file) => {
+		fileList.value.forEach((item,index)=>{
+			console.log(item.name+"======="+file.name)
+			if(item.name === file.name){
+
+				fileList.value.splice(index, 1);
+				formData.value.filePathList.splice(index,1)
+				formData.value.fileNameList.splice(index,1)
+			}
+		})
+	}
+
+	const beforeUpload = (file) => {
+		const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png'
+		if (!isJpgOrPng) {
+			message.error('请上传JPG/PNG格式的图片!')
+		}
+		return isJpgOrPng || Upload.LIST_IGNORE
+	}
+	// 抛出函数
+	defineExpose({
+		onOpen
+	})
+</script>

+ 6 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizloadappoint/entity/BizLoadAppoint.java

@@ -162,4 +162,10 @@ public class BizLoadAppoint extends CommonEntity {
 
     /**卸货重量**/
     private BigDecimal loadWeight;
+
+    /**起卸费结算**/
+    private String loadCostSettle;
+
+    /**起卸路运结算**/
+    private String loadRoadSettle;
 }

+ 2 - 1
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizloadappoint/mapper/mapping/BizLoadAppointMapper.xml

@@ -34,7 +34,8 @@
             bla.already_appoint_number,
             bla.load_type,
             bla.end_sign,
-            bla.end_sign_time
+            bla.end_sign_time,
+            ifnull(bla.fill_weight/1000,0) fill_weight
         from biz_load_appoint bla
          left join biz_service_customer bsc on bla.customer_id = bsc.id
          left join biz_goods bg on bg.id = bla.goods_id

+ 1 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizloadappoint/param/BizLoadAppointPageParam.java

@@ -69,4 +69,5 @@ public class BizLoadAppointPageParam {
 
     private String id;
 
+    private String loadCostSettle;
 }

+ 42 - 14
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizloadappoint/service/impl/BizLoadAppointServiceImpl.java

@@ -133,6 +133,14 @@ public class BizLoadAppointServiceImpl extends ServiceImpl<BizLoadAppointMapper,
             queryWrapper.between("bla.create_time",bizLoadAppointPageParam.getCreateTimeBegin()+" 00:00:00",
                     bizLoadAppointPageParam.getCreateTimeEnd()+" 23:59:59");
         }
+        //状态查询
+        if(ObjectUtil.isNotEmpty(bizLoadAppointPageParam.getStatus())){
+            queryWrapper.eq("bla.status",bizLoadAppointPageParam.getStatus());
+        }
+        //结算查询
+        if(ObjectUtil.isNotEmpty(bizLoadAppointPageParam.getLoadCostSettle())){
+            queryWrapper.eq("bla.load_cost_settle",bizLoadAppointPageParam.getLoadCostSettle());
+        }
         // 校验数据范围
         List<String> loginUserDataScope = StpLoginUserUtil.getLoginUserDataScope();
         if(ObjectUtil.isEmpty(loginUserDataScope)) {
@@ -184,14 +192,14 @@ public class BizLoadAppointServiceImpl extends ServiceImpl<BizLoadAppointMapper,
     public void checkParam(BizLoadAppointAddParam bizLoadAppointAddParam){
         lock.lock();
         try{
+            //查询客户帐号信息
+            BizServiceCustomerAccount customerAccount = bizServiceCustomerAccountService.getOne(new QueryWrapper<BizServiceCustomerAccount>().lambda().
+                    eq(BizServiceCustomerAccount::getServiceCustomerId, bizLoadAppointAddParam.getCustomerId()).
+                    last("limit 1"));
+            if(ObjectUtil.isNull(customerAccount)){
+                throw new CommonException("未查询到客户信息!");
+            }
             if(StringUtils.equals(bizLoadAppointAddParam.getPayType(),"1")){
-                //查询客户帐号信息
-                BizServiceCustomerAccount customerAccount = bizServiceCustomerAccountService.getOne(new QueryWrapper<BizServiceCustomerAccount>().lambda().
-                        eq(BizServiceCustomerAccount::getServiceCustomerId, bizLoadAppointAddParam.getCustomerId()).
-                        last("limit 1"));
-                if(ObjectUtil.isNull(customerAccount)){
-                    throw new CommonException("未查询到客户信息!");
-                }
                 //可用金额 - 账户锁定金额
                 BigDecimal amount = customerAccount.getAccountAmount().subtract(customerAccount.getLockAmount());
                 if(amount.compareTo(BigDecimal.ZERO) <0){
@@ -203,6 +211,16 @@ public class BizLoadAppointServiceImpl extends ServiceImpl<BizLoadAppointMapper,
                     throw new CommonException("客户账户余额不足以支付起卸费用!");
                 }
             }
+
+            if(StringUtils.equals(bizLoadAppointAddParam.getPayType(),"2")){
+                //授信  校验授信额度是否充足
+                BigDecimal orderPrice = bizLoadAppointAddParam.getLoadPrice().multiply(bizLoadAppointAddParam.getOrderWeight());
+                //可使用授信额度
+                BigDecimal creditAmount = customerAccount.getCreditAmount().subtract(customerAccount.getCreditAmountUse());
+                if(creditAmount.compareTo(orderPrice) < 0){
+                    throw new CommonException("授信额度不足!");
+                }
+            }
         }finally {
             //释放锁
             lock.unlock();
@@ -260,14 +278,14 @@ public class BizLoadAppointServiceImpl extends ServiceImpl<BizLoadAppointMapper,
         if(!StringUtils.equals(bizLoadAppointEditParam.getCustomerId(),bizLoadAppoint.getCustomerId())){
             lock.lock();
             try{
+                //查询客户帐号信息
+                BizServiceCustomerAccount customerAccount = bizServiceCustomerAccountService.getOne(new QueryWrapper<BizServiceCustomerAccount>().lambda().
+                        eq(BizServiceCustomerAccount::getServiceCustomerId, bizLoadAppointEditParam.getCustomerId()).
+                        last("limit 1"));
+                if(ObjectUtil.isNull(customerAccount)){
+                    throw new CommonException("未查询到客户信息!");
+                }
                 if(StringUtils.equals(bizLoadAppointEditParam.getPayType(),"1")){
-                    //查询客户帐号信息
-                    BizServiceCustomerAccount customerAccount = bizServiceCustomerAccountService.getOne(new QueryWrapper<BizServiceCustomerAccount>().lambda().
-                            eq(BizServiceCustomerAccount::getServiceCustomerId, bizLoadAppointEditParam.getCustomerId()).
-                            last("limit 1"));
-                    if(ObjectUtil.isNull(customerAccount)){
-                        throw new CommonException("未查询到客户信息!");
-                    }
                     //可用金额 - 账户锁定金额
                     BigDecimal amount = customerAccount.getAccountAmount().subtract(customerAccount.getLockAmount());
                     if(amount.compareTo(BigDecimal.ZERO) < 0){
@@ -299,6 +317,16 @@ public class BizLoadAppointServiceImpl extends ServiceImpl<BizLoadAppointMapper,
                     newCustomerAccount.setLockAmount(newCustomerAccount.getLockAmount().add(newPrice));
                     bizServiceCustomerAccountService.updateById(newCustomerAccount);
                 }
+
+                if(StringUtils.equals(bizLoadAppointEditParam.getPayType(),"2")){
+                    //授信  校验授信额度是否充足
+                    BigDecimal orderPrice = bizLoadAppointEditParam.getLoadPrice().multiply(bizLoadAppointEditParam.getOrderWeight());
+                    //可使用授信额度
+                    BigDecimal creditAmount = customerAccount.getCreditAmount().subtract(customerAccount.getCreditAmountUse());
+                    if(creditAmount.compareTo(orderPrice) < 0){
+                        throw new CommonException("授信额度不足!");
+                    }
+                }
             }finally {
                 //释放锁
                 lock.unlock();

+ 12 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizloadarrive/entity/BizLoadArrive.java

@@ -107,4 +107,16 @@ public class BizLoadArrive extends CommonEntity {
     /**起卸数量*/
     @TableField(exist = false)
     private BigDecimal fillWeight;
+
+    /**供应商名称*/
+    @TableField(exist = false)
+    private String supplierName;
+
+    /**订单数量*/
+    @TableField(exist = false)
+    private BigDecimal orderWeight;
+
+    /**船运运费单价*/
+    @TableField(exist = false)
+    private BigDecimal freightPrice;
 }

+ 5 - 1
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizloadarrive/mapper/mapping/BizLoadArriveMapper.xml

@@ -24,11 +24,15 @@
             bla.status loadStatus,
             blv.arrive_sign,
             blv.sign_time,
-            ifnull(bla.fill_weight/1000,0) fill_weight
+            ifnull(bla.fill_weight/1000,0) fill_weight,
+            bs.supplier_name,
+            ifnull(bla.order_weight/1000,0) order_weight,
+            bla.freight_price
         from biz_load_arrive blv
          left join biz_load_appoint bla on blv.appoint_id = bla.id
          left join biz_service_customer bsc on bla.customer_id = bsc.id
          left join biz_goods bg on bg.id = bla.goods_id
+         left join biz_supplier bs on bs.id = bla.supplier_id
          ${ew.customSqlSegment}
     </select>
 </mapper>

+ 2 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizloadarrive/param/BizLoadArrivePageParam.java

@@ -77,4 +77,6 @@ public class BizLoadArrivePageParam {
     /**状态**/
     private String status;
 
+    private String id;
+
 }

+ 7 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizloadarrive/service/BizLoadArriveService.java

@@ -103,4 +103,11 @@ public interface BizLoadArriveService extends IService<BizLoadArrive> {
      * @date  2025/06/26 14:12
      */
     void arriveSign(BizLoadArriveEditParam bizLoadArriveEditParam);
+
+    /**
+     * 船运结算列表
+     * @param bizLoadArrivePageParam
+     * @return
+     */
+    List<BizLoadArrive> getList(BizLoadArrivePageParam bizLoadArrivePageParam);
 }

+ 18 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizloadarrive/service/impl/BizLoadArriveServiceImpl.java

@@ -95,6 +95,10 @@ public class BizLoadArriveServiceImpl extends ServiceImpl<BizLoadArriveMapper, B
         if(ObjectUtil.isNotEmpty(bizLoadArrivePageParam.getCustomerName())){
             queryWrapper.like("bsc.`name`",bizLoadArrivePageParam.getCustomerName());
         }
+        //id
+        if(ObjectUtil.isNotEmpty(bizLoadArrivePageParam.getId())){
+            queryWrapper.eq("blv.id",bizLoadArrivePageParam.getId());
+        }
         //联系人
         if(ObjectUtil.isNotEmpty(bizLoadArrivePageParam.getCustomerContact())){
             queryWrapper.like("bsc.contact",bizLoadArrivePageParam.getCustomerContact());
@@ -140,6 +144,10 @@ public class BizLoadArriveServiceImpl extends ServiceImpl<BizLoadArriveMapper, B
         if(ObjectUtil.isEmpty(loginUserDataScope)) {
             queryWrapper.eq("blv.create_user", StpUtil.getLoginIdAsString());
         }
+        //供应商角色
+        if(StpLoginUserUtil.getLoginUser().getRoleCodeList().contains("supplier")){
+            queryWrapper.eq("bla.supplier_id",StpLoginUserUtil.getLoginUser().getCustomerId());
+        }
         queryWrapper.eq("blv.delete_flag","NOT_DELETE");
         queryWrapper.orderByDesc("blv.create_time");
         return queryWrapper;
@@ -455,4 +463,14 @@ public class BizLoadArriveServiceImpl extends ServiceImpl<BizLoadArriveMapper, B
         }
 
     }
+
+    @Override
+    public List<BizLoadArrive> getList(BizLoadArrivePageParam bizLoadArrivePageParam) {
+        QueryWrapper<BizLoadArrive> queryWrapper = new QueryWrapper<BizLoadArrive>();
+        if(ObjectUtil.isNotEmpty(bizLoadArrivePageParam.getId())){
+            queryWrapper.eq("blv.id",bizLoadArrivePageParam.getId());
+        }
+        List<BizLoadArrive> page = this.getBaseMapper().getPage(queryWrapper);
+        return page;
+    }
 }

+ 3 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizservicecustomer/entity/BizServiceCustomerAccount.java

@@ -63,4 +63,7 @@ public class BizServiceCustomerAccount extends CommonEntity {
     /** 授信额度 */
     @Schema(description = "授信额度")
     private BigDecimal creditAmount;
+
+    /**已使用授信额度**/
+    private BigDecimal creditAmountUse;
 }

+ 57 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizsettle/controller/BizSettleController.java

@@ -73,6 +73,20 @@ public class BizSettleController {
         return CommonResult.ok();
     }
 
+    /**
+     * 添加船运运费结算
+     *
+     * @author xiaofan
+     * @date  2025/06/12 09:54
+     */
+    @Operation(summary = "添加船运运费结算")
+    @CommonLog("添加船运运费结算")
+    @PostMapping("/biz/bizsettle/addShipSettle")
+    public CommonResult<String> addShipSettle(@RequestBody @Valid BizSettleAddParam bizSettleAddParam) {
+        bizSettleService.addShipSettle(bizSettleAddParam);
+        return CommonResult.ok();
+    }
+
     /**
      * 编辑运费结算
      *
@@ -87,6 +101,20 @@ public class BizSettleController {
         return CommonResult.ok();
     }
 
+    /**
+     * 编辑船运结算
+     *
+     * @author xiaofan
+     * @date  2025/06/12 09:54
+     */
+    @Operation(summary = "编辑船运结算")
+    @CommonLog("编辑船运结算")
+    @PostMapping("/biz/bizsettle/editShipSettle")
+    public CommonResult<String> editShipSettle(@RequestBody @Valid BizSettleEditParam bizSettleEditParam) {
+        bizSettleService.editShipSettle(bizSettleEditParam);
+        return CommonResult.ok();
+    }
+
     /**
      * 删除运费结算
      *
@@ -102,6 +130,21 @@ public class BizSettleController {
         return CommonResult.ok();
     }
 
+    /**
+     * 删除船运运费结算
+     *
+     * @author xiaofan
+     * @date  2025/06/12 09:54
+     */
+    @Operation(summary = "删除船运运费结算")
+    @CommonLog("删除船运运费结算")
+    @PostMapping("/biz/bizsettle/deleteArrive")
+    public CommonResult<String> deleteArrive(@RequestBody @Valid @NotEmpty(message = "集合不能为空")
+                                       List<BizSettleIdParam> bizSettleIdParamList) {
+        bizSettleService.deleteArrive(bizSettleIdParamList);
+        return CommonResult.ok();
+    }
+
     /**
      * 获取运费结算详情
      *
@@ -126,6 +169,20 @@ public class BizSettleController {
         return CommonResult.data(bizSettleService.detailOrder(bizSettleIdParam));
     }
 
+    /**
+     * 编辑获取船运明细
+     *
+     * @author xiaofan
+     * @date  2025/06/12 09:54
+     */
+    @Operation(summary = "编辑获取船运明细")
+    @GetMapping("/biz/bizsettle/detailArrive")
+    public CommonResult<BizSettle> detailArrive(@Valid BizSettleIdParam bizSettleIdParam) {
+        return CommonResult.data(bizSettleService.detailArrive(bizSettleIdParam));
+    }
+
+
+
 
     /**
      * 运费结算提交

+ 4 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizsettle/entity/BizSettle.java

@@ -16,6 +16,7 @@ import com.baomidou.mybatisplus.annotation.*;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Getter;
 import lombok.Setter;
+import vip.xiaonuo.biz.modular.bizloadarrive.entity.BizLoadArrive;
 import vip.xiaonuo.biz.modular.bizorder.entity.BizOrder;
 import vip.xiaonuo.common.pojo.CommonEntity;
 
@@ -76,4 +77,7 @@ public class BizSettle extends CommonEntity {
 
     @TableField(exist = false)
     private List<BizOrder> orderList;
+
+    @TableField(exist = false)
+    private List<BizLoadArrive> arriveList;
 }

+ 3 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizsettle/param/BizSettleAddParam.java

@@ -18,6 +18,7 @@ import lombok.Setter;
 
 import jakarta.validation.constraints.NotBlank;
 import jakarta.validation.constraints.NotNull;
+import vip.xiaonuo.biz.modular.bizloadarrive.entity.BizLoadArrive;
 import vip.xiaonuo.biz.modular.bizorder.entity.BizOrder;
 
 import java.math.BigDecimal;
@@ -48,6 +49,8 @@ public class BizSettleAddParam {
 
     private List<BizOrder> orderList;
 
+    private List<BizLoadArrive> arriveList;
+
     private List<String> fileNameList;
 
     private List<String> filePathList;

+ 3 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizsettle/param/BizSettleEditParam.java

@@ -18,6 +18,7 @@ import lombok.Setter;
 
 import jakarta.validation.constraints.NotBlank;
 import jakarta.validation.constraints.NotNull;
+import vip.xiaonuo.biz.modular.bizloadarrive.entity.BizLoadArrive;
 import vip.xiaonuo.biz.modular.bizorder.entity.BizOrder;
 
 import java.math.BigDecimal;
@@ -53,6 +54,8 @@ public class BizSettleEditParam {
 
     private List<BizOrder> orderList;
 
+    private List<BizLoadArrive> arriveList;
+
     private List<String> fileNameList;
 
     private List<String> filePathList;

+ 23 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizsettle/service/BizSettleService.java

@@ -51,6 +51,19 @@ public interface BizSettleService extends IService<BizSettle> {
      */
     void edit(BizSettleEditParam bizSettleEditParam);
 
+    /**
+     * 新增船运结算
+     * @param bizSettleAddParam
+     */
+    void addShipSettle(BizSettleAddParam bizSettleAddParam);
+
+    /**
+     * 编辑船运结算
+     */
+    void editShipSettle(BizSettleEditParam bizSettleEditParam);
+
+
+
     /**
      * 删除运费结算
      *
@@ -59,6 +72,11 @@ public interface BizSettleService extends IService<BizSettle> {
      */
     void delete(List<BizSettleIdParam> bizSettleIdParamList);
 
+    /**
+     * 删除船运结算
+     */
+    void deleteArrive(List<BizSettleIdParam> bizSettleIdParamList);
+
     /**
      * 获取运费结算详情
      *
@@ -80,6 +98,11 @@ public interface BizSettleService extends IService<BizSettle> {
      */
     BizSettle detailOrder(BizSettleIdParam bizSettleIdParam);
 
+    /**
+     * 编辑船运结算查询明细
+     */
+    BizSettle detailArrive(BizSettleIdParam bizSettleIdParam);
+
     /**
      * 提交
      */

+ 134 - 8
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizsettle/service/impl/BizSettleServiceImpl.java

@@ -31,6 +31,9 @@ import vip.xiaonuo.biz.modular.bizauditlog.entity.BizAuditLog;
 import vip.xiaonuo.biz.modular.bizauditlog.service.BizAuditLogService;
 import vip.xiaonuo.biz.modular.bizconfig.entity.BizConfig;
 import vip.xiaonuo.biz.modular.bizconfig.service.BizConfigService;
+import vip.xiaonuo.biz.modular.bizloadarrive.entity.BizLoadArrive;
+import vip.xiaonuo.biz.modular.bizloadarrive.param.BizLoadArrivePageParam;
+import vip.xiaonuo.biz.modular.bizloadarrive.service.BizLoadArriveService;
 import vip.xiaonuo.biz.modular.bizorder.entity.BizOrder;
 import vip.xiaonuo.biz.modular.bizorder.param.BizOrderPageParam;
 import vip.xiaonuo.biz.modular.bizorder.service.BizOrderService;
@@ -71,6 +74,8 @@ public class BizSettleServiceImpl extends ServiceImpl<BizSettleMapper, BizSettle
     private BizAuditLogService bizAuditLogService;
     @Resource
     private BizOrderSupplierService bizOrderSupplierService;
+    @Resource
+    private BizLoadArriveService bizLoadArriveService;
 
     @Override
     public Page<BizSettle> page(BizSettlePageParam bizSettlePageParam) {
@@ -106,12 +111,7 @@ public class BizSettleServiceImpl extends ServiceImpl<BizSettleMapper, BizSettle
     @Override
     public void add(BizSettleAddParam bizSettleAddParam) {
 
-        if(ObjectUtil.isNotEmpty(bizSettleAddParam.getSettleAccount())){
-            BizConfig bizConfig = bizConfigService.getOne(new QueryWrapper<BizConfig>().lambda().last("limit 1"));
-            if(bizSettleAddParam.getSettleAccount().compareTo(bizConfig.getSettleAccount()) < 0){
-                throw new CommonException("结算基础金额为{},低于该金额不可结算!",bizConfig.getSettleAccount());
-            }
-        }
+        checkParam(bizSettleAddParam);
 
         BizSettle bizSettle = BeanUtil.toBean(bizSettleAddParam, BizSettle.class);
         String settleNo = getNumber();
@@ -134,11 +134,21 @@ public class BizSettleServiceImpl extends ServiceImpl<BizSettleMapper, BizSettle
                         last("limit 1"));
                 if(ObjectUtil.isNotNull(orderSupplier)){
                     //修改订单状态:待结算->已结算
-                    /*updateWrapper.set("order_status","9").eq("id",bizOrder.getId());
-                    bizOrderService.update(updateWrapper);*/
+                /*updateWrapper.set("order_status","9").eq("id",bizOrder.getId());
+                bizOrderService.update(updateWrapper);*/
                     orderSupplier.setStatus("1");
                     bizOrderSupplierService.updateById(orderSupplier);
                 }
+
+            }
+        }
+    }
+
+    public void checkParam(BizSettleAddParam bizSettleAddParam){
+        if(ObjectUtil.isNotEmpty(bizSettleAddParam.getSettleAccount())){
+            BizConfig bizConfig = bizConfigService.getOne(new QueryWrapper<BizConfig>().lambda().last("limit 1"));
+            if(bizSettleAddParam.getSettleAccount().compareTo(bizConfig.getSettleAccount()) < 0){
+                throw new CommonException("结算基础金额为{},低于该金额不可结算!",bizConfig.getSettleAccount());
             }
         }
     }
@@ -224,6 +234,81 @@ public class BizSettleServiceImpl extends ServiceImpl<BizSettleMapper, BizSettle
         }
     }
 
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public void addShipSettle(BizSettleAddParam bizSettleAddParam) {
+        checkParam(bizSettleAddParam);
+
+        BizSettle bizSettle = BeanUtil.toBean(bizSettleAddParam, BizSettle.class);
+        String settleNo = getNumber();
+        bizSettle.setSettleNo(settleNo);
+        this.save(bizSettle);
+
+        if(ObjectUtil.isNotEmpty(bizSettleAddParam.getArriveList())){
+            for(BizLoadArrive bizLoadArrive : bizSettleAddParam.getArriveList()){
+                //新增数据关联表
+                BizSettleOrder bizSettleOrder = new BizSettleOrder();
+                bizSettleOrder.setSettleId(bizSettle.getId());
+                bizSettleOrder.setOrderId(bizLoadArrive.getId());
+                bizSettleOrderService.save(bizSettleOrder);
+
+                //修改报港预约状态
+                BizLoadArrive loadArrive = bizLoadArriveService.getById(bizLoadArrive.getId());
+                loadArrive.setStatus("5");
+                bizLoadArriveService.updateById(loadArrive);
+            }
+        }
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public void editShipSettle(BizSettleEditParam bizSettleEditParam) {
+        checkParam(bizSettleEditParam);
+
+        BizSettle bizSettle = this.queryEntity(bizSettleEditParam.getId());
+        BeanUtil.copyProperties(bizSettleEditParam, bizSettle);
+        if(StringUtils.equals(bizSettle.getSettleStatus(),"3")){
+            bizSettle.setSettleStatus("2");
+        }
+        this.updateById(bizSettle);
+
+        //删除之前关联信息
+        List<BizSettleOrder> list = bizSettleOrderService.list(new QueryWrapper<BizSettleOrder>().lambda().
+                eq(BizSettleOrder::getSettleId, bizSettle.getId()));
+        //修改订单状态
+        for(BizSettleOrder bizSettleOrder: list){
+            BizLoadArrive loadArrive = bizLoadArriveService.getById(bizSettleOrder.getOrderId());
+            loadArrive.setStatus("4");
+            bizLoadArriveService.updateById(loadArrive);
+        }
+        //删除关联信息表
+        bizSettleOrderService.removeByIds(CollStreamUtil.toList(list,BizSettleOrder::getId));
+
+        //新增新的关联信息
+        if(ObjectUtil.isNotEmpty(bizSettleEditParam.getArriveList())){
+            for(BizLoadArrive bizLoadArrive : bizSettleEditParam.getArriveList()){
+                //新增数据关联表
+                BizSettleOrder bizSettleOrder = new BizSettleOrder();
+                bizSettleOrder.setSettleId(bizSettle.getId());
+                bizSettleOrder.setOrderId(bizLoadArrive.getId());
+                bizSettleOrderService.save(bizSettleOrder);
+
+                BizLoadArrive loadArrive = bizLoadArriveService.getById(bizLoadArrive.getId());
+                loadArrive.setStatus("5");
+                bizLoadArriveService.updateById(loadArrive);
+            }
+        }
+    }
+
+    public void checkParam(BizSettleEditParam bizSettleEditParam){
+        if(ObjectUtil.isNotEmpty(bizSettleEditParam.getSettleAccount())){
+            BizConfig bizConfig = bizConfigService.getOne(new QueryWrapper<BizConfig>().lambda().last("limit 1"));
+            if(bizSettleEditParam.getSettleAccount().compareTo(bizConfig.getSettleAccount()) < 0){
+                throw new CommonException("结算基础金额为{},低于该金额不可结算!",bizConfig.getSettleAccount());
+            }
+        }
+    }
+
     @Transactional(rollbackFor = Exception.class)
     @Override
     public void delete(List<BizSettleIdParam> bizSettleIdParamList) {
@@ -253,6 +338,29 @@ public class BizSettleServiceImpl extends ServiceImpl<BizSettleMapper, BizSettle
         }
     }
 
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public void deleteArrive(List<BizSettleIdParam> bizSettleIdParamList) {
+        for(BizSettleIdParam bizSettleIdParam : bizSettleIdParamList){
+            //删除关联表信息
+            List<BizSettleOrder> list = bizSettleOrderService.list(new QueryWrapper<BizSettleOrder>().lambda().
+                    eq(BizSettleOrder::getSettleId, bizSettleIdParam.getId()));
+            //修改订单状态
+            for(BizSettleOrder bizSettleOrder: list){
+                BizLoadArrive loadArrive = bizLoadArriveService.getById(bizSettleOrder.getOrderId());
+                loadArrive.setStatus("4");
+                bizLoadArriveService.updateById(loadArrive);
+
+            }
+            //删除关联信息表
+            bizSettleOrderService.removeByIds(CollStreamUtil.toList(list,BizSettleOrder::getId));
+
+
+            //删除运费结算信息
+            this.removeById(bizSettleIdParam.getId());
+        }
+    }
+
     @Override
     public BizSettle detail(BizSettleIdParam bizSettleIdParam) {
         return this.queryEntity(bizSettleIdParam.getId());
@@ -286,6 +394,24 @@ public class BizSettleServiceImpl extends ServiceImpl<BizSettleMapper, BizSettle
         return bizSettle;
     }
 
+    @Override
+    public BizSettle detailArrive(BizSettleIdParam bizSettleIdParam) {
+        BizSettle bizSettle = this.queryEntity(bizSettleIdParam.getId());
+        List<BizSettleOrder> list = bizSettleOrderService.list(new QueryWrapper<BizSettleOrder>().lambda().
+                eq(BizSettleOrder::getSettleId, bizSettleIdParam.getId()));
+        List<BizLoadArrive> arriveList = Lists.newArrayList();
+        for(BizSettleOrder bizSettleOrder : list){
+            BizLoadArrivePageParam bizLoadArrivePageParam = new BizLoadArrivePageParam();
+            bizLoadArrivePageParam.setId(bizSettleOrder.getOrderId());
+            List<BizLoadArrive> detailOrder = bizLoadArriveService.getList(bizLoadArrivePageParam);
+            for(BizLoadArrive bizLoadArrive : detailOrder){
+                arriveList.add(bizLoadArrive);
+            }
+        }
+        bizSettle.setArriveList(arriveList);
+        return bizSettle;
+    }
+
     @Override
     public void submit(BizSettleEditParam bizSettleEditParam) {
         BizSettle bizSettle = this.queryEntity(bizSettleEditParam.getId());

+ 2 - 2
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizsupplier/service/impl/BizSupplierServiceImpl.java

@@ -112,12 +112,12 @@ public class BizSupplierServiceImpl extends ServiceImpl<BizSupplierMapper, BizSu
         }
         BizSupplier bizSupplier = BeanUtil.toBean(bizSupplierAddParam, BizSupplier.class);
 
+        this.save(bizSupplier);
+
         //查询账号是否添加过
         if(ObjectUtil.isNotEmpty(bizSupplierAddParam.getSupplierPhone())){
             addUserAccount(bizSupplier);
         }
-
-        this.save(bizSupplier);
     }
 
     @Transactional(rollbackFor = Exception.class)