浏览代码

Merge remote-tracking branch 'origin/master'

shasha 1 周之前
父节点
当前提交
954745ccd1
共有 52 个文件被更改,包括 2269 次插入82 次删除
  1. 4 0
      snowy-admin-web/src/api/biz/bizAppointmentRecordApi.js
  2. 4 0
      snowy-admin-web/src/api/biz/bizLoadAppointApi.js
  3. 4 0
      snowy-admin-web/src/api/biz/bizLoadArriveApi.js
  4. 12 0
      snowy-admin-web/src/api/biz/bizOrderApi.js
  5. 2 2
      snowy-admin-web/src/views/biz/bizappointload/index.vue
  6. 36 5
      snowy-admin-web/src/views/biz/bizappointmentrecord/index.vue
  7. 106 11
      snowy-admin-web/src/views/biz/bizchargestation/index.vue
  8. 20 9
      snowy-admin-web/src/views/biz/bizconfig/form.vue
  9. 18 7
      snowy-admin-web/src/views/biz/bizconfig/index.vue
  10. 31 2
      snowy-admin-web/src/views/biz/bizloadappoint/form.vue
  11. 150 3
      snowy-admin-web/src/views/biz/bizloadappoint/index.vue
  12. 7 0
      snowy-admin-web/src/views/biz/bizloadarrive/detail.vue
  13. 22 14
      snowy-admin-web/src/views/biz/bizloadarrive/index.vue
  14. 19 11
      snowy-admin-web/src/views/biz/bizorder/dispatch.vue
  15. 311 0
      snowy-admin-web/src/views/biz/bizorder/dispatchadd.vue
  16. 58 4
      snowy-admin-web/src/views/biz/bizorder/index.vue
  17. 64 0
      snowy-admin-web/src/views/biz/bizorder/reject.vue
  18. 2 2
      snowy-admin-web/src/views/biz/bizsendrecord/index.vue
  19. 195 0
      snowy-admin-web/src/views/biz/bizsignrecord/detail.vue
  20. 158 0
      snowy-admin-web/src/views/biz/bizsignrecord/form.vue
  21. 535 0
      snowy-admin-web/src/views/biz/bizsignrecord/index.vue
  22. 2 2
      snowy-admin-web/src/views/biz/record/index.vue
  23. 43 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizappointmentrecord/controller/BizAppointmentRecordController.java
  24. 15 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizappointmentrecord/service/BizAppointmentRecordService.java
  25. 46 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizappointmentrecord/service/impl/BizAppointmentRecordServiceImpl.java
  26. 3 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizconfig/entity/BizConfig.java
  27. 3 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizconfig/param/BizConfigAddParam.java
  28. 3 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizconfig/param/BizConfigEditParam.java
  29. 15 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizloadappoint/controller/BizLoadAppointController.java
  30. 12 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizloadappoint/entity/BizLoadAppoint.java
  31. 5 1
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizloadappoint/mapper/mapping/BizLoadAppointMapper.xml
  32. 6 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizloadappoint/param/BizLoadAppointAddParam.java
  33. 8 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizloadappoint/param/BizLoadAppointEditParam.java
  34. 2 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizloadappoint/param/BizLoadAppointPageParam.java
  35. 5 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizloadappoint/service/BizLoadAppointService.java
  36. 137 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizloadappoint/service/impl/BizLoadAppointServiceImpl.java
  37. 14 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizloadarrive/controller/BizLoadArriveController.java
  38. 6 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizloadarrive/entity/BizLoadArrive.java
  39. 2 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizloadarrive/mapper/mapping/BizLoadArriveMapper.xml
  40. 3 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizloadarrive/param/BizLoadArriveEditParam.java
  41. 9 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizloadarrive/service/BizLoadArriveService.java
  42. 27 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizloadarrive/service/impl/BizLoadArriveServiceImpl.java
  43. 46 3
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizorder/controller/BizOrderController.java
  44. 6 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizorder/entity/BizOrder.java
  45. 3 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizorder/param/BizOrderAddParam.java
  46. 6 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizorder/param/BizOrderEditParam.java
  47. 9 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizorder/service/BizOrderService.java
  48. 57 4
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizorder/service/impl/BizOrderServiceImpl.java
  49. 8 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizorderload/service/impl/BizOrderLoadServiceImpl.java
  50. 1 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/mq/MqttSubscribeClient.java
  51. 6 2
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/record/service/impl/BizRecordServiceImpl.java
  52. 3 0
      snowy-web-app/src/main/java/vip/xiaonuo/core/config/GlobalConfigure.java

+ 4 - 0
snowy-admin-web/src/api/biz/bizAppointmentRecordApi.js

@@ -98,5 +98,9 @@ export default {
 	//车辆执行状态分析
 	gerVehicleTotal(data){
 		return request('gerVehicleTotal',data,'get')
+	},
+	//司机取消
+	cloudCancel(data){
+		return request('cloudCancel',data)
 	}
 }

+ 4 - 0
snowy-admin-web/src/api/biz/bizLoadAppointApi.js

@@ -50,5 +50,9 @@ export default {
 	// 填报起卸订单
 	fillLoad(data){
 		return request('fillLoad',data)
+	},
+	//修改预约次数
+	updateAppointNumber(data){
+		return request('updateAppointNumber',data)
 	}
 }

+ 4 - 0
snowy-admin-web/src/api/biz/bizLoadArriveApi.js

@@ -38,5 +38,9 @@ export default {
 	//船主确认
 	arriveConfirm(data){
 		return request('arriveConfirm',data)
+	},
+	//船主确认
+	arriveSign(data){
+		return request('arriveSign',data)
 	}
 }

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

@@ -54,10 +54,18 @@ export default {
 	updateOrderSign(data){
 		return request('updateOrderSign',data)
 	},
+	//订单结束签名
+	endOrderSign(data){
+		return request('endOrderSign',data)
+	},
 	//订单确认
 	orderConfirm(data){
 		return request('orderConfirm',data)
 	},
+	//发货确认
+	sendConfirm(data){
+		return request('sendConfirm',data)
+	},
 	//订单审核
 	auditOrder(data){
 		return request('auditOrder',data)
@@ -70,6 +78,10 @@ export default {
 	getOrderTotal(data){
 		return request('getOrderTotal',data,'get')
 	},
+	//客户驳回
+	rejectOrder(data){
+		return request('rejectOrder',data)
+	},
 	//导出
 	exportRecordTotal(data){
 		return request('exportRecordTotal', data, 'get', {

+ 2 - 2
snowy-admin-web/src/views/biz/bizappointload/index.vue

@@ -25,8 +25,8 @@
 						</a-form-item>
 					</a-col>
 					<a-col :span="6">
-						<a-form-item label="司机名" name="driverName">
-							<a-input v-model:value="searchFormState.driverName" placeholder="司机名查询" />
+						<a-form-item label="司机名" name="driverName">
+							<a-input v-model:value="searchFormState.driverName" placeholder="司机名查询" />
 						</a-form-item>
 					</a-col>
 					<a-col :span="6">

+ 36 - 5
snowy-admin-web/src/views/biz/bizappointmentrecord/index.vue

@@ -183,17 +183,20 @@
 										<a style="color:red" type="link" danger size="small" @click="deleteConfig(record)">删除</a>
 									</a-menu-item>
 									<a-menu-item v-if="hasPerm('bizAppointmentDriverConfim') && record.status == '8'">
-										<a @click="XnSignNameRef.show(record.recordId)" >确认</a>
+										<a @click="XnSignNameRef.show(record.recordId)" >司机确认</a>
 									</a-menu-item>
 									<a-menu-item v-if="hasPerm('bizAppointmentDriverSign') && record.status=='10' && record.orderType=='1'">
 										<a  @click="signRef.onOpen(record)" >回签</a>
 									</a-menu-item>
 									<a-menu-item v-if="record.status=='4'">
-										<a style="color:green"  @click="cancel(record)" >取消</a>
+										<a style="color:green"  @click="cancel(record)" >取消预约</a>
 									</a-menu-item>
 									<a-menu-item v-if="hasPerm('bizAppointmentDriverExit') && (record.status=='5' || record.status=='6' || record.status=='7' || record.status=='8')">
 										<a style="color:orange"  @click="exit(record)" >授权出场</a>
 									</a-menu-item>
+									<a-menu-item v-if="record.status=='8' && hasPerm('bizAppointmentDriverCancel') ">
+										<a style="color:green"  @click="driverCancel(record)" >司机取消</a>
+									</a-menu-item>
 
 
 								</a-menu>
@@ -289,7 +292,7 @@
 		{
 			title: '车牌号',
 			dataIndex: 'licenseNumber',
-			width:150,
+			width:130,
 			align: 'center'
 		},
 		{
@@ -330,7 +333,7 @@
 			title: '状态',
 			dataIndex: 'status',
 			align: 'center',
-			width:130
+			width:100
 		},
 	]
 	// 操作栏通过权限判断是否显示
@@ -338,7 +341,7 @@
 		title: '操作',
 		dataIndex: 'action',
 		align: 'center',
-		width: 150,
+		width: 180,
 
 	})
 
@@ -437,6 +440,34 @@
 		})
 	}
 
+	//司机取消
+	const driverCancel = (record) => {
+
+		Modal.confirm({
+			title: '确定要取消吗?',
+			icon: createVNode(ExclamationCircleOutlined),
+			content: '',
+			onOk() {
+				submitLoading.value = true
+				let params =
+					{
+						id: record.id
+					}
+
+
+				bizAppointmentRecordApi
+					.cloudCancel(params)
+					.then(() => {
+						tableRef.value.refresh(true)
+					})
+					.finally(() => {
+						submitLoading.value = false
+					})
+			},
+			onCancel() {}
+		})
+	}
+
 
 	//授权出场
 	const exit = (record) => {

+ 106 - 11
snowy-admin-web/src/views/biz/bizchargestation/index.vue

@@ -4,11 +4,8 @@
 			ref="tableRef"
 			:columns="columns"
 			:data="loadData"
-			:alert="options.alert.show"
 			bordered
 			:row-key="(record) => record.id"
-			:tool-config="toolConfig"
-			:row-selection="options.rowSelection"
 		>
 			<template #operator class="table-operator">
 				<a-space>
@@ -31,6 +28,8 @@
 				</template>
 				<template v-if="column.dataIndex === 'action'">
 					<a-space>
+						<a @click="showModal(record)">二维码</a>
+						<a-divider type="vertical" />
 						<a @click="formRef.onOpen(record)" v-if="hasPerm('bizChargeStationEdit')">编辑</a>
 						<a-divider type="vertical" v-if="hasPerm(['bizChargeStationEdit', 'bizChargeStationDelete'], 'and')" />
 						<a-popconfirm title="确定要删除吗?" @confirm="deleteBizChargeStation(record)">
@@ -41,6 +40,29 @@
 			</template>
 		</s-table>
 	</a-card>
+
+
+	<a-modal v-model:visible="open" title="二维码" width="600px" style="height: 700px">
+		<div id="qrcode" style="text-align: center; margin:  15px 5px 15px 5px">
+			<a-row>
+				<a-col :span="13" id="colFlag">
+					<div style="margin-top:10px;font-size:16px;">
+						<p id="projectCodeFlag">充电桩总数量:{{ nowRecord.chargeStationTotalNumber }}</p>
+						<p id="projectCodeFlag">充电桩已使用数量:{{ nowRecord.chargeStationUsedNumber }}</p>
+						<p id="projectCodeFlag">充电桩剩余数量:{{ nowRecord.chargeStationTotalNumber - nowRecord.chargeStationUsedNumber }}</p>
+					</div>
+				</a-col>
+				<a-col :span="11">
+					<a-image width="250"  height="100%" :src="qrCodeUrl.codeUrl"></a-image>
+				</a-col>
+			</a-row>
+		</div>
+		<template #footer>
+			<a-button @click="closeQrCode">关闭</a-button>
+			<a-button type="primary" @click="downloadFile">下载</a-button>
+		</template>
+	</a-modal>
+
 	<Form ref="formRef" @successful="tableRef.refresh()" />
 </template>
 
@@ -48,6 +70,11 @@
 	import { cloneDeep } from 'lodash-es'
 	import Form from './form.vue'
 	import bizChargeStationApi from '@/api/biz/bizChargeStationApi'
+	import html2canvas from "html2canvas";
+	import QRCode from 'qrcode'
+
+
+
 	const tableRef = ref()
 	const formRef = ref()
 	const toolConfig = { refresh: true, height: true, columnSetting: true, striped: false }
@@ -69,14 +96,13 @@
 		}
 	]
 	// 操作栏通过权限判断是否显示
-	if (hasPerm(['bizChargeStationEdit', 'bizChargeStationDelete'])) {
-		columns.push({
-			title: '操作',
-			dataIndex: 'action',
-			align: 'center',
-			width: 150
-		})
-	}
+	columns.push({
+		title: '操作',
+		dataIndex: 'action',
+		align: 'center',
+		width: 220
+	})
+
 	const selectedRowKeys = ref([])
 	// 列表选择配置
 	const options = {
@@ -120,4 +146,73 @@
 			tableRef.value.clearRefreshSelected()
 		})
 	}
+
+
+	//二维码
+	const nowRecord = ref()
+	const open = ref(false);
+	const qrCodeUrl = ref({})
+	const showModal = (record) => {
+		nowRecord.value = record
+		open.value = true;
+		getQrCode(record)
+
+	};
+
+
+	const getQrCode = (record) => {
+		//QRCode.toDataURL("id:"+record.id+"saleCode:"+record.saleCode, {
+		let param = {
+			id:'',
+			type:'4'
+		}
+		QRCode.toDataURL(JSON.stringify(param), {
+			errorCorrectionLevel: 'H',
+			margin: 1,
+			height: 206,
+			width: 206,
+			type: '10',
+			scal: 177,
+			color: {
+				dark: '#000' // 二维码背景颜色
+			},
+			rendererOpts: {
+				quality: 0.9
+			}
+		})
+			.then((url) => {
+				qrCodeUrl.value.codeUrl = url
+			})
+			.catch((err) => {
+				console.error(err)
+			})
+	}
+
+	const closeQrCode = () => {
+		open.value = false;
+	}
+
+	// 下载二维码
+	const downloadFile = () => {
+		const qrcodeDiv = document.getElementById('qrcode');
+		html2canvas(qrcodeDiv, {
+			logging: false,
+			allowTaint: true,
+			scale: window.devicePixelRatio,
+			scrollY: 0,
+			scrollX: 0,
+			useCORS: true,
+			backgroundColor: '#ffffff'
+		})
+			.then(function (canvas) {
+				const a = window.document.createElement('a')
+				a.href = canvas.toDataURL('image/png')
+				a.download = '二维码'
+				a.click()
+				this.$message.success('正在进行下载保存')
+			})
+			.catch((err) => {
+				console.log(err)
+			})
+	}
 </script>

+ 20 - 9
snowy-admin-web/src/views/biz/bizconfig/form.vue

@@ -7,21 +7,21 @@
 		@close="onClose"
 	>
 		<a-form ref="formRef" :model="formData" :rules="formRules" :wrapper-col="wrapperCol" :label-col="labelCol">
-			<a-form-item label="排队时效:" name="queueEfficiency">
+<!--			<a-form-item label="排队时效:" name="queueEfficiency">
 				<a-input-number v-model:value="formData.queueEfficiency" style="width:90%"  :precision="0" :min="1" :max="99999" placeholder="请输入排队时效" allow-clear /><span style="margin-left:10px;">分钟</span>
-			</a-form-item>
+			</a-form-item>-->
 <!--			<a-form-item label="时段下拉个数:" name="pullNumber">
 				<a-input-number v-model:value="formData.pullNumber" style="width:90%"  :precision="0" :min="1" :max="99999" placeholder="请输入时段下拉个数" allow-clear /><span style="margin-left:10px;">个</span>
 			</a-form-item>-->
-			<a-form-item label="停留时长:" name="stopDuration">
+<!--			<a-form-item label="停留时长:" name="stopDuration">
 				<a-input-number v-model:value="formData.stopDuration" style="width:90%" :precision="0" :min="1" :max="99999" placeholder="请输入停留时长" allow-clear /><span style="margin-left:10px;">分钟</span>
-			</a-form-item>
+			</a-form-item>-->
 			<a-form-item label="装卸损耗预警值:" name="lossWarn">
 				<a-input-number v-model:value="formData.lossWarn" style="width:90%"  :precision="0" :min="1" :max="99999" placeholder="请输入装卸损耗预警值" allow-clear /><span style="margin-left:10px;">%</span>
 			</a-form-item>
-			<a-form-item label="预约申请数量:" name="applyCount">
+<!--			<a-form-item label="预约申请数量:" name="applyCount">
 				<a-input-number v-model:value="formData.applyCount" style="width:90%"  :precision="0" :min="1" :max="99999" placeholder="请输入预约申请数量" allow-clear /><span style="margin-left:10px;">个</span>
-			</a-form-item>
+			</a-form-item>-->
 			<a-form-item label="车辆装载量:" name="loadWeight">
 				<a-input-number v-model:value="formData.loadWeight" style="width:90%"  :precision="2" :min="0.01" :max="99999" placeholder="请输入车辆装载量" allow-clear /><span style="margin-left:10px;">吨</span>
 			</a-form-item>
@@ -58,7 +58,7 @@
 					</a-radio-button>
 				</a-radio-group>
 			</a-form-item>
-			<a-form-item label="排队通知开关:" name="lineNoticeSwitch">
+<!--			<a-form-item label="排队通知开关:" name="lineNoticeSwitch">
 				<a-radio-group button-style="solid" v-model:value="formData.lineNoticeSwitch">
 					<a-radio-button value="1">
 						开启
@@ -67,8 +67,8 @@
 						关闭
 					</a-radio-button>
 				</a-radio-group>
-			</a-form-item>
-			<a-form-item label="临时预约审核开关:" name="temporaryAuditSwitch">
+			</a-form-item>-->
+<!--			<a-form-item label="临时预约审核开关:" name="temporaryAuditSwitch">
 				<a-radio-group button-style="solid" v-model:value="formData.temporaryAuditSwitch">
 					<a-radio-button value="1">
 						开启
@@ -77,6 +77,17 @@
 						关闭
 					</a-radio-button>
 				</a-radio-group>
+			</a-form-item>-->
+
+			<a-form-item label="装货点位共享开关:" name="loadSwitch">
+				<a-radio-group button-style="solid" v-model:value="formData.loadSwitch">
+					<a-radio-button value="1">
+						开启
+					</a-radio-button>
+					<a-radio-button value="2">
+						关闭
+					</a-radio-button>
+				</a-radio-group>
 			</a-form-item>
 		</a-form>
 		<template #footer>

+ 18 - 7
snowy-admin-web/src/views/biz/bizconfig/index.vue

@@ -56,6 +56,12 @@
 				<template v-if="column.dataIndex === 'loadWeight'">
 					{{record.loadWeight + '吨'}}
 				</template>
+				<template v-if="column.dataIndex === 'settleAccount'">
+					{{record.settleAccount + '元'}}
+				</template>
+				<template v-if="column.dataIndex === 'loadSwitch'">
+					{{ $TOOL.dictTypeData('biz_switch', record.loadSwitch) }}
+				</template>
 			</template>
 		</s-table>
 	</a-card>
@@ -76,21 +82,21 @@
 	const loading = ref(false)
 	const submitLoading = ref(false)
 	const columns = [
-		{
+		/*{
 			title: '排队时效',
 			dataIndex: 'queueEfficiency',
 			align:'center'
-		},
+		},*/
 		/*{
 			title: '时段下拉个数',
 			dataIndex: 'pullNumber',
 			align:'center'
 		},*/
-		{
+		/*{
 			title: '停留时长',
 			dataIndex: 'stopDuration',
 			align:'center'
-		},
+		},*/
 		{
 			title: '预约审核开关',
 			dataIndex: 'auditSwitch',
@@ -121,14 +127,19 @@
 			dataIndex: 'loadWeight',
 			align:'center'
 		},
-		{
+		/*{
 			title: '排队通知开关',
 			dataIndex: 'lineNoticeSwitch',
 			align:'center'
+		},*/
+		{
+			title: '结算基础金额',
+			dataIndex: 'settleAccount',
+			align:'center'
 		},
 		{
-			title: '临时预约审核开关',
-			dataIndex: 'temporaryAuditSwitch',
+			title: '装货点位共享开关',
+			dataIndex: 'loadSwitch',
 			align:'center'
 		},
 	]

+ 31 - 2
snowy-admin-web/src/views/biz/bizloadappoint/form.vue

@@ -26,12 +26,15 @@
 			<a-form-item label="订单总额:" name="orderAmount">
 				<a-input-number v-model:value="formData.orderAmount" style="width:90%"  :precision="2" :min="0.01" :max="9999999"  placeholder="请输入订单总额" allow-clear/><span style="margin-left:10px;">元</span>
 			</a-form-item>
+			<a-form-item label="起卸单价:" name="loadPrice">
+				<a-input-number v-model:value="formData.loadPrice" style="width:90%"  :precision="2" :min="0.01" :max="999999"  placeholder="请输入运费单价" allow-clear/><span style="margin-left:10px;">元/吨</span>
+			</a-form-item>
 			<a-form-item label="船运供应商:" name="supplierId">
 				<a-select v-model:value="formData.supplierId" placeholder="请选择船运供应商"
 						  :options="supplierIds"
 				> </a-select>
 			</a-form-item>
-			<a-form-item label="运费单价:" name="freightPrice">
+			<a-form-item label="船运运费单价:" name="freightPrice">
 				<a-input-number v-model:value="formData.freightPrice" style="width:90%"  :precision="2" :min="0.01" :max="999999"  placeholder="请输入运费单价" allow-clear/><span style="margin-left:10px;">元/吨</span>
 			</a-form-item>
 			<a-form-item label="支付方式:" name="payType">
@@ -45,7 +48,7 @@
 				</a-radio-group>
 			</a-form-item>
 			<a-form-item label="订单类型:" name="orderType">
-				<a-radio-group button-style="solid" v-model:value="formData.orderType">
+				<a-radio-group button-style="solid" v-model:value="formData.orderType" @change="onChangeOrder">
 					<a-radio-button value="1">
 						配送订单
 					</a-radio-button>
@@ -59,6 +62,9 @@
 						  :options="supplierIdLists" mode="tags"
 				> </a-select>
 			</a-form-item>
+			<a-form-item label="汽运运费单价:" name="landFreightPrice" >
+				<a-input-number v-model:value="formData.landFreightPrice" style="width:90%"  :precision="2" :min="0.01" :max="999999"  placeholder="请输入运费单价" allow-clear  :rules="landPriceRules"/><span style="margin-left:10px;">元/吨</span>
+			</a-form-item>
 		</a-form>
 		<template #footer>
 			<a-button style="margin-right: 8px" @click="onClose">关闭</a-button>
@@ -86,6 +92,8 @@
 	const goodsIdList = ref()
 	const supplierIds = ref()
 	const supplierIdLists = ref()
+	const landPriceRules = ref([])
+	const landPriceFlag = ref(false)
 
 	//设置表单样式
 	const labelCol = ref({ span: 5})
@@ -144,6 +152,8 @@
 		formRef.value.resetFields()
 		formData.value = {}
 		open.value = false
+		landPriceFlag.value = false
+		landPriceRules.value = []
 	}
 	// 默认要校验的
 	const formRules = {
@@ -154,9 +164,11 @@
 		orderAmount:[required('请输入订单总额')],
 		supplierId:[required('请选择船运供应商')],
 		freightPrice:[required('请输入运费单价')],
+		loadPrice:[required('请输入起卸单价')],
 		payType:[required('请选择支付方式')],
 		orderType:[required('请选择订单类型')],
 		supplierIdList:[required('请选择汽运供应商')],
+		landFreightPrice:[required('请选择汽运运费单价')],
 	}
 
 	//获取订单总额
@@ -187,6 +199,23 @@
 			})
 			.catch(() => {})
 	}
+
+	//选择订单类型事件
+	/*const onChangeOrder = (value) => {
+		console.log("value:"+JSON.stringify(value.target.value))
+		console.log("formRules:"+JSON.stringify(formRules))
+		landPriceRules.value = []
+		if(value.target.value == '1'){
+			landPriceFlag.value = true
+			landPriceRules.value.push({ required: true, message: '请输入合同金额' ,trigger:["blur","change"]})
+
+		}else{
+			landPriceFlag.value = false
+			landPriceRules.value = []
+		}
+		formRules.landFreightPrice = landPriceRules.value
+		console.log("formRules:"+JSON.stringify(formRules))
+	}*/
 	// 抛出函数
 	defineExpose({
 		onOpen

+ 150 - 3
snowy-admin-web/src/views/biz/bizloadappoint/index.vue

@@ -110,6 +110,9 @@
 								<a-menu-item v-if="hasPerm('bizLoadAppointFill') && (record.status=='7' )">
 									<a style="color:orange" @click="fillRef.showModal(record.id)">填报</a>
 								</a-menu-item>
+								<a-menu-item v-if="hasPerm('bizLoadAppointConfig') && (record.orderStatus != '0' )">
+									<a style="color:forestgreen" @click="showMore(record)">配置</a>
+								</a-menu-item>
 							</a-menu>
 						</template>
 					</a-dropdown>
@@ -172,6 +175,54 @@
 			<a-button type="primary" @click="downloadFile">下载</a-button>
 		</template>
 	</a-modal>
+
+
+	<a-modal
+		v-model:visible="moreFlag"
+		title="扫码次数配置"
+		:footer="null"
+		width="1100px"
+		:body-style="{
+			height: 'calc(100vh - 300px)',
+			overflow: 'auto'
+		}"
+		@cancel="onCloseAccount"
+	>
+		<a-card :bordered="false">
+			<a-table ref="tableRef" :columns="columns1" :data-source="data1" bordered :row-key="(record) => record.id" :pagination="false">
+				<template #bodyCell="{ column, record }">
+					<template v-if="column.dataIndex === 'action'">
+						<a @click="editAccount(record)"   v-if="hasPerm('bizLoadAppointConfigEdit')">编辑</a>
+					</template>
+					<template v-if="column.dataIndex === 'remain'">
+						{{record.appointNumber-record.alreadyAppointNumber}}
+					</template>
+				</template>
+			</a-table>
+		</a-card>
+	</a-modal>
+
+
+	<a-modal
+		v-model:visible="editAccountFlag"
+		:title="formData.id ? '编辑扫码次数' : '添加扫码次数'"
+		class="custom-modal"
+		width="800px"
+		:body-style="{
+			height: 'calc(100vh - 600px)',
+			overflow: 'auto'
+		}"
+		@ok="handleOk"
+		@cancel="onClose"
+	>
+
+		<a-form ref="formSubmitRef" :model="formData" :rules="formRules" :wrapper-col="wrapperCol" :label-col="labelCol">
+			<a-form-item label="申请数量:" name="appointNumber">
+				<a-input-number v-model:value="formData.appointNumber" style="width:90%"  :precision="0" :min="1" :max="99999" placeholder="请输入申请数量" allow-clear /><span style="margin-left:10px;">次</span>
+			</a-form-item>
+		</a-form>
+
+	</a-modal>
 </template>
 
 <script setup name="bizloadappoint">
@@ -190,9 +241,12 @@
 	import DispatchLoad from './dispatchload.vue'
 	import End from "./end.vue";
 	import Fill from './fill.vue'
+	import bizOrderConfigApi from "@/api/biz/bizOrderConfigApi";
 
-
+	const editAccountFlag = ref(false)
+	const formSubmitRef = ref()
 	const tableRef = ref()
+	const moreFlag = ref(false)
 	const formRef = ref()
 	const dispatchRef = ref()
 	const dispatchLoadRef = ref()
@@ -216,14 +270,107 @@
 	}
 
 
+	const data1 = ref([])
+	const appointId = ref()
+	//打开扫码次数配置页
+	const showMore = (record) => {
+		appointId.value  = record.id
+		loadData1()
+		moreFlag.value = true
+
+	}
+
+	const loadData1 = () => {
+		let param={
+			id:appointId.value
+		}
+		bizLoadAppointApi.bizLoadAppointPage(param).then((res)=>{
+			data1.value = res.records
+		})
+	}
+
+	const columns1 = [
+		{
+			title: '申请数量',
+			dataIndex: 'appointNumber',
+			align: 'center',
+			resizable: true,
+			ellipsis: true,
+			width: 100
+		},
+		{
+			title: '申请数量',
+			dataIndex: 'appointNumber',
+			align: 'center',
+			resizable: true,
+			ellipsis: true,
+			width: 100
+		},
+		{
+			title: '已约数量',
+			dataIndex: 'alreadyAppointNumber',
+			align: 'center',
+			resizable: true,
+			ellipsis: true,
+			width: 100
+		},
+		{
+			title: '可约数量',
+			dataIndex: 'remain',
+			align: 'center',
+			resizable: true,
+			ellipsis: true,
+			width: 100
+		},
+	]
+	columns1.push({
+		title: '操作',
+		dataIndex: 'action',
+		align: 'center',
+		fixed: 'right',
+		width: 140,
+	})
+
+	// 表单数据
+	const formData = ref({})
+	const editAccount = (record) => {
+		formData.value = record
+		editAccountFlag.value = true
+	}
+
+	//表单提交
+	const handleOk = () => {
+		console.log("handleOk")
+		formSubmitRef.value.validate().then(() => {
+			submitLoading.value = true
+			const formDataParam = cloneDeep(formData.value)
+			bizLoadAppointApi
+				.updateAppointNumber(formDataParam)
+				.then(() => {
+					onClose()
+					emit('successful')
+				})
+				.finally(() => {
+					submitLoading.value = false
+				})
+		})
+	}
+
+	const onClose = () => {
+		formSubmitRef.value.resetFields()
+		formData.value = {}
+		editAccountFlag.value = false
+		loadData1()
+	}
+
 	const columns = [
 		{
-			title: '预约单号',
+			title: '起卸单号',
 			dataIndex: 'loadNumber',
 			align:'center'
 		},
 		{
-			title: '服务客户名称',
+			title: '客户名称',
 			dataIndex: 'customerName',
 			align:'center'
 		},

+ 7 - 0
snowy-admin-web/src/views/biz/bizloadarrive/detail.vue

@@ -48,6 +48,13 @@
 					</p>
 				</a-descriptions-item>
 
+				<a-descriptions-item label="船主确认签名" :span="4">
+					<a-image v-if="formData.arriveSign != null" :width="200" :src="formData.arriveSign" />
+				</a-descriptions-item>
+				<a-descriptions-item label="船主签名时间" :span="4">
+					{{formData.signTime}}
+				</a-descriptions-item>
+
 			</a-descriptions>
 
 			<a-divider dashed style="border-color: gray" v-if="auditDataSource.length > 0">审核记录</a-divider>

+ 22 - 14
snowy-admin-web/src/views/biz/bizloadarrive/index.vue

@@ -8,20 +8,21 @@
 					</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 label="船号" name="shipNo">
+						<a-input v-model:value="searchFormState.shipNo" 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 label="客户名称" name="customerName">
+						<a-input v-model:value="searchFormState.customerName" placeholder="客户名称查询" />
 					</a-form-item>
 				</a-col>
+
 				<template v-if="advanced">
 
 					<a-col :span="6">
-						<a-form-item label="船号" name="shipNo">
-							<a-input v-model:value="searchFormState.shipNo" placeholder="船号查询" />
+						<a-form-item label="货品名称" name="goodsName">
+							<a-input v-model:value="searchFormState.goodsName" placeholder="货品名称查询" />
 						</a-form-item>
 					</a-col>
 
@@ -77,13 +78,6 @@
 			</template>
 			<template #bodyCell="{ column, record }">
 				<template v-if="column.dataIndex === 'action'">
-<!--					<a-space>
-						<a @click="formRef.onOpen(record)" v-if="hasPerm('bizLoadArriveEdit')">编辑</a>
-						<a-divider type="vertical" v-if="hasPerm(['bizLoadArriveEdit', 'bizLoadArriveDelete'], 'and')" />
-						<a-popconfirm title="确定要删除吗?" @confirm="deleteBizLoadArrive(record)">
-							<a-button type="link" danger size="small" v-if="hasPerm('bizLoadArriveDelete')">删除</a-button>
-						</a-popconfirm>
-					</a-space>-->
 
 					<a-dropdown>
 						<a class="ant-dropdown-link">
@@ -107,7 +101,8 @@
 								</a-menu-item>
 								<!--确认-->
 								<a-menu-item v-if="hasPerm('bizLoadArriveConfirm') && (record.status == '2' ) && record.loadStatus == '8'">
-									<a style="color:blue" size="small" type="link" @click="confirmConfig(record)">确认</a>
+<!--									<a style="color:blue" size="small" type="link" @click="confirmConfig(record)">确认</a>-->
+									<a style="color:blue" @click="XnSignNameRef.show(record.id)" >确认</a>
 								</a-menu-item>
 							</a-menu>
 						</template>
@@ -144,6 +139,7 @@
 	<Form ref="formRef" @successful="tableRef.refresh()" />
 	<Review ref="reviewRef" @successful="tableRef.refresh(true)" />
 	<Detail ref="detailRef" @successful="tableRef.refresh()" />
+	<XnSignName ref="XnSignNameRef" :image="searchFormState.driverSign" @successful="signSuccess" />
 </template>
 
 <script setup name="bizloadarrive">
@@ -175,6 +171,7 @@
 	const reviewRef = ref()
 	const detailRef = ref()
 	const submitLoading = ref(false)
+	const XnSignNameRef = ref()
 	const toolConfig = { refresh: true, height: true, columnSetting: true, striped: false }
 	const columns = [
 		{
@@ -361,4 +358,15 @@
 			tableRef.value.clearRefreshSelected()
 		})
 	}
+
+	// 签名板组件回调
+	const signSuccess = (value) => {
+		const param = {
+			id:value.id,
+			arriveSign: value.value
+		}
+		bizLoadArriveApi.arriveSign(param).then(() => {
+			tableRef.value.refresh(true)
+		})
+	}
 </script>

+ 19 - 11
snowy-admin-web/src/views/biz/bizorder/dispatch.vue

@@ -6,15 +6,10 @@
 		:destroy-on-close="true"
 		@close="onClose"
 	>
-		<a-form ref="formRef" :model="formData" :rules="formRules" :wrapper-col="wrapperCol" :label-col="labelCol">
+<!--		<a-form ref="formRef" :model="formData" :rules="formRules" :wrapper-col="wrapperCol" :label-col="labelCol">
 			<a-form-item label="订单编号:" name="orderNumber">
 				<a-input v-model:value="formData.orderNumber" placeholder="请输入订单编号" allow-clear disabled/>
 			</a-form-item>
-<!--			<a-form-item label="客户信息:" name="customerId">
-				<a-select v-model:value="formData.customerId" placeholder="请选择客户信息"
-						  :options="customerIdList" @change="onChangeCustomer" disabled
-				> </a-select>
-			</a-form-item>-->
 			<a-form-item label="提货时间:" name="deliveryTimeId" >
 				<a-select v-model:value="formData.deliveryTimeId" placeholder="请选择提货时间"
 						  :options="deliveryTimeIdList" disabled
@@ -39,7 +34,7 @@
 			<a-form-item label="已约次数:" name="alreadyNumber" v-show="numberFlag">
 				<a-input v-model:value="formData.alreadyNumber" placeholder="请输入已约次数" allow-clear disabled/>
 			</a-form-item>
-		</a-form>
+		</a-form>-->
 
 		<s-table
 			ref="tableRef"
@@ -47,7 +42,16 @@
 			:data="loadData"
 			bordered
 			:row-key="(record) => record.id"
+			:pagination="false"
 		>
+			<template #operator class="table-operator">
+				<a-space>
+					<a-button type="primary" @click="dispatchAddRef.onOpen(dispatchRecord)">
+						<template #icon><plus-outlined /></template>
+						新增
+					</a-button>
+				</a-space>
+			</template>
 			<template #bodyCell="{ column, record }">
 				<template v-if="column.dataIndex === 'action'">
 					<a-space>
@@ -60,12 +64,13 @@
 			</template>
 		</s-table>
 
-		<template #footer>
+<!--		<template #footer>
 			<a-button style="margin-right: 8px" @click="onClose">关闭</a-button>
 			<a-button type="primary" @click="onSubmit" :loading="submitLoading">保存</a-button>
-		</template>
+		</template>-->
 
 		<Replace ref="replaceRef" @successful="tableRef.refresh(true)" />
+		<DispatchAdd ref="dispatchAddRef" @successful="tableRef.refresh(true)" />
 	</xn-form-container>
 </template>
 
@@ -88,6 +93,7 @@
 	import {createVNode} from 'vue';
 	import Review from "@/views/biz/bizorder/review.vue";
 	import Replace from './replace.vue'
+	import DispatchAdd from "./dispatchadd.vue";
 
 	// 抽屉状态
 	const open = ref(false)
@@ -95,6 +101,7 @@
 	const formRef = ref()
 	const tableRef = ref()
 	const replaceRef = ref()
+	const dispatchAddRef = ref()
 
 	const numberFlag = ref(false)
 	// 表单数据
@@ -115,12 +122,14 @@
 	const loadPointIdList = ref()
 	const loadTimeIdList = ref()
 
+	const dispatchRecord = ref()
 	// 打开抽屉
 	const onOpen = (record) => {
 		open.value = true
 		if (record) {
 			let recordData = cloneDeep(record)
 			formData.value = Object.assign({}, recordData)
+			dispatchRecord.value = Object.assign({}, recordData)
 		}
 		//查询客户信息
 		customerApi.getList().then((res)=>{
@@ -229,13 +238,12 @@
 
 	// 关闭抽屉
 	const onClose = () => {
+		emit('successful')
 		formRef.value.resetFields()
 		formData.value = {}
 		open.value = false
 		loadTimeIdList.value = ''
 		numberFlag.value = false
-		emit('successful')
-
 	}
 	// 默认要校验的
 	const formRules = {

+ 311 - 0
snowy-admin-web/src/views/biz/bizorder/dispatchadd.vue

@@ -0,0 +1,311 @@
+<template>
+	<xn-form-container
+		:title="formData.id ? '装载车调度' : '装载车调度'"
+		:width="900"
+		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="orderNumber">
+				<a-input v-model:value="formData.orderNumber" placeholder="请输入订单编号" allow-clear disabled/>
+			</a-form-item>
+			<a-form-item label="提货时间:" name="deliveryTimeId" >
+				<a-select v-model:value="formData.deliveryTimeId" placeholder="请选择提货时间"
+						  :options="deliveryTimeIdList" disabled
+				> </a-select>
+			</a-form-item>
+			<a-form-item label="申请次数:" name="applyNumber" >
+				<a-input v-model:value="formData.applyNumber" placeholder="请输入申请次数" allow-clear disabled/>
+			</a-form-item>
+			<a-form-item label="装卸点位:" name="loadPointId">
+				<a-select v-model:value="formData.loadPointId" placeholder="请选择装卸点位"
+						  :options="loadPointIdList" @change="onChangePoint"
+				> </a-select>
+			</a-form-item>
+			<a-form-item label="装卸时间:" name="loadTimeId" >
+				<a-select v-model:value="formData.loadTimeId" placeholder="请选择装卸时间"
+						  :options="loadTimeIdList" @change="onChangeLoadTime"
+				> </a-select>
+			</a-form-item>
+			<a-form-item label="可约次数:" name="availableNumber" v-show="numberFlag">
+				<a-input v-model:value="formData.availableNumber" placeholder="请输入可约次数" allow-clear disabled/>
+			</a-form-item>
+			<a-form-item label="已约次数:" name="alreadyNumber" v-show="numberFlag">
+				<a-input v-model:value="formData.alreadyNumber" placeholder="请输入已约次数" allow-clear disabled/>
+			</a-form-item>
+		</a-form>
+
+<!--		<s-table
+			ref="tableRef"
+			:columns="columns"
+			:data="loadData"
+			bordered
+			:row-key="(record) => record.id"
+		>
+			<template #bodyCell="{ column, record }">
+				<template v-if="column.dataIndex === 'action'">
+					<a-space>
+						<a-button type="link" size="small" v-if="hasPerm('bizOrderReplace')" @click="replaceRef.onOpen(record)">更换</a-button>
+					</a-space>
+					<a-space>
+						<a-button type="link" danger size="small" v-if="hasPerm('bizOrderDispatchDelete')" @click="deleteConfig(record)">删除</a-button>
+					</a-space>
+				</template>
+			</template>
+		</s-table>-->
+
+		<template #footer>
+			<a-button style="margin-right: 8px" @click="onClose">关闭</a-button>
+			<a-button type="primary" @click="onSubmit" :loading="submitLoading">保存</a-button>
+		</template>
+
+		<Replace ref="replaceRef" @successful="tableRef.refresh(true)" />
+	</xn-form-container>
+</template>
+
+<script setup name="bizOrderForm">
+	import { cloneDeep } from 'lodash-es'
+	import { required } from '@/utils/formRules'
+	import bizOrderApi from '@/api/biz/bizOrderApi'
+	import tool from '@/utils/tool'
+	import bizGoodsApi from '@/api/biz/bizGoodsApi'
+	import customerApi from '@/api/biz/customerApi'
+	import goodsConfApi from '@/api/biz/goodsConfApi'
+	import bizSaleOrderApi from "@/api/biz/bizSaleOrderApi";
+	import bizSupplierApi from "@/api/biz/bizSupplierApi";
+	import bizLoadPointApi from "@/api/biz/bizLoadPointApi";
+	import bizLoadTimeApi from "@/api/biz/bizLoadTimeApi"
+	import bizOrderLoadApi from "@/api/biz/bizOrderLoadApi";
+	import bizLoadUserApi from "@/api/biz/bizLoadUserApi";
+	import {ExclamationCircleOutlined} from '@ant-design/icons-vue';
+	import {Modal} from 'ant-design-vue';
+	import {createVNode} from 'vue';
+	import Review from "@/views/biz/bizorder/review.vue";
+	import Replace from './replace.vue'
+
+	// 抽屉状态
+	const open = ref(false)
+	const emit = defineEmits({ successful: null })
+	const formRef = ref()
+	const tableRef = ref()
+	const replaceRef = ref()
+
+	const numberFlag = ref(false)
+	// 表单数据
+	const formData = ref({})
+	const submitLoading = ref(false)
+
+	//设置表单样式
+	const labelCol = ref({ span: 5})
+	const wrapperCol = ref({ span: 16})
+
+	//订单类型
+	const orderTypeList = tool.dictList('order_type')
+	const goodIdList = ref()
+	const customerIdList = ref()
+	const saleOrderInfoList = ref()
+	const deliveryTimeIdList = ref()
+	const supplierIdList = ref()
+	const loadPointIdList = ref()
+	const loadTimeIdList = ref()
+
+	// 打开抽屉
+	const onOpen = (record) => {
+		open.value = true
+		if (record) {
+			let recordData = cloneDeep(record)
+			formData.value = Object.assign({}, recordData)
+		}
+		//查询客户信息
+		customerApi.getList().then((res)=>{
+			customerIdList.value = res.map((item)=>{
+				return{
+					value:item.id,
+					label:item.name
+				}
+			})
+		})
+
+		//装货点位查询
+		bizLoadPointApi.getList().then((res)=>{
+			loadPointIdList.value = res.map((item)=>{
+				return{
+					value:item.id,
+					label:item.loadPoint
+				}
+			})
+		})
+
+		if(formData.value.saleOrderInfo){
+			bizSaleOrderApi.detailById({id:formData.value.saleOrderInfo}).then((res)=>{
+				//根据货品名称和重量查询提货时间段
+				goodsConfApi.getList({goodsName:res.saleGoodsName,goodsCode:res.goodsCode,needWeight:res.saleOrderWeight}).then((res)=>{
+					deliveryTimeIdList.value = res.map((item)=>{
+						return{
+							value:item.id,
+							label:item.confStartTime+'~'+item.confEndTime
+						}
+					})
+				})
+			})
+		}
+
+
+	}
+
+	//卸货点位点击事件
+	const onChangePoint =(value)=>{
+		formData.value.loadTimeId = ''
+		loadTimeIdList.value = ''
+		formData.value.availableNumber = ''
+		formData.value.alreadyNumber = ''
+		bizLoadTimeApi.search({pointId:formData.value.loadPointId,goodsConfId:formData.value.deliveryTimeId,orderId:formData.value.id,orderFlag:'1'}).then((res)=>{
+			loadTimeIdList.value = res.map((item)=>{
+				return{
+					value:item.id,
+					label:item.beginTime+'~'+item.endTime
+				}
+			})
+		})
+	}
+
+	const onChangeLoadTime = (value) => {
+		bizLoadTimeApi.bizLoadTimeDetail({id:value}).then((res)=>{
+			formData.value.availableNumber = res.availableNumber
+			formData.value.alreadyNumber = res.alreadyNumber
+			numberFlag.value = true
+		})
+	}
+
+	const loadData = (parameter) => {
+		return bizOrderLoadApi.bizOrderLoadPage({orderId:formData.value.id}).then((data) => {
+			return data
+		})
+	}
+
+	const columns = [
+		{
+			title: '装卸点位',
+			dataIndex: 'loadPoint',
+			align:'center'
+		},
+		{
+			title: '开始时间',
+			dataIndex: 'beginTime',
+			align:'center'
+		},
+		{
+			title: '结束时间',
+			dataIndex: 'endTime',
+			align:'center'
+		},
+		{
+			title: '可约次数',
+			dataIndex: 'availableNumber',
+			align:'center'
+		},
+		{
+			title: '已约次数',
+			dataIndex: 'alreadyNumber',
+			align:'center'
+		},
+	]
+	// 操作栏通过权限判断是否显示
+	columns.push({
+		title: '操作',
+		dataIndex: 'action',
+		align: 'center',
+		width: 150
+	})
+
+
+
+
+	// 关闭抽屉
+	const onClose = () => {
+		formRef.value.resetFields()
+		formData.value = {}
+		open.value = false
+		loadTimeIdList.value = ''
+		numberFlag.value = false
+		emit('successful')
+
+	}
+	// 默认要校验的
+	const formRules = {
+		//orderNumber: [required('请输入订单编号')],
+		//orderName: [required('请输入订单名称')],
+		//customerId:[required('请选择客户信息')],
+		loadPointId:[required('请选择装卸点位')],
+		loadTimeId: [required('请选择装卸时间')],
+	}
+
+
+	// 删除
+	const deleteConfig = (record) => {
+
+		Modal.confirm({
+			title: '确定删除该数据吗?',
+			icon: createVNode(ExclamationCircleOutlined),
+			content: '',
+			onOk() {
+				submitLoading.value = true
+				let params = [
+					{
+						id: record.id
+					}
+				]
+
+				bizOrderLoadApi
+					.bizOrderLoadDelete(params)
+					.then(() => {
+						tableRef.value.refresh(true)
+					})
+					.finally(() => {
+						submitLoading.value = false
+					})
+			},
+			onCancel() {}
+		})
+	}
+
+	// 验证并提交数据
+	const onSubmit = () => {
+		formRef.value
+			.validate()
+			.then(() => {
+				submitLoading.value = true
+				const formDataParam = cloneDeep(formData.value)
+				formDataParam.orderId = formDataParam.id
+				formDataParam.id = ''
+				bizOrderLoadApi
+					.bizOrderLoadSubmitForm(formDataParam, formDataParam.id)
+					.then(() => {
+						onClose()
+					})
+					.finally(() => {
+						submitLoading.value = false
+					})
+			})
+			.catch(() => {})
+	}
+	// 抛出函数
+	defineExpose({
+		onOpen
+	})
+</script>
+
+<style>
+/* 修改禁用状态下的颜色 */
+.ant-radio-button-wrapper-disabled {
+	color: black !important; /* 设置文字颜色 */
+	background-color: #f0f0f0 !important; /* 设置背景颜色 */
+}
+
+/* 修改禁用状态下选中项的颜色 */
+.ant-radio-button-wrapper-checked.ant-radio-button-wrapper-disabled {
+	color: white !important; /* 设置文字颜色 */
+	background-color: blue !important; /* 设置选中项的背景颜色 */
+}
+</style>

+ 58 - 4
snowy-admin-web/src/views/biz/bizorder/index.vue

@@ -193,9 +193,21 @@
 									<a style="color:forestgreen" @click="showMore(record)">配置</a>
 								</a-menu-item>
 
-								<a-menu-item v-if="hasPerm('bizOrderEnd') && (record.orderStatus == '3' || record.orderStatus == '4')">
+								<a-menu-item v-if="hasPerm('bizOrderEnd') && (record.orderStatus == '3' || record.orderStatus == '4' || record.orderStatus == '11')">
 									<a style="color:red" @click="endRef.showModal(record.id)">结束</a>
 								</a-menu-item>
+
+								<a-menu-item v-if="hasPerm('bizOrderEndConfirm') && record.orderStatus == '10'">
+									<a style="color:orange" @click="endSignRef.show(record.id)">手签确认</a>
+								</a-menu-item>
+
+								<a-menu-item v-if="hasPerm('bizOrderEndReject') && record.orderStatus == '10'">
+									<a style="color:orangered" @click="rejectRef.showModal(record.id)">驳回</a>
+								</a-menu-item>
+
+								<a-menu-item v-if="hasPerm('bizOrderSendConfirm') && record.orderStatus == '11'">
+									<a style="color:deepskyblue" @click="sendConfirm(record.id)">发货确认</a>
+								</a-menu-item>
 							</a-menu>
 						</template>
 					</a-dropdown>
@@ -210,13 +222,15 @@
 		</s-table>
 	</a-card>
 	<Form ref="formRef" @successful="tableRef.refresh()" />
-	<Dispatch ref="dispatchRef" @successful="tableRef.refresh()" />
+	<dispatch ref="dispatchRef"  @successful="tableRef.refresh(true)" />
 
 	<Detail ref="detailRef" @successful="tableRef.refresh()" />
 	<Flow ref="flowRef" @successful="tableRef.refresh()" />
 	<Review ref="reviewRef" @successful="tableRef.refresh(true)" />
 	<End ref="endRef" @successful="tableRef.refresh(true)" />
+	<Reject ref="rejectRef" @successful="tableRef.refresh(true)" />
 	<XnSignName ref="XnSignNameRef" @successful="signSuccess" />
+	<XnSignName ref="endSignRef" @successful="endSignSuccess" />
 
 
 	<a-modal v-model:visible="open" title="二维码" width="600px" style="height: 700px">
@@ -284,7 +298,7 @@
 				<template #icon><plus-outlined /></template>
 				新增
 			</a-button>-->
-			<a-table ref="tableRef" :columns="columns1" :data-source="data1" bordered :row-key="(record) => record.id">
+			<a-table ref="tableRef" :columns="columns1" :data-source="data1" bordered :row-key="(record) => record.id" :pagination="false">
 				<template #bodyCell="{ column, record }">
 					<template v-if="column.dataIndex === 'action'">
 						<a @click="editAccount(record)"   v-if="hasPerm('BizApplyNumber')">编辑</a>
@@ -343,7 +357,8 @@
 	import bizOrderConfigApi from "@/api/biz/bizOrderConfigApi";
 	import { required } from '@/utils/formRules'
 	import End from './end.vue'
-	import Dispatch from './dispatch.vue'
+	import dispatch from './dispatch.vue'
+	import Reject from './reject.vue'
 
 	const editAccountFlag = ref(false)
 	const moreFlag = ref(false)
@@ -357,8 +372,10 @@
 	const dispatchRef = ref()
 	const reviewRef = ref()
 	const endRef = ref()
+	const rejectRef = ref()
 	const detailRef = ref()
 	const XnSignNameRef = ref()
+	const endSignRef = ref()
 	const submitLoading = ref(false)
 	const toolConfig = { refresh: true, height: true, columnSetting: true, striped: false }
 
@@ -524,6 +541,32 @@
 		})
 	}
 
+	//发货确认sendConfirm
+	const sendConfirm = (id) =>{
+		Modal.confirm({
+			title: '提示',
+			icon: createVNode(ExclamationCircleOutlined),
+			content: '确定发货确认吗?',
+			onOk() {
+				submitLoading.value = true
+				let params =
+					{
+						id: id
+					}
+
+				bizOrderApi
+					.sendConfirm(params)
+					.then(() => {
+						tableRef.value.refresh(true)
+					})
+					.finally(() => {
+						submitLoading.value = false
+					})
+			},
+			onCancel() {}
+		})
+	}
+
 	//提交
 	const submit = (id) =>{
 		Modal.confirm({
@@ -762,6 +805,17 @@
 		})
 	}
 
+	//订单结束客户确认
+	const endSignSuccess = (value) =>{
+		const param = {
+			id:value.id,
+			endSign: value.value
+		}
+		bizOrderApi.endOrderSign(param).then(() => {
+			tableRef.value.refresh(true)
+		})
+	}
+
 	//结束订单
 	const endOrder = (record) => {
 		/*let param = {

+ 64 - 0
snowy-admin-web/src/views/biz/bizorder/reject.vue

@@ -0,0 +1,64 @@
+<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="endRemark"
+            >
+                <a-textarea v-model:value="formData.endRemark" placeholder="请输入驳回说明"
+                            :auto-size="{ minRows: 3, maxRows: 5 }"/>
+            </a-form-item>
+        </a-form>
+        <template #footer>
+            <a-spin :spinning="submitLoading">
+                <a-button type="primary" @click="onsubmit(true)">驳回</a-button>
+            </a-spin>
+        </template>
+    </a-modal>
+</template>
+<script setup>
+import {message} from 'ant-design-vue';
+import bizOrderApi from '@/api/biz/bizOrderApi'
+
+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 === true) {
+        if (!formData.value.endRemark) {
+            message.error('驳回时,说明信息不能为空')
+            return
+        }
+    }
+    submitLoading.value = true
+	formData.value.auditFlag = flag
+	bizOrderApi.rejectOrder(formData.value).then(() => {
+        onClose()
+        emit('successful', null)
+    }).finally(() => {
+        submitLoading.value = false
+    })
+}
+// 抛出函数
+defineExpose({
+    showModal
+})
+</script>
+<style scoped>
+
+</style>

+ 2 - 2
snowy-admin-web/src/views/biz/bizsendrecord/index.vue

@@ -266,11 +266,11 @@
 			dataIndex: 'driver',
 			width: '150px'
 		},
-		{
+		/*{
 			title: '供应商',
 			dataIndex: 'supplierName',
 			width: '150px'
-		}
+		}*/
 	]
 	// 操作栏通过权限判断是否显示
 	columns.push({

+ 195 - 0
snowy-admin-web/src/views/biz/bizsignrecord/detail.vue

@@ -0,0 +1,195 @@
+<template>
+	<xn-form-container
+		:title="'详情'"
+		:width="1200"
+		v-model:open="open"
+		:destroy-on-close="true"
+		@close="onClose"
+	>
+		<a-descriptions>
+			<a-descriptions-item span="3" label="车次编码">{{ formData.carNumber }}</a-descriptions-item>
+			<a-descriptions-item label="车牌号码">{{ formData.licensePlate }}</a-descriptions-item>
+			<a-descriptions-item span="2" label="车牌颜色">{{ formData.plateColor }}</a-descriptions-item>
+<!--			<a-descriptions-item label="发货单位">{{ formData.shippingCompany }}</a-descriptions-item>
+			<a-descriptions-item label="收货单位">{{ formData.receiptCompany }}</a-descriptions-item>
+			<a-descriptions-item label="运输单位">{{ formData.transportCompany }}</a-descriptions-item>-->
+			<!-- <a-descriptions-item label="运输路线">{{ formData.transportRoute }}</a-descriptions-item> -->
+			<a-descriptions-item label="货品名称">{{ formData.goodsName }}</a-descriptions-item>
+			<a-descriptions-item label="货品编码">{{ formData.goodsModel }}</a-descriptions-item>
+			<a-descriptions-item label="司机姓名">{{ formData.driverName }}</a-descriptions-item>
+			<a-descriptions-item label="订单名称">{{ formData.orderName }}</a-descriptions-item>
+			<a-descriptions-item label="订单编号">{{ formData.orderNumber }}</a-descriptions-item>
+			<a-descriptions-item label="客户名称">{{ formData.customerName }}</a-descriptions-item>
+			<a-descriptions-item label="司机电话">{{ formData.driverMobile }}</a-descriptions-item>
+			<a-descriptions-item label="供应商名称">{{ formData.supplierName }}</a-descriptions-item>
+<!--			<a-descriptions-item label="过磅人">{{ formData.extKey1 }}</a-descriptions-item>
+			<a-descriptions-item label="打印时间">{{ formData.extKey2 }}</a-descriptions-item>-->
+		</a-descriptions>
+		<a-divider></a-divider>
+		<a-descriptions>
+			<a-descriptions-item label="毛重"
+				><a-tag color="blue">{{ formData.grossWeight }} 吨</a-tag></a-descriptions-item
+			>
+			<a-descriptions-item label="皮重"
+				><a-tag color="orange">{{ formData.tareWeight }} 吨</a-tag></a-descriptions-item
+			>
+			<a-descriptions-item label="净重"
+				><a-tag color="green">{{ formData.netWeight }} 吨</a-tag></a-descriptions-item
+			>
+		</a-descriptions>
+		<a-divider></a-divider>
+		<a-descriptions title="过毛">
+			<a-descriptions-item label="过磅时间">{{ formData.grossTime }}</a-descriptions-item>
+		</a-descriptions>
+		<a-space>
+			<a-image :width="200" :src="formData.grossPlateName" />
+			<a-image :width="200" :src="formData.grossLicenseName" />
+		</a-space>
+		<a-space style="margin-top: 15px; margin-left: 10px">
+			<a-image v-if="formData.grossCaptureHead != null" :width="200" :src="formData.grossCaptureHead" />
+			<a-image v-if="formData.grossCaptureTail != null" :width="200" :src="formData.grossCaptureTail" />
+			<a-image v-if="formData.grossCaptureBody != null" :width="200" :src="formData.grossCaptureBody" />
+		</a-space>
+		<a-space style="margin-top: 15px; margin-left: 10px">
+			<a-image v-if="formData.grossCaptureWare != null" :width="200" :src="formData.grossCaptureWare" />
+			<a-image v-if="formData.grossCapturePoundRoom != null" :width="200" :src="formData.grossCapturePoundRoom" />
+		</a-space>
+		<a-divider></a-divider>
+		<a-descriptions title="过皮" style="margin-top: 15px">
+			<a-descriptions-item label="过磅时间">{{ formData.tareTime }}</a-descriptions-item>
+		</a-descriptions>
+		<a-space>
+			<a-image :width="200" :src="formData.tarePlateName" />
+			<a-image :width="200" :src="formData.tareLicenseName" />
+		</a-space>
+		<a-space style="margin-top: 15px; margin-left: 10px">
+			<a-image v-if="formData.tareCaptureHead != null" :width="200" :src="formData.tareCaptureHead" />
+			<a-image v-if="formData.tareCaptureTail != null" :width="200" :src="formData.tareCaptureTail" />
+			<a-image v-if="formData.tareCaptureBody != null" :width="200" :src="formData.tareCaptureBody" />
+		</a-space>
+		<a-space style="margin-top: 15px; margin-left: 10px">
+			<a-image v-if="formData.tareCaptureWare != null" :width="200" :src="formData.tareCaptureWare" />
+			<a-image v-if="formData.tareCapturePoundRoom != null" :width="200" :src="formData.tareCapturePoundRoom" />
+		</a-space>
+		<a-divider></a-divider>
+		<a-descriptions title="司机确认" style="margin-top: 15px">
+		</a-descriptions>
+		<a-space>
+			<a-image :width="200" :src="formData.driverSign" />
+		</a-space>
+		<a-divider></a-divider>
+		<a-descriptions title="司机回签" style="margin-top: 15px">
+			<a-descriptions-item label="卸货重量"><a-tag color="green">{{ formData.unloadWeight }} 吨</a-tag></a-descriptions-item>
+		</a-descriptions>
+		<a-space>
+			<div v-for="(item,index) in fileList " :key="item.value">
+				<a-image :width="200" :src="item.url" />
+			</div>
+
+		</a-space>
+		<a-divider></a-divider>
+		<a-descriptions title="签收审核" style="margin-top: 15px">
+		</a-descriptions>
+		<a-space>
+			<a-image :width="200" :src="formData.auditSign" />
+		</a-space>
+		<template #footer>
+			<a-button style="margin-right: 8px" @click="onClose">关闭</a-button>
+		</template>
+	</xn-form-container>
+</template>
+
+<script setup name="bizRecordForm">
+	import tool from '@/utils/tool'
+	import { cloneDeep } from 'lodash-es'
+	import bizRecordApi from '@/api/biz/bizRecordApi'
+	import sysConfig from "@/config";
+
+	// 抽屉状态
+	const open = ref(false)
+	const emit = defineEmits({ successful: null })
+	// const formRef = ref()
+	// 表单数据
+	const formData = ref({})
+	// const submitLoading = ref(false)
+	const tareTypeOptions = ref([])
+
+	const fileList = ref([])
+	// 打开抽屉
+	const onOpen = (record) => {
+		open.value = true
+		tareTypeOptions.value = tool.dictList('TARE_TYPE')
+		if (record) {
+			/*const param = {
+				id: record.id
+			}
+			bizRecordApi.bizRecordDetail(param).then((data) => {
+				formData.value = Object.assign({}, data)
+			})*/
+			let recordData = cloneDeep(record)
+			formData.value = Object.assign({}, recordData)
+			fileList.value = []
+			if(formData.value.unloadImg!=null){
+				for (var i=0;i<formData.value.unloadImg.split(',').length;i++){
+					fileList.value.push({
+						name: formData.value.unloadName.split(',')[i],
+						url:sysConfig.PREVIEW_PATH + formData.value.unloadImg.split(',')[i]
+					})
+				}
+			}
+			if(formData.value.grossPlateName.includes("http://218.2.6.74:8065")){
+				console.log("str:"+formData.value.grossPlateName.indexOf("preview/"))
+				formData.value.grossPlateName = formData.value.grossPlateName.replace("http://218.2.6.74:8065/preview/",sysConfig.PREVIEW_PATH)
+			}
+			if(formData.value.grossLicenseName.includes("http://218.2.6.74:8065")){
+				formData.value.grossLicenseName = formData.value.grossLicenseName.replace("http://218.2.6.74:8065/preview/",sysConfig.PREVIEW_PATH)
+			}
+			if(formData.value.grossCaptureHead.includes("http://218.2.6.74:8065")){
+				formData.value.grossCaptureHead = formData.value.grossCaptureHead.replace("http://218.2.6.74:8065/preview/",sysConfig.PREVIEW_PATH)
+			}
+			if(formData.value.grossCaptureTail.includes("http://218.2.6.74:8065")){
+				formData.value.grossCaptureTail = formData.value.grossCaptureTail.replace("http://218.2.6.74:8065/preview/",sysConfig.PREVIEW_PATH)
+			}
+			if(formData.value.grossCaptureBody.includes("http://218.2.6.74:8065")){
+				formData.value.grossCaptureBody = formData.value.grossCaptureBody.replace("http://218.2.6.74:8065/preview/",sysConfig.PREVIEW_PATH)
+			}
+			if(formData.value.grossCaptureWare.includes("http://218.2.6.74:8065")){
+				formData.value.grossCaptureWare = formData.value.grossCaptureWare.replace("http://218.2.6.74:8065/preview/",sysConfig.PREVIEW_PATH)
+			}
+			if(formData.value.grossCapturePoundRoom.includes("http://218.2.6.74:8065")){
+				formData.value.grossCapturePoundRoom = formData.value.grossCapturePoundRoom.replace("http://218.2.6.74:8065/preview/",sysConfig.PREVIEW_PATH)
+			}
+			if(formData.value.tarePlateName.includes("http://218.2.6.74:8065")){
+				formData.value.tarePlateName = formData.value.tarePlateName.replace("http://218.2.6.74:8065/preview/",sysConfig.PREVIEW_PATH)
+			}
+			if(formData.value.tareLicenseName.includes("http://218.2.6.74:8065")){
+				formData.value.tareLicenseName = formData.value.tareLicenseName.replace("http://218.2.6.74:8065/preview/",sysConfig.PREVIEW_PATH)
+			}
+			if(formData.value.tareCaptureHead.includes("http://218.2.6.74:8065")){
+				formData.value.tareCaptureHead = formData.value.tareCaptureHead.replace("http://218.2.6.74:8065/preview/",sysConfig.PREVIEW_PATH)
+			}
+			if(formData.value.tareCaptureTail.includes("http://218.2.6.74:8065")){
+				formData.value.tareCaptureTail = formData.value.tareCaptureTail.replace("http://218.2.6.74:8065/preview/",sysConfig.PREVIEW_PATH)
+			}
+			if(formData.value.tareCaptureBody.includes("http://218.2.6.74:8065")){
+				formData.value.tareCaptureBody = formData.value.tareCaptureBody.replace("http://218.2.6.74:8065/preview/",sysConfig.PREVIEW_PATH)
+			}
+			if(formData.value.tareCaptureWare.includes("http://218.2.6.74:8065")){
+				formData.value.tareCaptureWare = formData.value.tareCaptureWare.replace("http://218.2.6.74:8065/preview/",sysConfig.PREVIEW_PATH)
+			}
+			if(formData.value.tareCapturePoundRoom.includes("http://218.2.6.74:8065")){
+				formData.value.tareCapturePoundRoom = formData.value.tareCapturePoundRoom.replace("http://218.2.6.74:8065/preview/",sysConfig.PREVIEW_PATH)
+			}
+		}
+	}
+	// 关闭抽屉
+	const onClose = () => {
+		// formRef.value.resetFields()
+		formData.value = {}
+		open.value = false
+	}
+	// 抛出函数
+	defineExpose({
+		onOpen
+	})
+</script>

+ 158 - 0
snowy-admin-web/src/views/biz/bizsignrecord/form.vue

@@ -0,0 +1,158 @@
+<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="unloadWeight">
+				<a-input-number v-model:value="formData.unloadWeight" style="width:90%"  :precision="2" :min="1" :max="999999"  placeholder="请输入卸货重量" allow-clear /><span style="margin-left:10px;">吨</span>
+			</a-form-item>
+<!--			<a-form-item label="单据图片:" name="licensePlate">
+				<a-input v-model:value="formData.licensePlate" placeholder="请输入车牌号码" allow-clear />
+			</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>
+		<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 bizRecordApi from '@/api/biz/bizRecordApi'
+	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.unloadImg!=null){
+				for (var i=0;i<formData.value.unloadImg.split(',').length;i++){
+					fileList.value.push({
+						name: formData.value.unloadName.split(',')[i],
+						url:sysConfig.PREVIEW_PATH + formData.value.unloadImg.split(',')[i]
+					})
+					formData.value.filePathList.push(formData.value.unloadImg.split(",")[i])
+					formData.value.fileNameList.push(formData.value.unloadName.split(",")[i])
+				}
+			}
+		}
+	}
+	// 关闭抽屉
+	const onClose = () => {
+		formRef.value.resetFields()
+		formData.value = {}
+		formData.value.fileNameList = []
+		formData.value.filePathList = []
+		fileList.value = []
+		open.value = false
+	}
+	// 默认要校验的
+	const formRules = {
+		unloadWeight: [required('请输入卸货重量')],
+	}
+	// 验证并提交数据
+	const onSubmit = () => {
+		formRef.value
+			.validate()
+			.then(() => {
+				submitLoading.value = true
+				const formDataParam = cloneDeep(formData.value)
+				console.log("formData:"+formDataParam.filePahList)
+				bizRecordApi
+					.updateWeight(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>

+ 535 - 0
snowy-admin-web/src/views/biz/bizsignrecord/index.vue

@@ -0,0 +1,535 @@
+<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="carNumber">
+						<a-input v-model:value="searchFormState.carNumber" placeholder="请输入车次编码" />
+					</a-form-item>
+				</a-col>
+				<a-col :span="6">
+					<a-form-item label="车牌号码" name="licensePlate">
+						<a-input v-model:value="searchFormState.licensePlate" placeholder="请输入车牌号码" />
+					</a-form-item>
+				</a-col>
+				<a-col :span="6">
+					<a-form-item label="过毛时间" name="grossTime">
+						<a-range-picker
+							v-model:value="searchFormState.grossTime"
+							value-format="YYYY-MM-DD"
+						/>
+					</a-form-item>
+				</a-col>
+				<a-col :span="6" v-show="advanced">
+					<a-form-item label="过皮时间" name="tareTime">
+						<a-range-picker
+							v-model:value="searchFormState.tareTime"
+							value-format="YYYY-MM-DD"
+						/>
+					</a-form-item>
+				</a-col>
+				<a-col :span="6" v-show="advanced">
+					<a-form-item label="司机姓名" name="driverName">
+						<a-input v-model:value="searchFormState.driverName" placeholder="请输入司机姓名" />
+					</a-form-item>
+				</a-col>
+				<a-col :span="6" v-show="advanced">
+					<a-form-item label="司机电话" name="driverMobile">
+						<a-input v-model:value="searchFormState.driverMobile" placeholder="请输入司机电话" />
+					</a-form-item>
+				</a-col>
+				<a-col :span="6" v-show="advanced">
+					<a-form-item label="货品名称" name="goodsName">
+						<a-input v-model:value="searchFormState.goodsName" placeholder="请输入货品名称" />
+					</a-form-item>
+				</a-col>
+				<a-col :span="6" v-show="advanced">
+					<a-form-item label="规格型号" name="goodsModel">
+						<a-input v-model:value="searchFormState.goodsModel" placeholder="请输入规格型号" />
+					</a-form-item>
+				</a-col>
+<!--				<a-col :span="6" v-show="advanced">
+					<a-form-item label="收货单位" name="receiptCompany">
+						<a-input v-model:value="searchFormState.receiptCompany" placeholder="请输入收货单位" />
+					</a-form-item>
+				</a-col>
+				<a-col :span="6" v-show="advanced">
+					<a-form-item label="发货单位" name="shippingCompany">
+						<a-input v-model:value="searchFormState.shippingCompany" placeholder="请输入发货单位" />
+					</a-form-item>
+				</a-col>
+				<a-col :span="6" v-show="advanced">
+					<a-form-item label="运输单位" name="transportCompany">
+						<a-input v-model:value="searchFormState.transportCompany" placeholder="请输入运输单位" />
+					</a-form-item>
+				</a-col>-->
+				<a-col :span="6" v-show="advanced">
+					<a-form-item label="订单编号" name="orderNumber">
+						<a-input v-model:value="searchFormState.orderNumber" placeholder="请输入订单编号" />
+					</a-form-item>
+				</a-col>
+<!--				<a-col :span="6" v-show="advanced">
+					<a-form-item label="订单名称" name="orderName">
+						<a-input v-model:value="searchFormState.orderName" placeholder="请输入订单名称" />
+					</a-form-item>
+				</a-col>-->
+				<a-col :span="6" v-show="advanced">
+					<a-form-item label="客户名称" name="customerName">
+						<a-input v-model:value="searchFormState.customerName" placeholder="请输入客户名称" />
+					</a-form-item>
+				</a-col>
+				<a-col :span="6" v-show="advanced">
+					<a-form-item label="供应商名称" name="supplierName">
+						<a-input v-model:value="searchFormState.supplierName" placeholder="请输入供应商名称" />
+					</a-form-item>
+				</a-col>
+				<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="dashed" class="snowy-buttom-left" @click="exportData()" v-if="hasPerm('bizRecordBatchExport')"
+						><export-outlined />记录导出</a-button
+					>-->
+				</a-space>
+			</template>
+			<template #bodyCell="{ column, record }">
+				<template v-if="column.dataIndex === 'licensePlate'">
+					<span v-if="record.plateColor === '蓝色'" class="blue-background">{{ record.licensePlate }}</span>
+					<span v-else-if="record.plateColor === '黄色'" class="yellow-background">{{ record.licensePlate }}</span>
+					<span v-else-if="record.plateColor === '绿色'" class="green-background">{{ record.licensePlate }}</span>
+					<span v-else-if="record.plateColor === '白色'" class="white-background">{{ record.licensePlate }}</span>
+					<span v-else-if="record.plateColor === '黑色'" class="black-background">{{ record.licensePlate }}</span>
+					<span v-else class="blue-background">{{ record.licensePlate }}</span>
+				</template>
+
+				<template v-if="column.dataIndex === 'enterTime'">
+					<div class="time-list">
+						<p>
+							<span class="blueTag">过毛</span>
+							<span style="font-weight: normal">{{ record.grossTime }}</span>
+						</p>
+						<p style="margin-bottom: 0">
+							<span class="orangeTag">过皮</span>
+							<span style="font-weight: normal">{{ record.tareTime }}</span>
+						</p>
+					</div>
+				</template>
+
+				<template v-if="column.dataIndex === 'weight'">
+					<div class="time-list">
+						<p>
+							<span class="blueTag">毛重</span>
+							<span class="showNum">{{ record.grossWeight }} </span>
+						</p>
+						<p>
+							<span class="orangeTag">皮重</span>
+							<span class="showNum">{{ record.tareWeight }}</span>
+						</p>
+						<p>
+							<span class="greenTag">净重</span>
+							<span class="showNum">{{ record.netWeight }}</span>
+						</p>
+					</div>
+				</template>
+
+				<template v-if="column.dataIndex === 'company'">
+					<div class="company-list">
+						<p>收货:{{ record.receiptCompany }}</p>
+						<p>发货:{{ record.shippingCompany }}</p>
+						<p style="margin-bottom: 0">运输:{{ record.transportCompany }}</p>
+					</div>
+				</template>
+
+				<template v-if="column.dataIndex === 'goods'">
+					<div class="time-list">
+						<p>名称:{{ record.goodsName }}</p>
+						<p style="margin-bottom: 0">编码:{{ record.goodsModel }}</p>
+					</div>
+				</template>
+
+				<template v-if="column.dataIndex === 'driver'">
+					<div class="time-list">
+						<p>姓名:{{ record.driverName }}</p>
+						<p style="margin-bottom: 0">电话:{{ record.driverMobile }}</p>
+					</div>
+				</template>
+				<template v-if="column.dataIndex === 'orderInfo'">
+					<div class="time-list">
+						<p>名称:{{ record.orderName }}</p>
+						<p style="margin-bottom: 0">编号:{{ record.orderNumber }}</p>
+					</div>
+				</template>
+				<template v-if="column.dataIndex === 'action'">
+					<a-space>
+						<a @click="detailRef.onOpen(record)">详情</a>
+<!--						<a-divider type="vertical"  v-if="hasPerm('bizRecordSign') && record.status=='10' " />
+						<a  @click="formRef.onOpen(record)" v-if="hasPerm('bizRecordSign') && record.status=='10' ">签收</a>-->
+						<a-divider type="vertical"  v-if="hasPerm('bizRecordAudit') && record.status=='12' " />
+						<a  @click="XnSignNameRef.show(record.id)" v-if="hasPerm('bizRecordAudit') && record.status=='12' ">审核</a>
+					</a-space>
+				</template>
+			</template>
+		</s-table>
+	</a-card>
+	<Form ref="formRef" @successful="tableRef.refresh()" />
+	<Review ref="reviewRef" @successful="tableRef.refresh(true)" />
+	<Detail ref="detailRef" />
+	<XnSignName ref="XnSignNameRef" :image="searchFormState.driverSign" @successful="signSuccess" />
+</template>
+
+<script setup name="record">
+	import { message, Modal } from 'ant-design-vue'
+	import { cloneDeep } from 'lodash-es'
+	import Form from './form.vue'
+	import Detail from './detail.vue'
+	import bizRecordApi from '@/api/biz/bizRecordApi'
+	import downloadUtil from '@/utils/downloadUtil'
+	import {createVNode} from "vue";
+	import {ExclamationCircleOutlined} from "@ant-design/icons-vue";
+	import bizAppointmentRecordApi from "@/api/biz/bizAppointmentRecordApi";
+	import Review from './review.vue'
+
+	const reviewRef = ref()
+	const searchFormState = ref({signFlag:1})
+	const searchFormRef = ref()
+	const tableRef = ref()
+	const formRef = ref()
+	const detailRef = ref()
+	const XnSignNameRef = ref()
+	const toolConfig = { refresh: true, height: true, columnSetting: true, striped: false }
+	// 查询区域显示更多控制
+	const advanced = ref(false)
+
+	const submitLoading = ref(false)
+
+	const toggleAdvanced = () => {
+		advanced.value = !advanced.value
+	}
+	const columns = [
+		{
+			title: '车次编码',
+			dataIndex: 'carNumber',
+			width: 120,
+			align: 'center'
+		},
+		{
+			title: '车牌号码',
+			dataIndex: 'licensePlate',
+			width: '130px',
+			align: 'center'
+		},
+		{
+			title: '过车时间',
+			dataIndex: 'enterTime',
+			width: '130px'
+		},
+		{
+			title: '重量(吨)',
+			dataIndex: 'weight',
+			align: 'center'
+		},
+		/*{
+			title: '订单信息',
+			dataIndex: 'orderInfo'
+		},*/
+		{
+			title: '订单编号',
+			dataIndex: 'orderNumber',
+			align:'center'
+		},
+		{
+			title: '客户名称',
+			dataIndex: 'customerName',
+			align:'center'
+		},
+		{
+			title: '货品',
+			dataIndex: 'goods'
+		},
+		{
+			title: '司机信息',
+			dataIndex: 'driver',
+			width: '150px'
+		},
+		/*{
+			title: '供应商',
+			dataIndex: 'supplierName',
+			width: '150px'
+		}*/
+	]
+	// 操作栏通过权限判断是否显示
+	columns.push({
+		title: '操作',
+		dataIndex: 'action',
+		align: 'center',
+		width: 150
+	})
+
+
+	const loadData = (parameter) => {
+		const searchFormParam = cloneDeep(searchFormState.value)
+		// grossTime范围查询条件重载
+		if (searchFormParam.grossTime) {
+			searchFormParam.startGrossTime = searchFormParam.grossTime[0]
+			searchFormParam.endGrossTime = searchFormParam.grossTime[1]
+			delete searchFormParam.grossTime
+		}
+		// tareTime范围查询条件重载
+		if (searchFormParam.tareTime) {
+			searchFormParam.startTareTime = searchFormParam.tareTime[0]
+			searchFormParam.endTareTime = searchFormParam.tareTime[1]
+			delete searchFormParam.tareTime
+		}
+		return bizRecordApi.bizRecordPage(Object.assign(parameter, searchFormParam)).then((data) => {
+			return data
+		})
+	}
+	const dateRangeOnChange = (date, dateString) => {
+		searchFormState.startGrossTime = dateString[0]
+		searchFormState.endGrossTime = dateString[1]
+	}
+	const dateRangeOnChangeTare = (date, dateString) => {
+		searchFormState.startTareTime = dateString[0]
+		searchFormState.endTareTime = dateString[1]
+	}
+	// 重置
+	const reset = () => {
+		searchFormRef.value.resetFields()
+		searchFormState.startGrossTime = null
+		searchFormState.endGrossTime = null
+		searchFormState.startTareTime = null
+		searchFormState.endTareTime = null
+		tableRef.value.refresh(true)
+	}
+	const exportData = () => {
+		const paramData = {
+			licensePlate: searchFormState.value.licensePlate,
+			carNumber: searchFormState.value.carNumber,
+			goodsName: searchFormState.value.goodsName,
+			goodsModel: searchFormState.value.goodsModel,
+			receiptCompany: searchFormState.value.receiptCompany,
+			shippingCompany: searchFormState.value.shippingCompany,
+			transportCompany: searchFormState.value.transportCompany,
+			driverName: searchFormState.value.driverName,
+			driverMobile: searchFormState.value.driverMobile,
+			startGrossTime: searchFormState.startGrossTime,
+			endGrossTime: searchFormState.endGrossTime,
+			startTareTime: searchFormState.startTareTime,
+			endTareTime: searchFormState.endTareTime
+		}
+		Modal.confirm({
+			title: '提示',
+			content: '确定要导出过磅记录?',
+			maskClosable: true,
+			onOk: () => {
+				bizRecordApi.bizRecordExport(paramData).then((res) => {
+					downloadUtil.resultDownload(res)
+					tableRef.value.clearSelected()
+				})
+			}
+		})
+	}
+
+	//确认
+	const confirmRecord = (record) => {
+
+		Modal.confirm({
+			title: '提示',
+			content: '确定完成发货吗?',
+			onOk() {
+				submitLoading.value = true
+				let params =
+					{
+						id: record.id
+					}
+
+
+				bizRecordApi
+					.confirmRecord(params)
+					.then(() => {
+						tableRef.value.refresh(true)
+					})
+					.finally(() => {
+						submitLoading.value = false
+					})
+			},
+			onCancel() {}
+		})
+	}
+
+
+	// 签名板组件回调
+	const signSuccess = (value) => {
+		const param = {
+			id:value.id,
+			auditSign: value.value
+		}
+		bizRecordApi.auditRecord(param).then(() => {
+			tableRef.value.refresh(true)
+		})
+	}
+</script>
+
+<style lang="less" scoped>
+	/** 表头居中 */
+	:deep .ant-table-thead > tr > th {
+		text-align: center;
+	}
+
+	.time-list {
+		-webkit-text-size-adjust: none;
+		font-size: 13px;
+		display: flex;
+		flex-direction: column;
+
+		p {
+			white-space: nowrap;
+			span {
+				display: inline-block;
+				font-weight: 600;
+				height: 16px;
+				line-height: 16px;
+				border-radius: 5px;
+				text-align: center;
+				margin-right: 2px;
+				padding: 0 5px;
+			}
+			.blueTag {
+				color: #1890ff;
+				background: rgba(24, 144, 255, 0.1);
+			}
+			.orangeTag {
+				color: #ff7c18;
+				background: rgba(24, 144, 255, 0.1);
+			}
+			.greenTag {
+				color: rgb(82, 196, 26);
+				background: rgba(82, 196, 26, 0.1);
+			}
+			.purpleTag {
+				color: rgb(77, 26, 196);
+				background: rgba(82, 196, 26, 0.1);
+			}
+			.showNum {
+				display: inline-block;
+				height: 16px;
+				line-height: 16px;
+				width: 45px;
+				border-radius: 5px;
+				text-align: center;
+				margin-right: 2px;
+				text-align: right;
+			}
+		}
+	}
+
+	.order-list,
+	.company-list {
+		-webkit-text-size-adjust: none;
+		font-size: 13px;
+		display: flex;
+		flex-direction: column;
+		p {
+			white-space: nowrap;
+			margin-bottom: 5px;
+			.weightSpan,
+			.company {
+				display: inline-block;
+				width: 17px;
+				height: 17px;
+				line-height: 16px;
+				border-radius: 50%;
+				color: #fff;
+				text-align: center;
+			}
+			.company {
+				margin-right: 5px;
+			}
+			.weight,
+			.receiptCompany {
+				background-color: #1890ff;
+			}
+			.tare {
+				background-color: #2f54eb;
+			}
+			.netWeight,
+			.shippingCompany {
+				background-color: #52c41a;
+			}
+			.transportCompany {
+				background-color: #c61263;
+			}
+			.showNum {
+				display: inline-block;
+				height: 16px;
+				line-height: 16px;
+				width: 45px;
+				border-radius: 5px;
+				text-align: center;
+				margin-right: 2px;
+				text-align: right;
+			}
+			em {
+				font-style: normal;
+			}
+		}
+	}
+	.blue-background {
+		background-color: #0d84ff;
+		border-radius: 5px; /* 你可以根据需要调整圆角的大小 */
+		padding: 5px; /* 可选:添加一些内边距 */
+		color: white; /* 可选:设置文字颜色 */
+		font-size: large;
+	}
+	.yellow-background {
+		background-color: yellow;
+		border-radius: 5px;
+		padding: 5px;
+		color: black;
+		font-size: large;
+	}
+	.green-background {
+		background: linear-gradient(to bottom, white, #39b54a);
+		border-radius: 5px;
+		padding: 5px;
+		color: black; /* 文字颜色改为黑色以便在渐变背景上更清晰 */
+		font-size: large;
+		border: 1px solid #ccc; /* 增加边框 */
+		box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); /* 增加阴影 */
+	}
+
+	.white-background {
+		background-color: white;
+		border-radius: 5px;
+		padding: 5px;
+		color: black;
+		font-size: large;
+		border: 1px solid #ccc; /* 增加边框 */
+		box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); /* 增加阴影 */
+	}
+
+	.black-background {
+		background-color: black;
+		border-radius: 5px;
+		padding: 5px;
+		color: white;
+		font-size: large;
+	}
+</style>

+ 2 - 2
snowy-admin-web/src/views/biz/record/index.vue

@@ -262,11 +262,11 @@
 			dataIndex: 'driver',
 			width: '150px'
 		},
-		{
+		/*{
 			title: '供应商',
 			dataIndex: 'supplierName',
 			width: '150px'
-		}
+		}*/
 	]
 	// 操作栏通过权限判断是否显示
 	columns.push({

+ 43 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizappointmentrecord/controller/BizAppointmentRecordController.java

@@ -568,4 +568,47 @@ public class BizAppointmentRecordController {
     }
 
 
+    /**
+     * 地磅端司机确认
+     *
+     * @author fanzherong
+     * @date  2025/03/24 14:47
+     */
+    @Operation(summary = "地磅端司机确认")
+    @CommonLog("地磅端司机确认")
+    @PostMapping("/biz/bizappointmentrecord/localConfirm")
+    public CommonResult<String> localConfirm(@RequestBody @Valid BizAppointmentRecordEditParam bizAppointmentRecordEditParam) {
+        bizAppointmentRecordService.localConfirm(bizAppointmentRecordEditParam);
+        return CommonResult.ok();
+    }
+
+    /**
+     * 地磅端司机取消
+     *
+     * @author fanzherong
+     * @date  2025/03/24 14:47
+     */
+    @Operation(summary = "地磅端司机取消")
+    @CommonLog("地磅端司机取消")
+    @PostMapping("/biz/bizappointmentrecord/localCancel")
+    public CommonResult<String> localCancel(@RequestBody @Valid BizAppointmentRecordEditParam bizAppointmentRecordEditParam) {
+        bizAppointmentRecordService.localCancel(bizAppointmentRecordEditParam);
+        return CommonResult.ok();
+    }
+
+    /**
+     * 云端司机取消
+     *
+     * @author fanzherong
+     * @date  2025/03/24 14:47
+     */
+    @Operation(summary = "云端司机取消")
+    @CommonLog("云端司机取消")
+    @PostMapping("/biz/bizappointmentrecord/cloudCancel")
+    public CommonResult<String> cloudCancel(@RequestBody @Valid BizAppointmentRecordEditParam bizAppointmentRecordEditParam) {
+        bizAppointmentRecordService.cloudCancel(bizAppointmentRecordEditParam);
+        return CommonResult.ok();
+    }
+
+
 }

+ 15 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizappointmentrecord/service/BizAppointmentRecordService.java

@@ -209,4 +209,19 @@ public interface BizAppointmentRecordService extends IService<BizAppointmentReco
      */
     void bizChargeStationReservationExit(BizAppointmentRecordIdParam bizAppointmentRecordIdParam);
 
+    /**
+     * 地磅端确认
+     */
+    void localConfirm(BizAppointmentRecordEditParam bizAppointmentRecordEditParam);
+
+    /**
+     * 地磅端取消
+     */
+    void localCancel(BizAppointmentRecordEditParam bizAppointmentRecordEditParam);
+
+    /**
+     * 云端取消
+     */
+    void cloudCancel(BizAppointmentRecordEditParam bizAppointmentRecordEditParam);
+
 }

+ 46 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizappointmentrecord/service/impl/BizAppointmentRecordServiceImpl.java

@@ -20,6 +20,7 @@ import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.PhoneUtil;
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
@@ -1782,5 +1783,50 @@ public class BizAppointmentRecordServiceImpl extends ServiceImpl<BizAppointmentR
 
     }
 
+    @Override
+    public void localConfirm(BizAppointmentRecordEditParam bizAppointmentRecordEditParam) {
+        BizAppointmentRecord bizAppointmentRecord = this.queryEntity(bizAppointmentRecordEditParam.getId());
+        bizAppointmentRecord.setStatus("9");
+        this.updateById(bizAppointmentRecord);
+    }
+
+    @Override
+    public void localCancel(BizAppointmentRecordEditParam bizAppointmentRecordEditParam) {
+        BizAppointmentRecord bizAppointmentRecord = this.queryEntity(bizAppointmentRecordEditParam.getId());
+        bizAppointmentRecord.setStatus("6");
+        this.updateById(bizAppointmentRecord);
+
+        //查询过磅记录
+        BizRecord bizRecord = bizRecordService.getOne(new QueryWrapper<BizRecord>().lambda().
+                eq(BizRecord::getAppointmentId, bizAppointmentRecord.getId()).
+                last("limit 1"));
+        if(ObjectUtil.isNotNull(bizRecord)){
+            bizRecord.setConfirmUser(null);
+            LambdaUpdateWrapper<BizRecord> updateWrapper = new LambdaUpdateWrapper<>();
+            updateWrapper.eq(BizRecord::getId,bizRecord.getId()).set(BizRecord::getConfirmUser,null);
+            bizRecordService.update(updateWrapper);
+        }
+    }
+
+    @Override
+    public void cloudCancel(BizAppointmentRecordEditParam bizAppointmentRecordEditParam) {
+        BizAppointmentRecord bizAppointmentRecord = this.queryEntity(bizAppointmentRecordEditParam.getId());
+        //查询过磅记录
+        BizRecord bizRecord = bizRecordService.getOne(new QueryWrapper<BizRecord>().lambda().
+                eq(BizRecord::getAppointmentId, bizAppointmentRecord.getId()).
+                last("limit 1"));
+
+        if(ObjectUtil.isNotNull(bizRecord)){
+            //司机取消,下发mqtt
+            Map<String, Object> map = Maps.newHashMap();
+            map.put("id", bizRecord.getRelationId());
+            map.put("type", "21");
+            //mqtt发送过磅记录id给地磅端,告诉地磅端可打印磅单,抬道闸
+            mqttSubscribeClient.publishMessage(commonProperties.getMqttTopic(), JSONObject.toJSONString(map));
+            log.info("司机取消下发车牌号:" + bizRecord.getLicensePlate());
+        }
+
+    }
+
 
 }

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

@@ -78,4 +78,7 @@ public class BizConfig extends CommonEntity {
 
     /**结算金额*/
     private BigDecimal settleAccount;
+
+    /**装货点位共享开关*/
+    private String loadSwitch;
 }

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

@@ -79,4 +79,7 @@ public class BizConfigAddParam {
     /**结算金额*/
     private BigDecimal settleAccount;
 
+    /**装货点位共享开关*/
+    private String loadSwitch;
+
 }

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

@@ -84,4 +84,7 @@ public class BizConfigEditParam {
     /**结算金额*/
     private BigDecimal settleAccount;
 
+    /**装货点位共享开关*/
+    private String loadSwitch;
+
 }

+ 15 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizloadappoint/controller/BizLoadAppointController.java

@@ -201,4 +201,19 @@ public class BizLoadAppointController {
         bizLoadAppointService.fillLoad(bizLoadAppointEditParam);
         return CommonResult.ok();
     }
+
+
+    /**
+     * 修改扫码次数
+     *
+     * @author fanzherong
+     * @date  2025/06/25 14:51
+     */
+    @Operation(summary = "修改扫码次数")
+    @CommonLog("修改扫码次数")
+    @PostMapping("/biz/bizloadappoint/updateAppointNumber")
+    public CommonResult<String> updateAppointNumber(@RequestBody @Valid BizLoadAppointEditParam bizLoadAppointEditParam) {
+        bizLoadAppointService.updateAppointNumber(bizLoadAppointEditParam);
+        return CommonResult.ok();
+    }
 }

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

@@ -135,4 +135,16 @@ public class BizLoadAppoint extends CommonEntity {
 
     /**填报时间*/
     private Date fillTime;
+
+    /**起卸单价*/
+    private BigDecimal loadPrice;
+
+    /**陆运运费单价**/
+    private BigDecimal landFreightPrice;
+
+    /**可约次数**/
+    private Integer appointNumber;
+
+    /**已约次数*/
+    private Integer alreadyAppointNumber;
 }

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

@@ -27,7 +27,11 @@
             bla.create_time,
             bla.customer_sign,
             bla.sign_time,
-            ba.status arriveStatus
+            ba.status arriveStatus,
+            bla.load_price,
+            bla.land_freight_price,
+            bla.appoint_number,
+            bla.already_appoint_number
         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

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

@@ -75,4 +75,10 @@ public class BizLoadAppointAddParam {
     /**汽运供应商*/
     private List<String> supplierIdList;
 
+    /**起卸单价*/
+    private BigDecimal loadPrice;
+
+    /**陆运运费单价**/
+    private BigDecimal landFreightPrice;
+
 }

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

@@ -92,4 +92,12 @@ public class BizLoadAppointEditParam {
     /**填报时间*/
     private Date fillTime;
 
+
+    /**起卸单价*/
+    private BigDecimal loadPrice;
+
+    /**陆运运费单价**/
+    private BigDecimal landFreightPrice;
+
+    private Integer appointNumber;
 }

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

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

+ 5 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizloadappoint/service/BizLoadAppointService.java

@@ -110,4 +110,9 @@ public interface BizLoadAppointService extends IService<BizLoadAppoint> {
      * 填报起卸数量
      */
     void fillLoad(BizLoadAppointEditParam bizLoadAppointEditParam);
+
+    /**
+     * 修改预约次数
+     */
+    void updateAppointNumber(BizLoadAppointEditParam bizLoadAppointEditParam);
 }

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

@@ -26,14 +26,20 @@ import com.fhs.trans.service.impl.TransService;
 import jakarta.annotation.Resource;
 import jakarta.servlet.http.HttpServletResponse;
 import org.apache.commons.compress.utils.Lists;
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import vip.xiaonuo.auth.core.util.StpLoginUserUtil;
+import vip.xiaonuo.biz.modular.bizconfig.entity.BizConfig;
+import vip.xiaonuo.biz.modular.bizconfig.service.BizConfigService;
 import vip.xiaonuo.biz.modular.bizloadappoint.param.*;
 import vip.xiaonuo.biz.modular.bizloadappointsupplier.entity.BizLoadAppointSupplier;
 import vip.xiaonuo.biz.modular.bizloadappointsupplier.service.BizLoadAppointSupplierService;
 import vip.xiaonuo.biz.modular.bizorder.entity.BizOrder;
 import vip.xiaonuo.biz.modular.bizorder.param.BizOrderExportResult;
+import vip.xiaonuo.biz.modular.bizorderconfig.entity.BizOrderConfig;
+import vip.xiaonuo.biz.modular.bizservicecustomer.entity.BizServiceCustomerAccount;
+import vip.xiaonuo.biz.modular.bizservicecustomer.service.BizServiceCustomerAccountService;
 import vip.xiaonuo.biz.modular.bizsettle.entity.BizSettle;
 import vip.xiaonuo.biz.modular.utils.CommonExportUtil;
 import vip.xiaonuo.common.enums.CommonSortOrderEnum;
@@ -44,6 +50,7 @@ import vip.xiaonuo.biz.modular.bizloadappoint.mapper.BizLoadAppointMapper;
 import vip.xiaonuo.biz.modular.bizloadappoint.service.BizLoadAppointService;
 
 import java.math.BigDecimal;
+import java.math.RoundingMode;
 import java.text.SimpleDateFormat;
 import java.util.Arrays;
 import java.util.Date;
@@ -67,6 +74,12 @@ public class BizLoadAppointServiceImpl extends ServiceImpl<BizLoadAppointMapper,
     @Resource
     private TransService transService;
 
+    @Resource
+    private BizServiceCustomerAccountService bizServiceCustomerAccountService;
+
+    @Resource
+    private BizConfigService bizConfigService;
+
     @Override
     public Page<BizLoadAppoint> page(BizLoadAppointPageParam bizLoadAppointPageParam) {
         QueryWrapper<BizLoadAppoint> queryWrapper = getQueryWrapper(bizLoadAppointPageParam);
@@ -88,6 +101,10 @@ public class BizLoadAppointServiceImpl extends ServiceImpl<BizLoadAppointMapper,
         if(ObjectUtil.isNotEmpty(bizLoadAppointPageParam.getLoadNumber())){
             queryWrapper.like("bla.load_number",bizLoadAppointPageParam.getLoadNumber());
         }
+        //主键id
+        if(ObjectUtil.isNotEmpty(bizLoadAppointPageParam.getId())){
+            queryWrapper.eq("bla.id",bizLoadAppointPageParam.getId());
+        }
         //客户名称查询
         if(ObjectUtil.isNotEmpty(bizLoadAppointPageParam.getCustomerName())){
             queryWrapper.like("bsc.`name`",bizLoadAppointPageParam.getCustomerName());
@@ -123,12 +140,26 @@ public class BizLoadAppointServiceImpl extends ServiceImpl<BizLoadAppointMapper,
     @Transactional(rollbackFor = Exception.class)
     @Override
     public void add(BizLoadAppointAddParam bizLoadAppointAddParam) {
+        //校验
+        checkParam(bizLoadAppointAddParam);
         //新增起卸预约信息
         BizLoadAppoint bizLoadAppoint = BeanUtil.toBean(bizLoadAppointAddParam, BizLoadAppoint.class);
         bizLoadAppoint.setLoadNumber(getNumber());
         bizLoadAppoint.setOrderWeight(bizLoadAppoint.getOrderWeight().multiply(new BigDecimal(1000)));
         this.save(bizLoadAppoint);
 
+        if(StringUtils.equals(bizLoadAppointAddParam.getPayType(),"1")){
+            //查询客户帐号信息
+            BizServiceCustomerAccount customerAccount = bizServiceCustomerAccountService.getOne(new QueryWrapper<BizServiceCustomerAccount>().lambda().
+                    eq(BizServiceCustomerAccount::getServiceCustomerId, bizLoadAppointAddParam.getCustomerId()).
+                    last("limit 1"));
+            //订单起卸费(起卸单价*订单数量)
+            BigDecimal orderPrice = bizLoadAppointAddParam.getLoadPrice().multiply(bizLoadAppointAddParam.getOrderWeight());
+            customerAccount.setLockAmount(customerAccount.getLockAmount().add(orderPrice));
+            bizServiceCustomerAccountService.updateById(customerAccount);
+        }
+
+
         //新增起卸预约汽运供应商
         if(ObjectUtil.isNotEmpty(bizLoadAppointAddParam.getSupplierIdList())){
             for(String supplierId : bizLoadAppointAddParam.getSupplierIdList()){
@@ -140,10 +171,39 @@ public class BizLoadAppointServiceImpl extends ServiceImpl<BizLoadAppointMapper,
         }
     }
 
+    public void checkParam(BizLoadAppointAddParam bizLoadAppointAddParam){
+        lock.lock();
+        try{
+            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){
+                    throw new CommonException("客户账户可用余额不足!");
+                }
+                //订单起卸费(起卸单价*订单数量)
+                BigDecimal orderPrice = bizLoadAppointAddParam.getLoadPrice().multiply(bizLoadAppointAddParam.getOrderWeight());
+                if(amount.compareTo(orderPrice) <0){
+                    throw new CommonException("客户账户余额不足以支付起卸费用!");
+                }
+            }
+        }finally {
+            //释放锁
+            lock.unlock();
+        }
+    }
+
     @Transactional(rollbackFor = Exception.class)
     @Override
     public void edit(BizLoadAppointEditParam bizLoadAppointEditParam) {
         BizLoadAppoint bizLoadAppoint = this.queryEntity(bizLoadAppointEditParam.getId());
+        checkParam(bizLoadAppointEditParam,bizLoadAppoint);
         BeanUtil.copyProperties(bizLoadAppointEditParam, bizLoadAppoint);
         //吨转kg
         bizLoadAppoint.setOrderWeight(bizLoadAppointEditParam.getOrderWeight().multiply(new BigDecimal(1000)));
@@ -165,6 +225,56 @@ public class BizLoadAppointServiceImpl extends ServiceImpl<BizLoadAppointMapper,
         }
     }
 
+    public void checkParam(BizLoadAppointEditParam bizLoadAppointEditParam,BizLoadAppoint bizLoadAppoint){
+        if(!StringUtils.equals(bizLoadAppointEditParam.getCustomerId(),bizLoadAppoint.getCustomerId())){
+            lock.lock();
+            try{
+                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){
+                        throw new CommonException("客户账户可用余额不足!");
+                    }
+                    //订单起卸费(起卸单价*订单数量)
+                    BigDecimal orderPrice = bizLoadAppointEditParam.getLoadPrice().multiply(bizLoadAppointEditParam.getOrderWeight());
+                    if(amount.compareTo(orderPrice) < 0){
+                        throw new CommonException("客户账户余额不足以支付起卸费用!");
+                    }
+
+
+                    //查询旧客户信息
+                    //查询客户帐号信息
+                    BizServiceCustomerAccount oldCustomerAccount = bizServiceCustomerAccountService.getOne(new QueryWrapper<BizServiceCustomerAccount>().lambda().
+                            eq(BizServiceCustomerAccount::getServiceCustomerId, bizLoadAppoint.getCustomerId()).
+                            last("limit 1"));
+                    //订单起卸费(起卸单价*订单数量)
+                    BigDecimal olderPrice = bizLoadAppoint.getLoadPrice().divide(new BigDecimal(1000)).multiply(bizLoadAppoint.getOrderWeight());
+                    oldCustomerAccount.setLockAmount(oldCustomerAccount.getLockAmount().subtract(olderPrice));
+                    bizServiceCustomerAccountService.updateById(oldCustomerAccount);
+
+                    //查询新客户信息
+                    BizServiceCustomerAccount newCustomerAccount = bizServiceCustomerAccountService.getOne(new QueryWrapper<BizServiceCustomerAccount>().lambda().
+                            eq(BizServiceCustomerAccount::getServiceCustomerId, bizLoadAppointEditParam.getCustomerId()).
+                            last("limit 1"));
+                    //订单起卸费(起卸单价*订单数量)
+                    BigDecimal newPrice = bizLoadAppointEditParam.getLoadPrice().multiply(bizLoadAppointEditParam.getOrderWeight());
+                    newCustomerAccount.setLockAmount(newCustomerAccount.getLockAmount().add(newPrice));
+                    bizServiceCustomerAccountService.updateById(newCustomerAccount);
+                }
+            }finally {
+                //释放锁
+                lock.unlock();
+            }
+        }
+    }
+
     @Transactional(rollbackFor = Exception.class)
     @Override
     public void delete(List<BizLoadAppointIdParam> bizLoadAppointIdParamList) {
@@ -175,6 +285,18 @@ public class BizLoadAppointServiceImpl extends ServiceImpl<BizLoadAppointMapper,
                     eq(BizLoadAppointSupplier::getAppointId, bizLoadAppointIdParam.getId()));
             bizLoadAppointSupplierService.removeByIds(CollStreamUtil.toList(list,BizLoadAppointSupplier::getId));
 
+            BizLoadAppoint bizLoadAppoint = this.queryEntity(bizLoadAppointIdParam.getId());
+            BizServiceCustomerAccount oldCustomerAccount = bizServiceCustomerAccountService.getOne(new QueryWrapper<BizServiceCustomerAccount>().lambda().
+                    eq(BizServiceCustomerAccount::getServiceCustomerId, bizLoadAppoint.getCustomerId()).
+                    last("limit 1"));
+            if(ObjectUtil.isNotNull(oldCustomerAccount)){
+                //订单起卸费(起卸单价*订单数量)
+                BigDecimal olderPrice = bizLoadAppoint.getLoadPrice().divide(new BigDecimal(1000)).multiply(bizLoadAppoint.getOrderWeight());
+                oldCustomerAccount.setLockAmount(oldCustomerAccount.getLockAmount().subtract(olderPrice));
+                bizServiceCustomerAccountService.updateById(oldCustomerAccount);
+            }
+
+
             this.removeById(bizLoadAppointIdParam.getId());
         }
         //this.removeByIds(CollStreamUtil.toList(bizLoadAppointIdParamList, BizLoadAppointIdParam::getId));
@@ -203,6 +325,11 @@ public class BizLoadAppointServiceImpl extends ServiceImpl<BizLoadAppointMapper,
     public void submit(BizLoadAppointEditParam bizLoadAppointEditParam) {
         BizLoadAppoint bizLoadAppoint = this.queryEntity(bizLoadAppointEditParam.getId());
         bizLoadAppoint.setStatus("1");
+
+        //存取预约次数配置
+        BizConfig bizConfig = bizConfigService.getOne(new QueryWrapper<BizConfig>().lambda().last("limit 1"));
+        BigDecimal applyCount = bizLoadAppoint.getOrderWeight().divide(bizConfig.getLoadWeight(), RoundingMode.FLOOR);
+        bizLoadAppoint.setAppointNumber(applyCount.intValue());
         this.updateById(bizLoadAppoint);
     }
 
@@ -272,6 +399,16 @@ public class BizLoadAppointServiceImpl extends ServiceImpl<BizLoadAppointMapper,
         this.updateById(bizLoadAppoint);
     }
 
+    @Override
+    public void updateAppointNumber(BizLoadAppointEditParam bizLoadAppointEditParam) {
+        BizLoadAppoint bizLoadAppoint = this.queryEntity(bizLoadAppointEditParam.getId());
+        if(bizLoadAppointEditParam.getAppointNumber() <= bizLoadAppoint.getAlreadyAppointNumber()){
+            throw new CommonException("申请数量不能小于等于已约数量!");
+        }
+        bizLoadAppoint.setAppointNumber(bizLoadAppointEditParam.getAppointNumber());
+        this.updateById(bizLoadAppoint);
+    }
+
 
     public String getNumber(){
         lock.lock();

+ 14 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizloadarrive/controller/BizLoadArriveController.java

@@ -157,4 +157,18 @@ public class BizLoadArriveController {
         bizLoadArriveService.arriveConfirm(bizLoadArriveEditParam);
         return CommonResult.ok();
     }
+
+    /**
+     * 船主确认
+     *
+     * @author fanzherong
+     * @date  2025/06/26 14:12
+     */
+    @Operation(summary = "船主确认")
+    @CommonLog("船主确认")
+    @PostMapping("/biz/bizloadarrive/arriveSign")
+    public CommonResult<String> arriveSign(@RequestBody @Valid BizLoadArriveEditParam bizLoadArriveEditParam) {
+        bizLoadArriveService.arriveSign(bizLoadArriveEditParam);
+        return CommonResult.ok();
+    }
 }

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

@@ -66,6 +66,12 @@ public class BizLoadArrive extends CommonEntity {
     @Trans(type = TransType.DICTIONARY, key = "arrive_status")
     private String status;
 
+    /**船主签字*/
+    private String arriveSign;
+
+    /**签字时间**/
+    private Date signTime;
+
     /**客户名称*/
     @TableField(exist = false)
     private String customerName;

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

@@ -22,6 +22,8 @@
             bg.GOODS_NAME goodsName,
             bg.GOODS_CODE goodsCode,
             bla.status loadStatus,
+            blv.arrive_sign,
+            blv.sign_time,
             ifnull(bla.fill_weight/1000,0) fill_weight
         from biz_load_arrive blv
          left join biz_load_appoint bla on blv.appoint_id = bla.id

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

@@ -72,4 +72,7 @@ public class BizLoadArriveEditParam {
     /**审核备注*/
     private String arriveReason;
 
+    /**船主签字*/
+    private String arriveSign;
+
 }

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

@@ -94,4 +94,13 @@ public interface BizLoadArriveService extends IService<BizLoadArrive> {
      * 船主确认
      */
     void arriveConfirm(BizLoadArriveEditParam bizLoadArriveEditParam);
+
+
+    /**
+     * 船主签字
+     *
+     * @author fanzherong
+     * @date  2025/06/26 14:12
+     */
+    void arriveSign(BizLoadArriveEditParam bizLoadArriveEditParam);
 }

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

@@ -15,6 +15,7 @@ package vip.xiaonuo.biz.modular.bizloadarrive.service.impl;
 import cn.dev33.satoken.stp.StpUtil;
 import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.collection.CollStreamUtil;
+import cn.hutool.core.img.ImgUtil;
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
@@ -47,6 +48,7 @@ import vip.xiaonuo.biz.modular.bizloadarrive.mapper.BizLoadArriveMapper;
 import vip.xiaonuo.biz.modular.bizloadarrive.service.BizLoadArriveService;
 
 import java.math.BigDecimal;
+import java.util.Date;
 import java.util.List;
 
 /**
@@ -359,6 +361,31 @@ public class BizLoadArriveServiceImpl extends ServiceImpl<BizLoadArriveMapper, B
         bizLoadArrive.setStatus("4");
         this.updateById(bizLoadArrive);
 
+        //修改起卸订单状态
+        BizLoadAppoint loadAppoint = bizLoadAppointService.getById(bizLoadArrive.getAppointId());
+        loadAppoint.setStatus("9");
+        bizLoadAppointService.updateById(loadAppoint);
+    }
+
+    @Override
+    public void arriveSign(BizLoadArriveEditParam bizLoadArriveEditParam) {
+        BizLoadArrive bizLoadArrive = this.queryEntity(bizLoadArriveEditParam.getId());
+        if(ObjectUtil.isEmpty(bizLoadArriveEditParam.getArriveSign())){
+            throw new CommonException("签名不能为空!");
+        }
+        String driverSign = bizLoadArriveEditParam.getArriveSign();
+        if(bizLoadArriveEditParam.getArriveSign().contains(StrUtil.COMMA)) {
+            driverSign = StrUtil.split(driverSign, StrUtil.COMMA).get(1);
+        }
+        String base64 = ImgUtil.toBase64DataUri(ImgUtil.scale(ImgUtil.toImage(driverSign),
+                100, 50, null), ImgUtil.IMAGE_TYPE_PNG);
+
+        bizLoadArrive.setArriveSign(base64);
+        bizLoadArrive.setStatus("4");
+        bizLoadArrive.setSignTime(new Date());
+        this.updateById(bizLoadArrive);
+
+
         //修改起卸订单状态
         BizLoadAppoint loadAppoint = bizLoadAppointService.getById(bizLoadArrive.getAppointId());
         loadAppoint.setStatus("9");

+ 46 - 3
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizorder/controller/BizOrderController.java

@@ -202,19 +202,33 @@ public class BizOrderController {
 
 
     /**
-     * 订单签名
+     * 订单开始签名
      *
      * @author fanzherong
      * @date  2025/03/21 17:16
      */
-    @Operation(summary = "订单签名")
-    @CommonLog("订单签名")
+    @Operation(summary = "订单开始签名")
+    @CommonLog("订单开始签名")
     @PostMapping("/biz/bizorder/updateOrderSign")
     public CommonResult<String> updateOrderSign(@RequestBody @Valid BizOrderEditParam bizOrderEditParam) {
         bizOrderService.updateOrderSign(bizOrderEditParam);
         return CommonResult.ok();
     }
 
+    /**
+     * 订单结束签名
+     *
+     * @author fanzherong
+     * @date  2025/03/21 17:16
+     */
+    @Operation(summary = "订单结束签名")
+    @CommonLog("订单结束签名")
+    @PostMapping("/biz/bizorder/endOrderSign")
+    public CommonResult<String> endOrderSign(@RequestBody @Valid BizOrderEditParam bizOrderEditParam) {
+        bizOrderService.endOrderSign(bizOrderEditParam);
+        return CommonResult.ok();
+    }
+
     /**
      * 订单确认
      *
@@ -243,6 +257,35 @@ public class BizOrderController {
         return CommonResult.ok();
     }
 
+    /**
+     * 客户驳回
+     *
+     * @author fanzherong
+     * @date  2025/03/21 17:16
+     */
+    @Operation(summary = "客户驳回")
+    @CommonLog("客户驳回")
+    @PostMapping("/biz/bizorder/rejectOrder")
+    public CommonResult<String> rejectOrder(@RequestBody @Valid BizOrderEditParam bizOrderEditParam) {
+        bizOrderService.rejectOrder(bizOrderEditParam);
+        return CommonResult.ok();
+    }
+
+
+    /**
+     * 发货确认
+     *
+     * @author fanzherong
+     * @date  2025/03/21 17:16
+     */
+    @Operation(summary = "发货确认")
+    @CommonLog("发货确认")
+    @PostMapping("/biz/bizorder/sendConfirm")
+    public CommonResult<String> sendConfirm(@RequestBody @Valid BizOrderEditParam bizOrderEditParam) {
+        bizOrderService.sendConfirm(bizOrderEditParam);
+        return CommonResult.ok();
+    }
+
     /**
      * 订单审核
      *

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

@@ -169,4 +169,10 @@ public class BizOrder extends CommonEntity{
     @TableField(exist = false)
     private Integer applyNumber;
 
+    /**订单结束签名确认*/
+    private String endSign;
+
+    /**结束确认时间*/
+    private Date endSignTime;
+
 }

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

@@ -90,4 +90,7 @@ public class BizOrderAddParam {
     /**运费单价*/
     private BigDecimal freightPrice;
 
+    /**订单结束签名确认*/
+    private String endSign;
+
 }

+ 6 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizorder/param/BizOrderEditParam.java

@@ -106,4 +106,10 @@ public class BizOrderEditParam {
     /**运费单价*/
     private BigDecimal freightPrice;
 
+    /**订单结束签名确认*/
+    private String endSign;
+
+    /**结束说明*/
+    private String endRemark;
+
 }

+ 9 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizorder/service/BizOrderService.java

@@ -108,12 +108,21 @@ public interface BizOrderService extends IService<BizOrder> {
     /***订单签名*/
     void updateOrderSign(BizOrderEditParam bizOrderEditParam);
 
+    /***订单结束签名确认*/
+    void endOrderSign(BizOrderEditParam bizOrderEditParam);
+
     /**确认*/
     void orderConfirm(BizOrderEditParam bizOrderEditParam);
 
     /**结束订单*/
     void endOrder(BizOrderEditParam bizOrderEditParam);
 
+    /**驳回订单*/
+    void rejectOrder(BizOrderEditParam bizOrderEditParam);
+
+    /**发货确认*/
+    void sendConfirm(BizOrderEditParam bizOrderEditParam);
+
     /**审核**/
     void auditOrder(BizOrderEditParam bizOrderEditParam);
 

+ 57 - 4
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizorder/service/impl/BizOrderServiceImpl.java

@@ -43,6 +43,8 @@ import vip.xiaonuo.biz.modular.bizappointmentrecord.entity.BizAppointmentRecord;
 import vip.xiaonuo.biz.modular.bizappointmentrecord.mapper.BizAppointmentRecordMapper;
 import vip.xiaonuo.biz.modular.bizappointmentrecord.param.BizAppointmentExportResult;
 import vip.xiaonuo.biz.modular.bizappointmentrecord.service.BizAppointmentRecordService;
+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.bizorderconfig.entity.BizOrderConfig;
@@ -71,6 +73,7 @@ import java.math.BigDecimal;
 import java.math.RoundingMode;
 import java.net.URL;
 import java.net.URLConnection;
+import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -113,6 +116,9 @@ public class BizOrderServiceImpl extends ServiceImpl<BizOrderMapper, BizOrder> i
     @Resource
     private BizOrderSupplierService bizOrderSupplierService;
 
+    @Resource
+    private BizAuditLogService bizAuditLogService;
+
     @Resource(name = "loginUserApi")
     private SaBaseLoginUserApi loginUserApi;
 
@@ -458,6 +464,29 @@ public class BizOrderServiceImpl extends ServiceImpl<BizOrderMapper, BizOrder> i
         this.updateById(bizOrder);
     }
 
+    @Transactional
+    @Override
+    public void endOrderSign(BizOrderEditParam bizOrderEditParam) {
+        BizOrder bizOrder = this.queryEntity(bizOrderEditParam.getId());
+        if(ObjectUtil.isEmpty(bizOrderEditParam.getEndSign())){
+            throw new CommonException("签名不能为空!");
+        }
+        String endSign = bizOrderEditParam.getEndSign();
+        if(bizOrderEditParam.getEndSign().contains(StrUtil.COMMA)) {
+            endSign = StrUtil.split(endSign, StrUtil.COMMA).get(1);
+        }
+        String base64 = ImgUtil.toBase64DataUri(ImgUtil.scale(ImgUtil.toImage(endSign),
+                100, 50, null), ImgUtil.IMAGE_TYPE_PNG);
+
+        bizOrder.setEndSign(base64);
+        bizOrder.setOrderStatus("7");
+        bizOrder.setEndSignTime(new Date());
+        this.updateById(bizOrder);
+
+        //上传erp
+        sendOrderForErp(bizOrder);
+    }
+
     @Transactional
     @Override
     public void orderConfirm(BizOrderEditParam bizOrderEditParam) {
@@ -491,7 +520,7 @@ public class BizOrderServiceImpl extends ServiceImpl<BizOrderMapper, BizOrder> i
             BigDecimal result = orderBalance.divide(bizOrder.getOrderWeight(),2, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100));
             if(result.compareTo(new BigDecimal(20)) <= 0){
                 //大于80%不需要审核
-                bizOrder.setOrderStatus("7");
+                bizOrder.setOrderStatus("10");
 
                 //销售订单结束
                 BizSaleOrder bizSaleOrder = bizSaleOrderService.getById(bizOrder.getSaleOrderInfo());
@@ -501,7 +530,7 @@ public class BizOrderServiceImpl extends ServiceImpl<BizOrderMapper, BizOrder> i
                 }
 
                 //上传订单给erp
-                sendOrderForErp(bizOrder);
+                //sendOrderForErp(bizOrder);
             }else{
                 bizOrder.setOrderStatus("5");
             }
@@ -512,6 +541,29 @@ public class BizOrderServiceImpl extends ServiceImpl<BizOrderMapper, BizOrder> i
         this.updateById(bizOrder);
     }
 
+    @Override
+    public void rejectOrder(BizOrderEditParam bizOrderEditParam) {
+        BizOrder bizOrder = this.queryEntity(bizOrderEditParam.getId());
+        //设置客户驳回状态
+        bizOrder.setOrderStatus("11");
+        this.updateById(bizOrder);
+
+        //插入审核记录
+        BizAuditLog bizAuditLog = new BizAuditLog();
+        bizAuditLog.setType("WLDD");
+        bizAuditLog.setDataId(bizOrder.getId());
+        bizAuditLog.setStatus("2");
+        bizAuditLog.setRemark(bizOrderEditParam.getEndRemark());
+        bizAuditLogService.save(bizAuditLog);
+    }
+
+    @Override
+    public void sendConfirm(BizOrderEditParam bizOrderEditParam) {
+        BizOrder bizOrder = this.queryEntity(bizOrderEditParam.getId());
+        bizOrder.setOrderStatus("4");
+        this.updateById(bizOrder);
+    }
+
     public void sendOrderForErp(BizOrder bizOrder){
         String code = null;
         String msg = null;
@@ -599,6 +651,7 @@ public class BizOrderServiceImpl extends ServiceImpl<BizOrderMapper, BizOrder> i
         }
     }
 
+    @Transactional
     @Override
     public void auditOrder(BizOrderEditParam bizOrderEditParam) {
         BizOrder bizOrder = this.queryEntity(bizOrderEditParam.getId());
@@ -610,7 +663,7 @@ public class BizOrderServiceImpl extends ServiceImpl<BizOrderMapper, BizOrder> i
                 //bizOrder.setOrderStatus("4");
                 status = "4";
             }else{
-                status = "7";
+                status = "10";
                 //bizOrder.setOrderStatus("7");
 
                 //销售订单结束
@@ -621,7 +674,7 @@ public class BizOrderServiceImpl extends ServiceImpl<BizOrderMapper, BizOrder> i
                 }
 
                 //上传订单给erp
-                sendOrderForErp(bizOrder);
+                //sendOrderForErp(bizOrder);
             }
             updateWrapper.eq("id",bizOrder.getId()).
                     set("order_status",status).

+ 8 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/bizorderload/service/impl/BizOrderLoadServiceImpl.java

@@ -21,10 +21,12 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import jakarta.annotation.Resource;
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import vip.xiaonuo.biz.modular.bizappointmentrecord.entity.BizAppointmentRecord;
 import vip.xiaonuo.biz.modular.bizappointmentrecord.service.BizAppointmentRecordService;
+import vip.xiaonuo.biz.modular.bizloaddispatch.entity.BizLoadDispatch;
 import vip.xiaonuo.biz.modular.bizloadtime.entity.BizLoadTime;
 import vip.xiaonuo.biz.modular.bizloadtime.service.BizLoadTimeService;
 import vip.xiaonuo.biz.modular.bizorder.entity.BizOrder;
@@ -97,6 +99,12 @@ public class BizOrderLoadServiceImpl extends ServiceImpl<BizOrderLoadMapper, Biz
             throw new CommonException("装卸点位和时间已经添加过!");
         }
 
+        long count1 = this.count(new QueryWrapper<BizOrderLoad>().lambda().
+                eq(BizOrderLoad::getOrderId, bizOrderLoadAddParam.getOrderId()));
+        if(count1>0){
+            throw new CommonException("已添加过装卸调度!");
+        }
+
         //判断物流订单提货时段的总预约次数
        /* BizOrder bizOrder = bizOrderService.getById(bizOrderLoadAddParam.getOrderId());
         if(ObjectUtil.isNotNull(bizOrder)){

+ 1 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/mq/MqttSubscribeClient.java

@@ -42,6 +42,7 @@ public class MqttSubscribeClient implements CommandLineRunner {
                 client.connect(connOpts);
                 log.info("Connected");
                 // client.subscribe(ConstantContextHolder.getMqttTopic() + ConstantContextHolder.getSysItemCode(), 2);
+                client.subscribe(commonProperties.getMqttTopic(), 2);
                 client.setCallback(new MqttCallback() {
                     @Override
                     public void connectionLost(Throwable cause) {

+ 6 - 2
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/record/service/impl/BizRecordServiceImpl.java

@@ -190,8 +190,12 @@ public class BizRecordServiceImpl extends ServiceImpl<BizRecordMapper, BizRecord
             }
 
             if(StpLoginUserUtil.getLoginUser().getRoleCodeList().contains("send")){
-                //查询装卸地点
-                queryWrapper.eq("blu.user_id",StpLoginUserUtil.getLoginUser().getId());
+                //查询系统配置装货点位共享开关  1:开启   2:关闭
+                BizConfig bizConfig = bizConfigService.getOne(new QueryWrapper<BizConfig>().lambda().last("limit 1"));
+                if(StringUtils.equals(bizConfig.getLoadSwitch(),"2")){
+                    //查询装卸地点
+                    queryWrapper.eq("blu.user_id",StpLoginUserUtil.getLoginUser().getId());
+                }
             }
         }
         if (ObjectUtil.isNotEmpty(bizRecordPageParam.getOrderName())){

+ 3 - 0
snowy-web-app/src/main/java/vip/xiaonuo/core/config/GlobalConfigure.java

@@ -193,6 +193,9 @@ public class GlobalConfigure implements WebMvcConfigurer {
             "/biz/record/push",
             "/biz/record/edit",
             "/biz/record/mqttConfirm",
+            /*地磅端司机确认和取消*/
+            "/biz/bizappointmentrecord/localConfirm",
+            "/biz/bizappointmentrecord/localCancel",
 
             "/thirdPart/v1/**",