-
项圈编号: {{ device.collarId }}
+
项圈编号: {{ device.sn }}
设备电量/%:
@@ -101,20 +101,20 @@
{{ device.temperature }}
- 被采集主机:
- {{ device.collectedHost }}
+ 设备信号值:
+ {{ device.rsrp }}
总运动量:
- {{ device.totalMovement }}
+ {{ device.steps }}
今日运动量:
{{ device.todayMovement }}
- GPS位置:
- {{ device.gpsLocation }}
+ 绑带状态:
+ {{ getBandStatusText(device) }}
数据更新时间:
@@ -615,6 +615,64 @@ export default {
device.state === 1 || device.state === '1'
},
+ // 获取绑带状态文本
+ getBandStatusText(device) {
+ // 优先使用bandge_status字段,其次使用state字段
+ const bandStatus = device.bandge_status !== undefined ? device.bandge_status : device.state
+ if (bandStatus === 1 || bandStatus === '1') {
+ return '连接'
+ } else if (bandStatus === 0 || bandStatus === '0') {
+ return '断开'
+ } else {
+ return '未知'
+ }
+ },
+
+ // 格式化数据更新时间
+ formatUpdateTime(device) {
+ // 优先使用time字段,其次使用uptime字段,最后使用updateTime字段
+ const updateTime = device.time || device.uptime || device.updateTime
+
+ if (!updateTime || updateTime === '未知') {
+ return '未知'
+ }
+
+ try {
+ // 如果是时间戳(数字),转换为日期
+ if (typeof updateTime === 'number' || /^\d+$/.test(updateTime)) {
+ const timestamp = parseInt(updateTime)
+ // 判断是秒级还是毫秒级时间戳
+ const date = new Date(timestamp < 10000000000 ? timestamp * 1000 : timestamp)
+ return date.toLocaleString('zh-CN', {
+ year: 'numeric',
+ month: '2-digit',
+ day: '2-digit',
+ hour: '2-digit',
+ minute: '2-digit',
+ second: '2-digit'
+ })
+ }
+
+ // 如果是字符串,尝试解析
+ const date = new Date(updateTime)
+ if (!isNaN(date.getTime())) {
+ return date.toLocaleString('zh-CN', {
+ year: 'numeric',
+ month: '2-digit',
+ day: '2-digit',
+ hour: '2-digit',
+ minute: '2-digit',
+ second: '2-digit'
+ })
+ }
+
+ return updateTime
+ } catch (error) {
+ console.warn('时间格式化失败:', error, updateTime)
+ return updateTime
+ }
+ },
+
// 加载统计信息
async loadStatistics() {
try {
diff --git a/mini_program/farm-monitor-dashboard/src/components/SmartEartagAlert.vue b/mini_program/farm-monitor-dashboard/src/components/SmartEartagAlert.vue
new file mode 100644
index 0000000..a520138
--- /dev/null
+++ b/mini_program/farm-monitor-dashboard/src/components/SmartEartagAlert.vue
@@ -0,0 +1,984 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 最后更新: {{ formatTime(lastRefreshTime) }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
{{ alert.title }}
+
{{ alert.description }}
+
+ 设备ID:
+ {{ alert.deviceId }}
+
+
+
+
+
+ {{ getStatusText(alert.status) }}
+
+
>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
基本信息
+
+ 预警级别:
+
+ {{ getSeverityText(selectedAlert.severity) }}
+
+
+
+ 设备ID:
+ {{ selectedAlert.deviceId }}
+
+
+ 预警时间:
+ {{ formatTime(selectedAlert.createdAt) }}
+
+
+ 处理状态:
+
+ {{ getStatusText(selectedAlert.status) }}
+
+
+
+
+
+
预警内容
+
+
{{ selectedAlert.title }}
+
{{ selectedAlert.description }}
+
+
+
+
+
详细数据
+
+
+ {{ key }}:
+ {{ value }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/mini_program/farm-monitor-dashboard/src/components/SmartHost.vue b/mini_program/farm-monitor-dashboard/src/components/SmartHost.vue
index a35e12a..7417f88 100644
--- a/mini_program/farm-monitor-dashboard/src/components/SmartHost.vue
+++ b/mini_program/farm-monitor-dashboard/src/components/SmartHost.vue
@@ -29,7 +29,7 @@
@@ -63,41 +63,38 @@
class="device-card"
>
-
主机编号: {{ device.hostId }}
+
主机编号: {{ device.deviceNumber || device.sid || device.hostId }}
- 设备状态:
-
- {{ device.isOnline ? '在线' : '离线' }}
-
+ 设备电量:
+ {{ device.voltage || device.battery || 0 }}%
- CPU使用率:
- {{ device.cpuUsage }}%
+ 设备信号值:
+ {{ device.signa || device.signal || 0 }}%
- 内存使用率:
- {{ device.memoryUsage }}%
+ 设备温度:
+ {{ device.temperature || 0 }}°C
- 存储空间:
- {{ device.storageUsage }}%
-
-
- 网络状态:
- {{ device.networkStatus }}
-
-
- 连接设备数:
- {{ device.connectedDevices }}
+ 绑带状态:
+ {{ getBandStatusText(device) }}
数据更新时间:
- {{ device.updateTime }}
+ {{ device.updateTime || device.lastUpdateTime || '未知' }}
+
暂无主机设备
+
+
+
+
+
+
+
+
diff --git a/mini_program/farm-monitor-dashboard/src/router/index.js b/mini_program/farm-monitor-dashboard/src/router/index.js
index c31e98c..583c712 100644
--- a/mini_program/farm-monitor-dashboard/src/router/index.js
+++ b/mini_program/farm-monitor-dashboard/src/router/index.js
@@ -12,6 +12,18 @@ import Login from '@/components/Login.vue'
import SmsLogin from '@/components/SmsLogin.vue'
import Register from '@/components/Register.vue'
import PasswordLogin from '@/components/PasswordLogin.vue'
+import ElectronicFencePage from '@/views/ElectronicFencePage.vue'
+import SmartEartagAlertPage from '@/views/SmartEartagAlertPage.vue'
+import AlertTest from '@/components/AlertTest.vue'
+import MapTest from '@/components/MapTest.vue'
+import ApiTest from '@/components/ApiTest.vue'
+import WechatFenceDrawer from '@/components/WechatFenceDrawer.vue'
+import CattleProfile from '@/components/CattleProfile.vue'
+import CattleAdd from '@/components/CattleAdd.vue'
+import CattleTest from '@/components/CattleTest.vue'
+import CattleTransfer from '@/components/CattleTransfer.vue'
+import CattleTransferRegister from '@/components/CattleTransferRegister.vue'
+import ApiTestPage from '@/components/ApiTestPage.vue'
Vue.use(VueRouter)
@@ -75,6 +87,66 @@ const routes = [
path: '/auth-test',
name: 'AuthTest',
component: AuthTest
+ },
+ {
+ path: '/electronic-fence',
+ name: 'ElectronicFence',
+ component: ElectronicFencePage
+ },
+ {
+ path: '/smart-eartag-alert',
+ name: 'SmartEartagAlert',
+ component: SmartEartagAlertPage
+ },
+ {
+ path: '/alert-test',
+ name: 'AlertTest',
+ component: AlertTest
+ },
+ {
+ path: '/map-test',
+ name: 'MapTest',
+ component: MapTest
+ },
+ {
+ path: '/api-test',
+ name: 'ApiTest',
+ component: ApiTest
+ },
+ {
+ path: '/wechat-fence-drawer',
+ name: 'WechatFenceDrawer',
+ component: WechatFenceDrawer
+ },
+ {
+ path: '/cattle-profile',
+ name: 'CattleProfile',
+ component: CattleProfile
+ },
+ {
+ path: '/cattle-add',
+ name: 'CattleAdd',
+ component: CattleAdd
+ },
+ {
+ path: '/cattle-test',
+ name: 'CattleTest',
+ component: CattleTest
+ },
+ {
+ path: '/cattle-transfer',
+ name: 'CattleTransfer',
+ component: CattleTransfer
+ },
+ {
+ path: '/cattle-transfer-register',
+ name: 'CattleTransferRegister',
+ component: CattleTransferRegister
+ },
+ {
+ path: '/api-test-page',
+ name: 'ApiTestPage',
+ component: ApiTestPage
}
]
diff --git a/mini_program/farm-monitor-dashboard/src/services/alertService.js b/mini_program/farm-monitor-dashboard/src/services/alertService.js
new file mode 100644
index 0000000..d0126da
--- /dev/null
+++ b/mini_program/farm-monitor-dashboard/src/services/alertService.js
@@ -0,0 +1,127 @@
+import api from './api'
+
+// 智能耳标预警相关API服务
+export const alertService = {
+ // 获取预警列表
+ async getAlerts(params = {}) {
+ try {
+ const response = await api.get('/smart-eartag-alerts', { params })
+ return response
+ } catch (error) {
+ console.error('获取预警列表失败:', error)
+ throw error
+ }
+ },
+
+ // 获取预警详情
+ async getAlertById(id) {
+ try {
+ const response = await api.get(`/smart-eartag-alerts/${id}`)
+ return response
+ } catch (error) {
+ console.error('获取预警详情失败:', error)
+ throw error
+ }
+ },
+
+ // 处理预警(标记为已处理)
+ async resolveAlert(id) {
+ try {
+ const response = await api.put(`/smart-eartag-alerts/${id}/resolve`)
+ return response
+ } catch (error) {
+ console.error('处理预警失败:', error)
+ throw error
+ }
+ },
+
+ // 批量处理预警
+ async batchResolveAlerts(ids) {
+ try {
+ const response = await api.put('/smart-eartag-alerts/batch-resolve', { ids })
+ return response
+ } catch (error) {
+ console.error('批量处理预警失败:', error)
+ throw error
+ }
+ },
+
+ // 删除预警
+ async deleteAlert(id) {
+ try {
+ const response = await api.delete(`/smart-eartag-alerts/${id}`)
+ return response
+ } catch (error) {
+ console.error('删除预警失败:', error)
+ throw error
+ }
+ },
+
+ // 获取预警统计
+ async getAlertStats() {
+ try {
+ const response = await api.get('/smart-eartag-alerts/stats')
+ return response
+ } catch (error) {
+ console.error('获取预警统计失败:', error)
+ throw error
+ }
+ },
+
+ // 获取设备预警历史
+ async getDeviceAlertHistory(deviceId, params = {}) {
+ try {
+ const response = await api.get(`/smart-eartag-alerts/device/${deviceId}`, { params })
+ return response
+ } catch (error) {
+ console.error('获取设备预警历史失败:', error)
+ throw error
+ }
+ },
+
+ // 设置预警规则
+ async setAlertRule(ruleData) {
+ try {
+ const response = await api.post('/smart-eartag-alerts/rules', ruleData)
+ return response
+ } catch (error) {
+ console.error('设置预警规则失败:', error)
+ throw error
+ }
+ },
+
+ // 获取预警规则
+ async getAlertRules() {
+ try {
+ const response = await api.get('/smart-eartag-alerts/rules')
+ return response
+ } catch (error) {
+ console.error('获取预警规则失败:', error)
+ throw error
+ }
+ },
+
+ // 更新预警规则
+ async updateAlertRule(id, ruleData) {
+ try {
+ const response = await api.put(`/smart-eartag-alerts/rules/${id}`, ruleData)
+ return response
+ } catch (error) {
+ console.error('更新预警规则失败:', error)
+ throw error
+ }
+ },
+
+ // 删除预警规则
+ async deleteAlertRule(id) {
+ try {
+ const response = await api.delete(`/smart-eartag-alerts/rules/${id}`)
+ return response
+ } catch (error) {
+ console.error('删除预警规则失败:', error)
+ throw error
+ }
+ }
+}
+
+export default alertService
\ No newline at end of file
diff --git a/mini_program/farm-monitor-dashboard/src/services/api.js b/mini_program/farm-monitor-dashboard/src/services/api.js
index 00ccd58..dce737a 100644
--- a/mini_program/farm-monitor-dashboard/src/services/api.js
+++ b/mini_program/farm-monitor-dashboard/src/services/api.js
@@ -1,9 +1,9 @@
import axios from 'axios'
-import { getToken } from '@/utils/auth'
+import auth from '@/utils/auth'
// 创建axios实例
const service = axios.create({
- baseURL: process.env.VUE_APP_BASE_URL || '/api',
+ baseURL: process.env.VUE_APP_BASE_URL || 'http://localhost:5300/api',
timeout: 10000,
headers: {
'Content-Type': 'application/json'
@@ -14,7 +14,7 @@ const service = axios.create({
service.interceptors.request.use(
(config) => {
// 添加token到请求头
- const token = getToken()
+ const token = auth.getToken()
if (token) {
config.headers['Authorization'] = `Bearer ${token}`
}
@@ -38,17 +38,30 @@ service.interceptors.request.use(
service.interceptors.response.use(
(response) => {
const res = response.data
+ console.log('原始API响应:', res)
+ console.log('响应状态码:', response.status)
// 统一处理响应格式
if (res.code === 200) {
+ console.log('处理code=200格式')
return res.data
+ } else if (res.success === true) {
+ // 处理 {success: true, data: ...} 格式
+ console.log('处理success=true格式')
+ return res
+ } else if (res.success === false) {
+ // 处理 {success: false, message: ...} 格式
+ console.log('处理success=false格式')
+ return res
+ } else if (res.code === undefined && res.success === undefined) {
+ // 直接返回数据的情况
+ console.log('处理直接数据格式')
+ return res
} else {
// 业务错误
- uni.showToast({
- title: res.message || '请求失败',
- icon: 'none',
- duration: 2000
- })
+ console.error('请求失败:', res.message || '请求失败')
+ console.error('完整响应:', res)
+ // 这里可以添加用户提示,比如使用Element UI的Message组件
return Promise.reject(new Error(res.message || '请求失败'))
}
},
@@ -63,11 +76,10 @@ service.interceptors.response.use(
case 401:
message = '未授权,请重新登录'
// 清除token并跳转到登录页
- uni.removeStorageSync('token')
- uni.removeStorageSync('userInfo')
- uni.reLaunch({
- url: '/pages/login/login'
- })
+ localStorage.removeItem('token')
+ localStorage.removeItem('userInfo')
+ // 跳转到登录页
+ window.location.href = '/login'
break
case 403:
message = '拒绝访问'
@@ -87,11 +99,8 @@ service.interceptors.response.use(
message = error.message
}
- uni.showToast({
- title: message,
- icon: 'none',
- duration: 2000
- })
+ console.error('网络错误:', message)
+ // 这里可以添加用户提示,比如使用Element UI的Message组件
return Promise.reject(error)
}
@@ -139,29 +148,134 @@ export const del = (url, params = {}) => {
}
// 上传文件
-export const upload = (url, filePath, formData = {}) => {
+export const upload = (url, file, formData = {}) => {
return new Promise((resolve, reject) => {
- uni.uploadFile({
- url: service.defaults.baseURL + url,
- filePath,
- name: 'file',
- formData,
- header: {
- 'Authorization': `Bearer ${getToken()}`
- },
- success: (res) => {
- const data = JSON.parse(res.data)
- if (data.code === 200) {
- resolve(data.data)
- } else {
- reject(new Error(data.message))
- }
- },
- fail: (error) => {
- reject(error)
+ const uploadFormData = new FormData()
+
+ // 添加文件
+ uploadFormData.append('file', file)
+
+ // 添加其他表单数据
+ Object.keys(formData).forEach(key => {
+ uploadFormData.append(key, formData[key])
+ })
+
+ // 使用fetch上传文件
+ fetch(service.defaults.baseURL + url, {
+ method: 'POST',
+ body: uploadFormData,
+ headers: {
+ 'Authorization': `Bearer ${auth.getToken()}`
}
})
+ .then(response => response.json())
+ .then(data => {
+ if (data.code === 200) {
+ resolve(data.data)
+ } else {
+ reject(new Error(data.message))
+ }
+ })
+ .catch(error => {
+ reject(error)
+ })
})
}
+// 牛只档案相关API
+export const cattleApi = {
+ // 获取牛只档案列表
+ getCattleList: (params = {}) => {
+ return get('/iot-cattle/public', params)
+ },
+
+ // 根据耳号搜索牛只
+ searchCattleByEarNumber: (earNumber) => {
+ return get('/iot-cattle/public', { search: earNumber })
+ },
+
+ // 获取牛只详情
+ getCattleDetail: (id) => {
+ return get(`/iot-cattle/public/${id}`)
+ },
+
+ // 获取牛只类型列表
+ getCattleTypes: () => {
+ return get('/cattle-type')
+ },
+
+ // 获取栏舍列表
+ getPens: (farmId) => {
+ return get('/iot-cattle/public/pens/list', { farmId })
+ },
+
+ // 获取批次列表
+ getBatches: (farmId) => {
+ return get('/iot-cattle/public/batches/list', { farmId })
+ },
+
+ // 创建牛只档案
+ createCattle: (data) => {
+ return post('/iot-cattle', data)
+ },
+
+ // 更新牛只档案
+ updateCattle: (id, data) => {
+ return put(`/iot-cattle/${id}`, data)
+ },
+
+ // 删除牛只档案
+ deleteCattle: (id) => {
+ return del(`/iot-cattle/${id}`)
+ }
+}
+
+// 牛只转栏记录相关API
+export const cattleTransferApi = {
+ // 获取转栏记录列表
+ getTransferRecords: (params = {}) => {
+ return get('/cattle-transfer-records', params)
+ },
+
+ // 根据耳号搜索转栏记录
+ searchTransferRecordsByEarNumber: (earNumber, params = {}) => {
+ return get('/cattle-transfer-records', { earNumber, ...params })
+ },
+
+ // 获取转栏记录详情
+ getTransferRecordDetail: (id) => {
+ return get(`/cattle-transfer-records/${id}`)
+ },
+
+ // 创建转栏记录
+ createTransferRecord: (data) => {
+ return post('/cattle-transfer-records', data)
+ },
+
+ // 更新转栏记录
+ updateTransferRecord: (id, data) => {
+ return put(`/cattle-transfer-records/${id}`, data)
+ },
+
+ // 删除转栏记录
+ deleteTransferRecord: (id) => {
+ return del(`/cattle-transfer-records/${id}`)
+ },
+
+ // 批量删除转栏记录
+ batchDeleteTransferRecords: (ids) => {
+ return post('/cattle-transfer-records/batch-delete', { ids })
+ },
+
+ // 获取可用的牛只列表
+ getAvailableAnimals: (params = {}) => {
+ return get('/cattle-transfer-records/available-animals', params)
+ },
+
+ // 获取栏舍列表(用于转栏选择)
+ getBarnsForTransfer: (params = {}) => {
+ return get('/cattle-pens', params)
+ }
+}
+
export default service
\ No newline at end of file
diff --git a/mini_program/farm-monitor-dashboard/src/services/collarService.js b/mini_program/farm-monitor-dashboard/src/services/collarService.js
index 9333bb4..4e0e31e 100644
--- a/mini_program/farm-monitor-dashboard/src/services/collarService.js
+++ b/mini_program/farm-monitor-dashboard/src/services/collarService.js
@@ -92,7 +92,7 @@ export const getAllCollarDevices = async (params = {}) => {
temperature: device.temperature || 0,
collectedHost: device.sid || device.collectedHost || '未知',
totalMovement: device.walk || device.totalMovement || 0,
- todayMovement: (device.walk || 0) - (device.y_steps || 0),
+ todayMovement: (device.steps || device.walk || 0) - (device.y_steps || 0),
gpsLocation: device.gps || device.gpsLocation || '未知',
updateTime: device.time || device.uptime || device.updateTime || '未知',
// 绑定状态映射 - 优先使用bandge_status字段,其次使用state字段
diff --git a/mini_program/farm-monitor-dashboard/src/services/fenceService.js b/mini_program/farm-monitor-dashboard/src/services/fenceService.js
new file mode 100644
index 0000000..0ab48f2
--- /dev/null
+++ b/mini_program/farm-monitor-dashboard/src/services/fenceService.js
@@ -0,0 +1,198 @@
+import { get, post, put, del } from './api'
+
+// 电子围栏API服务
+export const fenceService = {
+ // 获取围栏列表
+ getFences(params = {}) {
+ return get('/electronic-fences', params)
+ },
+
+ // 获取单个围栏详情
+ getFenceById(id) {
+ return get(`/electronic-fences/${id}`)
+ },
+
+ // 创建围栏
+ createFence(data) {
+ return post('/electronic-fences', data)
+ },
+
+ // 更新围栏
+ updateFence(id, data) {
+ return put(`/electronic-fences/${id}`, data)
+ },
+
+ // 删除围栏
+ deleteFence(id) {
+ return del(`/electronic-fences/${id}`)
+ },
+
+ // 搜索围栏
+ searchFences(params) {
+ return get('/electronic-fences/search', params)
+ }
+}
+
+// 电子围栏坐标点API服务
+export const fencePointService = {
+ // 获取围栏的所有坐标点
+ getByFenceId(fenceId) {
+ return get(`/electronic-fence-points/fence/${fenceId}`)
+ },
+
+ // 获取单个坐标点详情
+ getPointById(id) {
+ return get(`/electronic-fence-points/${id}`)
+ },
+
+ // 创建坐标点
+ createPoint(data) {
+ return post('/electronic-fence-points', data)
+ },
+
+ // 批量创建坐标点
+ createPoints(data) {
+ return post('/electronic-fence-points/batch', data)
+ },
+
+ // 更新坐标点
+ updatePoint(id, data) {
+ return put(`/electronic-fence-points/${id}`, data)
+ },
+
+ // 更新围栏的所有坐标点
+ updateFencePoints(fenceId, data) {
+ return put(`/electronic-fence-points/fence/${fenceId}`, data)
+ },
+
+ // 删除坐标点
+ deletePoint(id) {
+ return del(`/electronic-fence-points/${id}`)
+ },
+
+ // 删除围栏的所有坐标点
+ deleteFencePoints(fenceId) {
+ return del(`/electronic-fence-points/fence/${fenceId}`)
+ },
+
+ // 获取围栏边界框
+ getFenceBounds(fenceId) {
+ return get(`/electronic-fence-points/fence/${fenceId}/bounds`)
+ },
+
+ // 搜索坐标点
+ searchPoints(params) {
+ return get('/electronic-fence-points/search', params)
+ }
+}
+
+// 围栏类型配置
+export const fenceTypes = {
+ grazing: {
+ name: '放牧区',
+ color: '#52c41a',
+ icon: '🌿'
+ },
+ safety: {
+ name: '安全区',
+ color: '#1890ff',
+ icon: '🛡️'
+ },
+ restricted: {
+ name: '限制区',
+ color: '#ff4d4f',
+ icon: '⚠️'
+ },
+ collector: {
+ name: '收集区',
+ color: '#fa8c16',
+ icon: '📦'
+ }
+}
+
+// 围栏工具函数
+export const fenceUtils = {
+ // 计算多边形中心点
+ calculateCenter(points) {
+ if (points.length === 0) return { lng: 0, lat: 0 }
+
+ let lngSum = 0
+ let latSum = 0
+
+ points.forEach(point => {
+ lngSum += point.lng
+ latSum += point.lat
+ })
+
+ return {
+ lng: lngSum / points.length,
+ lat: latSum / points.length
+ }
+ },
+
+ // 计算多边形面积(简化计算)
+ calculateArea(points) {
+ if (points.length < 3) return 0
+
+ let area = 0
+ const n = points.length
+
+ for (let i = 0; i < n; i++) {
+ const j = (i + 1) % n
+ area += points[i].lng * points[j].lat
+ area -= points[j].lng * points[i].lat
+ }
+
+ area = Math.abs(area) / 2
+
+ // 转换为平方米(粗略计算)
+ return area * 111000 * 111000
+ },
+
+ // 验证围栏数据
+ validateFence(fence) {
+ const errors = []
+
+ if (!fence.name || fence.name.trim() === '') {
+ errors.push('围栏名称不能为空')
+ }
+
+ if (!fence.type) {
+ errors.push('请选择围栏类型')
+ }
+
+ if (!fence.coordinates || fence.coordinates.length < 3) {
+ errors.push('围栏至少需要3个坐标点')
+ }
+
+ return {
+ valid: errors.length === 0,
+ errors
+ }
+ },
+
+ // 格式化围栏数据
+ formatFenceData(rawData) {
+ return {
+ id: rawData.id,
+ name: rawData.name,
+ type: rawData.type,
+ description: rawData.description || '',
+ coordinates: rawData.coordinates || [],
+ center_lng: rawData.center_lng,
+ center_lat: rawData.center_lat,
+ area: rawData.area,
+ farm_id: rawData.farm_id,
+ is_active: rawData.is_active !== false,
+ created_at: rawData.created_at,
+ updated_at: rawData.updated_at
+ }
+ }
+}
+
+export default {
+ fenceService,
+ fencePointService,
+ fenceTypes,
+ fenceUtils
+}
diff --git a/mini_program/farm-monitor-dashboard/src/services/hostService.js b/mini_program/farm-monitor-dashboard/src/services/hostService.js
index 9b1cad0..cb91d5f 100644
--- a/mini_program/farm-monitor-dashboard/src/services/hostService.js
+++ b/mini_program/farm-monitor-dashboard/src/services/hostService.js
@@ -12,11 +12,24 @@ const api = axios.create({
// 请求拦截器
api.interceptors.request.use(
config => {
- const token = localStorage.getItem('token')
+ // 尝试多种token存储方式
+ const token = localStorage.getItem('token') ||
+ localStorage.getItem('authToken') ||
+ localStorage.getItem('accessToken') ||
+ sessionStorage.getItem('token') ||
+ sessionStorage.getItem('authToken')
+
if (token) {
config.headers.Authorization = `Bearer ${token}`
+ console.log('使用认证token:', token.substring(0, 10) + '...')
} else {
- console.warn('未找到认证token,使用模拟数据')
+ console.warn('未找到认证token,尝试无认证访问')
+ // 尝试其他认证方式
+ const apiKey = localStorage.getItem('apiKey')
+ if (apiKey) {
+ config.headers['X-API-Key'] = apiKey
+ console.log('使用API Key认证')
+ }
}
return config
},
@@ -32,74 +45,110 @@ api.interceptors.response.use(
},
error => {
console.error('API请求错误:', error)
- // 如果是401错误,直接返回模拟数据而不是抛出错误
- if (error.response && error.response.status === 401) {
- console.warn('认证失败,返回模拟数据')
- return Promise.resolve({ data: { data: [] } })
- }
return Promise.reject(error)
}
)
/**
* 获取智能主机设备列表
- * @param {Object} params - 查询参数
+ * @param {Object} params - 查询参数 (page, pageSize, search等)
* @returns {Promise} API响应
*/
-// 模拟数据
-const getMockHostDevices = () => {
- return [
- {
- hostId: '2490246426',
- isOnline: true,
- cpuUsage: 45,
- memoryUsage: 62,
- storageUsage: 38,
- networkStatus: '正常',
- connectedDevices: 15,
- updateTime: '2025-09-18 14:30:15'
- },
- {
- hostId: '23107000007',
- isOnline: false,
- cpuUsage: 0,
- memoryUsage: 0,
- storageUsage: 45,
- networkStatus: '断开',
- connectedDevices: 0,
- updateTime: '2025-09-18 12:15:30'
- },
- {
- hostId: '23C0270112',
- isOnline: true,
- cpuUsage: 78,
- memoryUsage: 85,
- storageUsage: 67,
- networkStatus: '正常',
- connectedDevices: 23,
- updateTime: '2025-09-18 14:25:45'
- },
- {
- hostId: '2490246427',
- isOnline: true,
- cpuUsage: 32,
- memoryUsage: 48,
- storageUsage: 29,
- networkStatus: '正常',
- connectedDevices: 8,
- updateTime: '2025-09-18 14:20:20'
+// 模拟数据生成器
+const generateMockHostDevices = (page = 1, pageSize = 10) => {
+ const totalDevices = 25 // 模拟总共25台设备
+ const startIndex = (page - 1) * pageSize
+ const endIndex = Math.min(startIndex + pageSize, totalDevices)
+
+ const devices = []
+ for (let i = startIndex; i < endIndex; i++) {
+ const deviceId = `2490246${String(426 + i).padStart(3, '0')}`
+ devices.push({
+ hostId: deviceId,
+ sid: deviceId,
+ isOnline: Math.random() > 0.3, // 70% 在线概率
+ battery: Math.floor(Math.random() * 40) + 60, // 60-100%
+ voltage: Math.floor(Math.random() * 40) + 60,
+ signal: Math.floor(Math.random() * 50) + 10, // 10-60%
+ signa: Math.floor(Math.random() * 50) + 10,
+ temperature: (Math.random() * 10 + 20).toFixed(1), // 20-30°C
+ state: Math.random() > 0.2 ? 1 : 0, // 80% 连接状态
+ bandge_status: Math.random() > 0.2 ? 1 : 0,
+ updateTime: new Date(Date.now() - Math.random() * 7 * 24 * 60 * 60 * 1000).toLocaleString('zh-CN', {
+ year: 'numeric',
+ month: '2-digit',
+ day: '2-digit',
+ hour: '2-digit',
+ minute: '2-digit',
+ second: '2-digit'
+ }).replace(/\//g, '-'),
+ lastUpdateTime: new Date(Date.now() - Math.random() * 7 * 24 * 60 * 60 * 1000).toLocaleString('zh-CN', {
+ year: 'numeric',
+ month: '2-digit',
+ day: '2-digit',
+ hour: '2-digit',
+ minute: '2-digit',
+ second: '2-digit'
+ }).replace(/\//g, '-')
+ })
+ }
+
+ return {
+ data: devices,
+ pagination: {
+ currentPage: page,
+ pageSize: pageSize,
+ total: totalDevices,
+ totalPages: Math.ceil(totalDevices / pageSize)
}
- ]
+ }
}
export const getHostDevices = async (params = {}) => {
- try {
- const response = await api.get('/api/smart-devices/hosts', { params })
- return response.data
- } catch (error) {
- console.error('获取主机设备列表失败,使用模拟数据:', error)
- return { data: getMockHostDevices() }
+ console.log('正在调用真实API获取主机设备列表...', params)
+
+ const response = await api.get('/api/smart-devices/hosts', {
+ params: {
+ page: params.page || 1,
+ pageSize: params.pageSize || 10,
+ search: params.search || '',
+ ...params
+ }
+ })
+
+ console.log('API响应成功:', response.data)
+
+ // 根据API响应结构处理数据
+ const apiData = response.data
+
+ // 如果API返回的数据结构包含data字段和total字段
+ if (apiData.success && apiData.data) {
+ return {
+ data: apiData.data,
+ pagination: {
+ currentPage: params.page || 1,
+ pageSize: params.pageSize || 10,
+ total: apiData.total || apiData.data.length,
+ totalPages: Math.ceil((apiData.total || apiData.data.length) / (params.pageSize || 10))
+ }
+ }
}
+
+ // 如果API直接返回数组
+ if (Array.isArray(apiData)) {
+ return {
+ data: apiData,
+ pagination: {
+ currentPage: params.page || 1,
+ pageSize: params.pageSize || 10,
+ total: apiData.length,
+ totalPages: Math.ceil(apiData.length / (params.pageSize || 10))
+ }
+ }
+ }
+
+ // 默认返回API数据
+ return apiData
}
/**
@@ -153,9 +202,26 @@ export const stopHost = async (hostId) => {
}
}
+/**
+ * 更新主机设备信息
+ * @param {string} hostId - 主机ID
+ * @param {Object} updateData - 更新数据
+ * @returns {Promise} API响应
+ */
+export const updateHostDevice = async (hostId, updateData) => {
+ try {
+ const response = await api.put(`/api/smart-devices/hosts/${hostId}`, updateData)
+ return response.data
+ } catch (error) {
+ console.error('更新主机设备信息失败:', error)
+ throw error
+ }
+}
+
export default {
getHostDevices,
restartHost,
startHost,
- stopHost
+ stopHost,
+ updateHostDevice
}
diff --git a/mini_program/farm-monitor-dashboard/src/utils/index.js b/mini_program/farm-monitor-dashboard/src/utils/index.js
index 3f4f4f4..28951c2 100644
--- a/mini_program/farm-monitor-dashboard/src/utils/index.js
+++ b/mini_program/farm-monitor-dashboard/src/utils/index.js
@@ -173,7 +173,7 @@ export const buildUrlParams = (params) => {
export const storage = {
set: (key, value) => {
try {
- uni.setStorageSync(key, value)
+ localStorage.setItem(key, JSON.stringify(value))
} catch (error) {
console.error('存储数据失败:', error)
}
@@ -181,8 +181,8 @@ export const storage = {
get: (key, defaultValue = null) => {
try {
- const value = uni.getStorageSync(key)
- return value !== null && value !== undefined ? value : defaultValue
+ const value = localStorage.getItem(key)
+ return value !== null && value !== undefined ? JSON.parse(value) : defaultValue
} catch (error) {
console.error('获取存储数据失败:', error)
return defaultValue
@@ -191,7 +191,7 @@ export const storage = {
remove: (key) => {
try {
- uni.removeStorageSync(key)
+ localStorage.removeItem(key)
} catch (error) {
console.error('删除存储数据失败:', error)
}
@@ -199,7 +199,7 @@ export const storage = {
clear: () => {
try {
- uni.clearStorageSync()
+ localStorage.clear()
} catch (error) {
console.error('清空存储失败:', error)
}
diff --git a/mini_program/farm-monitor-dashboard/src/utils/mapping.js b/mini_program/farm-monitor-dashboard/src/utils/mapping.js
new file mode 100644
index 0000000..6f7fb80
--- /dev/null
+++ b/mini_program/farm-monitor-dashboard/src/utils/mapping.js
@@ -0,0 +1,265 @@
+/**
+ * 中文映射工具
+ * 统一管理所有字段的中文映射
+ */
+
+// 性别映射
+export const sexMap = {
+ 1: '公',
+ 2: '母'
+}
+
+// 品类映射
+export const categoryMap = {
+ 1: '犊牛',
+ 2: '育成母牛',
+ 3: '架子牛',
+ 4: '青年牛',
+ 5: '基础母牛',
+ 6: '育肥牛'
+}
+
+// 品种映射
+export const breedMap = {
+ 1: '西藏高山牦牛',
+ 2: '宁夏牛',
+ 3: '华西牛',
+ 4: '秦川牛',
+ 5: '西门塔尔牛',
+ 6: '荷斯坦牛'
+}
+
+// 品系映射
+export const strainMap = {
+ 1: '乳肉兼用',
+ 2: '肉用型',
+ 3: '乳用型',
+ 4: '兼用型'
+}
+
+// 生理阶段映射
+export const physiologicalStageMap = {
+ 1: '犊牛',
+ 2: '育成期',
+ 3: '青年期',
+ 4: '成年期',
+ 5: '老年期'
+}
+
+// 来源映射
+export const sourceMap = {
+ 1: '合作社',
+ 2: '农户',
+ 3: '养殖场',
+ 4: '进口',
+ 5: '自繁'
+}
+
+// 事件映射
+export const eventMap = {
+ 1: '正常',
+ 2: '生病',
+ 3: '怀孕',
+ 4: '分娩',
+ 5: '断奶',
+ 6: '转栏',
+ 7: '离栏'
+}
+
+// 是否佩戴设备映射
+export const wearMap = {
+ 0: '否',
+ 1: '是'
+}
+
+// 是否删除映射
+export const deleteMap = {
+ 0: '否',
+ 1: '是'
+}
+
+// 是否出栏映射
+export const outMap = {
+ 0: '否',
+ 1: '是'
+}
+
+// 是否电子认证映射
+export const eleAuthMap = {
+ 0: '否',
+ 1: '是'
+}
+
+// 是否检疫认证映射
+export const quaAuthMap = {
+ 0: '否',
+ 1: '是'
+}
+
+// 是否免疫映射
+export const vaccinMap = {
+ 0: '否',
+ 1: '是'
+}
+
+// 是否配种映射
+export const inseminationMap = {
+ 0: '否',
+ 1: '是'
+}
+
+// 是否保险映射
+export const insureMap = {
+ 0: '否',
+ 1: '是'
+}
+
+// 是否抵押映射
+export const mortgageMap = {
+ 0: '否',
+ 1: '是'
+}
+
+// 销售状态映射
+export const sellStatusMap = {
+ 100: '在栏',
+ 200: '已售',
+ 300: '死亡',
+ 400: '淘汰'
+}
+
+/**
+ * 获取性别中文名称
+ * @param {number} sex 性别代码
+ * @returns {string} 中文名称
+ */
+export function getSexName(sex) {
+ return sexMap[sex] || '--'
+}
+
+/**
+ * 获取品类中文名称
+ * @param {number} cate 品类代码
+ * @returns {string} 中文名称
+ */
+export function getCategoryName(cate) {
+ return categoryMap[cate] || '--'
+}
+
+/**
+ * 获取品种中文名称
+ * @param {number} varieties 品种代码
+ * @returns {string} 中文名称
+ */
+export function getBreedName(varieties) {
+ return breedMap[varieties] || varieties || '--'
+}
+
+/**
+ * 获取品系中文名称
+ * @param {number} strain 品系代码
+ * @returns {string} 中文名称
+ */
+export function getStrainName(strain) {
+ return strainMap[strain] || strain || '--'
+}
+
+/**
+ * 获取生理阶段中文名称
+ * @param {number} level 生理阶段代码
+ * @returns {string} 中文名称
+ */
+export function getPhysiologicalStage(level) {
+ return physiologicalStageMap[level] || '--'
+}
+
+/**
+ * 获取来源中文名称
+ * @param {number} source 来源代码
+ * @returns {string} 中文名称
+ */
+export function getSourceName(source) {
+ return sourceMap[source] || '--'
+}
+
+/**
+ * 获取事件中文名称
+ * @param {number} event 事件代码
+ * @returns {string} 中文名称
+ */
+export function getEventName(event) {
+ return eventMap[event] || '--'
+}
+
+/**
+ * 获取是否佩戴设备中文名称
+ * @param {number} isWear 是否佩戴代码
+ * @returns {string} 中文名称
+ */
+export function getWearName(isWear) {
+ return wearMap[isWear] || '--'
+}
+
+/**
+ * 获取销售状态中文名称
+ * @param {number} sellStatus 销售状态代码
+ * @returns {string} 中文名称
+ */
+export function getSellStatusName(sellStatus) {
+ return sellStatusMap[sellStatus] || '--'
+}
+
+/**
+ * 格式化日期
+ * @param {number} timestamp 时间戳(秒)
+ * @returns {string} 格式化后的日期
+ */
+export function formatDate(timestamp) {
+ if (!timestamp) return '--'
+
+ // 如果是时间戳(秒),转换为毫秒
+ const date = new Date(timestamp * 1000)
+ return date.toISOString().split('T')[0]
+}
+
+/**
+ * 格式化日期为时间戳
+ * @param {string} dateString 日期字符串
+ * @returns {number} 时间戳(秒)
+ */
+export function formatDateToTimestamp(dateString) {
+ if (!dateString) return 0
+ return Math.floor(new Date(dateString).getTime() / 1000)
+}
+
+// 默认导出所有映射对象
+export default {
+ sexMap,
+ categoryMap,
+ breedMap,
+ strainMap,
+ physiologicalStageMap,
+ sourceMap,
+ eventMap,
+ wearMap,
+ deleteMap,
+ outMap,
+ eleAuthMap,
+ quaAuthMap,
+ vaccinMap,
+ inseminationMap,
+ insureMap,
+ mortgageMap,
+ sellStatusMap,
+ getSexName,
+ getCategoryName,
+ getBreedName,
+ getStrainName,
+ getPhysiologicalStage,
+ getSourceName,
+ getEventName,
+ getWearName,
+ getSellStatusName,
+ formatDate,
+ formatDateToTimestamp
+}
diff --git a/mini_program/farm-monitor-dashboard/src/views/ElectronicFencePage.vue b/mini_program/farm-monitor-dashboard/src/views/ElectronicFencePage.vue
new file mode 100644
index 0000000..658be19
--- /dev/null
+++ b/mini_program/farm-monitor-dashboard/src/views/ElectronicFencePage.vue
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
diff --git a/mini_program/farm-monitor-dashboard/src/views/SmartEartagAlertPage.vue b/mini_program/farm-monitor-dashboard/src/views/SmartEartagAlertPage.vue
new file mode 100644
index 0000000..8212f91
--- /dev/null
+++ b/mini_program/farm-monitor-dashboard/src/views/SmartEartagAlertPage.vue
@@ -0,0 +1,133 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/mini_program/farm-monitor-dashboard/test-api.html b/mini_program/farm-monitor-dashboard/test-api.html
new file mode 100644
index 0000000..d6c941f
--- /dev/null
+++ b/mini_program/farm-monitor-dashboard/test-api.html
@@ -0,0 +1,108 @@
+
+
+
+
+
+
API测试
+
+
+
+
API连接测试
+
+
+
1. 测试基础连接
+
+
点击按钮开始测试
+
+
+
+
2. 测试牛只档案API
+
+
点击按钮开始测试
+
+
+
+
3. 测试牛只类型API
+
+
点击按钮开始测试
+
+
+
+
+
diff --git a/mini_program/farm-monitor-dashboard/test-api.js b/mini_program/farm-monitor-dashboard/test-api.js
new file mode 100644
index 0000000..c9e3bda
--- /dev/null
+++ b/mini_program/farm-monitor-dashboard/test-api.js
@@ -0,0 +1,159 @@
+// API测试脚本 - 测试真实后端API
+const axios = require('axios')
+
+// 获取认证token
+async function getAuthToken() {
+ const baseURL = process.env.VUE_APP_API_BASE_URL || 'http://localhost:5350'
+ try {
+ const response = await axios.post(`${baseURL}/api/auth/login`, {
+ username: 'admin',
+ password: '123456'
+ })
+ return response.data.success ? response.data.token : null
+ } catch (error) {
+ console.error('获取认证token失败:', error.message)
+ return null
+ }
+}
+
+// 测试API连接
+async function testSmartHostAPI() {
+ const baseURL = process.env.VUE_APP_API_BASE_URL || 'http://localhost:5350'
+
+ console.log('🔍 开始测试真实智能主机API接口...')
+ console.log('API地址:', baseURL)
+ console.log('⚠️ 注意: 此测试将调用真实后端API,不使用模拟数据')
+
+ // 获取认证token
+ console.log('\n0. 获取认证token...')
+ const token = await getAuthToken()
+ if (!token) {
+ console.error('❌ 无法获取认证token,测试终止')
+ return
+ }
+ console.log('✅ 认证token获取成功')
+
+ try {
+ // 测试基本连接
+ console.log('\n1. 测试基本连接...')
+ const response = await axios.get(`${baseURL}/api/smart-devices/hosts`, {
+ params: {
+ page: 1,
+ pageSize: 10
+ },
+ timeout: 15000,
+ headers: {
+ 'Content-Type': 'application/json',
+ 'Authorization': `Bearer ${token}`
+ }
+ })
+
+ console.log('✅ API连接成功!')
+ console.log('响应状态:', response.status)
+ console.log('响应数据结构:', {
+ success: response.data.success,
+ total: response.data.total,
+ dataLength: response.data.data ? response.data.data.length : 0,
+ message: response.data.message
+ })
+
+ // 检查总数是否正确
+ if (response.data.total) {
+ console.log(`📊 主机总数: ${response.data.total}`)
+ if (response.data.total === 371) {
+ console.log('✅ 主机总数正确 (371)')
+ } else {
+ console.log(`⚠️ 主机总数不匹配,期望: 371,实际: ${response.data.total}`)
+ }
+ } else {
+ console.log('❌ API响应中没有total字段')
+ }
+
+ // 测试分页
+ console.log('\n2. 测试分页功能...')
+ const page2Response = await axios.get(`${baseURL}/api/smart-devices/hosts`, {
+ params: {
+ page: 2,
+ pageSize: 5
+ },
+ timeout: 15000,
+ headers: {
+ 'Authorization': `Bearer ${token}`
+ }
+ })
+
+ console.log('✅ 分页测试成功!')
+ console.log('第2页数据长度:', page2Response.data.data ? page2Response.data.data.length : 0)
+ console.log('第2页总数:', page2Response.data.total)
+
+ // 测试搜索
+ console.log('\n3. 测试搜索功能...')
+ const searchResponse = await axios.get(`${baseURL}/api/smart-devices/hosts`, {
+ params: {
+ page: 1,
+ pageSize: 10,
+ search: '2490246'
+ },
+ timeout: 15000,
+ headers: {
+ 'Authorization': `Bearer ${token}`
+ }
+ })
+
+ console.log('✅ 搜索测试成功!')
+ console.log('搜索结果长度:', searchResponse.data.data ? searchResponse.data.data.length : 0)
+ console.log('搜索结果总数:', searchResponse.data.total)
+
+ // 测试完整数据获取
+ console.log('\n4. 测试完整数据获取...')
+ const allDataResponse = await axios.get(`${baseURL}/api/smart-devices/hosts`, {
+ params: {
+ page: 1,
+ pageSize: 1000 // 获取更多数据
+ },
+ timeout: 30000,
+ headers: {
+ 'Authorization': `Bearer ${token}`
+ }
+ })
+
+ console.log('✅ 完整数据测试成功!')
+ console.log('实际获取数据长度:', allDataResponse.data.data ? allDataResponse.data.data.length : 0)
+ console.log('API返回总数:', allDataResponse.data.total)
+
+ console.log('\n🎉 所有测试通过! 前端应该能正确显示371台主机')
+
+ } catch (error) {
+ console.error('❌ API测试失败:')
+ if (error.response) {
+ console.error('状态码:', error.response.status)
+ console.error('错误信息:', error.response.data)
+
+ if (error.response.status === 401) {
+ console.log('\n🔐 认证问题:')
+ console.log('1. 检查是否需要登录token')
+ console.log('2. 检查API是否需要认证头')
+ console.log('3. 联系后端开发者获取正确的认证方式')
+ }
+ } else if (error.request) {
+ console.error('网络错误:', error.message)
+ console.error('请检查API服务是否启动')
+ } else {
+ console.error('请求配置错误:', error.message)
+ }
+
+ console.log('\n💡 解决方案:')
+ console.log('1. 确保后端服务已启动并运行在', baseURL)
+ console.log('2. 检查API地址是否正确')
+ console.log('3. 检查防火墙设置')
+ console.log('4. 查看后端日志获取详细错误信息')
+ console.log('5. 确认API接口路径: /api/smart-devices/hosts')
+ }
+}
+
+// 运行测试
+if (require.main === module) {
+ testSmartHostAPI()
+}
+
+module.exports = { testSmartHostAPI }
diff --git a/mini_program/farm-monitor-dashboard/test-host-number-fix.js b/mini_program/farm-monitor-dashboard/test-host-number-fix.js
new file mode 100644
index 0000000..895d7e8
--- /dev/null
+++ b/mini_program/farm-monitor-dashboard/test-host-number-fix.js
@@ -0,0 +1,86 @@
+// 测试主机编号显示修复
+const axios = require('axios')
+
+async function testHostNumberFix() {
+ console.log('🔍 测试主机编号显示修复...')
+
+ try {
+ // 1. 获取认证token
+ console.log('\n1. 获取认证token...')
+ const loginResponse = await axios.post('http://localhost:5350/api/auth/login', {
+ username: 'admin',
+ password: '123456'
+ })
+
+ if (!loginResponse.data.success) {
+ throw new Error('登录失败')
+ }
+
+ const token = loginResponse.data.token
+ console.log('✅ 认证成功')
+
+ // 2. 获取主机数据
+ console.log('\n2. 获取主机数据...')
+ const hostResponse = await axios.get('http://localhost:5350/api/smart-devices/hosts', {
+ headers: { Authorization: `Bearer ${token}` },
+ params: { page: 1, pageSize: 5 }
+ })
+
+ if (!hostResponse.data.success) {
+ throw new Error('获取主机数据失败')
+ }
+
+ console.log('✅ 主机数据获取成功')
+ console.log('主机总数:', hostResponse.data.total)
+
+ // 3. 检查主机编号字段
+ console.log('\n3. 检查主机编号字段...')
+ const devices = hostResponse.data.data
+
+ devices.forEach((device, index) => {
+ console.log(`\n设备 ${index + 1}:`)
+ console.log(' - deviceNumber:', device.deviceNumber || '未定义')
+ console.log(' - sid:', device.sid || '未定义')
+ console.log(' - hostId:', device.hostId || '未定义')
+ console.log(' - 显示的主机编号:', device.deviceNumber || device.sid || device.hostId || '无')
+
+ // 检查其他字段
+ console.log(' - 设备电量:', device.voltage || device.battery || '无')
+ console.log(' - 设备信号:', device.signa || device.signal || '无')
+ console.log(' - 设备温度:', device.temperature || '无')
+ console.log(' - 绑带状态:', device.bandge_status !== undefined ? device.bandge_status : (device.state !== undefined ? device.state : '无'))
+ console.log(' - 更新时间:', device.updateTime || device.lastUpdateTime || '无')
+ })
+
+ // 4. 测试搜索功能
+ console.log('\n4. 测试搜索功能...')
+ const searchResponse = await axios.get('http://localhost:5350/api/smart-devices/hosts', {
+ headers: { Authorization: `Bearer ${token}` },
+ params: {
+ page: 1,
+ pageSize: 10,
+ search: devices[0].deviceNumber || devices[0].sid || devices[0].hostId
+ }
+ })
+
+ console.log('✅ 搜索测试完成')
+ console.log('搜索结果数量:', searchResponse.data.data ? searchResponse.data.data.length : 0)
+
+ console.log('\n🎉 主机编号显示修复测试完成!')
+ console.log('\n📋 修复内容:')
+ console.log('1. 显示字段: device.deviceNumber || device.sid || device.hostId')
+ console.log('2. 搜索字段: device.deviceNumber || device.sid || device.hostId')
+ console.log('3. 编辑字段: device.deviceNumber || device.sid || device.hostId')
+
+ } catch (error) {
+ console.error('❌ 测试失败:', error.response?.data || error.message)
+ }
+}
+
+// 运行测试
+if (require.main === module) {
+ testHostNumberFix()
+}
+
+module.exports = { testHostNumberFix }
+
diff --git a/mini_program/farm-monitor-dashboard/vite.config.js b/mini_program/farm-monitor-dashboard/vite.config.js
index 6a9400a..79ecb82 100644
--- a/mini_program/farm-monitor-dashboard/vite.config.js
+++ b/mini_program/farm-monitor-dashboard/vite.config.js
@@ -10,12 +10,12 @@ export default defineConfig({
}
},
server: {
- port: 3000,
+ port: 8080,
proxy: {
'/api': {
- target: process.env.VUE_APP_BASE_URL || 'http://localhost:3001',
+ target: 'http://localhost:5350',
changeOrigin: true,
- rewrite: (path) => path.replace(/^\/api/, '')
+ rewrite: (path) => path.replace(/^\/api/, '/api')
}
}
},