基本完成v1.0
This commit is contained in:
@@ -70,7 +70,7 @@ export function jbqServerList(data) {
|
||||
data,
|
||||
});
|
||||
}
|
||||
// 预警记录
|
||||
// 预警记录列表
|
||||
export function warningLogList(data) {
|
||||
return request({
|
||||
url: '/warningLog/pageQuery',
|
||||
@@ -79,6 +79,15 @@ export function warningLogList(data) {
|
||||
});
|
||||
}
|
||||
|
||||
// 预警详情
|
||||
export function warningDetail(id) {
|
||||
return request({
|
||||
url: '/warningLog/warningDetail',
|
||||
method: 'POST',
|
||||
params: { id },
|
||||
});
|
||||
}
|
||||
|
||||
// 智能项圈 -列表
|
||||
export function collarList(data) {
|
||||
return request({
|
||||
|
||||
@@ -86,12 +86,9 @@ const handleChange = (editor) => {
|
||||
emits('update:html', valueHtml.value);
|
||||
};
|
||||
const handleFocus = (editor) => {
|
||||
// console.log('focus', editor);
|
||||
};
|
||||
// };
|
||||
const handleBlur = (editor) => {
|
||||
// console.log('blur', editor);
|
||||
// console.log(valueHtml.value);
|
||||
};
|
||||
// // };
|
||||
const customAlert = (info, type) => {
|
||||
// alert(`【自定义提示】${type} - ${info}`);
|
||||
};
|
||||
@@ -103,8 +100,7 @@ const customPaste = (editor, event, callback) => {
|
||||
};
|
||||
|
||||
const handleDestroyed = (editor) => {
|
||||
// console.log('destroyed', editor);
|
||||
};
|
||||
// };
|
||||
// 组件销毁时,也及时销毁编辑器
|
||||
onBeforeUnmount(() => {
|
||||
const editor = editorRef.value;
|
||||
|
||||
@@ -169,8 +169,7 @@ export default defineComponent({
|
||||
imgUploading.value = false;
|
||||
})
|
||||
.catch((err) => {
|
||||
// console.log(err);
|
||||
imgUploading.value = false;
|
||||
// imgUploading.value = false;
|
||||
});
|
||||
} else {
|
||||
alert(`文件过大,请选择不超过${(maxFileSizeType.value / 1024 / 1024).toFixed(2)}MB的文件`);
|
||||
@@ -189,9 +188,7 @@ export default defineComponent({
|
||||
if (acceptType.value == 'video/*') {
|
||||
dialogVisible.value = true;
|
||||
}
|
||||
// console.log(acceptType.value);
|
||||
// console.log(imgUrl.value);
|
||||
},
|
||||
// // },
|
||||
imgPreviewClose: () => {
|
||||
showImageViewer.value = false;
|
||||
},
|
||||
|
||||
@@ -38,9 +38,7 @@ const handlers = reactive({
|
||||
};
|
||||
});
|
||||
data.options = handleTree(list);
|
||||
// console.log('====================================');
|
||||
// console.log(data.options);
|
||||
});
|
||||
// // });
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -172,7 +172,7 @@ watch(
|
||||
() => props.emitSearch,
|
||||
(newVal, oldVal) => {
|
||||
if (newVal) {
|
||||
console.log('此时触发--立即执行搜索');
|
||||
|
||||
emit('search', formInline);
|
||||
}
|
||||
},
|
||||
@@ -205,7 +205,6 @@ const change = (e, param) => {
|
||||
emit('change', { e, param });
|
||||
};
|
||||
const onSubmit = () => {
|
||||
// console.log('submit!',formInline);
|
||||
emit('search', formInline);
|
||||
};
|
||||
|
||||
|
||||
@@ -167,7 +167,7 @@ const toggleSelection = (rows) => {
|
||||
}
|
||||
};
|
||||
const handleClick = (type, e) => {
|
||||
console.log(e);
|
||||
|
||||
if (type == 'select') {
|
||||
emit('select', e);
|
||||
} else if (type == 'pageSize') {
|
||||
|
||||
@@ -24,13 +24,13 @@
|
||||
</template>
|
||||
<template v-for="cItem in route.children">
|
||||
<template v-if="cItem.children && cItem.children.length > 0">
|
||||
<el-sub-menu :index="route.path + '/' + cItem.path">
|
||||
<el-sub-menu :index="joinPath(route.path, cItem.path)">
|
||||
<template #title>
|
||||
<!-- <svg-icon :icon-class="cItem.meta.icon" /> -->
|
||||
<span class="pl-3">{{ cItem.meta.title }}</span>
|
||||
</template>
|
||||
<template v-for="subItem in cItem.children">
|
||||
<el-menu-item :index="route.path + '/' + cItem.path + '/' + subItem.path">
|
||||
<el-menu-item :index="joinPath(joinPath(route.path, cItem.path), subItem.path)">
|
||||
<svg-icon :icon-class="subItem.meta.icon" />
|
||||
<span class="pl-3">{{ subItem.meta.title }}</span>
|
||||
</el-menu-item>
|
||||
@@ -38,7 +38,7 @@
|
||||
</el-sub-menu>
|
||||
</template>
|
||||
<template v-else>
|
||||
<el-menu-item :index="route.path + '/' + cItem.path">
|
||||
<el-menu-item :index="joinPath(route.path, cItem.path)">
|
||||
<svg-icon :icon-class="cItem.meta.icon" />
|
||||
<span class="pl-3">{{ cItem.meta.title }}</span>
|
||||
</el-menu-item>
|
||||
@@ -72,6 +72,21 @@ const data = reactive({
|
||||
const sidebarRouters = computed(() => permissionStore.sidebarRouters);
|
||||
const route = useRoute();
|
||||
|
||||
// 安全拼接路径,避免双斜杠
|
||||
const joinPath = (parentPath, childPath) => {
|
||||
if (!parentPath || !childPath) return parentPath || childPath || '/';
|
||||
|
||||
// 移除父路径末尾的斜杠
|
||||
parentPath = parentPath.replace(/\/+$/, '');
|
||||
// 移除子路径开头的斜杠
|
||||
childPath = childPath.replace(/^\/+/, '');
|
||||
|
||||
// 拼接并规范化
|
||||
const joined = `${parentPath}/${childPath}`;
|
||||
// 移除重复的斜杠
|
||||
return joined.replace(/\/+/g, '/');
|
||||
};
|
||||
|
||||
const currentMenu = ref('/');
|
||||
const isCollapse = ref(false);
|
||||
const userStore = JSON.parse(localStorage.getItem('userStore'));
|
||||
|
||||
@@ -12,7 +12,6 @@ import { useUserStore } from '~/store/user';
|
||||
|
||||
const userStore = useUserStore();
|
||||
// 打印useUserStore里 state的信息
|
||||
console.log(userStore.$state);
|
||||
|
||||
const updateUserName = () => {
|
||||
userStore.updateUserName('嗨!');
|
||||
|
||||
@@ -26,14 +26,6 @@ export default {
|
||||
// 检查是否是超级管理员 - 只检查用户store中的权限,避免权限数据不一致
|
||||
const isSuperAdmin = userStore.permissions.includes('*:*:*') || userStore.roles.includes('admin');
|
||||
|
||||
console.log('=== 权限检查调试 ===', {
|
||||
permissionStorePermissions: permissionStore.userPermission,
|
||||
userStorePermissions: userStore.permissions,
|
||||
finalPermissions: permissions,
|
||||
isSuperAdmin: isSuperAdmin,
|
||||
requiredPermissions: value
|
||||
});
|
||||
|
||||
if (value && value instanceof Array && value.length > 0) {
|
||||
const permissionFlag = value;
|
||||
|
||||
@@ -42,15 +34,8 @@ export default {
|
||||
return all_permission === permission || permissionFlag.includes(permission);
|
||||
});
|
||||
|
||||
console.log('=== 权限检查结果 ===', {
|
||||
hasPermissions: hasPermissions,
|
||||
isSuperAdmin: isSuperAdmin,
|
||||
shouldShow: hasPermissions || isSuperAdmin
|
||||
});
|
||||
|
||||
// 只有非超级管理员且没有相应权限时才隐藏元素
|
||||
if (!hasPermissions && !isSuperAdmin) {
|
||||
console.log('=== 隐藏元素 ===', permissionFlag);
|
||||
// 安全地隐藏元素,避免DOM操作错误
|
||||
try {
|
||||
// 检查元素是否还在DOM中
|
||||
|
||||
@@ -13,14 +13,6 @@ const whiteList = ['/login', '/register'];
|
||||
router.beforeEach((to, from, next) => {
|
||||
NProgress.start();
|
||||
|
||||
// 修复双斜杠路径问题
|
||||
if (to.path && to.path.includes('//')) {
|
||||
const fixedPath = to.path.replace(/\/+/g, '/');
|
||||
console.warn('检测到双斜杠路径,已修复:', to.path, '->', fixedPath);
|
||||
next({ path: fixedPath, query: to.query, hash: to.hash, replace: true });
|
||||
return;
|
||||
}
|
||||
|
||||
if (getToken()) {
|
||||
if (to.path === '/login') {
|
||||
usePermissionStore().setRoutes([]);
|
||||
@@ -41,6 +33,16 @@ router.beforeEach((to, from, next) => {
|
||||
usePermissionStore()
|
||||
.generateRoutes()
|
||||
.then((accessRoutes) => {
|
||||
// 递归修复所有路由(包括子路由)的双斜杠
|
||||
const fixRouteSlashes = (route) => {
|
||||
if (route.path && route.path.includes('//')) {
|
||||
route.path = route.path.replace(/\/+/g, '/');
|
||||
}
|
||||
if (route.children && Array.isArray(route.children)) {
|
||||
route.children.forEach(child => fixRouteSlashes(child));
|
||||
}
|
||||
};
|
||||
|
||||
// 根据roles权限生成可访问的路由表
|
||||
accessRoutes.forEach((route) => {
|
||||
// 验证路由路径
|
||||
@@ -49,11 +51,8 @@ router.beforeEach((to, from, next) => {
|
||||
return;
|
||||
}
|
||||
|
||||
// 修复双斜杠路径
|
||||
if (route.path && route.path.includes('//')) {
|
||||
console.warn('修复路由双斜杠路径:', route.path, '->', route.path.replace(/\/+/g, '/'));
|
||||
route.path = route.path.replace(/\/+/g, '/');
|
||||
}
|
||||
// 递归修复路由及其所有子路由的双斜杠
|
||||
fixRouteSlashes(route);
|
||||
|
||||
router.addRoute(route); // 动态添加可访问路由表
|
||||
});
|
||||
|
||||
@@ -27,11 +27,9 @@ const usePermissionStore = defineStore('permission', {
|
||||
},
|
||||
setUserPermission(arr) {
|
||||
this.userPermission = arr;
|
||||
console.log('=== 权限store更新 ===', arr);
|
||||
},
|
||||
// 强制刷新权限数据
|
||||
async refreshPermissions() {
|
||||
console.log('=== 强制刷新权限数据 ===');
|
||||
this.routeFlag = false; // 重置路由标志,强制重新生成路由
|
||||
return this.generateRoutes();
|
||||
},
|
||||
@@ -40,11 +38,9 @@ const usePermissionStore = defineStore('permission', {
|
||||
// 向后端请求路由数据
|
||||
getUserMenu().then((res) => {
|
||||
const { code, data } = res;
|
||||
console.log('=== 权限路由生成 ===', { code, data });
|
||||
|
||||
const btnList = data.filter((i) => i.type === 2);
|
||||
const permissionList = btnList.map((i) => i.authority).filter(auth => auth); // 过滤掉空权限
|
||||
console.log('=== 设置用户权限列表 ===', permissionList);
|
||||
this.setUserPermission(permissionList);
|
||||
|
||||
let menuList = data.filter((i) => i.type !== 2);
|
||||
@@ -52,8 +48,15 @@ const usePermissionStore = defineStore('permission', {
|
||||
// 确保 routeUrl 存在且不为空
|
||||
let routeUrl = item.routeUrl || item.pageUrl || '';
|
||||
|
||||
// 规范化路径
|
||||
routeUrl = normalizeRoutePath(routeUrl);
|
||||
// 对于顶级菜单(parentId === 0),添加前导斜杠
|
||||
// 对于子菜单,保持为相对路径(不带前导斜杠)
|
||||
if (item.parentId === 0 || item.parentId === '0') {
|
||||
// 顶级菜单:确保以 / 开头
|
||||
routeUrl = normalizeRoutePath(routeUrl);
|
||||
} else {
|
||||
// 子菜单:移除前导斜杠,使用相对路径
|
||||
routeUrl = routeUrl.replace(/^\/+/, '');
|
||||
}
|
||||
|
||||
return {
|
||||
id: item.id,
|
||||
@@ -75,22 +78,21 @@ const usePermissionStore = defineStore('permission', {
|
||||
JSON.parse(JSON.stringify(menuList));
|
||||
const sdata = JSON.parse(JSON.stringify(menuList));
|
||||
|
||||
console.log('=== 处理后的菜单列表 ===', menuList);
|
||||
console.log('=== 路径检查 ===', menuList.map(item => ({ name: item.name, path: item.path })));
|
||||
|
||||
// 检查并修复双斜杠路径
|
||||
const doubleSlashPaths = menuList.filter(item => item.path && item.path.includes('//'));
|
||||
if (doubleSlashPaths.length > 0) {
|
||||
console.error('=== 发现双斜杠路径 ===', doubleSlashPaths);
|
||||
// 修复双斜杠路径
|
||||
menuList.forEach(item => {
|
||||
// 递归修复所有路径中的双斜杠
|
||||
const fixDoubleSlashes = (items) => {
|
||||
if (!items || !Array.isArray(items)) return;
|
||||
items.forEach(item => {
|
||||
if (item.path && item.path.includes('//')) {
|
||||
const originalPath = item.path;
|
||||
item.path = item.path.replace(/\/+/g, '/');
|
||||
console.warn('修复菜单路径:', originalPath, '->', item.path);
|
||||
}
|
||||
if (item.children && item.children.length > 0) {
|
||||
fixDoubleSlashes(item.children);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
fixDoubleSlashes(menuList);
|
||||
fixDoubleSlashes(sdata);
|
||||
|
||||
// eslint-disable-next-line no-use-before-define
|
||||
const rewriteRoutes = filterAsyncRouter(menuList, false, true);
|
||||
@@ -99,12 +101,6 @@ const usePermissionStore = defineStore('permission', {
|
||||
// eslint-disable-next-line no-use-before-define
|
||||
const asyncRoutes = filterDynamicRoutes(dynamicRoutes);
|
||||
|
||||
console.log('=== 最终路由配置 ===', {
|
||||
rewriteRoutes,
|
||||
sidebarRoutes,
|
||||
asyncRoutes
|
||||
});
|
||||
|
||||
asyncRoutes.forEach((route) => {
|
||||
router.addRoute(route);
|
||||
});
|
||||
@@ -113,7 +109,7 @@ const usePermissionStore = defineStore('permission', {
|
||||
|
||||
resolve(rewriteRoutes);
|
||||
}).catch((error) => {
|
||||
console.error('=== 获取用户菜单失败 ===', error);
|
||||
console.error('获取用户菜单失败', error);
|
||||
// 如果获取菜单失败,返回空路由数组
|
||||
this.setSidebarRouters([], 500);
|
||||
this.setRoutes([]);
|
||||
@@ -127,7 +123,6 @@ const usePermissionStore = defineStore('permission', {
|
||||
function capitalizeFirstLetter(string) {
|
||||
// 处理 null 或 undefined 值
|
||||
if (!string || typeof string !== 'string') {
|
||||
console.warn('capitalizeFirstLetter: Invalid string input:', string);
|
||||
return 'Unknown';
|
||||
}
|
||||
|
||||
@@ -281,18 +276,18 @@ export const loadView = (view) => {
|
||||
const defaultView = () => import('~/views/entry/details.vue');
|
||||
|
||||
if (!view) {
|
||||
console.warn('loadView: view parameter is empty, using default view');
|
||||
console.error('loadView: view parameter is empty, using default view');
|
||||
return defaultView;
|
||||
}
|
||||
|
||||
console.log('loadView: Loading view:', view);
|
||||
// 规范化 view 路径:移除开头的斜杠(如果有)
|
||||
const normalizedView = view.startsWith('/') ? view.slice(1) : view;
|
||||
|
||||
let res;
|
||||
// eslint-disable-next-line guard-for-in,no-restricted-syntax
|
||||
for (const path in modules) {
|
||||
const dir = path.split('views/')[1].split('.vue')[0];
|
||||
if (dir === view) {
|
||||
console.log('loadView: Found matching module:', path);
|
||||
if (dir === normalizedView) {
|
||||
// 使用函数包装导入过程,添加错误处理
|
||||
res = () =>
|
||||
modules[path]().catch((error) => {
|
||||
@@ -306,7 +301,7 @@ export const loadView = (view) => {
|
||||
|
||||
// 如果没有找到匹配的视图,返回默认视图
|
||||
if (!res) {
|
||||
console.warn('loadView: View not found:', view, 'Available modules:', Object.keys(modules));
|
||||
console.error('loadView: View not found:', normalizedView);
|
||||
return defaultView;
|
||||
}
|
||||
|
||||
|
||||
@@ -61,18 +61,29 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="warningTime" label="预警时间" />
|
||||
<el-table-column label="操作" width="120" fixed="right">
|
||||
<template #default="scope">
|
||||
<el-button type="primary" link @click="viewDetail(scope.row)">查看详情</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<pagination v-model:limit="form.pageSize" v-model:page="form.pageNum" :total="form1.total" @pagination="getList" />
|
||||
</div>
|
||||
|
||||
<!-- 预警详情对话框 -->
|
||||
<warning-detail-dialog ref="detailDialogRef" />
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { onMounted, reactive, ref } from 'vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import baseSearch from '@/components/common/searchCustom/index.vue';
|
||||
import { warningLogList } from '~/api/hardware.js';
|
||||
import warningDetailDialog from './warningDetailDialog.vue';
|
||||
import { warningLogList, warningDetail } from '~/api/hardware.js';
|
||||
|
||||
const dataListLoading = ref(false);
|
||||
const baseSearchRef = ref();
|
||||
const detailDialogRef = ref();
|
||||
const form = reactive({
|
||||
pageSize: 10,
|
||||
pageNum: 1,
|
||||
@@ -92,7 +103,7 @@ const searchFrom = () => {
|
||||
};
|
||||
|
||||
const searchChange = (val) => {
|
||||
console.log('Search change:', val);
|
||||
|
||||
// 在这里可以处理搜索条件变化的逻辑
|
||||
};
|
||||
|
||||
@@ -160,6 +171,50 @@ const getList = () => {
|
||||
dataListLoading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
// 查看预警详情
|
||||
const viewDetail = async (row) => {
|
||||
|
||||
try {
|
||||
// ✅ 调用后端接口获取完整的预警详情(包括设备位置信息)
|
||||
const res = await warningDetail(row.id);
|
||||
|
||||
if (res.code === 200 && res.data) {
|
||||
const detailData = res.data;
|
||||
|
||||
// ✅ 修复:使用列表中的预警类型,而不是后端API返回的类型
|
||||
// 因为后端API可能返回的是旧数据,列表中的类型才是用户看到的
|
||||
if (row.warningType && row.warningType !== detailData.warningType) {
|
||||
console.warn('[WARNING-LIST] ⚠️ 预警类型不一致!列表中:', row.warningType, '后端返回:', detailData.warningType);
|
||||
console.warn('[WARNING-LIST] 使用列表中的预警类型:', row.warningType);
|
||||
detailData.warningType = row.warningType;
|
||||
}
|
||||
|
||||
// 补充预警类型描述
|
||||
const warningTypeMap = {
|
||||
2: '数量盘单预警',
|
||||
3: '运输距离预警',
|
||||
4: '设备停留预警',
|
||||
5: '高温预警',
|
||||
6: '低温预警',
|
||||
7: '位置偏离预警',
|
||||
8: '延误预警',
|
||||
9: '超前到达预警'
|
||||
};
|
||||
detailData.warningTypeDesc = warningTypeMap[detailData.warningType] || detailData.warningReason || '未知预警';
|
||||
|
||||
|
||||
// 打开详情对话框
|
||||
detailDialogRef.value.open(detailData);
|
||||
} else {
|
||||
ElMessage.error(res.msg || '获取预警详情失败');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[WARNING-LIST] 获取预警详情失败:', error);
|
||||
ElMessage.error('获取预警详情失败,请稍后重试');
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getList();
|
||||
});
|
||||
|
||||
@@ -0,0 +1,725 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="dialogVisible"
|
||||
:title="dialogTitle"
|
||||
width="900px"
|
||||
:close-on-click-modal="false"
|
||||
@close="handleClose"
|
||||
>
|
||||
<!-- 温度预警 - 只显示设备信息,不显示地图 -->
|
||||
<div v-if="isTemperatureWarning" class="warning-content temperature-warning">
|
||||
<!-- 预警基本信息 -->
|
||||
<el-descriptions title="温度预警基本信息" :column="2" border>
|
||||
<el-descriptions-item label="预警时间">
|
||||
<span style="font-weight: 600;">{{ warningData.warningTime }}</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="预警类型">
|
||||
<el-tag :type="warningData.warningType == 5 ? 'danger' : 'primary'" size="large">
|
||||
{{ warningData.warningTypeDesc }}
|
||||
</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="预警温度">
|
||||
<span :style="{
|
||||
color: getTemperatureColor(parseFloat(warningData.deviceTemp)),
|
||||
fontWeight: 'bold',
|
||||
fontSize: '18px'
|
||||
}">
|
||||
{{ warningData.deviceTemp || '--' }}°C
|
||||
</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="设备ID">
|
||||
{{ warningData.serverDeviceSn || warningData.deviceId || '未知' }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="运单号">{{ warningData.deliveryNumber }}</el-descriptions-item>
|
||||
<el-descriptions-item label="车牌号">{{ warningData.licensePlate }}</el-descriptions-item>
|
||||
<el-descriptions-item label="司机姓名">{{ warningData.driverName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="创建人">{{ warningData.createByName || '--' }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
|
||||
<!-- 预警详情描述 -->
|
||||
<div v-if="warningData.warningDetail" class="warning-description">
|
||||
<el-alert
|
||||
:title="warningData.warningDetail"
|
||||
:type="warningData.warningType == 5 ? 'error' : 'warning'"
|
||||
:closable="false"
|
||||
show-icon
|
||||
style="margin-top: 20px;"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<el-divider content-position="left">
|
||||
<el-icon><InfoFilled /></el-icon>
|
||||
<span style="margin-left: 5px;">设备详细信息</span>
|
||||
</el-divider>
|
||||
|
||||
<!-- 绑定设备列表 -->
|
||||
<div v-if="deviceList.length > 0" class="device-list-section">
|
||||
<div class="section-header">
|
||||
<h4>
|
||||
<el-icon style="vertical-align: middle;"><Connection /></el-icon>
|
||||
绑定设备列表
|
||||
<el-tag type="info" size="small" style="margin-left: 10px;">{{ deviceList.length }}个</el-tag>
|
||||
</h4>
|
||||
</div>
|
||||
<el-table :data="deviceList" border style="width: 100%" size="small">
|
||||
<el-table-column prop="deviceId" label="设备ID" width="150" />
|
||||
<el-table-column prop="deviceTypeName" label="设备类型" width="120">
|
||||
<template #default="scope">
|
||||
<el-tag
|
||||
:type="scope.row.deviceType == 1 || scope.row.deviceType == 4 ? 'primary' : (scope.row.deviceType == 2 ? 'success' : 'warning')"
|
||||
>
|
||||
{{ scope.row.deviceTypeName || '未知' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="sn" label="设备SN" min-width="150" />
|
||||
<el-table-column prop="battery" label="电量" width="100">
|
||||
<template #default="scope">
|
||||
<span v-if="scope.row.battery || scope.row.batteryPercentage">
|
||||
{{ scope.row.battery || scope.row.batteryPercentage }}%
|
||||
</span>
|
||||
<span v-else>--</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="status" label="状态" width="100">
|
||||
<template #default="scope">
|
||||
<el-tag :type="scope.row.status == 1 ? 'success' : 'info'">
|
||||
{{ scope.row.status == 1 ? '在线' : '离线' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<div v-else class="no-data-tip">
|
||||
<el-empty description="暂无绑定设备信息" :image-size="80" />
|
||||
</div>
|
||||
|
||||
<!-- 设备温度日志(重点显示温度数据) -->
|
||||
<div v-if="deviceLogs.length > 0" class="device-logs-section">
|
||||
<div class="section-header">
|
||||
<h4>
|
||||
<el-icon style="vertical-align: middle;"><DataLine /></el-icon>
|
||||
设备温度记录
|
||||
<el-tag type="info" size="small" style="margin-left: 10px;">{{ deviceLogs.length }}条</el-tag>
|
||||
</h4>
|
||||
<p class="section-desc">显示设备的温度历史记录,可以查看温度变化趋势</p>
|
||||
</div>
|
||||
<el-table
|
||||
:data="deviceLogs"
|
||||
border
|
||||
style="width: 100%"
|
||||
size="small"
|
||||
max-height="350"
|
||||
v-loading="loadingLogs"
|
||||
:default-sort="{ prop: 'createTime', order: 'descending' }"
|
||||
>
|
||||
<el-table-column label="记录时间" width="170" sortable>
|
||||
<template #default="scope">
|
||||
{{ scope.row.hourTime || scope.row.createTime || '--' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="deviceTypeName" label="设备类型" width="110">
|
||||
<template #default="scope">
|
||||
<el-tag
|
||||
size="small"
|
||||
:type="scope.row.deviceType == 1 || scope.row.deviceType == 4 ? 'primary' : (scope.row.deviceType == 2 ? 'success' : 'warning')"
|
||||
>
|
||||
{{ scope.row.deviceTypeName }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="deviceId" label="设备ID" width="140" />
|
||||
<el-table-column label="温度(°C)" width="120" sortable>
|
||||
<template #default="scope">
|
||||
<span v-if="scope.row.deviceTemp"
|
||||
:style="{
|
||||
color: getTemperatureColor(parseFloat(scope.row.deviceTemp)),
|
||||
fontWeight: '600',
|
||||
fontSize: '14px'
|
||||
}">
|
||||
{{ scope.row.deviceTemp }}°C
|
||||
</span>
|
||||
<span v-else style="color: #909399;">--</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="heartRate" label="心率" width="80" />
|
||||
<el-table-column label="步数" width="90">
|
||||
<template #default="scope">
|
||||
{{ scope.row.stepCount || scope.row.steps || '--' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="latitude" label="纬度" width="100" />
|
||||
<el-table-column prop="longitude" label="经度" width="100" />
|
||||
</el-table>
|
||||
</div>
|
||||
<div v-else-if="!loadingLogs" class="no-data-tip">
|
||||
<el-empty description="暂无设备日志记录" :image-size="80" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 停留预警/位置偏离预警 - 显示地图 -->
|
||||
<div v-else-if="isLocationWarning" class="warning-content">
|
||||
<el-descriptions title="位置预警详情" :column="2" border>
|
||||
<el-descriptions-item label="预警时间">{{ warningData.warningTime }}</el-descriptions-item>
|
||||
<el-descriptions-item label="预警类型">
|
||||
<el-tag :type="getWarningTagType(warningData.warningType)">
|
||||
{{ warningData.warningTypeDesc }}
|
||||
</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="预警经度">{{ warningData.longitude || '未知' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="预警纬度">{{ warningData.latitude || '未知' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="运单号">{{ warningData.deliveryNumber }}</el-descriptions-item>
|
||||
<el-descriptions-item label="车牌号">{{ warningData.licensePlate }}</el-descriptions-item>
|
||||
<el-descriptions-item label="司机姓名">{{ warningData.driverName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="创建人">{{ warningData.createByName }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
|
||||
<el-divider />
|
||||
|
||||
<!-- 百度地图显示 -->
|
||||
<div class="map-container">
|
||||
<h4>预警位置地图</h4>
|
||||
<div id="warningMap" style="width: 100%; height: 400px;"></div>
|
||||
</div>
|
||||
|
||||
<!-- 预警详情描述 -->
|
||||
<div v-if="warningData.warningDetail" class="warning-description">
|
||||
<h4>预警详情</h4>
|
||||
<p>{{ warningData.warningDetail }}</p>
|
||||
</div>
|
||||
|
||||
<!-- ✅ 新增:绑定设备列表 -->
|
||||
<div v-if="deviceList.length > 0" class="device-list-section">
|
||||
<h4>绑定设备列表({{ deviceList.length }}个)</h4>
|
||||
<el-table :data="deviceList" border style="width: 100%" size="small">
|
||||
<el-table-column prop="deviceId" label="设备ID" width="150" />
|
||||
<el-table-column prop="deviceTypeName" label="设备类型" width="120">
|
||||
<template #default="scope">
|
||||
<el-tag :type="scope.row.deviceType == 1 ? 'primary' : (scope.row.deviceType == 2 ? 'success' : 'warning')">
|
||||
{{ scope.row.deviceTypeName || '未知' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="sn" label="设备SN" min-width="150" />
|
||||
<el-table-column prop="status" label="状态" width="100">
|
||||
<template #default="scope">
|
||||
<el-tag :type="scope.row.status == 1 ? 'success' : 'info'">
|
||||
{{ scope.row.status == 1 ? '在线' : '离线' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
|
||||
<!-- ✅ 新增:设备日志列表 -->
|
||||
<div v-if="deviceLogs.length > 0" class="device-logs-section">
|
||||
<h4>设备日志记录({{ deviceLogs.length }}条)</h4>
|
||||
<el-table
|
||||
:data="deviceLogs"
|
||||
border
|
||||
style="width: 100%"
|
||||
size="small"
|
||||
max-height="300"
|
||||
v-loading="loadingLogs"
|
||||
>
|
||||
<el-table-column label="时间" width="160">
|
||||
<template #default="scope">
|
||||
{{ scope.row.hourTime || scope.row.createTime || '--' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="deviceTypeName" label="设备类型" width="110">
|
||||
<template #default="scope">
|
||||
<el-tag size="small" :type="scope.row.deviceType == 1 ? 'primary' : (scope.row.deviceType == 2 ? 'success' : 'warning')">
|
||||
{{ scope.row.deviceTypeName }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="deviceId" label="设备ID" width="130" />
|
||||
<el-table-column prop="latitude" label="纬度" width="90" />
|
||||
<el-table-column prop="longitude" label="经度" width="90" />
|
||||
<el-table-column prop="deviceTemp" label="温度(°C)" width="100">
|
||||
<template #default="scope">
|
||||
<span v-if="scope.row.deviceTemp" :style="{ color: getTemperatureColor(parseFloat(scope.row.deviceTemp)) }">
|
||||
{{ scope.row.deviceTemp }}°C
|
||||
</span>
|
||||
<span v-else>--</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="heartRate" label="心率" width="80" />
|
||||
<el-table-column label="步数" width="80">
|
||||
<template #default="scope">
|
||||
{{ scope.row.stepCount || scope.row.steps || '--' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 其他类型预警 -->
|
||||
<div v-else class="warning-content">
|
||||
<el-descriptions title="预警详情" :column="2" border>
|
||||
<el-descriptions-item label="预警时间">{{ warningData.warningTime }}</el-descriptions-item>
|
||||
<el-descriptions-item label="预警类型">
|
||||
<el-tag :type="getWarningTagType(warningData.warningType)">
|
||||
{{ warningData.warningTypeDesc }}
|
||||
</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="运单号">{{ warningData.deliveryNumber }}</el-descriptions-item>
|
||||
<el-descriptions-item label="车牌号">{{ warningData.licensePlate }}</el-descriptions-item>
|
||||
<el-descriptions-item label="司机姓名">{{ warningData.driverName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="创建人">{{ warningData.createByName }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
|
||||
<el-divider />
|
||||
|
||||
<div v-if="warningData.warningDetail" class="warning-description">
|
||||
<h4>预警详情</h4>
|
||||
<p>{{ warningData.warningDetail }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="dialogVisible = false">关闭</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, computed, nextTick } from 'vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { BMPGL } from '@/utils/loadBmap.js';
|
||||
import { pageDeviceList, getCollarLogs, getEarTagLogs, getHostLogs } from '@/api/abroad.js';
|
||||
|
||||
const dialogVisible = ref(false);
|
||||
const warningData = reactive({
|
||||
id: null,
|
||||
warningType: null,
|
||||
warningTypeDesc: '',
|
||||
warningTime: '',
|
||||
latitude: '',
|
||||
longitude: '',
|
||||
deviceId: '',
|
||||
deviceName: '',
|
||||
deviceTemp: '', // 修改:使用 deviceTemp
|
||||
temperature: null,
|
||||
warningDetail: '',
|
||||
deliveryNumber: '',
|
||||
licensePlate: '',
|
||||
driverName: '',
|
||||
createByName: '',
|
||||
deliveryId: null, // 新增:运单ID
|
||||
serverDeviceSn: '', // 新增:主机设备SN
|
||||
});
|
||||
|
||||
const temperatureHistory = ref([]);
|
||||
const deviceList = ref([]); // 新增:设备列表
|
||||
const deviceLogs = ref([]); // 新增:设备日志列表
|
||||
const loadingDevices = ref(false); // 新增:加载设备列表状态
|
||||
const loadingLogs = ref(false); // 新增:加载日志状态
|
||||
let mapInstance = null;
|
||||
let markerInstance = null;
|
||||
|
||||
// 计算属性:判断预警类型
|
||||
const isTemperatureWarning = computed(() => {
|
||||
// 5-高温预警,6-低温预警
|
||||
const type = parseInt(warningData.warningType);
|
||||
const isTempWarning = type === 5 || type === 6;
|
||||
|
||||
return isTempWarning;
|
||||
});
|
||||
|
||||
const isLocationWarning = computed(() => {
|
||||
// 4-设备停留预警,7-位置偏离预警,8-延误预警
|
||||
const type = parseInt(warningData.warningType);
|
||||
const isLocWarning = type === 4 || type === 7 || type === 8;
|
||||
|
||||
return isLocWarning;
|
||||
});
|
||||
|
||||
const dialogTitle = computed(() => {
|
||||
return `${warningData.warningTypeDesc || '预警'}详情`;
|
||||
});
|
||||
|
||||
// 打开对话框
|
||||
const open = async (row) => {
|
||||
|
||||
// 填充数据
|
||||
Object.keys(warningData).forEach(key => {
|
||||
if (row[key] !== undefined) {
|
||||
warningData[key] = row[key];
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
dialogVisible.value = true;
|
||||
|
||||
// ✅ 查询运单绑定的设备列表
|
||||
if (warningData.deliveryId) {
|
||||
await loadDeviceList(warningData.deliveryId);
|
||||
}
|
||||
|
||||
// 如果是位置相关预警,加载地图
|
||||
if (isLocationWarning.value && warningData.latitude && warningData.longitude) {
|
||||
await nextTick();
|
||||
initMap();
|
||||
}
|
||||
|
||||
// 注意:温度预警的日志已经通过 loadDeviceList 自动加载,无需单独调用
|
||||
// 设备列表加载后会自动调用 loadAllDeviceLogs()
|
||||
};
|
||||
|
||||
// ✅ 新增:加载运单绑定的设备列表
|
||||
const loadDeviceList = async (deliveryId) => {
|
||||
if (!deliveryId) {
|
||||
console.warn('[WARNING-DETAIL] 运单ID为空,无法加载设备列表');
|
||||
return;
|
||||
}
|
||||
|
||||
loadingDevices.value = true;
|
||||
try {
|
||||
|
||||
const res = await pageDeviceList({
|
||||
deliveryId: deliveryId,
|
||||
pageNum: 1,
|
||||
pageSize: 100, // 一次性加载所有设备
|
||||
});
|
||||
|
||||
if (res.code === 200 && res.data) {
|
||||
// ✅ 修复:后端直接返回数组,不是嵌套在 list 或 rows 中
|
||||
if (Array.isArray(res.data)) {
|
||||
deviceList.value = res.data;
|
||||
} else {
|
||||
deviceList.value = res.data.list || res.data.rows || [];
|
||||
}
|
||||
|
||||
// 自动加载所有设备的日志
|
||||
await loadAllDeviceLogs();
|
||||
} else {
|
||||
ElMessage.warning('加载设备列表失败:' + (res.msg || '未知错误'));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[WARNING-DETAIL] 加载设备列表失败:', error);
|
||||
ElMessage.error('加载设备列表失败');
|
||||
} finally {
|
||||
loadingDevices.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// ✅ 新增:加载所有设备的日志数据
|
||||
const loadAllDeviceLogs = async () => {
|
||||
if (deviceList.value.length === 0) {
|
||||
console.warn('[WARNING-DETAIL] 设备列表为空,无法加载日志');
|
||||
return;
|
||||
}
|
||||
|
||||
loadingLogs.value = true;
|
||||
deviceLogs.value = []; // 清空之前的日志
|
||||
|
||||
try {
|
||||
|
||||
// 并行加载所有设备的日志
|
||||
const logPromises = deviceList.value.map(device => {
|
||||
|
||||
return loadDeviceLogs(device.deviceId || device.sn, device.deviceType, warningData.deliveryId);
|
||||
});
|
||||
|
||||
await Promise.all(logPromises);
|
||||
|
||||
|
||||
} catch (error) {
|
||||
console.error('[WARNING-DETAIL] 加载设备日志失败:', error);
|
||||
ElMessage.error('加载设备日志失败');
|
||||
} finally {
|
||||
loadingLogs.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// ✅ 新增:加载单个设备的日志数据
|
||||
const loadDeviceLogs = async (deviceId, deviceType, deliveryId) => {
|
||||
if (!deviceId) {
|
||||
console.warn('[WARNING-DETAIL] 设备ID为空,无法加载日志');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!deliveryId) {
|
||||
console.warn('[WARNING-DETAIL] 运单ID为空,无法加载日志');
|
||||
return;
|
||||
}
|
||||
|
||||
// 确保 deviceType 是数字
|
||||
const typeNum = parseInt(deviceType);
|
||||
|
||||
try {
|
||||
// 根据设备类型选择不同的API
|
||||
let apiFunc;
|
||||
let deviceTypeName;
|
||||
|
||||
switch (typeNum) {
|
||||
case 1: // 智能主机
|
||||
apiFunc = getHostLogs;
|
||||
deviceTypeName = '智能主机';
|
||||
break;
|
||||
case 2: // 智能耳标
|
||||
apiFunc = getEarTagLogs;
|
||||
deviceTypeName = '智能耳标';
|
||||
break;
|
||||
case 3: // 智能项圈
|
||||
case 4: // 也可能是4
|
||||
apiFunc = getCollarLogs;
|
||||
deviceTypeName = '智能项圈';
|
||||
break;
|
||||
default:
|
||||
console.warn(`[WARNING-DETAIL] 未知的设备类型: ${typeNum} (原始值: ${deviceType})`);
|
||||
return;
|
||||
}
|
||||
|
||||
// 调用对应的日志查询API(必须传入 deliveryId)
|
||||
const res = await apiFunc({
|
||||
deviceId: deviceId,
|
||||
deliveryId: deliveryId, // ✅ 新增:后端必需参数
|
||||
pageNum: 1,
|
||||
pageSize: 50, // 查询最近50条日志
|
||||
// 可选:添加时间范围过滤(预警时间前后1小时)
|
||||
// startTime: getStartTime(warningData.warningTime),
|
||||
// endTime: getEndTime(warningData.warningTime),
|
||||
});
|
||||
|
||||
if (res.code === 200 && res.data) {
|
||||
// ✅ 修复:后端可能直接返回数组,也可能嵌套在 list/rows 中
|
||||
let logs = [];
|
||||
if (Array.isArray(res.data)) {
|
||||
logs = res.data;
|
||||
} else {
|
||||
logs = res.data.list || res.data.rows || [];
|
||||
}
|
||||
|
||||
console.log('[WARNING-DETAIL] 原始日志数据:', logs);
|
||||
|
||||
// 为每条日志添加设备信息
|
||||
const logsWithDeviceInfo = logs.map(log => ({
|
||||
...log,
|
||||
deviceId: deviceId,
|
||||
deviceType: typeNum, // 使用转换后的数字类型
|
||||
deviceTypeName: deviceTypeName,
|
||||
}));
|
||||
|
||||
deviceLogs.value.push(...logsWithDeviceInfo);
|
||||
} else {
|
||||
console.warn('[WARNING-DETAIL] 加载' + deviceTypeName + '日志失败:', res.msg);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[WARNING-DETAIL] 加载设备(' + deviceId + ')日志失败:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// 初始化地图
|
||||
const initMap = async () => {
|
||||
try {
|
||||
// 使用百度地图 API Key
|
||||
const BMapGL = await BMPGL('SOawZTeQbxdgrKYYx0o2hn34G0DyU2uo');
|
||||
const lat = parseFloat(warningData.latitude);
|
||||
const lon = parseFloat(warningData.longitude);
|
||||
|
||||
if (isNaN(lat) || isNaN(lon)) {
|
||||
ElMessage.warning('经纬度数据无效');
|
||||
return;
|
||||
}
|
||||
|
||||
// 创建地图实例(使用 BMapGL)
|
||||
mapInstance = new BMapGL.Map('warningMap');
|
||||
const point = new BMapGL.Point(lon, lat);
|
||||
mapInstance.centerAndZoom(point, 15);
|
||||
mapInstance.enableScrollWheelZoom(true);
|
||||
|
||||
// 添加标注
|
||||
markerInstance = new BMapGL.Marker(point);
|
||||
mapInstance.addOverlay(markerInstance);
|
||||
|
||||
// 添加信息窗口
|
||||
const warningTypeText = warningData.warningTypeDesc || '预警位置';
|
||||
const infoWindow = new BMapGL.InfoWindow(
|
||||
'<div style="padding: 10px;">' +
|
||||
'<p style="margin: 0; font-weight: bold; color: #f56c6c;">' + warningTypeText + '</p>' +
|
||||
'<p style="margin: 5px 0 0 0;">时间: ' + warningData.warningTime + '</p>' +
|
||||
'<p style="margin: 5px 0 0 0;">经度: ' + lon + '</p>' +
|
||||
'<p style="margin: 5px 0 0 0;">纬度: ' + lat + '</p>' +
|
||||
'</div>',
|
||||
{ width: 250, height: 120 }
|
||||
);
|
||||
markerInstance.addEventListener('click', function () {
|
||||
mapInstance.openInfoWindow(infoWindow, point);
|
||||
});
|
||||
|
||||
// 默认打开信息窗口
|
||||
mapInstance.openInfoWindow(infoWindow, point);
|
||||
|
||||
|
||||
} catch (error) {
|
||||
console.error('[WARNING-DETAIL] 地图初始化失败:', error);
|
||||
ElMessage.error('地图加载失败');
|
||||
}
|
||||
};
|
||||
|
||||
// 根据温度值返回颜色
|
||||
const getTemperatureColor = (temp) => {
|
||||
if (temp == null) return '#909399';
|
||||
if (temp >= 35) return '#f56c6c'; // 高温-红色
|
||||
if (temp <= 5) return '#409eff'; // 低温-蓝色
|
||||
return '#67c23a'; // 正常-绿色
|
||||
};
|
||||
|
||||
// 根据预警类型返回标签类型
|
||||
const getWarningTagType = (type) => {
|
||||
const typeNum = parseInt(type);
|
||||
switch (typeNum) {
|
||||
case 2: return 'danger'; // 数量盘单预警
|
||||
case 3: return 'warning'; // 运输距离预警
|
||||
case 4: return 'info'; // 设备停留预警
|
||||
case 5: return 'danger'; // 高温预警
|
||||
case 6: return 'info'; // 低温预警
|
||||
case 7: return 'warning'; // 位置偏离预警
|
||||
case 8: return 'danger'; // 延误预警
|
||||
case 9: return 'success'; // 超前到达预警
|
||||
default: return 'info';
|
||||
}
|
||||
};
|
||||
|
||||
// 关闭对话框
|
||||
const handleClose = () => {
|
||||
// 清理地图实例
|
||||
if (mapInstance) {
|
||||
mapInstance.clearOverlays();
|
||||
mapInstance = null;
|
||||
markerInstance = null;
|
||||
}
|
||||
|
||||
// 清空温度历史数据
|
||||
temperatureHistory.value = [];
|
||||
|
||||
// ✅ 清空设备列表和日志数据
|
||||
deviceList.value = [];
|
||||
deviceLogs.value = [];
|
||||
loadingDevices.value = false;
|
||||
loadingLogs.value = false;
|
||||
|
||||
// 重置数据
|
||||
Object.keys(warningData).forEach(key => {
|
||||
if (typeof warningData[key] === 'number') {
|
||||
warningData[key] = null;
|
||||
} else {
|
||||
warningData[key] = '';
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 导出方法
|
||||
defineExpose({
|
||||
open
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.warning-content {
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
// 温度预警专用样式
|
||||
.temperature-warning {
|
||||
.warning-description {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.section-header {
|
||||
margin-bottom: 15px;
|
||||
|
||||
h4 {
|
||||
margin: 0 0 8px 0;
|
||||
color: #303133;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.section-desc {
|
||||
margin: 0;
|
||||
font-size: 13px;
|
||||
color: #909399;
|
||||
}
|
||||
}
|
||||
|
||||
.no-data-tip {
|
||||
padding: 40px 0;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.warning-description {
|
||||
margin-top: 20px;
|
||||
|
||||
h4 {
|
||||
margin: 0 0 10px 0;
|
||||
color: #303133;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
padding: 10px;
|
||||
background-color: #f5f7fa;
|
||||
border-left: 3px solid #409eff;
|
||||
border-radius: 4px;
|
||||
line-height: 1.6;
|
||||
color: #606266;
|
||||
}
|
||||
}
|
||||
|
||||
.map-container {
|
||||
margin-top: 20px;
|
||||
|
||||
h4 {
|
||||
margin: 0 0 10px 0;
|
||||
color: #303133;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.temperature-chart {
|
||||
margin-top: 20px;
|
||||
|
||||
h4 {
|
||||
margin: 0 0 10px 0;
|
||||
color: #303133;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.device-list-section {
|
||||
margin-top: 20px;
|
||||
|
||||
h4 {
|
||||
margin: 0 0 10px 0;
|
||||
color: #303133;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
.device-logs-section {
|
||||
margin-top: 20px;
|
||||
|
||||
h4 {
|
||||
margin: 0 0 10px 0;
|
||||
color: #303133;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
:deep(.el-table) {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -168,8 +168,7 @@ const formItemList = reactive([
|
||||
// 获取指定订单的设备数量
|
||||
const getDeviceCounts = async (deliveryId) => {
|
||||
try {
|
||||
console.log('=== 获取订单设备数量,deliveryId:', deliveryId);
|
||||
|
||||
|
||||
// 获取所有设备类型的数据
|
||||
const [hostRes, earRes, collarRes] = await Promise.all([
|
||||
pageDeviceList({ pageNum: 1, pageSize: 100, deliveryId: parseInt(deliveryId), deviceType: 1 }),
|
||||
@@ -182,14 +181,7 @@ const getDeviceCounts = async (deliveryId) => {
|
||||
const collarCount = collarRes.code === 200 ? collarRes.data.length : 0;
|
||||
const totalCount = hostCount + earCount + collarCount;
|
||||
|
||||
console.log('=== 设备数量统计:', {
|
||||
deliveryId,
|
||||
hostCount,
|
||||
earCount,
|
||||
collarCount,
|
||||
totalCount
|
||||
});
|
||||
|
||||
|
||||
// 存储设备数量
|
||||
data.deviceCounts[deliveryId] = {
|
||||
host: hostCount,
|
||||
@@ -244,63 +236,40 @@ const getDataList = () => {
|
||||
// 处理精确的创建时间查询
|
||||
if (searchParams.createTime) {
|
||||
params.createTime = searchParams.createTime;
|
||||
console.log('精确创建时间查询:', searchParams.createTime);
|
||||
|
||||
}
|
||||
|
||||
// 处理精确的车牌号查询
|
||||
if (searchParams.licensePlate) {
|
||||
params.licensePlate = searchParams.licensePlate.trim();
|
||||
console.log('精确车牌号查询:', params.licensePlate);
|
||||
|
||||
}
|
||||
|
||||
console.log('查询参数:', params);
|
||||
|
||||
|
||||
inspectionList(params)
|
||||
.then(async (ret) => {
|
||||
console.log('入境检疫列表返回结果:', ret);
|
||||
|
||||
data.rows = ret.data.rows;
|
||||
data.total = ret.data.total;
|
||||
dataListLoading.value = false;
|
||||
|
||||
// 为每个订单获取设备数量
|
||||
if (ret.data.rows && ret.data.rows.length > 0) {
|
||||
console.log('=== 开始为每个订单获取设备数量');
|
||||
|
||||
for (const row of ret.data.rows) {
|
||||
if (row.id) {
|
||||
await getDeviceCounts(row.id);
|
||||
}
|
||||
}
|
||||
console.log('=== 所有订单设备数量获取完成');
|
||||
|
||||
}
|
||||
|
||||
// 调试:检查第一行数据的字段
|
||||
if (ret.data.rows && ret.data.rows.length > 0) {
|
||||
const firstRow = ret.data.rows[0];
|
||||
console.log('入境检疫第一行数据完整字段:', firstRow);
|
||||
console.log('入境检疫关键字段检查:', {
|
||||
status: firstRow.status,
|
||||
statusDesc: firstRow.statusDesc,
|
||||
registeredJbqCount: firstRow.registeredJbqCount,
|
||||
earTagCount: firstRow.earTagCount,
|
||||
driverName: firstRow.driverName,
|
||||
licensePlate: firstRow.licensePlate
|
||||
});
|
||||
|
||||
|
||||
// 检查Word导出所需字段
|
||||
console.log('Word导出字段检查:', {
|
||||
supplierName: firstRow.supplierName,
|
||||
buyerName: firstRow.buyerName,
|
||||
startLocation: firstRow.startLocation,
|
||||
createTime: firstRow.createTime,
|
||||
endLocation: firstRow.endLocation,
|
||||
driverName: firstRow.driverName,
|
||||
driverMobile: firstRow.driverMobile,
|
||||
licensePlate: firstRow.licensePlate,
|
||||
ratedQuantity: firstRow.ratedQuantity,
|
||||
landingEntruckWeight: firstRow.landingEntruckWeight,
|
||||
emptyWeight: firstRow.emptyWeight,
|
||||
firmPrice: firstRow.firmPrice
|
||||
});
|
||||
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
@@ -346,16 +315,7 @@ const download = async (row) => {
|
||||
totalAmount: totalAmount
|
||||
};
|
||||
|
||||
console.log('生成Word文档数据:', data);
|
||||
console.log('原始数据字段检查:', {
|
||||
supplierName: row.supplierName,
|
||||
buyerName: row.buyerName,
|
||||
supplierMobile: row.supplierMobile,
|
||||
buyerMobile: row.buyerMobile,
|
||||
fundName: row.fundName,
|
||||
fundMobile: row.fundMobile
|
||||
});
|
||||
|
||||
|
||||
// 生成HTML内容
|
||||
const htmlContent = `
|
||||
<!DOCTYPE html>
|
||||
@@ -601,8 +561,7 @@ const viewDevices = (row) => {
|
||||
// 编辑运送清单
|
||||
const editDelivery = async (row) => {
|
||||
try {
|
||||
console.log('[EDIT-DELIVERY] 准备编辑运送清单, ID:', row.id);
|
||||
|
||||
|
||||
// 检查编辑对话框组件是否已加载
|
||||
if (!editDialogRef.value || !editDialogRef.value.open) {
|
||||
ElMessage.warning('编辑功能暂不可用,请刷新页面重试');
|
||||
@@ -611,8 +570,7 @@ const editDelivery = async (row) => {
|
||||
|
||||
// 调用 detail 接口获取完整数据(包含 supplierId, buyerId, 设备信息等)
|
||||
const detailRes = await getDeliveryDetail(row.id);
|
||||
console.log('[EDIT-DELIVERY] 获取到详情数据:', detailRes);
|
||||
|
||||
|
||||
if (detailRes.code === 200 && detailRes.data) {
|
||||
// 传入完整的 detail 数据给 open() 方法
|
||||
editDialogRef.value.open(detailRes.data);
|
||||
|
||||
@@ -638,8 +638,7 @@ const collarLogForm = reactive({
|
||||
});
|
||||
// 查详情
|
||||
const getDetail = () => {
|
||||
console.log('查询运单详情, deliveryId:', route.query.id);
|
||||
|
||||
|
||||
if (!route.query.id) {
|
||||
console.warn('=== 警告:deliveryId为空,跳过运单详情查询');
|
||||
return;
|
||||
@@ -647,19 +646,12 @@ const getDetail = () => {
|
||||
|
||||
waybillDetail(route.query.id)
|
||||
.then((res) => {
|
||||
console.log('运单详情返回结果:', res);
|
||||
|
||||
if (res.code === 200) {
|
||||
data.baseInfo = res.data.delivery ? res.data.delivery : {};
|
||||
data.warnInfo = res.data.warningLog ? res.data.warningLog : {};
|
||||
data.serverIds = res.data.serverIds ? res.data.serverIds : [];
|
||||
console.log('基础信息:', {
|
||||
driverName: data.baseInfo.driverName,
|
||||
licensePlate: data.baseInfo.licensePlate,
|
||||
carFrontPhoto: data.baseInfo.carFrontPhoto,
|
||||
carBehindPhoto: data.baseInfo.carBehindPhoto,
|
||||
driverId: data.baseInfo.driverId
|
||||
});
|
||||
|
||||
|
||||
// 查询车辆照片
|
||||
if (data.baseInfo.licensePlate) {
|
||||
loadVehiclePhotos();
|
||||
@@ -678,10 +670,7 @@ const getDetail = () => {
|
||||
const loadVehiclePhotos = () => {
|
||||
// 后端已经从delivery/driver信息中获取了车身照片,无需额外前端查询
|
||||
// carFrontPhoto和carBehindPhoto应该已经由后端的DeliveryServiceImpl填充
|
||||
console.log('车身照片信息:', {
|
||||
carFrontPhoto: data.baseInfo.carFrontPhoto,
|
||||
carBehindPhoto: data.baseInfo.carBehindPhoto
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
// 智能主机列表查询
|
||||
@@ -700,10 +689,10 @@ const getHostList = () => {
|
||||
deviceType: 1, // 智能主机设备类型
|
||||
})
|
||||
.then((res) => {
|
||||
console.log('=== 主机设备API返回结果:', res);
|
||||
|
||||
data.hostDataListLoading = false;
|
||||
if (res.code === 200) {
|
||||
console.log('=== 主机设备数据:', res.data);
|
||||
|
||||
// 新API返回的是数组格式,过滤出智能主机设备
|
||||
const hostDevices = res.data.filter(device => device.deviceType === 1 || device.deviceType === '1');
|
||||
data.hostRows = hostDevices || [];
|
||||
@@ -712,13 +701,12 @@ const getHostList = () => {
|
||||
if (hostDevices.length > 0) {
|
||||
// 如果有主机设备,取第一个作为主要主机
|
||||
data.serverIds = hostDevices[0].deviceId || hostDevices[0].sn || '';
|
||||
console.log('=== 设置后的serverIds:', data.serverIds);
|
||||
|
||||
} else {
|
||||
data.serverIds = '';
|
||||
}
|
||||
|
||||
console.log('=== 设置后的hostRows:', data.hostRows);
|
||||
console.log('=== 设置后的hostTotal:', data.hostTotal);
|
||||
|
||||
} else {
|
||||
console.warn('获取主机设备信息失败:', res.msg);
|
||||
data.hostRows = [];
|
||||
@@ -819,16 +807,15 @@ const getEarList = () => {
|
||||
deviceType: 2, // 智能耳标设备类型
|
||||
})
|
||||
.then((res) => {
|
||||
console.log('=== 耳标设备API返回结果:', res);
|
||||
|
||||
data.dataListLoading = false;
|
||||
if (res.code === 200) {
|
||||
console.log('=== 耳标设备数据:', res.data);
|
||||
|
||||
// 新API返回的是数组格式,需要过滤出智能耳标设备
|
||||
const earDevices = res.data.filter(device => device.deviceType === 2 || device.deviceType === '2');
|
||||
data.rows = earDevices || [];
|
||||
data.total = earDevices.length || 0;
|
||||
console.log('=== 设置后的rows:', data.rows);
|
||||
console.log('=== 设置后的total:', data.total);
|
||||
|
||||
} else {
|
||||
ElMessage.error(res.msg);
|
||||
data.total = 0;
|
||||
@@ -839,9 +826,7 @@ const getEarList = () => {
|
||||
});
|
||||
};
|
||||
const earLogClick = (row) => {
|
||||
console.log('=== 智能耳标日志点击 ===');
|
||||
console.log('设备信息:', row);
|
||||
|
||||
|
||||
data.deviceId = row.deviceId || row.sn || '';
|
||||
data.earLogDialogVisible = true;
|
||||
|
||||
@@ -850,13 +835,12 @@ const earLogClick = (row) => {
|
||||
deviceId: data.deviceId,
|
||||
deliveryId: parseInt(route.query.id)
|
||||
}).then((res) => {
|
||||
console.log('=== 智能耳标日志API返回结果:', res);
|
||||
|
||||
if (res.code === 200) {
|
||||
// 新API返回的是按60分钟分组的日志数据
|
||||
data.earLogRows = res.data || [];
|
||||
data.earLogTotal = res.data.length || 0;
|
||||
console.log('=== 设置后的earLogRows:', data.earLogRows);
|
||||
console.log('=== 设置后的earLogTotal:', data.earLogTotal);
|
||||
|
||||
} else {
|
||||
ElMessage.error(res.msg || '获取智能耳标日志失败');
|
||||
data.earLogRows = [];
|
||||
@@ -872,20 +856,17 @@ const earLogClick = (row) => {
|
||||
|
||||
// 智能耳标运动轨迹
|
||||
const earTrackClick = (row) => {
|
||||
console.log('=== 智能耳标运动轨迹点击 ===');
|
||||
console.log('设备信息:', row);
|
||||
|
||||
|
||||
// 调用新的API获取60分钟间隔的轨迹数据
|
||||
getEarTagTrajectory({
|
||||
deviceId: row.deviceId || row.sn || '',
|
||||
deliveryId: parseInt(route.query.id)
|
||||
}).then((res) => {
|
||||
console.log('=== 智能耳标轨迹API返回结果:', res);
|
||||
|
||||
if (res.code === 200 && res.data && res.data.length > 0) {
|
||||
// 新API返回的是按60分钟分组的轨迹点数据
|
||||
const trajectoryPoints = res.data;
|
||||
console.log('=== 轨迹点数据:', trajectoryPoints);
|
||||
|
||||
|
||||
// 使用TrackDialog显示轨迹
|
||||
if (TrackDialogRef.value) {
|
||||
const info = {
|
||||
@@ -921,16 +902,15 @@ const getCollarList = () => {
|
||||
deviceType: 4, // 智能项圈设备类型
|
||||
})
|
||||
.then((res) => {
|
||||
console.log('=== 项圈设备API返回结果:', res);
|
||||
|
||||
data.collarDataListLoading = false;
|
||||
if (res.code === 200) {
|
||||
console.log('=== 项圈设备数据:', res.data);
|
||||
|
||||
// 新API返回的是数组格式,需要过滤出智能项圈设备
|
||||
const collarDevices = res.data.filter(device => device.deviceType === 4 || device.deviceType === '4');
|
||||
data.collarRows = collarDevices || [];
|
||||
data.collarTotal = collarDevices.length || 0;
|
||||
console.log('=== 设置后的collarRows:', data.collarRows);
|
||||
console.log('=== 设置后的collarTotal:', data.collarTotal);
|
||||
|
||||
} else {
|
||||
ElMessage.error(res.msg);
|
||||
data.collarTotal = 0;
|
||||
@@ -942,9 +922,7 @@ const getCollarList = () => {
|
||||
});
|
||||
};
|
||||
const collarLogClick = (row) => {
|
||||
console.log('=== 智能项圈日志点击 ===');
|
||||
console.log('设备信息:', row);
|
||||
|
||||
|
||||
data.sn = row.sn || row.deviceId || '';
|
||||
data.collarDialogVisible = true;
|
||||
|
||||
@@ -953,13 +931,12 @@ const collarLogClick = (row) => {
|
||||
deviceId: data.sn,
|
||||
deliveryId: parseInt(route.query.id)
|
||||
}).then((res) => {
|
||||
console.log('=== 智能项圈日志API返回结果:', res);
|
||||
|
||||
if (res.code === 200) {
|
||||
// 新API返回的是按60分钟分组的日志数据
|
||||
data.collarLogRows = res.data || [];
|
||||
data.collarLogTotal = res.data.length || 0;
|
||||
console.log('=== 设置后的collarLogRows:', data.collarLogRows);
|
||||
console.log('=== 设置后的collarLogTotal:', data.collarLogTotal);
|
||||
|
||||
} else {
|
||||
ElMessage.error(res.msg || '获取智能项圈日志失败');
|
||||
data.collarLogRows = [];
|
||||
@@ -1054,20 +1031,17 @@ const getCollarLogList = () => {
|
||||
};
|
||||
// 查看运动轨迹
|
||||
const collarTrackClick = (row) => {
|
||||
console.log('=== 智能项圈运动轨迹点击 ===');
|
||||
console.log('设备信息:', row);
|
||||
|
||||
|
||||
// 调用新的API获取60分钟间隔的轨迹数据
|
||||
getCollarTrajectory({
|
||||
deviceId: row.sn || row.deviceId || '',
|
||||
deliveryId: parseInt(route.query.id)
|
||||
}).then((res) => {
|
||||
console.log('=== 智能项圈轨迹API返回结果:', res);
|
||||
|
||||
if (res.code === 200 && res.data && res.data.length > 0) {
|
||||
// 新API返回的是按60分钟分组的轨迹点数据
|
||||
const trajectoryPoints = res.data;
|
||||
console.log('=== 轨迹点数据:', trajectoryPoints);
|
||||
|
||||
|
||||
// 使用TrackDialog显示轨迹
|
||||
if (TrackDialogRef.value) {
|
||||
const info = {
|
||||
@@ -1089,9 +1063,7 @@ const collarTrackClick = (row) => {
|
||||
|
||||
// 智能主机操作函数
|
||||
const hostLogClick = (row) => {
|
||||
console.log('=== 智能主机日志点击 ===');
|
||||
console.log('设备信息:', row);
|
||||
|
||||
|
||||
data.deviceId = row.deviceId || row.sn || '';
|
||||
data.hostLogDialogVisible = true;
|
||||
|
||||
@@ -1100,13 +1072,12 @@ const hostLogClick = (row) => {
|
||||
deviceId: data.deviceId,
|
||||
deliveryId: parseInt(route.query.id)
|
||||
}).then((res) => {
|
||||
console.log('=== 智能主机日志API返回结果:', res);
|
||||
|
||||
if (res.code === 200) {
|
||||
// 新API返回的是按60分钟分组的日志数据
|
||||
data.hostLogRows = res.data || [];
|
||||
data.hostLogTotal = res.data.length || 0;
|
||||
console.log('=== 设置后的hostLogRows:', data.hostLogRows);
|
||||
console.log('=== 设置后的hostLogTotal:', data.hostLogTotal);
|
||||
|
||||
} else {
|
||||
ElMessage.error(res.msg || '获取智能主机日志失败');
|
||||
data.hostLogRows = [];
|
||||
@@ -1121,20 +1092,17 @@ const hostLogClick = (row) => {
|
||||
};
|
||||
|
||||
const hostTrackClick = (row) => {
|
||||
console.log('=== 智能主机运动轨迹点击 ===');
|
||||
console.log('设备信息:', row);
|
||||
|
||||
|
||||
// 调用新的API获取60分钟间隔的轨迹数据
|
||||
getHostTrajectory({
|
||||
deviceId: row.deviceId || row.sn || '',
|
||||
deliveryId: parseInt(route.query.id)
|
||||
}).then((res) => {
|
||||
console.log('=== 智能主机轨迹API返回结果:', res);
|
||||
|
||||
if (res.code === 200 && res.data && res.data.length > 0) {
|
||||
// 新API返回的是按60分钟分组的轨迹点数据
|
||||
const trajectoryPoints = res.data;
|
||||
console.log('=== 轨迹点数据:', trajectoryPoints);
|
||||
|
||||
|
||||
// 使用TrackDialog显示轨迹
|
||||
if (TrackDialogRef.value) {
|
||||
const info = {
|
||||
@@ -1167,7 +1135,7 @@ const totalRegisteredDevices = computed(() => {
|
||||
const earCount = data.total || 0;
|
||||
const collarCount = data.collarTotal || 0;
|
||||
const total = hostCount + earCount + collarCount;
|
||||
console.log('=== 计算设备总数 - 主机:', hostCount, '耳标:', earCount, '项圈:', collarCount, '总计:', total);
|
||||
|
||||
return total;
|
||||
});
|
||||
|
||||
@@ -1195,9 +1163,7 @@ onMounted(() => {
|
||||
data.status = route.query.status;
|
||||
data.length = route.query.length;
|
||||
|
||||
console.log('=== 详情页面初始化,deliveryId:', route.query.id);
|
||||
console.log('=== 路由参数:', route.query);
|
||||
|
||||
|
||||
// 检查deliveryId是否存在
|
||||
if (!route.query.id) {
|
||||
console.warn('=== 警告:deliveryId为空,无法加载详情页面');
|
||||
@@ -1208,7 +1174,7 @@ onMounted(() => {
|
||||
// 检查deliveryId是否存在,存在时才测试设备关联情况
|
||||
testDeliveryDevices({ deliveryId: route.query.id })
|
||||
.then(res => {
|
||||
console.log('=== 测试设备关联结果:', res);
|
||||
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('=== 测试设备关联失败:', err);
|
||||
|
||||
@@ -172,7 +172,7 @@ const goBack = () => {
|
||||
|
||||
// Tab切换
|
||||
const handleTabChange = (tabName) => {
|
||||
console.log('切换到Tab:', tabName);
|
||||
|
||||
};
|
||||
|
||||
// 获取智能主机列表
|
||||
@@ -191,7 +191,7 @@ const getHostList = async () => {
|
||||
deviceType: 1,
|
||||
});
|
||||
|
||||
console.log('主机设备API返回:', res);
|
||||
|
||||
if (res.code === 200) {
|
||||
const hostDevices = res.data.filter(device => device.deviceType === 1 || device.deviceType === '1');
|
||||
hostList.value = hostDevices || [];
|
||||
@@ -223,7 +223,7 @@ const getEarList = async () => {
|
||||
deviceType: 2,
|
||||
});
|
||||
|
||||
console.log('耳标设备API返回:', res);
|
||||
|
||||
if (res.code === 200) {
|
||||
const earDevices = res.data.filter(device => device.deviceType === 2 || device.deviceType === '2');
|
||||
earList.value = earDevices || [];
|
||||
@@ -255,7 +255,7 @@ const getCollarList = async () => {
|
||||
deviceType: 4,
|
||||
});
|
||||
|
||||
console.log('项圈设备API返回:', res);
|
||||
|
||||
if (res.code === 200) {
|
||||
const collarDevices = res.data.filter(device => device.deviceType === 4 || device.deviceType === '4');
|
||||
collarList.value = collarDevices || [];
|
||||
@@ -310,8 +310,6 @@ const unbindDevice = (device, deviceType) => {
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
console.log('设备管理页面初始化,deliveryId:', route.query.deliveryId);
|
||||
console.log('运单号:', route.query.deliveryNumber);
|
||||
|
||||
if (!route.query.deliveryId) {
|
||||
console.warn('deliveryId为空,无法加载设备列表');
|
||||
|
||||
@@ -112,7 +112,7 @@ const getList = async () => {
|
||||
const searchClick = async () => {
|
||||
form.pageNum = 1;
|
||||
await getList();
|
||||
console.log('searchClick');
|
||||
|
||||
};
|
||||
const resetClick = async (el) => {
|
||||
form.pageNum = 1;
|
||||
|
||||
@@ -103,7 +103,7 @@ const getList = async () => {
|
||||
const searchClick = async () => {
|
||||
form.pageNum = 1;
|
||||
await getList();
|
||||
console.log('searchClick');
|
||||
|
||||
};
|
||||
const resetClick = async (el) => {
|
||||
form.pageNum = 1;
|
||||
|
||||
@@ -185,8 +185,7 @@ const getTrack = () => {
|
||||
})
|
||||
.then((res) => {
|
||||
data.trackLoading = false;
|
||||
console.log('=== 查询轨迹API返回结果:', res);
|
||||
|
||||
|
||||
if (res.code === 200 && res.data && res.data.length > 0) {
|
||||
data.mapShow = true;
|
||||
data.path = [];
|
||||
@@ -206,14 +205,14 @@ const getTrack = () => {
|
||||
if (data.path.length > 0) {
|
||||
data.startMark = data.path[0];
|
||||
data.endMark = data.path[data.path.length - 1];
|
||||
console.log('轨迹查询成功,共', data.path.length, '个轨迹点');
|
||||
|
||||
} else {
|
||||
console.log('没有有效的轨迹点');
|
||||
|
||||
data.noTrack = true;
|
||||
ElMessage.warning('该时间范围内暂无有效轨迹点');
|
||||
}
|
||||
} else {
|
||||
console.log('没有轨迹数据');
|
||||
|
||||
ElMessage.warning('该时间范围内暂无轨迹数据');
|
||||
data.noTrack = true;
|
||||
}
|
||||
@@ -305,18 +304,14 @@ const onShowTrackDialog = (row) => {
|
||||
|
||||
// 如果传入了trajectoryPoints,直接使用这些轨迹点
|
||||
if (row.trajectoryPoints && row.trajectoryPoints.length > 0) {
|
||||
console.log('=== trackDialog: 直接使用传入的轨迹点 ===');
|
||||
console.log('轨迹点数量:', row.trajectoryPoints.length);
|
||||
console.log('轨迹点数据:', row.trajectoryPoints);
|
||||
|
||||
|
||||
data.mapShow = true;
|
||||
data.path = [];
|
||||
row.trajectoryPoints.forEach((item, index) => {
|
||||
const lng = parseFloat(item.longitude || item.lng || 0);
|
||||
const lat = parseFloat(item.latitude || item.lat || 0);
|
||||
|
||||
console.log(`轨迹点${index}: latitude=${item.latitude}, longitude=${item.longitude}, lng=${lng}, lat=${lat}`);
|
||||
|
||||
|
||||
// 检查经纬度是否有效
|
||||
if (lng !== 0 && lat !== 0 && !isNaN(lng) && !isNaN(lat)) {
|
||||
data.path.push({
|
||||
@@ -328,13 +323,11 @@ const onShowTrackDialog = (row) => {
|
||||
}
|
||||
});
|
||||
|
||||
console.log('最终path数据:', data.path);
|
||||
|
||||
|
||||
if (data.path.length > 0) {
|
||||
data.startMark = data.path[0]; // 起点
|
||||
data.endMark = data.path[data.path.length - 1]; // 终点
|
||||
console.log('起点:', data.startMark);
|
||||
console.log('终点:', data.endMark);
|
||||
|
||||
} else {
|
||||
console.error('没有有效的轨迹点,显示空状态');
|
||||
data.noTrack = true;
|
||||
|
||||
@@ -200,17 +200,11 @@ const onSubmit = async (val) => {
|
||||
const generateRoutes = async () => {
|
||||
try {
|
||||
const ret = await getUserMenu();
|
||||
console.log('=== 获取用户菜单 ===', ret.data);
|
||||
|
||||
|
||||
// 检查用户权限
|
||||
const userStore = useUserStore();
|
||||
const isSuperAdmin = userStore.permissions.includes('*:*:*') || userStore.roles.includes('admin');
|
||||
console.log('=== 用户权限检查 ===', {
|
||||
permissions: userStore.permissions,
|
||||
roles: userStore.roles,
|
||||
isSuperAdmin: isSuperAdmin
|
||||
});
|
||||
|
||||
|
||||
// 查找第一个有pageUrl的菜单项(type=1表示菜单)
|
||||
const findFirstMenuWithUrl = (menus) => {
|
||||
// 按sort排序,确保按顺序查找
|
||||
@@ -219,7 +213,7 @@ const generateRoutes = async () => {
|
||||
for (const menu of sortedMenus) {
|
||||
// 查找type=1(菜单)且有pageUrl的项目
|
||||
if (menu.type === 1 && menu.pageUrl) {
|
||||
console.log('=== 找到第一个菜单页面 ===', menu);
|
||||
|
||||
return menu;
|
||||
}
|
||||
}
|
||||
@@ -234,15 +228,15 @@ const generateRoutes = async () => {
|
||||
if (isSuperAdmin) {
|
||||
// 超级管理员优先跳转到系统管理页面
|
||||
targetPath = '/system/post';
|
||||
console.log('=== 超级管理员,跳转到系统管理页面 ===', targetPath);
|
||||
|
||||
} else if (firstMenu && firstMenu.pageUrl) {
|
||||
// 普通用户跳转到第一个有权限的菜单页面
|
||||
targetPath = firstMenu.pageUrl;
|
||||
console.log('=== 普通用户,跳转到第一个菜单页面 ===', targetPath);
|
||||
|
||||
} else {
|
||||
// 默认跳转到装车订单页面
|
||||
targetPath = '/shipping/loadingOrder';
|
||||
console.log('=== 没有找到有效菜单,跳转到默认页面 ===', targetPath);
|
||||
|
||||
}
|
||||
|
||||
// 等待路由完全生成后再执行跳转
|
||||
@@ -251,7 +245,7 @@ const generateRoutes = async () => {
|
||||
// 确保权限store的路由生成完成
|
||||
const permissionStore = usePermissionStore();
|
||||
if (!permissionStore.routeFlag) {
|
||||
console.log('=== 等待路由生成完成 ===');
|
||||
|
||||
await permissionStore.generateRoutes();
|
||||
}
|
||||
|
||||
@@ -263,13 +257,13 @@ const generateRoutes = async () => {
|
||||
// 使用replace而不是push,避免路由警告
|
||||
try {
|
||||
await router.replace({ path: targetPath });
|
||||
console.log('=== 成功跳转到目标页面 ===', targetPath);
|
||||
|
||||
} catch (error) {
|
||||
console.warn('Failed to navigate to', targetPath, 'error:', error);
|
||||
// 如果跳转失败,尝试跳转到首页
|
||||
try {
|
||||
await router.replace({ path: '/' });
|
||||
console.log('=== 跳转到首页 ===');
|
||||
|
||||
} catch (homeError) {
|
||||
console.error('Failed to navigate to home:', homeError);
|
||||
}
|
||||
@@ -280,7 +274,7 @@ const generateRoutes = async () => {
|
||||
// 获取菜单失败时跳转到首页
|
||||
try {
|
||||
await router.push({ path: '/' });
|
||||
console.log('=== 获取菜单失败,跳转到首页 ===');
|
||||
|
||||
} catch (navError) {
|
||||
console.error('Failed to navigate to home:', navError);
|
||||
}
|
||||
|
||||
@@ -226,10 +226,7 @@ const loadUserList = async () => {
|
||||
const handleUserChange = async (row) => {
|
||||
if (!row) return;
|
||||
|
||||
console.log('=== 菜单权限管理 - 用户选择改变 ===');
|
||||
console.log('选择的用户:', row);
|
||||
console.log('用户ID:', row.id);
|
||||
|
||||
|
||||
currentUser.value = row;
|
||||
await loadMenuTree();
|
||||
await loadUserMenus(row.id);
|
||||
@@ -244,7 +241,7 @@ const loadMenuTree = async () => {
|
||||
// 过滤掉按钮权限(type=2),只保留菜单(type=0,1)
|
||||
const filteredTree = filterMenuTree(res.data || []);
|
||||
menuTree.value = filteredTree;
|
||||
console.log('=== 菜单权限管理 - 过滤后的菜单树 ===', filteredTree);
|
||||
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载菜单树失败:', error);
|
||||
@@ -285,12 +282,7 @@ const loadUserMenus = async (userId) => {
|
||||
const menuOnlyIds = await filterMenuOnlyIds(allMenuIds);
|
||||
checkedMenuIds.value = menuOnlyIds;
|
||||
|
||||
console.log('=== 菜单权限管理 - 过滤后的菜单权限 ===', {
|
||||
userId: userId,
|
||||
allMenuIds: allMenuIds,
|
||||
menuOnlyIds: menuOnlyIds
|
||||
});
|
||||
|
||||
|
||||
await nextTick();
|
||||
if (menuTreeRef.value) {
|
||||
menuTreeRef.value.setCheckedKeys(checkedMenuIds.value);
|
||||
@@ -369,11 +361,6 @@ const handleSaveMenuPermissions = async () => {
|
||||
// 过滤掉按钮权限,只保留菜单权限
|
||||
const menuOnlyIds = await filterMenuOnlyIds(allKeys);
|
||||
|
||||
console.log('=== 保存菜单权限 ===', {
|
||||
user: currentUser.value,
|
||||
allKeys: allKeys,
|
||||
menuOnlyIds: menuOnlyIds
|
||||
});
|
||||
|
||||
saveLoading.value = true;
|
||||
try {
|
||||
@@ -390,7 +377,7 @@ const handleSaveMenuPermissions = async () => {
|
||||
const permissionStore = usePermissionStore();
|
||||
await permissionStore.refreshPermissions();
|
||||
ElMessage.success('权限已保存并刷新成功!');
|
||||
console.log('权限数据已刷新');
|
||||
|
||||
} catch (error) {
|
||||
console.error('刷新权限失败:', error);
|
||||
ElMessage.warning('权限已保存,但刷新失败,请手动刷新页面');
|
||||
@@ -443,12 +430,6 @@ const handleQuickAssignAll = async () => {
|
||||
const menuOnlyMenus = allMenus.filter(menu => menu.type !== 2);
|
||||
const menuOnlyIds = menuOnlyMenus.map(menu => menu.id);
|
||||
|
||||
console.log('=== 一键分配全部菜单权限 ===', {
|
||||
user: currentUser.value,
|
||||
totalMenus: allMenus.length,
|
||||
menuOnlyMenus: menuOnlyMenus.length,
|
||||
menuOnlyIds: menuOnlyIds
|
||||
});
|
||||
|
||||
// 分配所有菜单权限
|
||||
const res = await assignUserMenus({
|
||||
@@ -467,7 +448,7 @@ const handleQuickAssignAll = async () => {
|
||||
const permissionStore = usePermissionStore();
|
||||
await permissionStore.refreshPermissions();
|
||||
ElMessage.success('权限已保存并刷新成功!');
|
||||
console.log('权限数据已刷新');
|
||||
|
||||
} catch (error) {
|
||||
console.error('刷新权限失败:', error);
|
||||
ElMessage.warning('权限已保存,但刷新失败,请手动刷新页面');
|
||||
@@ -525,7 +506,7 @@ const handleClearUserPermissions = async () => {
|
||||
const permissionStore = usePermissionStore();
|
||||
await permissionStore.refreshPermissions();
|
||||
ElMessage.success('权限已清空并刷新成功!');
|
||||
console.log('权限数据已刷新');
|
||||
|
||||
} catch (error) {
|
||||
console.error('刷新权限失败:', error);
|
||||
ElMessage.warning('权限已清空,但刷新失败,请手动刷新页面');
|
||||
|
||||
@@ -184,10 +184,7 @@ const loadUserList = async () => {
|
||||
const handleUserChange = async (row) => {
|
||||
if (!row) return;
|
||||
|
||||
console.log('=== 操作权限管理 - 用户选择改变 ===');
|
||||
console.log('选择的用户:', row);
|
||||
console.log('用户ID:', row.id);
|
||||
|
||||
|
||||
currentUser.value = row;
|
||||
await loadPermissionTree();
|
||||
await loadUserPermissions(row.id);
|
||||
@@ -195,22 +192,18 @@ const handleUserChange = async (row) => {
|
||||
|
||||
// 加载用户已分配的权限
|
||||
const loadUserPermissions = async (userId) => {
|
||||
console.log('=== 加载用户权限 ===');
|
||||
console.log('userId:', userId);
|
||||
|
||||
|
||||
try {
|
||||
const res = await getUserMenuIds(userId);
|
||||
console.log('用户权限API响应:', res);
|
||||
|
||||
|
||||
if (res.code === 200) {
|
||||
const menuIds = res.data || [];
|
||||
console.log('已分配的用户权限IDs:', menuIds);
|
||||
|
||||
|
||||
// 设置权限树选中状态
|
||||
await nextTick();
|
||||
if (userPermissionTreeRef.value) {
|
||||
userPermissionTreeRef.value.setCheckedKeys(menuIds);
|
||||
console.log('用户权限树已设置选中状态');
|
||||
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -242,39 +235,29 @@ const handleSaveUserPermissions = async () => {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('=== 保存用户权限 ===');
|
||||
console.log('当前用户:', currentUser.value);
|
||||
|
||||
// 获取选中的节点
|
||||
const checkedKeys = userPermissionTreeRef.value.getCheckedKeys();
|
||||
const halfCheckedKeys = userPermissionTreeRef.value.getHalfCheckedKeys();
|
||||
const allKeys = [...checkedKeys, ...halfCheckedKeys];
|
||||
|
||||
console.log('选中的权限IDs:', checkedKeys);
|
||||
console.log('半选中的权限IDs:', halfCheckedKeys);
|
||||
console.log('所有权限IDs:', allKeys);
|
||||
|
||||
const saveData = {
|
||||
userId: currentUser.value.id,
|
||||
menuIds: allKeys,
|
||||
};
|
||||
console.log('保存数据:', saveData);
|
||||
|
||||
saveLoading.value = true;
|
||||
try {
|
||||
const res = await assignUserMenus(saveData);
|
||||
console.log('保存API响应:', res);
|
||||
|
||||
if (res.code === 200) {
|
||||
ElMessage.success(`用户 ${currentUser.value.name} 的操作权限保存成功!`);
|
||||
console.log('用户权限保存成功');
|
||||
|
||||
|
||||
// 权限保存成功后,刷新权限数据
|
||||
try {
|
||||
const permissionStore = usePermissionStore();
|
||||
await permissionStore.refreshPermissions();
|
||||
ElMessage.success('权限已保存并刷新成功!');
|
||||
console.log('权限数据已刷新');
|
||||
|
||||
} catch (error) {
|
||||
console.error('刷新权限失败:', error);
|
||||
ElMessage.warning('权限已保存,但刷新失败,请手动刷新页面');
|
||||
@@ -314,18 +297,13 @@ const handleClearUserPermissions = async () => {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('=== 清空用户权限 ===');
|
||||
console.log('当前用户:', currentUser.value);
|
||||
|
||||
clearLoading.value = true;
|
||||
try {
|
||||
const res = await clearUserMenus(currentUser.value.id);
|
||||
console.log('清空API响应:', res);
|
||||
|
||||
if (res.code === 200) {
|
||||
ElMessage.success(`用户 ${currentUser.value.name} 的权限已清空!`);
|
||||
console.log('用户权限清空成功');
|
||||
|
||||
|
||||
// 重新加载用户权限(显示空权限)
|
||||
await loadUserPermissions(currentUser.value.id);
|
||||
|
||||
@@ -334,7 +312,7 @@ const handleClearUserPermissions = async () => {
|
||||
const permissionStore = usePermissionStore();
|
||||
await permissionStore.refreshPermissions();
|
||||
ElMessage.success('权限已清空并刷新成功!');
|
||||
console.log('权限数据已刷新');
|
||||
|
||||
} catch (error) {
|
||||
console.error('刷新权限失败:', error);
|
||||
ElMessage.warning('权限已清空,但刷新失败,请手动刷新页面');
|
||||
|
||||
@@ -106,8 +106,7 @@ const getDataList = async () => {
|
||||
data.dataListLoading = true;
|
||||
|
||||
try {
|
||||
console.log('开始查询可分配设备列表...');
|
||||
|
||||
|
||||
const params = {
|
||||
pageNum: form.pageNum,
|
||||
pageSize: form.pageSize,
|
||||
@@ -115,11 +114,9 @@ const getDataList = async () => {
|
||||
deviceType: data.deviceType ? parseInt(data.deviceType) : null,
|
||||
};
|
||||
|
||||
console.log('查询参数:', params);
|
||||
|
||||
|
||||
const res = await iotDeviceAssignableList(params);
|
||||
console.log('API返回结果:', res);
|
||||
|
||||
|
||||
if (res.code === 200) {
|
||||
const rawData = res.data?.rows || [];
|
||||
const total = res.data?.total || 0;
|
||||
@@ -144,21 +141,14 @@ const getDataList = async () => {
|
||||
break;
|
||||
}
|
||||
|
||||
console.log(`处理设备 ${item.deviceId}:`, {
|
||||
deviceType: item.deviceType,
|
||||
deviceTypeName: processedItem.deviceTypeName,
|
||||
isAssigned: item.isAssigned
|
||||
});
|
||||
|
||||
|
||||
return processedItem;
|
||||
});
|
||||
|
||||
data.total = total;
|
||||
data.dataListLoading = false;
|
||||
|
||||
console.log('最终可分配设备列表:', data.rows);
|
||||
console.log('总设备数量:', data.total);
|
||||
|
||||
|
||||
} else {
|
||||
console.error('API返回错误:', res);
|
||||
data.dataListLoading = false;
|
||||
@@ -199,13 +189,12 @@ const onClickSave = () => {
|
||||
carNumber: data.licensePlate, // 车牌号
|
||||
};
|
||||
|
||||
console.log('设备分配参数:', params);
|
||||
|
||||
|
||||
data.saveLoading = true;
|
||||
iotDeviceAssign(params)
|
||||
.then((res) => {
|
||||
data.saveLoading = false;
|
||||
console.log('设备分配结果:', res);
|
||||
|
||||
if (res.code === 200) {
|
||||
ElMessage({
|
||||
message: res.msg,
|
||||
|
||||
@@ -856,8 +856,7 @@ const buildSubmitData = () => {
|
||||
}
|
||||
});
|
||||
|
||||
console.log('[buildSubmitData] 最终提交数据(已处理undefined):', data);
|
||||
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
@@ -874,9 +873,7 @@ const open = async (editData = null) => {
|
||||
loadOrderList()
|
||||
]);
|
||||
|
||||
console.log('[OPEN-DIALOG] 所有下拉列表加载完成');
|
||||
console.log('[OPEN-DIALOG] 车辆列表:', vehicleOptions.value);
|
||||
|
||||
|
||||
// 如果传入了编辑数据,则填充表单
|
||||
if (editData) {
|
||||
fillFormWithEditData(editData);
|
||||
@@ -885,8 +882,7 @@ const open = async (editData = null) => {
|
||||
|
||||
// 填充编辑数据到表单
|
||||
const fillFormWithEditData = (editData) => {
|
||||
console.log('[EDIT-FILL] 开始填充编辑数据:', editData);
|
||||
|
||||
|
||||
// editData 包含两个部分:
|
||||
// 1. editData.delivery - 运单基本信息
|
||||
// 2. editData 的根级字段 - supplierId, buyerId, eartagIds, collarIds, serverIds
|
||||
@@ -899,13 +895,10 @@ const fillFormWithEditData = (editData) => {
|
||||
// 发货方和采购方:优先使用根级的 supplierId 和 buyerId
|
||||
formData.shipper = editData.supplierId || (delivery.supplierId ? parseInt(delivery.supplierId) : null);
|
||||
formData.buyer = editData.buyerId || delivery.buyerId || null;
|
||||
console.log('[EDIT-FILL] 发货方ID:', formData.shipper, '采购方ID:', formData.buyer);
|
||||
|
||||
|
||||
// 车牌号
|
||||
formData.plateNumber = delivery.licensePlate || '';
|
||||
console.log('[EDIT-FILL] 车牌号:', formData.plateNumber);
|
||||
console.log('[EDIT-FILL] 当前车辆列表:', vehicleOptions.value);
|
||||
|
||||
|
||||
// 检查车牌号是否在车辆列表中
|
||||
const vehicleExists = vehicleOptions.value.find(v => v.licensePlate === formData.plateNumber);
|
||||
if (!vehicleExists && formData.plateNumber) {
|
||||
@@ -918,17 +911,17 @@ const fillFormWithEditData = (editData) => {
|
||||
// 设备信息:从根级读取
|
||||
if (editData.serverIds && editData.serverIds !== '') {
|
||||
formData.serverId = editData.serverIds;
|
||||
console.log('[EDIT-FILL] 主机ID:', formData.serverId);
|
||||
|
||||
}
|
||||
|
||||
if (editData.eartagIds && Array.isArray(editData.eartagIds) && editData.eartagIds.length > 0) {
|
||||
formData.eartagIds = editData.eartagIds;
|
||||
console.log('[EDIT-FILL] 耳标IDs:', formData.eartagIds);
|
||||
|
||||
}
|
||||
|
||||
if (editData.collarIds && Array.isArray(editData.collarIds) && editData.collarIds.length > 0) {
|
||||
formData.collarIds = editData.collarIds;
|
||||
console.log('[EDIT-FILL] 项圈IDs:', formData.collarIds);
|
||||
|
||||
}
|
||||
|
||||
// 地址和坐标
|
||||
@@ -972,7 +965,7 @@ const fillFormWithEditData = (editData) => {
|
||||
// 保存编辑的ID,用于区分是新增还是编辑
|
||||
formData.editId = delivery.id;
|
||||
|
||||
console.log('[EDIT-FILL] 表单数据已填充:', formData);
|
||||
|
||||
ElMessage.success('已加载运单数据');
|
||||
};
|
||||
|
||||
@@ -1109,8 +1102,7 @@ const handleOrderChange = async (orderId) => {
|
||||
formData.shipper = sellerId ? parseInt(sellerId) : null;
|
||||
formData.buyer = buyerId ? parseInt(buyerId) : null;
|
||||
|
||||
console.log('[订单选择] 选中的订单ID:', orderId);
|
||||
console.log('[订单选择] orderId已保存到formData.orderId:', formData.orderId);
|
||||
|
||||
ElMessage.success('已自动填充发货方和采购方信息');
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -1128,15 +1120,15 @@ const handleDriverChange = (driverId) => {
|
||||
const driver = driverOptions.value.find(item => item.id === driverId);
|
||||
if (driver && driver.mobile) {
|
||||
formData.driverPhone = driver.mobile;
|
||||
console.log('[司机选择] 司机ID:', driverId, ', 已自动填充手机号:', driver.mobile);
|
||||
|
||||
ElMessage.success('已自动填充司机手机号');
|
||||
} else {
|
||||
console.log('[司机选择] 司机ID:', driverId, ', 但未找到手机号');
|
||||
|
||||
}
|
||||
} else {
|
||||
formData.driverId = null;
|
||||
formData.driverPhone = '';
|
||||
console.log('[司机选择] 司机已清除');
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1195,7 +1187,7 @@ const updateSelectedDevicesDeliveryId = async (deliveryId) => {
|
||||
});
|
||||
}
|
||||
|
||||
console.log(`成功更新 ${devicesToUpdate.length} 个设备的delivery_id和car_number: ${formData.plateNumber}`);
|
||||
|
||||
} catch (error) {
|
||||
console.error('更新设备delivery_id和car_number失败:', error);
|
||||
// 不阻止流程,只记录错误
|
||||
@@ -1222,15 +1214,13 @@ const handleSubmit = () => {
|
||||
console.group('[CREATE-DELIVERY] 提交前检查');
|
||||
try {
|
||||
const formSnapshot = JSON.parse(JSON.stringify(formData));
|
||||
console.log('表单快照 formData:', formSnapshot);
|
||||
console.log('地图坐标校验: startLon/startLat/endLon/endLat =', formData.startLon, formData.startLat, formData.endLon, formData.endLat);
|
||||
console.log('Token 是否存在:', !!userStore.$state.token);
|
||||
|
||||
} catch (e) {
|
||||
console.warn('表单快照序列化失败:', e);
|
||||
}
|
||||
|
||||
const submitData = buildSubmitData();
|
||||
console.log('最终请求体 payload:', submitData);
|
||||
|
||||
console.table(Object.keys(submitData).map(k => ({ key: k, type: typeof submitData[k], value: Array.isArray(submitData[k]) ? `Array(len=${submitData[k].length})` : submitData[k] })));
|
||||
if (submitData.eartagIds && submitData.eartagIds.some(v => typeof v === 'string')) {
|
||||
console.warn('eartagIds 仍包含字符串,将被后端拒绝:', submitData.eartagIds);
|
||||
@@ -1244,17 +1234,17 @@ const handleSubmit = () => {
|
||||
// 判断是编辑还是新增
|
||||
if (formData.editId) {
|
||||
// 编辑模式:调用更新接口
|
||||
console.log('[EDIT-DELIVERY] 编辑模式,运单ID:', formData.editId);
|
||||
|
||||
submitData.deliveryId = formData.editId; // 添加deliveryId字段(后端需要)
|
||||
res = await shippingApi.updateDeliveryInfo(submitData);
|
||||
} else {
|
||||
// 新增模式:调用创建接口
|
||||
console.log('[CREATE-DELIVERY] 新增模式');
|
||||
|
||||
res = await createDelivery(submitData);
|
||||
}
|
||||
|
||||
console.group(formData.editId ? '[EDIT-DELIVERY] 响应日志' : '[CREATE-DELIVERY] 响应日志');
|
||||
console.log('完整响应:', res);
|
||||
|
||||
console.groupEnd();
|
||||
|
||||
if (res.code === 200) {
|
||||
@@ -1324,10 +1314,10 @@ const handleStartMarkerDrag = (e) => {
|
||||
|
||||
// 打开起点地图并处理地址搜索
|
||||
const openStartLocationMap = () => {
|
||||
console.log('openStartLocationMap 被调用');
|
||||
|
||||
// 如果输入框有地址,先进行地理编码
|
||||
if (formData.startLocation && formData.startLocation.trim()) {
|
||||
console.log('搜索起点地址:', formData.startLocation);
|
||||
|
||||
// 先打开地图对话框,让地图组件加载
|
||||
showStartLocationMap.value = true;
|
||||
|
||||
@@ -1339,31 +1329,31 @@ const openStartLocationMap = () => {
|
||||
const geocoder = new window.BMap.Geocoder();
|
||||
geocoder.getPoint(formData.startLocation, (point) => {
|
||||
if (point) {
|
||||
console.log('找到起点坐标:', point.lng, point.lat);
|
||||
|
||||
// 搜索到坐标,更新地图中心点和标记
|
||||
formData.startLon = point.lng;
|
||||
formData.startLat = point.lat;
|
||||
// 更新地图中心点
|
||||
ElMessage.success('已定位到该地址');
|
||||
} else {
|
||||
console.log('未找到起点地址');
|
||||
|
||||
ElMessage.warning('未找到该地址,请在地图上手动选择');
|
||||
}
|
||||
});
|
||||
}
|
||||
}, 500);
|
||||
} else {
|
||||
console.log('未输入起点地址,直接打开地图');
|
||||
|
||||
showStartLocationMap.value = true;
|
||||
}
|
||||
};
|
||||
|
||||
// 打开目的地地图并处理地址搜索
|
||||
const openEndLocationMap = () => {
|
||||
console.log('openEndLocationMap 被调用');
|
||||
|
||||
// 如果输入框有地址,先进行地理编码
|
||||
if (formData.endLocation && formData.endLocation.trim()) {
|
||||
console.log('搜索目的地地址:', formData.endLocation);
|
||||
|
||||
// 先打开地图对话框,让地图组件加载
|
||||
showEndLocationMap.value = true;
|
||||
|
||||
@@ -1373,21 +1363,21 @@ const openEndLocationMap = () => {
|
||||
const geocoder = new window.BMap.Geocoder();
|
||||
geocoder.getPoint(formData.endLocation, (point) => {
|
||||
if (point) {
|
||||
console.log('找到目的地坐标:', point.lng, point.lat);
|
||||
|
||||
// 搜索到坐标,更新地图中心点和标记
|
||||
formData.endLon = point.lng;
|
||||
formData.endLat = point.lat;
|
||||
// 更新地图中心点
|
||||
ElMessage.success('已定位到该地址');
|
||||
} else {
|
||||
console.log('未找到目的地地址');
|
||||
|
||||
ElMessage.warning('未找到该地址,请在地图上手动选择');
|
||||
}
|
||||
});
|
||||
}
|
||||
}, 500);
|
||||
} else {
|
||||
console.log('未输入目的地地址,直接打开地图');
|
||||
|
||||
showEndLocationMap.value = true;
|
||||
}
|
||||
};
|
||||
@@ -1428,7 +1418,7 @@ const makeUploadSuccessSetter = (key) => (response) => {
|
||||
const url = resolveUploadUrl(response);
|
||||
if (response?.code === 200 && url) {
|
||||
formData[key] = url;
|
||||
console.log(`[UPLOAD] ${key} =`, url);
|
||||
|
||||
ElMessage.success('上传成功');
|
||||
} else {
|
||||
console.warn(`[UPLOAD] 未识别的响应结构:`, response);
|
||||
|
||||
@@ -632,7 +632,7 @@ const onClickSave = () => {
|
||||
data.saveLoading = false;
|
||||
});
|
||||
} else {
|
||||
console.log('error submit!');
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -650,9 +650,8 @@ const onShowDialog = (val) => {
|
||||
if (val) {
|
||||
Object.assign(ruleForm, val);
|
||||
editId.value = val.id;
|
||||
console.log(val.supplierId);
|
||||
// console.log(data.purchaserOptions);
|
||||
// 资金方
|
||||
|
||||
// // 资金方
|
||||
if (data.financeOptions && data.financeOptions.length > 0) {
|
||||
const financeObj = data.financeOptions.find((item) => item.id == val.fundId);
|
||||
ruleForm.financeName = financeObj ? financeObj.mobile : '';
|
||||
@@ -663,7 +662,7 @@ const onShowDialog = (val) => {
|
||||
// 供应商
|
||||
if (val.supplierId && data.supplierOptions && data.supplierOptions.length > 0) {
|
||||
val.supplier = val.supplierId.split(',').map((id) => Number(id));
|
||||
console.log(val.supplier);
|
||||
|
||||
ruleForm.supplierName = data.supplierOptions.filter((supplier) => val.supplier.includes(supplier.id)).map((supplier) => supplier.mobile);
|
||||
} else {
|
||||
val.supplier = [];
|
||||
|
||||
@@ -450,16 +450,7 @@ const autoFillFormData = (apiData) => {
|
||||
ruleForm.controlSlotVideo = apiData.controlSlotVideo || '';
|
||||
ruleForm.cattleLoadingCircleVideo = apiData.cattleLoadingCircleVideo || '';
|
||||
|
||||
console.log('表单数据已自动填充:', ruleForm);
|
||||
console.log('API数据映射详情:', {
|
||||
deliveryId: apiData.id,
|
||||
estimatedDeliveryTime: apiData.estimatedDeliveryTime,
|
||||
emptyWeight: apiData.emptyWeight,
|
||||
entruckWeight: apiData.entruckWeight,
|
||||
landingEntruckWeight: apiData.landingEntruckWeight,
|
||||
quarantineTickeyUrl: apiData.quarantineTickeyUrl,
|
||||
poundListImg: apiData.poundListImg
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
// 查询详情
|
||||
@@ -468,10 +459,9 @@ const getOrderDetail = () => {
|
||||
orderLoadDetail({
|
||||
deliveryId: data.deliveryId,
|
||||
}).then((res) => {
|
||||
console.log('getOrderDetail API 响应:', res);
|
||||
|
||||
if (res.code === 200) {
|
||||
console.log('API 返回的数据:', res.data);
|
||||
|
||||
|
||||
// 自动填充表单数据
|
||||
autoFillFormData(res.data);
|
||||
|
||||
@@ -495,15 +485,12 @@ const getDevicesByOrder = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('=== 开始获取订单设备信息,deliveryId:', data.deliveryId);
|
||||
|
||||
|
||||
// 先调用测试接口检查订单设备数据
|
||||
testOrderDevices(parseInt(data.deliveryId)).then((res) => {
|
||||
console.log('=== 测试接口返回结果:', res);
|
||||
|
||||
if (res.code === 200) {
|
||||
console.log('=== 订单设备数据:', res.data);
|
||||
console.log('=== 设备总数:', res.data.totalDevices);
|
||||
console.log('=== 设备列表:', res.data.devices);
|
||||
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.error('=== 测试接口调用失败:', error);
|
||||
@@ -516,29 +503,22 @@ const getDevicesByOrder = () => {
|
||||
deliveryId: parseInt(data.deliveryId),
|
||||
deviceType: 2, // 智能耳标
|
||||
}).then((res) => {
|
||||
console.log('=== 智能耳标设备API返回结果:', res);
|
||||
console.log('=== API返回的原始数据:', res.data);
|
||||
console.log('=== 数据类型:', typeof res.data, '是否为数组:', Array.isArray(res.data));
|
||||
|
||||
if (res.code === 200) {
|
||||
if (res.data && Array.isArray(res.data)) {
|
||||
console.log('=== 原始设备数据:', res.data);
|
||||
|
||||
|
||||
// 过滤出智能耳标设备并转换为需要的格式
|
||||
const earDevices = res.data.filter(device => {
|
||||
console.log('=== 检查设备:', device, 'deviceType:', device.deviceType, '类型:', typeof device.deviceType);
|
||||
|
||||
return device.deviceType === 2 || device.deviceType === '2';
|
||||
});
|
||||
|
||||
console.log('=== 过滤后的智能耳标设备:', earDevices);
|
||||
|
||||
|
||||
data.deliveryDevices = earDevices.map(device => ({
|
||||
deviceId: device.deviceId,
|
||||
bindWeight: device.bindWeight || '', // 如果有绑定重量则使用,否则为空
|
||||
}));
|
||||
|
||||
console.log('=== 设置后的智能耳标设备:', data.deliveryDevices);
|
||||
console.log('=== data.deliveryDevices长度:', data.deliveryDevices.length);
|
||||
|
||||
} else {
|
||||
console.warn('API返回的数据不是数组格式:', res.data);
|
||||
data.deliveryDevices = [];
|
||||
@@ -559,29 +539,22 @@ const getDevicesByOrder = () => {
|
||||
deliveryId: parseInt(data.deliveryId),
|
||||
deviceType: 4, // 智能项圈
|
||||
}).then((res) => {
|
||||
console.log('=== 智能项圈设备API返回结果:', res);
|
||||
console.log('=== API返回的原始数据:', res.data);
|
||||
console.log('=== 数据类型:', typeof res.data, '是否为数组:', Array.isArray(res.data));
|
||||
|
||||
if (res.code === 200) {
|
||||
if (res.data && Array.isArray(res.data)) {
|
||||
console.log('=== 原始设备数据:', res.data);
|
||||
|
||||
|
||||
// 过滤出智能项圈设备并转换为需要的格式
|
||||
const collarDevices = res.data.filter(device => {
|
||||
console.log('=== 检查设备:', device, 'deviceType:', device.deviceType, '类型:', typeof device.deviceType);
|
||||
|
||||
return device.deviceType === 4 || device.deviceType === '4';
|
||||
});
|
||||
|
||||
console.log('=== 过滤后的智能项圈设备:', collarDevices);
|
||||
|
||||
|
||||
data.xqDevices = collarDevices.map(device => ({
|
||||
deviceId: device.deviceId,
|
||||
bindWeight: device.bindWeight || '', // 如果有绑定重量则使用,否则为空
|
||||
}));
|
||||
|
||||
console.log('=== 设置后的智能项圈设备:', data.xqDevices);
|
||||
console.log('=== data.xqDevices长度:', data.xqDevices.length);
|
||||
|
||||
} else {
|
||||
console.warn('API返回的数据不是数组格式:', res.data);
|
||||
data.xqDevices = [];
|
||||
@@ -615,7 +588,7 @@ const getHostList = () => {
|
||||
...(data.hostNumber ? { deviceId: data.hostNumber } : {}),
|
||||
// 不传递deliveryId,获取所有可用的主机
|
||||
}).then((res) => {
|
||||
console.log('=== 智能主机设备API返回结果:', res);
|
||||
|
||||
data.hostLoading = false;
|
||||
if (res.code === 200) {
|
||||
// 过滤出智能主机设备
|
||||
@@ -637,7 +610,7 @@ const getHostList = () => {
|
||||
}));
|
||||
|
||||
data.hostTotal = hostDevices.length;
|
||||
console.log('=== 设置后的智能主机选项:', data.hostOptions);
|
||||
|
||||
} else {
|
||||
console.error('获取智能主机设备失败:', res.msg);
|
||||
data.hostOptions = [];
|
||||
@@ -760,12 +733,9 @@ const onClickSave = () => {
|
||||
|
||||
// 确保 deliveryId 是数字类型
|
||||
const saveData = { ...ruleForm };
|
||||
console.log('保存时的 deliveryId:', saveData.deliveryId, '类型:', typeof saveData.deliveryId);
|
||||
console.log('选择的智能主机:', saveData.serverDeviceSn);
|
||||
|
||||
|
||||
if (saveData.deliveryId) {
|
||||
const parsedId = parseInt(saveData.deliveryId);
|
||||
console.log('解析后的 ID:', parsedId, 'isNaN:', isNaN(parsedId));
|
||||
if (isNaN(parsedId)) {
|
||||
ElMessage.error('运送清单ID格式错误');
|
||||
data.saveLoading = false;
|
||||
@@ -781,8 +751,7 @@ const onClickSave = () => {
|
||||
// 先保存装车信息
|
||||
orderLoadSave(saveData).then((res) => {
|
||||
if (res.code === 200) {
|
||||
console.log('装车信息保存成功:', res);
|
||||
|
||||
|
||||
// 如果选择了智能主机,需要更新主机的delivery_id
|
||||
if (saveData.serverDeviceSn) {
|
||||
updateHostDeliveryId(saveData.serverDeviceSn, saveData.deliveryId);
|
||||
@@ -803,17 +772,14 @@ const onClickSave = () => {
|
||||
|
||||
// 更新智能主机的delivery_id
|
||||
const updateHostDeliveryId = (hostDeviceId, deliveryId) => {
|
||||
console.log('=== 开始更新智能主机delivery_id ===');
|
||||
console.log('主机设备ID:', hostDeviceId);
|
||||
console.log('订单ID:', deliveryId);
|
||||
|
||||
|
||||
// 调用后端接口更新主机的delivery_id
|
||||
updateDeviceDeliveryId({
|
||||
deviceId: hostDeviceId,
|
||||
deliveryId: deliveryId
|
||||
}).then((res) => {
|
||||
if (res.code === 200) {
|
||||
console.log('智能主机delivery_id更新成功:', res);
|
||||
|
||||
// 更新设备重量
|
||||
updateDeviceWeightsLocal();
|
||||
} else {
|
||||
@@ -830,8 +796,7 @@ const updateHostDeliveryId = (hostDeviceId, deliveryId) => {
|
||||
|
||||
// 更新设备重量
|
||||
const updateDeviceWeightsLocal = (customDevices = null) => {
|
||||
console.log('=== 开始更新设备重量 ===');
|
||||
|
||||
|
||||
// 收集所有设备的重量信息
|
||||
const devices = [];
|
||||
|
||||
@@ -865,10 +830,9 @@ const updateDeviceWeightsLocal = (customDevices = null) => {
|
||||
});
|
||||
}
|
||||
|
||||
console.log('需要更新重量的设备:', devices);
|
||||
|
||||
|
||||
if (devices.length === 0) {
|
||||
console.log('没有设备需要更新重量,直接完成保存');
|
||||
|
||||
completeSave();
|
||||
return;
|
||||
}
|
||||
@@ -879,7 +843,7 @@ const updateDeviceWeightsLocal = (customDevices = null) => {
|
||||
devices: devices
|
||||
}).then((res) => {
|
||||
if (res.code === 200) {
|
||||
console.log('设备重量更新成功:', res);
|
||||
|
||||
completeSave();
|
||||
} else {
|
||||
console.error('设备重量更新失败:', res.msg);
|
||||
@@ -900,27 +864,19 @@ const checkOrderHostDevice = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('=== 检查订单绑定的智能主机 ===');
|
||||
console.log('订单ID:', data.deliveryId);
|
||||
console.log('调用API前的ruleForm.serverDeviceSn:', ruleForm.serverDeviceSn);
|
||||
|
||||
|
||||
getOrderHostDevice(parseInt(data.deliveryId)).then((res) => {
|
||||
console.log('=== 订单绑定主机查询结果:', res);
|
||||
console.log('API返回的完整响应:', JSON.stringify(res, null, 2));
|
||||
|
||||
if (res.code === 200) {
|
||||
if (res.data) {
|
||||
// 订单已绑定智能主机,自动填充
|
||||
console.log('订单已绑定智能主机:', res.data.deviceId);
|
||||
console.log('设置前的ruleForm.serverDeviceSn:', ruleForm.serverDeviceSn);
|
||||
|
||||
ruleForm.serverDeviceSn = res.data.deviceId;
|
||||
console.log('设置后的ruleForm.serverDeviceSn:', ruleForm.serverDeviceSn);
|
||||
console.log('自动填充智能主机成功');
|
||||
|
||||
} else {
|
||||
// 订单未绑定智能主机
|
||||
console.log('订单未绑定智能主机');
|
||||
|
||||
ruleForm.serverDeviceSn = '';
|
||||
console.log('清空智能主机选择');
|
||||
|
||||
}
|
||||
} else {
|
||||
console.error('查询订单绑定主机失败:', res.msg);
|
||||
@@ -959,8 +915,7 @@ const onShowDialog = (row, apiData = null) => {
|
||||
nextTick(() => {
|
||||
data.deliveryId = row.id;
|
||||
ruleForm.deliveryId = row.id;
|
||||
console.log('设置 deliveryId:', row.id, '类型:', typeof row.id);
|
||||
|
||||
|
||||
// 如果提供了API数据,直接填充表单
|
||||
if (apiData) {
|
||||
autoFillFormData(apiData);
|
||||
|
||||
@@ -129,7 +129,7 @@ const form = reactive({
|
||||
});
|
||||
|
||||
const searchFrom = () => {
|
||||
console.log('=== 搜索功能被触发 ===');
|
||||
|
||||
form.pageNum = 1;
|
||||
getDataList();
|
||||
};
|
||||
@@ -161,26 +161,21 @@ const getDataList = () => {
|
||||
if (params.sellerName === '') delete params.sellerName;
|
||||
}
|
||||
|
||||
console.log('订单列表查询参数:', params);
|
||||
|
||||
// 调用订单列表接口,而不是装车订单接口
|
||||
orderPageQuery(params)
|
||||
.then((res) => {
|
||||
console.log('订单列表返回结果:', res);
|
||||
|
||||
data.dataListLoading = false;
|
||||
|
||||
// 直接赋值订单数据
|
||||
console.log('=== 订单数据 ===');
|
||||
console.log('完整响应:', res);
|
||||
console.log('res.data:', res.data);
|
||||
console.log('数据行数:', res.data?.rows?.length || 0);
|
||||
|
||||
|
||||
rows.value = res.data?.rows || [];
|
||||
data.total = res.data?.total || 0;
|
||||
|
||||
console.log('更新后rows长度:', rows.value.length);
|
||||
console.log('更新后total:', data.total);
|
||||
|
||||
if (rows.value.length > 0) {
|
||||
console.log('第一行订单数据:', rows.value[0]);
|
||||
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
@@ -230,7 +225,7 @@ const del = (id) => {
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
console.log('=== 装车订单页面已加载 ===');
|
||||
|
||||
getDataList();
|
||||
});
|
||||
</script>
|
||||
@@ -278,8 +273,6 @@ onMounted(() => {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* 响应式设计 */
|
||||
@media (max-width: 768px) {
|
||||
.operation-scroll-bar {
|
||||
|
||||
@@ -241,7 +241,7 @@ const onClickSave = () => {
|
||||
data.saveLoading = false;
|
||||
});
|
||||
} else {
|
||||
console.log('error submit!');
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -166,7 +166,7 @@ const form = reactive({
|
||||
});
|
||||
|
||||
const searchFrom = () => {
|
||||
console.log('=== 运送清单搜索功能被触发 ===');
|
||||
|
||||
form.pageNum = 1;
|
||||
getDataList();
|
||||
};
|
||||
@@ -188,10 +188,10 @@ const getDataList = () => {
|
||||
delete params.createTimeRange;
|
||||
}
|
||||
|
||||
console.log('运送清单列表查询参数:', params);
|
||||
|
||||
shippingList(params)
|
||||
.then((res) => {
|
||||
console.log('运送清单列表返回结果:', res);
|
||||
|
||||
data.dataListLoading = false;
|
||||
|
||||
if (res.data.rows && res.data.rows.length > 0) {
|
||||
@@ -282,8 +282,7 @@ const handleDownload = async (row) => {
|
||||
totalAmount: totalAmount
|
||||
};
|
||||
|
||||
console.log('生成牛只验收单数据:', data);
|
||||
|
||||
|
||||
// 生成HTML内容
|
||||
const htmlContent = `
|
||||
<!DOCTYPE html>
|
||||
|
||||
@@ -98,8 +98,7 @@ const onClickSave = () => {
|
||||
FormDataRef.value.validate((valid) => {
|
||||
if (valid) {
|
||||
submitting.value = true;
|
||||
// console.log('用户ID:');
|
||||
// return false;
|
||||
// // return false;
|
||||
// if (pageNum.value == 2) {
|
||||
// 修改密码时
|
||||
// updatePassword({
|
||||
|
||||
@@ -89,7 +89,7 @@ const form = reactive({
|
||||
pageSize: 10,
|
||||
});
|
||||
const handleClick = (tab, event) => {
|
||||
console.log('=== 标签页切换 ===', tab.props.name);
|
||||
|
||||
data.activeName = tab.props.name;
|
||||
data.allotType = data.activeName === 'first' ? '0' : '1';
|
||||
form.pageNum = 1;
|
||||
@@ -100,52 +100,44 @@ const handleClick = (tab, event) => {
|
||||
};
|
||||
// 列表
|
||||
const getDataList = () => {
|
||||
console.log('=== getDataList 开始执行 ===');
|
||||
|
||||
data.dataListLoading = true;
|
||||
|
||||
let params;
|
||||
if (data.mode === 'tenant') {
|
||||
// 租户分配模式
|
||||
if (data.allotType === '0') {
|
||||
// 未分配标签页:查询未分配给任何租户的设备
|
||||
params = {
|
||||
...form,
|
||||
deviceType: data.deviceType,
|
||||
allotType: data.allotType,
|
||||
// 不传tenantId,让后端查询tenant_id为空的设备
|
||||
};
|
||||
console.log('=== 租户分配模式-未分配标签页参数 ===', params);
|
||||
} else {
|
||||
// 已分配标签页:查询已分配给该租户的设备
|
||||
params = {
|
||||
...form,
|
||||
deviceType: data.deviceType,
|
||||
allotType: data.allotType,
|
||||
tenantId: data.tenantId,
|
||||
};
|
||||
console.log('=== 租户分配模式-已分配标签页参数 ===', params);
|
||||
}
|
||||
} else {
|
||||
// 装车订单分配模式:查询未分配给装车订单的设备
|
||||
// 租户分配模式:传递 mode='tenant' 参数,让后端根据 tenant_id 判断
|
||||
params = {
|
||||
...form,
|
||||
deviceType: data.deviceType,
|
||||
allotType: data.allotType,
|
||||
mode: 'tenant', // ✅ 关键:明确告诉后端这是租户模式
|
||||
};
|
||||
|
||||
// 如果是"已分配"标签页,才传递 tenantId(用于过滤该租户的设备)
|
||||
if (data.allotType === '1') {
|
||||
params.tenantId = data.tenantId;
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
// 装车订单分配模式:传递 mode='delivery' 参数(或不传,默认为 delivery)
|
||||
params = {
|
||||
...form,
|
||||
deviceType: data.deviceType,
|
||||
allotType: data.allotType,
|
||||
mode: 'delivery', // ✅ 明确告诉后端这是装车订单模式
|
||||
tenantId: data.tenantId,
|
||||
};
|
||||
console.log('=== 装车订单分配模式参数 ===', params);
|
||||
|
||||
}
|
||||
|
||||
console.log('=== 请求参数 ===', params);
|
||||
|
||||
|
||||
// 使用新的IoT设备API
|
||||
console.log('=== 调用IoT设备API ===');
|
||||
|
||||
const apiCall = iotDeviceAssignableList(params);
|
||||
|
||||
apiCall
|
||||
.then((res) => {
|
||||
console.log('=== API 调用成功 ===', res);
|
||||
console.log('=== 原始返回数据 res.data ===', JSON.parse(JSON.stringify(res.data)));
|
||||
data.dataListLoading = false;
|
||||
if (res.code == 200) {
|
||||
let rawData = [];
|
||||
@@ -156,17 +148,13 @@ const getDataList = () => {
|
||||
// device.js 中的API返回 { list, total }
|
||||
rawData = res.data.list || [];
|
||||
total = res.data.total || 0;
|
||||
console.log('=== 使用 list 格式数据 ===', { rawData, total });
|
||||
|
||||
} else {
|
||||
// sys.js 中的API返回 { rows, total }
|
||||
rawData = res.data?.rows || [];
|
||||
total = res.data?.total || 0;
|
||||
console.log('=== 使用 rows 格式数据 ===', { rawData, total });
|
||||
}
|
||||
|
||||
console.log('=== rawData 原始数据数量 ===', rawData.length);
|
||||
console.log('=== rawData 详细内容 ===', JSON.parse(JSON.stringify(rawData)));
|
||||
|
||||
// 处理数据:添加设备类型和分配状态
|
||||
data.rows = rawData.map(item => {
|
||||
const processedItem = { ...item };
|
||||
@@ -187,39 +175,36 @@ const getDataList = () => {
|
||||
break;
|
||||
}
|
||||
|
||||
// 根据模式判断分配状态
|
||||
// ✅ 根据模式判断分配状态
|
||||
// ⚠️ 关键:租户模式和装车订单模式是完全独立的!
|
||||
if (data.mode === 'tenant') {
|
||||
// 租户模式:根据tenantId判断分配状态
|
||||
// 租户模式:仅根据 tenantId 判断分配状态(忽略 deliveryId)
|
||||
processedItem.isAssigned = !!(item.tenantId && item.tenantId !== null);
|
||||
} else {
|
||||
// 装车订单模式:根据deliveryNumber判断分配状态
|
||||
const deliveryNumber = item.deliveryNumber || item.delivery_number;
|
||||
processedItem.isAssigned = !!(deliveryNumber && deliveryNumber.trim() !== '');
|
||||
// 装车订单模式:仅根据 deliveryId 判断分配状态(忽略 tenantId)
|
||||
// 注意:这里应该用 deliveryId,而不是 deliveryNumber
|
||||
processedItem.isAssigned = !!(item.deliveryId && item.deliveryId !== null);
|
||||
}
|
||||
|
||||
console.log(`=== 处理设备 ${item.deviceId || item.sn} ===`, {
|
||||
deviceType: data.deviceType,
|
||||
deviceTypeName: processedItem.deviceTypeName,
|
||||
tenantId: item.tenantId,
|
||||
deliveryNumber: item.deliveryNumber || item.delivery_number,
|
||||
isAssigned: processedItem.isAssigned,
|
||||
mode: data.mode
|
||||
});
|
||||
|
||||
|
||||
return processedItem;
|
||||
});
|
||||
|
||||
|
||||
// 根据当前标签页过滤数据
|
||||
if (data.activeName === 'first') {
|
||||
// 未分配标签页:显示未分配的设备
|
||||
const beforeFilter = data.rows.length;
|
||||
data.rows = data.rows.filter(item => !item.isAssigned);
|
||||
|
||||
} else if (data.activeName === 'second') {
|
||||
// 已分配标签页:显示已分配的设备
|
||||
const beforeFilter = data.rows.length;
|
||||
data.rows = data.rows.filter(item => item.isAssigned);
|
||||
|
||||
}
|
||||
|
||||
data.total = data.rows.length;
|
||||
console.log('=== 处理后的数据 ===', { rows: data.rows, total: data.total });
|
||||
} else {
|
||||
console.error('=== API 返回错误 ===', res);
|
||||
ElMessage.error(res.msg || '获取数据失败');
|
||||
@@ -410,7 +395,7 @@ const getRowKey = (row) => {
|
||||
return row.id;
|
||||
};
|
||||
const onShowDialog = (tenantId, deviceType, deliveryId, deliveryNumber, carNumber, mode = 'delivery') => {
|
||||
console.log('=== onShowDialog 被调用 ===', { tenantId, deviceType, deliveryId, deliveryNumber, carNumber, mode });
|
||||
|
||||
data.dialogVisible = true;
|
||||
data.activeName = 'first';
|
||||
data.deviceType = deviceType;
|
||||
@@ -428,15 +413,7 @@ const onShowDialog = (tenantId, deviceType, deliveryId, deliveryNumber, carNumbe
|
||||
data.title = '设备分配';
|
||||
}
|
||||
|
||||
console.log('=== 设置后的数据 ===', {
|
||||
deviceType: data.deviceType,
|
||||
allotType: data.allotType,
|
||||
tenantId: data.tenantId,
|
||||
deliveryId: data.deliveryId,
|
||||
deliveryNumber: data.deliveryNumber,
|
||||
carNumber: data.carNumber,
|
||||
mode: data.mode
|
||||
});
|
||||
|
||||
getDataList();
|
||||
if (multipleTableUnRef.value) {
|
||||
multipleTableUnRef.value.clearSelection();
|
||||
|
||||
@@ -66,7 +66,7 @@ const searchFrom = () => {
|
||||
};
|
||||
|
||||
const searchChange = (val) => {
|
||||
console.log('Search change:', val);
|
||||
|
||||
};
|
||||
|
||||
const getDataList = () => {
|
||||
|
||||
@@ -72,7 +72,7 @@ const searchFrom = () => {
|
||||
getDataList();
|
||||
};
|
||||
const searchChange = (val) => {
|
||||
console.log(val);
|
||||
|
||||
};
|
||||
const getDataList = () => {
|
||||
dataListLoading.value = true;
|
||||
|
||||
@@ -77,7 +77,7 @@ const onClickSave = () => {
|
||||
})
|
||||
.catch((err) => {});
|
||||
} else {
|
||||
console.log('error submit!');
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -119,7 +119,7 @@ const delClick = (row) => {
|
||||
// 编辑用户
|
||||
const showAddDialog = (row) => {
|
||||
// TODO: 实现编辑对话框
|
||||
console.log('编辑用户:', row);
|
||||
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
|
||||
@@ -103,8 +103,7 @@ const rules = reactive({
|
||||
});
|
||||
|
||||
const handleAvatarSuccess = (res, file, fileList, type) => {
|
||||
console.log('上传成功响应:', res);
|
||||
|
||||
|
||||
if (ruleForm.hasOwnProperty(type)) {
|
||||
let imageUrl = null;
|
||||
|
||||
@@ -122,7 +121,7 @@ const handleAvatarSuccess = (res, file, fileList, type) => {
|
||||
// 直接更新 fileList
|
||||
file.url = imageUrl;
|
||||
ruleForm[type] = fileList;
|
||||
console.log(`${type} 上传成功:`, imageUrl, 'fileList:', fileList);
|
||||
|
||||
} else {
|
||||
console.error('无法解析图片URL:', res);
|
||||
ElMessage.error('上传失败:无法获取图片URL');
|
||||
@@ -182,8 +181,7 @@ const onClickSave = () => {
|
||||
idCard: ruleForm.id_card.length > 0 ? ruleForm.id_card.map((item) => item.url).join(',') : '',
|
||||
};
|
||||
|
||||
console.log('提交数据:', params);
|
||||
|
||||
|
||||
const apiCall = data.isEdit ? driverEdit(params) : driverAdd(params);
|
||||
|
||||
apiCall.then((res) => {
|
||||
|
||||
@@ -172,7 +172,7 @@ const onClickSave = () => {
|
||||
});
|
||||
}
|
||||
} else {
|
||||
console.log('error submit!');
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -174,18 +174,15 @@ const getDataList = async () => {
|
||||
...form,
|
||||
...baseSearchRef.value.penetrateParams(),
|
||||
};
|
||||
console.log('[VEHICLE-SEARCH] 查询参数:', params);
|
||||
|
||||
|
||||
const res = await vehicleList(params);
|
||||
console.log('查询结果:', res);
|
||||
|
||||
|
||||
if (res.code === 200) {
|
||||
// 数据嵌套在 res.data.data 中
|
||||
const dataInfo = res.data?.data || res.data;
|
||||
data.rows = dataInfo?.rows || [];
|
||||
data.total = dataInfo?.total || 0;
|
||||
console.log('提取的数据:', dataInfo);
|
||||
console.log('列表数据:', data.rows);
|
||||
|
||||
} else {
|
||||
ElMessage.error(res.msg || '查询失败');
|
||||
}
|
||||
|
||||
@@ -118,8 +118,7 @@ const rules = reactive({
|
||||
});
|
||||
|
||||
const handleAvatarSuccess = (res, file, fileList, type) => {
|
||||
console.log('上传成功响应:', res);
|
||||
|
||||
|
||||
if (ruleForm.hasOwnProperty(type)) {
|
||||
let imageUrl = null;
|
||||
|
||||
@@ -135,7 +134,7 @@ const handleAvatarSuccess = (res, file, fileList, type) => {
|
||||
|
||||
if (imageUrl) {
|
||||
ruleForm[type] = [{ url: imageUrl, uid: file.uid, name: file.name }];
|
||||
console.log(`${type} 上传成功:`, imageUrl);
|
||||
|
||||
} else {
|
||||
console.error('无法解析图片URL:', res);
|
||||
ElMessage.error('上传失败:无法获取图片URL');
|
||||
@@ -187,8 +186,7 @@ const onClickSave = async () => {
|
||||
remark: ruleForm.remark,
|
||||
};
|
||||
|
||||
console.log('提交数据:', formData);
|
||||
|
||||
|
||||
const res = data.isEdit ? await vehicleEdit(formData) : await vehicleAdd(formData);
|
||||
|
||||
if (res.code === 200) {
|
||||
|
||||
Reference in New Issue
Block a user