2026/03/13上线

This commit is contained in:
2026-03-13 00:18:57 +08:00
parent 42ce139dd1
commit 8298978a48
4 changed files with 409 additions and 43 deletions

View File

@@ -74,7 +74,10 @@ export const transportAPI = {
getAllGufeiItemCompany: (params) => get('/api/twopoint/zhxyGufeiItemCompany/getAll', params),
// 提交新增订单
createOrder: (data) => post('/api/twopoint/zhxyOrderCompany', data)
createOrder: (data) => post('/api/twopoint/zhxyOrderCompany', data),
// 编辑订单
updateOrder: (data) => put('/api/twopoint/zhxyOrderCompany', data)
}
// 车辆相关API

View File

@@ -48,6 +48,12 @@
<!-- <text class="phone-login-link" @click="switchToPhoneLogin">手机验证码登录</text> -->
</view>
<!-- 授权勾选 -->
<view class="auth-consent" @click="agreeAuth = !agreeAuth">
<checkbox class="auth-checkbox" :checked="agreeAuth" />
<text class="auth-text">登录即同意授权使用个人信息</text>
</view>
<!-- 登录按钮 -->
<button class="login-btn" @click="handleLogin" :disabled="isLoading">
{{ isLoading ? '登录中...' : '登录' }}
@@ -80,6 +86,9 @@ const loginForm = reactive({
password: ''
})
// 登录授权勾选
const agreeAuth = ref(false)
// 状态管理
const isLoading = ref(false)
const showToast = ref(false)
@@ -98,6 +107,10 @@ const forgotPassword = () => {
// 处理登录
const handleLogin = async () => {
if (!agreeAuth.value) {
showMessage('请勾选同意授权个人信息后再登录')
return
}
// 账号密码登录验证
if (!loginForm.username.trim()) {
showMessage('请输入用户名')
@@ -443,6 +456,26 @@ const handleLogin = async () => {
margin-bottom: 60rpx;
}
/* 授权勾选 */
.auth-consent {
display: flex;
align-items: center;
padding: 8rpx 4rpx;
margin-top: -28rpx;
margin-bottom: 28rpx;
}
.auth-checkbox {
transform: scale(0.85);
margin-right: 12rpx;
}
.auth-text {
font-size: 24rpx;
color: #64748B;
line-height: 1.4;
}
.forgot-password {
font-size: 28rpx;
color: #667eea;

View File

@@ -1,5 +1,5 @@
<template>
<view class="transport-page">
<view class="transport-page" :class="{ 'no-scroll': showFilterModal }">
<!-- 页面标题 -->
<view class="page-header">
<text class="page-title">运输管理</text>
@@ -21,7 +21,13 @@
</view>
<!-- 底部筛选弹窗全部使用原生 input / picker简化布局 -->
<view v-if="showFilterModal" class="filter-modal-overlay" @click="closeFilterModal">
<view
v-if="showFilterModal"
class="filter-modal-overlay"
@click="closeFilterModal"
@touchmove.stop.prevent
catchtouchmove="true"
>
<view class="filter-modal" @click.stop>
<view class="filter-modal-header">
<text class="filter-modal-title">筛选条件</text>
@@ -150,8 +156,14 @@
:value="searchForm.queryTime?.[0] || ''"
@change="handleStartDateChange"
>
<view class="filter-date">
{{ searchForm.queryTime?.[0] || '开始日期' }}
<view
class="filter-date"
:class="{ 'is-placeholder': !searchForm.queryTime?.[0] }"
>
<text class="filter-date-icon">📅</text>
<text class="filter-date-text">
{{ searchForm.queryTime?.[0] || '开始日期' }}
</text>
</view>
</picker>
<text class="date-separator"></text>
@@ -160,8 +172,14 @@
:value="searchForm.queryTime?.[1] || ''"
@change="handleEndDateChange"
>
<view class="filter-date">
{{ searchForm.queryTime?.[1] || '结束日期' }}
<view
class="filter-date"
:class="{ 'is-placeholder': !searchForm.queryTime?.[1] }"
>
<text class="filter-date-icon">📅</text>
<text class="filter-date-text">
{{ searchForm.queryTime?.[1] || '结束日期' }}
</text>
</view>
</picker>
</view>
@@ -259,10 +277,16 @@
</view>
</view>
<view class="card-actions">
<button
class="btn-action btn-edit"
@click.stop="handleEdit(item)"
>
编辑
</button>
<button
class="btn-action"
:class="item.gpsCount == '0' ? 'btn-danger' : ''"
@click="handleTrack(item)"
@click.stop="handleTrack(item)"
>
轨迹
</button>
@@ -302,8 +326,14 @@
:value="formData.carIndex"
@change="handleCarChange"
>
<view class="picker-view">
{{ carList[formData.carIndex]?.carNum || '请选择车牌号' }}
<view
class="picker-view"
:class="{ 'is-placeholder': !formData.carId }"
>
<text class="picker-label">
{{ formData.carId ? (carList[formData.carIndex]?.carNum || '') : '请选择车牌号' }}
</text>
<text class="picker-arrow"></text>
</view>
</picker>
</view>
@@ -316,8 +346,14 @@
:value="formData.orderTypeIndex"
@change="handleFormOrderTypeChange"
>
<view class="picker-view">
{{ orderTypeList[formData.orderTypeIndex]?.label || '请选择固废品类' }}
<view
class="picker-view"
:class="{ 'is-placeholder': !formData.orderTypeId }"
>
<text class="picker-label">
{{ formData.orderTypeId ? (orderTypeList[formData.orderTypeIndex]?.label || '') : '请选择固废品类' }}
</text>
<text class="picker-arrow"></text>
</view>
</picker>
</view>
@@ -365,6 +401,15 @@
<text class="summary-text">已选择 {{ formData.gufeiCode.length }} </text>
</view>
</view>
<view class="form-item">
<text class="form-label">备注</text>
<textarea
class="remark-textarea"
v-model="formData.remark"
placeholder="请输入备注信息(选填)"
auto-height
/>
</view>
<view class="form-item">
<text class="form-label required">司机</text>
<picker
@@ -374,8 +419,14 @@
:value="formData.driverIndex"
@change="handleDriverChange"
>
<view class="picker-view">
{{ driverList[formData.driverIndex]?.driverName || '请选择司机' }}
<view
class="picker-view"
:class="{ 'is-placeholder': !formData.driverId }"
>
<text class="picker-label">
{{ formData.driverId ? (driverList[formData.driverIndex]?.driverName || '') : '请选择司机' }}
</text>
<text class="picker-arrow"></text>
</view>
</picker>
</view>
@@ -517,9 +568,11 @@ export default {
const trackMapScale = ref(13)
const currentTrackPoint = ref(null)
// 新增订单相关状态
// 新增 / 编辑订单相关状态
const showAddOrderModal = ref(false)
const loadingFormData = ref(false)
const isEditMode = ref(false)
const currentOrderId = ref('')
const carList = ref([])
const driverList = ref([])
const gufeiTypeList = ref([])
@@ -534,7 +587,8 @@ export default {
orderTypeId: '',
gufeiType: [],
gufeiCode: [],
driverId: ''
driverId: '',
remark: ''
})
// 获取订单状态文本
@@ -836,12 +890,159 @@ export default {
}
// 编辑
const handleEdit = (item) => {
// TODO: 跳转到编辑页面
wx.showToast({
title: '编辑功能开发中',
icon: 'none'
})
const handleEdit = async (item) => {
if (!item || !item.id) {
wx.showToast({
title: '订单ID不存在无法编辑',
icon: 'none'
})
return
}
isEditMode.value = true
currentOrderId.value = item.id
showAddOrderModal.value = true
loadingFormData.value = true
// 基础重置
formData.carIndex = 0
formData.orderTypeIndex = 0
formData.driverIndex = 0
formData.carId = ''
formData.orderTypeId = ''
formData.driverId = ''
formData.gufeiType = []
formData.gufeiCode = []
formData.remark = item.remark || ''
gufeiCodeList.value = []
try {
const [carRes, driverRes, gufeiTypeRes, orderTypeRes] = await Promise.all([
transportAPI.getCompanyAllCar({ carStatus: '1' }).catch(err => {
console.error('获取车辆列表失败:', err)
return null
}),
transportAPI.getAllCompanyDriver().catch(err => {
console.error('获取司机列表失败:', err)
return null
}),
transportAPI.getAllGufeiCompany().catch(err => {
console.error('获取固废种类列表失败:', err)
return null
}),
transportAPI.getAllOrderTypeCompany().catch(err => {
console.error('获取固废品类列表失败:', err)
return null
})
])
// 车辆列表并匹配当前车牌
if (carRes && carRes.statusCode === 200 && carRes.data) {
const cars = carRes.data.data?.records || carRes.data.data || []
carList.value = cars.map(car => ({
carNum: car.carNum || '',
id: car.id || ''
}))
if (item.carId) {
const idx = carList.value.findIndex(car => String(car.id) === String(item.carId))
if (idx >= 0) {
formData.carIndex = idx
formData.carId = carList.value[idx].id
}
}
}
// 司机列表并匹配当前司机
if (driverRes && driverRes.statusCode === 200 && driverRes.data) {
const drivers = driverRes.data.data?.records || driverRes.data.data || []
driverList.value = drivers.map(driver => ({
driverName: driver.driverName || '',
id: driver.id || ''
}))
if (item.driverId) {
const idx = driverList.value.findIndex(driver => String(driver.id) === String(item.driverId))
if (idx >= 0) {
formData.driverIndex = idx
formData.driverId = driverList.value[idx].id
}
}
}
// 固废种类列表
if (gufeiTypeRes && gufeiTypeRes.statusCode === 200 && gufeiTypeRes.data) {
const types = gufeiTypeRes.data.data?.records || gufeiTypeRes.data.data || []
gufeiTypeList.value = types.map(type => ({
name: type.name || type.gufeiName || '',
id: type.id || ''
}))
}
// 固废品类列表并匹配当前品类
if (orderTypeRes && orderTypeRes.statusCode === 200 && orderTypeRes.data) {
if (orderTypeRes.data.code === 0 && Array.isArray(orderTypeRes.data.data)) {
const types = orderTypeRes.data.data.map(it => ({
label: it.orderTypeName || '',
value: it.id || ''
}))
if (orderTypeList.value.length <= 1) {
orderTypeList.value = [...orderTypeList.value, ...types]
}
if (item.orderTypeId) {
const idx = orderTypeList.value.findIndex(t => String(t.value) === String(item.orderTypeId))
if (idx >= 0) {
formData.orderTypeIndex = idx
formData.orderTypeId = orderTypeList.value[idx].value
}
}
}
}
// 处理固废种类、代码(接口可能返回逗号分隔)
if (item.gufeiType) {
if (Array.isArray(item.gufeiType)) {
formData.gufeiType = item.gufeiType.map(id => String(id))
} else if (typeof item.gufeiType === 'string') {
formData.gufeiType = item.gufeiType.split(',').filter(Boolean)
}
}
if (item.gufeiCode) {
if (Array.isArray(item.gufeiCode)) {
formData.gufeiCode = item.gufeiCode
} else if (typeof item.gufeiCode === 'string') {
formData.gufeiCode = item.gufeiCode.split(',').filter(Boolean)
}
}
// 根据当前固废种类重新拉取固废代码列表,确保选中状态正确
let gufeiIds = '17'
if (formData.gufeiType && formData.gufeiType.length > 0) {
const ids = formData.gufeiType.map(id => String(id))
if (!ids.includes('17')) ids.push('17')
gufeiIds = ids.join(',')
}
try {
const response = await transportAPI.getAllGufeiItemCompany({ gufeiIds })
if (response.statusCode === 200 && response.data) {
const codes = response.data.data?.records || response.data.data || []
gufeiCodeList.value = codes.map(code => ({
code: code.gufeiItemCode || '',
gufeiItemCode: code.gufeiItemCode || '',
id: code.id || ''
}))
}
} catch (error) {
console.error('获取固废代码列表失败:', error)
}
} catch (error) {
console.error('编辑订单时加载数据失败:', error)
wx.showToast({
title: '加载订单信息失败',
icon: 'none'
})
} finally {
loadingFormData.value = false
}
}
// 轨迹
@@ -948,12 +1149,14 @@ export default {
}, 300)
}
// 打开新增订单弹窗
// 打开新增订单弹窗(带上一次订单的大部分字段,清空车牌和司机)
const openAddOrderModal = async () => {
isEditMode.value = false
currentOrderId.value = ''
showAddOrderModal.value = true
loadingFormData.value = true
// 重置表单(仅重置索引和必填 ID上次订单会回填固废相关
// 基础重置
formData.carIndex = 0
formData.orderTypeIndex = 0
formData.driverIndex = 0
@@ -961,6 +1164,8 @@ export default {
formData.driverId = ''
formData.gufeiType = []
formData.gufeiCode = []
formData.orderTypeId = ''
formData.remark = ''
gufeiCodeList.value = []
try {
@@ -993,9 +1198,12 @@ export default {
if (lastOrderRes.data.code === 0 && lastOrderRes.data.data) {
const lastOrder = lastOrderRes.data.data
Object.assign(formData, lastOrder)
// 新增时不带上旧的主键和司机/车辆
formData.carId = ''
formData.driverId = ''
if (formData.id) delete formData.id
// 备注默认清空,让用户重新填写
formData.remark = ''
// 接口可能返回字符串 "id1,id2",转为数组供多选使用
if (typeof formData.gufeiType === 'string') {
formData.gufeiType = formData.gufeiType ? formData.gufeiType.split(',').filter(Boolean) : []
@@ -1008,26 +1216,22 @@ export default {
}
}
// 处理车辆列表
// 处理车辆列表(不默认选中,仅填充下拉选项)
if (carRes && carRes.statusCode === 200 && carRes.data) {
const cars = carRes.data.data?.records || carRes.data.data || []
carList.value = cars.map(car => ({
carNum: car.carNum || '',
id: car.id || ''
}))
// 当前展示的索引对应的车辆 ID 要同步到 formData否则提交校验会报「请选择车牌号」
formData.carId = carList.value[formData.carIndex]?.id || ''
}
// 处理司机列表
// 处理司机列表(不默认选中,仅填充下拉选项)
if (driverRes && driverRes.statusCode === 200 && driverRes.data) {
const drivers = driverRes.data.data?.records || driverRes.data.data || []
driverList.value = drivers.map(driver => ({
driverName: driver.driverName || '',
id: driver.id || ''
}))
// 当前展示的索引对应的司机 ID 要同步到 formData否则提交校验会报「请选择司机」
formData.driverId = driverList.value[formData.driverIndex]?.id || ''
}
// 处理固废种类列表
@@ -1049,8 +1253,11 @@ export default {
if (orderTypeList.value.length <= 1) {
orderTypeList.value = [...orderTypeList.value, ...types]
}
const idx = orderTypeList.value.findIndex(item => String(item.value) === String(formData.orderTypeId))
if (idx >= 0) formData.orderTypeIndex = idx
// 如果上次订单里带有 orderTypeId映射到下拉索引
if (formData.orderTypeId) {
const idx = orderTypeList.value.findIndex(item => String(item.value) === String(formData.orderTypeId))
if (idx >= 0) formData.orderTypeIndex = idx
}
}
}
@@ -1090,6 +1297,8 @@ export default {
// 关闭新增订单弹窗
const closeAddOrderModal = () => {
showAddOrderModal.value = false
isEditMode.value = false
currentOrderId.value = ''
}
// 处理车牌号选择
@@ -1190,7 +1399,7 @@ export default {
}
// 提交订单
// 提交订单(新增 / 编辑)
const handleSubmitOrder = async () => {
// 验证必填字段
if (!formData.carId) {
@@ -1235,15 +1444,23 @@ export default {
orderTypeId: formData.orderTypeId,
gufeiType: formData.gufeiType.join(','),
gufeiCode: formData.gufeiCode.join(','),
driverId: formData.driverId
driverId: formData.driverId,
remark: formData.remark || ''
}
const response = await transportAPI.createOrder(submitData)
// 编辑时带上主键ID
if (isEditMode.value && currentOrderId.value) {
submitData.id = currentOrderId.value
}
const response = isEditMode.value
? await transportAPI.updateOrder(submitData)
: await transportAPI.createOrder(submitData)
if (response.statusCode === 200 && response.data) {
if (response.data.code === 0) {
wx.showToast({
title: '新增订单成功',
title: isEditMode.value ? '编辑订单成功' : '新增订单成功',
icon: 'success'
})
closeAddOrderModal()
@@ -1367,6 +1584,15 @@ export default {
margin-top: 60rpx;
}
.transport-page.no-scroll {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
overflow: hidden;
}
.page-header {
background: #fff;
padding: 32rpx 30rpx;
@@ -1644,19 +1870,52 @@ export default {
.filter-date-row {
display: flex;
align-items: center;
gap: 12rpx;
}
.filter-date {
flex: 1;
height: 80rpx;
line-height: 80rpx;
text-align: center;
border-radius: 10rpx;
padding: 0 20rpx;
border-radius: 999rpx;
border: 1.5rpx solid #E2E8F0;
font-size: 28rpx;
background-color: #fff;
background: linear-gradient(135deg, #F9FAFB 0%, #EFF6FF 100%);
font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif;
letter-spacing: 0;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 2rpx 6rpx rgba(148, 163, 184, 0.25);
transition: all 0.18s ease;
}
.filter-date:active {
transform: translateY(1rpx) scale(0.99);
box-shadow: 0 1rpx 3rpx rgba(148, 163, 184, 0.2);
}
.filter-date-icon {
font-size: 30rpx;
margin-right: 10rpx;
opacity: 0.65;
}
.filter-date-text {
flex: 1;
text-align: center;
color: #0F172A;
font-weight: 500;
}
.filter-date.is-placeholder .filter-date-text {
color: #9CA3AF;
font-weight: 400;
}
.filter-date.is-placeholder {
background: #F8FAFC;
border-style: dashed;
}
.date-separator {
@@ -1974,6 +2233,17 @@ export default {
box-shadow: 0 1rpx 2rpx rgba(239, 68, 68, 0.2);
}
.btn-edit {
background: #F1F5F9;
color: #111827;
border: 1rpx solid #E5E7EB;
box-shadow: none;
}
.btn-edit:active {
background: #E5E7EB;
}
/* 加载更多 */
.load-more {
padding: 32rpx 20rpx;
@@ -2242,6 +2512,49 @@ export default {
margin-right: 4rpx;
}
/* 新增订单下拉框样式 */
.picker-view {
width: 100%;
height: 80rpx;
padding: 0 22rpx;
box-sizing: border-box;
border-radius: 12rpx;
border: 1.5rpx solid #E2E8F0;
background: #F9FAFB;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 28rpx;
color: #0F172A;
box-shadow: 0 2rpx 6rpx rgba(148, 163, 184, 0.18);
transition: all 0.18s ease;
}
.picker-view:active {
transform: translateY(1rpx) scale(0.99);
box-shadow: 0 1rpx 3rpx rgba(148, 163, 184, 0.2);
border-color: #2563EB;
}
.picker-view.is-placeholder {
background: #F8FAFC;
color: #9CA3AF;
border-style: dashed;
}
.picker-label {
flex: 1;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.picker-arrow {
margin-left: 12rpx;
font-size: 24rpx;
color: #94A3B8;
}
.add-order-form .form-actions {
display: flex;
gap: 24rpx;
@@ -2301,7 +2614,7 @@ export default {
border-radius: 12rpx;
padding: 20rpx 16rpx;
box-sizing: border-box;
height: 100rpx;
height: 80rpx;
cursor: pointer;
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
overflow: hidden;
@@ -2385,4 +2698,21 @@ export default {
color: #64748B;
font-weight: 500;
}
.remark-textarea {
width: 100%;
min-height: 120rpx;
padding: 16rpx 20rpx;
box-sizing: border-box;
border-radius: 12rpx;
border: 1.5rpx solid #E2E8F0;
background: #FFFFFF;
font-size: 28rpx;
color: #0F172A;
line-height: 1.5;
}
.remark-textarea::placeholder {
color: #9CA3AF;
}
</style>

View File

@@ -6,9 +6,9 @@ import { checkLoginAndRedirect, isLoggedIn, clearUserInfo, resetRedirectState }
// API基础配置
// 根据环境变量设置不同的API地址
const getBaseUrl = () => {
const getBaseUrl = () => {
// 生产环境使用正式地址
return 'https://green.cyweb.top' //'https://green.hrln.com.cn'
return 'https://green.hrln.com.cn'//'https://green.cyweb.top'
}
const API_CONFIG = {