diff --git a/backend/ngrok.exe b/backend/ngrok.exe deleted file mode 100644 index 74ac2c3..0000000 Binary files a/backend/ngrok.exe and /dev/null differ diff --git a/insurance_admin-system/src/router/index.js b/insurance_admin-system/src/router/index.js index 24e4bd7..945ec70 100644 --- a/insurance_admin-system/src/router/index.js +++ b/insurance_admin-system/src/router/index.js @@ -175,7 +175,7 @@ const routes = [ ] const router = createRouter({ - history: createWebHistory(), + history: createWebHistory('/insurance/'), routes }) diff --git a/insurance_admin-system/src/utils/api.js b/insurance_admin-system/src/utils/api.js index 7d1ed54..b9af461 100644 --- a/insurance_admin-system/src/utils/api.js +++ b/insurance_admin-system/src/utils/api.js @@ -58,6 +58,8 @@ export const applicationAPI = { export const policyAPI = { getList: (params) => api.get('/policies', { params }), getDetail: (id) => api.get(`/policies/${id}`), + create: (data) => api.post('/policies', data), + update: (id, data) => api.put(`/policies/${id}`, data), updateStatus: (id, data) => api.put(`/policies/${id}/status`, data), delete: (id) => api.delete(`/policies/${id}`) } diff --git a/insurance_admin-system/src/utils/request.js b/insurance_admin-system/src/utils/request.js index c4c7ced..10135da 100644 --- a/insurance_admin-system/src/utils/request.js +++ b/insurance_admin-system/src/utils/request.js @@ -164,6 +164,31 @@ const fetchRequest = async (url, options = {}) => { // 设置默认请求头 options.headers = createHeaders(options.headers) + // ========== 请求前日志 ========== + try { + const hasAuth = !!options.headers?.Authorization + const contentType = options.headers?.['Content-Type'] + const acceptType = options.headers?.['Accept'] + let bodyPreview = null + if (options.body) { + try { + bodyPreview = JSON.stringify(JSON.parse(options.body)) + } catch (_) { + bodyPreview = String(options.body).slice(0, 1000) + } + } + console.log('🔶 [前端] 准备发起请求', { + method: options.method || 'GET', + url: fullUrl, + hasAuthorization: hasAuth ? '是' : '否', + contentType, + acceptType, + bodyPreview + }) + } catch (logError) { + console.warn('记录请求前日志失败:', logError) + } + // 设置超时 const controller = new AbortController() const timeoutId = setTimeout(() => controller.abort(), API_CONFIG.timeout) @@ -172,10 +197,66 @@ const fetchRequest = async (url, options = {}) => { try { const response = await fetch(fullUrl, options) clearTimeout(timeoutId) - return await handleResponse(response) + + // ========== 原始响应日志 ========== + try { + console.log('🟩 [前端] 收到原始响应', { + status: response.status, + statusText: response.statusText, + url: fullUrl, + ok: response.ok, + contentType: response.headers.get('content-type') + }) + } catch (respLogErr) { + console.warn('记录原始响应日志失败:', respLogErr) + } + + const result = await handleResponse(response) + + // ========== 处理后响应日志 ========== + try { + const safeData = (() => { + try { + return typeof result.data === 'string' ? result.data.slice(0, 1000) : JSON.stringify(result.data).slice(0, 1000) + } catch (_) { + return '[不可序列化数据]' + } + })() + console.log('✅ [前端] 请求成功', { + url: fullUrl, + method: options.method || 'GET', + status: result.status, + statusText: result.statusText, + dataPreview: safeData + }) + } catch (resLogErr) { + console.warn('记录处理后响应日志失败:', resLogErr) + } + + return result } catch (error) { clearTimeout(timeoutId) + // ========== 错误日志 ========== + try { + console.error('❌ [前端] 请求失败', { + url: fullUrl, + method: options.method || 'GET', + message: error.message, + name: error.name, + responseStatus: error.response?.status, + responseDataPreview: (() => { + try { + return JSON.stringify(error.response?.data).slice(0, 1000) + } catch (_) { + return String(error.response?.data || '') + } + })() + }) + } catch (errLogErr) { + console.warn('记录错误日志失败:', errLogErr) + } + // 处理401错误 if (error.response?.status === 401) { const errorCode = error.response?.data?.code diff --git a/insurance_admin-system/src/views/InsuranceTypeManagement.vue b/insurance_admin-system/src/views/InsuranceTypeManagement.vue index 6482fbb..1d2f906 100644 --- a/insurance_admin-system/src/views/InsuranceTypeManagement.vue +++ b/insurance_admin-system/src/views/InsuranceTypeManagement.vue @@ -6,7 +6,7 @@ > @@ -17,19 +17,21 @@ - + 搜索 - + 重置 @@ -45,30 +47,32 @@ :pagination="pagination" @change="handleTableChange" :scroll="{ x: 1500 }" + :rowKey="getRowKey" > @@ -90,9 +97,11 @@ :title="isEdit ? '编辑险种' : '新增险种'" :ok-text="isEdit ? '更新' : '创建'" cancel-text="取消" + :confirmLoading="submitLoading" @ok="handleSubmit" @cancel="handleCancel" width="1000px" + :destroyOnClose="true" > - + @@ -135,9 +154,12 @@ 1个月 3个月 @@ -150,15 +172,25 @@ - + 电子保单 纸质保单 @@ -173,12 +205,14 @@ @@ -199,20 +235,38 @@ + + + + + + + @@ -227,6 +281,7 @@ title="险种详情" :footer="null" width="800px" + :destroyOnClose="true" > @@ -264,7 +319,7 @@ + + +
+ +
+
+ + 电子围栏 +
+
+ + + + +
+
+ + +
+
+
+ + +
+
+
智能采集器:4
+
智能设备:4
+
+
+
各德
+
设备:24065000912更多>>
+
+
切换地图
+
+ + +
+ + +
+ + +
+
+ 新增围栏 + +
+ + + + + +
+
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ +
+
+ 点击地图添加坐标点 +
+
+
+ +
+ + +
+
+
+ + + +
+ + + + \ No newline at end of file diff --git a/mini_program/farm-monitor-dashboard/test-map.html b/mini_program/farm-monitor-dashboard/test-map.html new file mode 100644 index 0000000..67f0441 --- /dev/null +++ b/mini_program/farm-monitor-dashboard/test-map.html @@ -0,0 +1,209 @@ + + + + + + 百度地图电子围栏测试 + + + +
+

百度地图电子围栏测试

+ +
+ + + + +
+ +
+ 状态: 准备就绪 +
+ +
+ +
+ +
+ 操作日志:
+
+
+ + + + \ No newline at end of file diff --git a/mini_program/farm-monitor-dashboard/utils/api.js b/mini_program/farm-monitor-dashboard/utils/api.js deleted file mode 100644 index 16c9ff8..0000000 --- a/mini_program/farm-monitor-dashboard/utils/api.js +++ /dev/null @@ -1,297 +0,0 @@ -// utils/api.js - API请求工具 - -const app = getApp() - -// 基础配置 -const config = { - // 使用真实的智能耳标API接口(直接连接后端) - baseUrl: 'https://ad.ningmuyun.com/farm/api', // 智能耳标API地址(生产环境) - timeout: 10000, - header: { - 'Content-Type': 'application/json' - } -} - -// 请求拦截器 -const requestInterceptor = (options) => { - // 添加token到请求头 - const token = wx.getStorageSync('token') - if (token) { - options.header = { - ...options.header, - 'Authorization': `Bearer ${token}` - } - } - - // 添加时间戳防止缓存 - if (options.method === 'GET') { - options.data = { - ...options.data, - _t: Date.now() - } - } - - return options -} - -// 响应拦截器 -const responseInterceptor = (response) => { - const { statusCode, data } = response - - // API响应处理 - - // 处理HTTP状态码 - if (statusCode >= 200 && statusCode < 300) { - // 统一处理响应格式 - if (data.code === 200) { - return data.data - } else if (data.success === true) { - // 处理 {success: true, data: ...} 格式 - return data - } else if (data.success === false) { - // 处理 {success: false, message: ...} 格式 - return data - } else if (data.code === undefined && data.success === undefined) { - // 直接返回数据的情况 - return data - } else { - // 业务错误 - return Promise.reject(new Error(data.message || '请求失败')) - } - } else { - // HTTP错误 - let message = '网络错误' - - switch (statusCode) { - case 401: - message = '未授权,请重新登录' - // 清除token并跳转到登录页 - wx.removeStorageSync('token') - wx.removeStorageSync('userInfo') - wx.reLaunch({ - url: '/pages/login/login' - }) - break - case 403: - message = '拒绝访问' - break - case 404: - message = '请求的资源不存在' - break - case 500: - message = '服务器内部错误' - break - default: - message = `连接错误${statusCode}` - } - - return Promise.reject(new Error(message)) - } -} - -// 通用请求方法(带故障转移) -const request = (options) => { - return new Promise((resolve, reject) => { - const failoverBases = [ - 'http://localhost:5350/api', - 'http://127.0.0.1:5350/api' - ] - - const allowFailover = options.allowFailover !== false - - const doWxRequest = (baseUrlToUse, isFailoverAttempt = false) => { - // 应用请求拦截器 - const processedOptions = requestInterceptor({ - url: baseUrlToUse + options.url, - method: options.method || 'GET', - data: options.data || {}, - header: { - ...config.header, - ...options.header - }, - timeout: options.timeout || config.timeout - }) - - console.log('[API] 请求URL:', processedOptions.url, '方法:', processedOptions.method, '是否故障转移:', isFailoverAttempt) - - wx.request({ - ...processedOptions, - success: (response) => { - console.log('[API] 响应状态码:', response.statusCode, '请求URL:', processedOptions.url) - // 当远程网关或上游故障(5xx)时,自动尝试本地备用服务(5350) - if ( - response.statusCode >= 500 && - allowFailover && - !isFailoverAttempt && - baseUrlToUse === config.baseUrl && - failoverBases.length > 0 - ) { - console.warn('[API] 远程服务返回', response.statusCode, ',尝试切换到本地备用服务:', failoverBases[0]) - return doWxRequest(failoverBases[0], true) - } - - try { - const result = responseInterceptor(response) - console.log('响应拦截器处理结果:', result) - resolve(result) - } catch (error) { - console.log('响应拦截器错误:', error) - reject(error) - } - }, - fail: (error) => { - console.log('wx.request失败:', error, '请求URL:', processedOptions.url) - let message = '网络连接异常' - - if (error.errMsg) { - if (error.errMsg.includes('timeout')) { - message = '请求超时' - } else if (error.errMsg.includes('fail')) { - message = '网络连接失败' - } - } - - // 如果是远程网络失败(非HTTP响应),也尝试本地备用 - if (allowFailover && !isFailoverAttempt && baseUrlToUse === config.baseUrl && failoverBases.length > 0) { - console.warn('[API] 远程网络失败,尝试切换到本地备用服务:', failoverBases[0]) - return doWxRequest(failoverBases[0], true) - } - - reject(new Error(message)) - } - }) - } - - // 首次请求使用当前配置的基础地址 - doWxRequest(config.baseUrl, false) - }) -} - -// GET请求 -export const get = (url, data = {}) => { - return request({ - url, - method: 'GET', - data - }) -} - -// POST请求 -export const post = (url, data = {}) => { - return request({ - url, - method: 'POST', - data - }) -} - -// PUT请求 -export const put = (url, data = {}) => { - return request({ - url, - method: 'PUT', - data - }) -} - -// DELETE请求 -export const del = (url, data = {}) => { - return request({ - url, - method: 'DELETE', - data - }) -} - -// 上传文件 -export const upload = (url, filePath, formData = {}) => { - return new Promise((resolve, reject) => { - const token = wx.getStorageSync('token') - const header = { - 'Content-Type': 'multipart/form-data' - } - - if (token) { - header['Authorization'] = `Bearer ${token}` - } - - wx.uploadFile({ - url: config.baseUrl + url, - filePath: filePath, - name: 'file', - formData: formData, - header: header, - success: (response) => { - try { - const data = JSON.parse(response.data) - if (data.code === 200) { - resolve(data.data) - } else { - reject(new Error(data.message)) - } - } catch (error) { - reject(new Error('上传失败')) - } - }, - fail: (error) => { - console.error('上传失败:', error) - reject(new Error('上传失败')) - } - }) - }) -} - -// 下载文件 -export const download = (url, filePath) => { - return new Promise((resolve, reject) => { - wx.downloadFile({ - url: config.baseUrl + url, - filePath: filePath, - success: (response) => { - if (response.statusCode === 200) { - resolve(response.filePath) - } else { - reject(new Error('下载失败')) - } - }, - fail: (error) => { - console.error('下载失败:', error) - reject(new Error('下载失败')) - } - }) - }) -} - -// 设置基础URL -export const setBaseUrl = (baseUrl) => { - config.baseUrl = baseUrl -} - -// 获取基础URL -export const getBaseUrl = () => { - return config.baseUrl -} - -// 设置超时时间 -export const setTimeout = (timeout) => { - config.timeout = timeout -} - -// 获取超时时间 -export const getTimeout = () => { - return config.timeout -} - -export default { - request, - get, - post, - put, - del, - upload, - download, - setBaseUrl, - getBaseUrl, - setTimeout, - getTimeout -} diff --git a/mini_program/farm-monitor-dashboard/utils/auth.js b/mini_program/farm-monitor-dashboard/utils/auth.js deleted file mode 100644 index 02b9916..0000000 --- a/mini_program/farm-monitor-dashboard/utils/auth.js +++ /dev/null @@ -1,311 +0,0 @@ -// utils/auth.js - 认证相关工具 - -// 获取token -export const getToken = () => { - return wx.getStorageSync('token') -} - -// 设置token -export const setToken = (token) => { - wx.setStorageSync('token', token) -} - -// 清除token -export const clearToken = () => { - wx.removeStorageSync('token') -} - -// 获取用户信息 -export const getUserInfo = () => { - return wx.getStorageSync('userInfo') -} - -// 设置用户信息 -export const setUserInfo = (userInfo) => { - wx.setStorageSync('userInfo', userInfo) -} - -// 清除用户信息 -export const clearUserInfo = () => { - wx.removeStorageSync('userInfo') -} - -// 检查是否已登录 -export const isLoggedIn = () => { - const token = getToken() - const userInfo = getUserInfo() - return !!(token && userInfo) -} - -// 清除所有认证信息 -export const clearAuth = () => { - clearToken() - clearUserInfo() -} - -// 跳转到登录页 -export const redirectToLogin = () => { - wx.reLaunch({ - url: '/pages/login/login' - }) -} - -// 检查登录状态,未登录则跳转到登录页 -export const checkAuth = () => { - if (!isLoggedIn()) { - redirectToLogin() - return false - } - return true -} - -// 获取用户权限 -export const getUserPermissions = () => { - const userInfo = getUserInfo() - return userInfo ? userInfo.permissions || [] : [] -} - -// 检查用户权限 -export const hasPermission = (permission) => { - const permissions = getUserPermissions() - return permissions.includes(permission) -} - -// 检查用户角色 -export const hasRole = (role) => { - const userInfo = getUserInfo() - return userInfo ? userInfo.role === role : false -} - -// 获取用户ID -export const getUserId = () => { - const userInfo = getUserInfo() - return userInfo ? userInfo.id : null -} - -// 获取用户名 -export const getUsername = () => { - const userInfo = getUserInfo() - return userInfo ? userInfo.username : '' -} - -// 获取用户手机号 -export const getUserPhone = () => { - const userInfo = getUserInfo() - return userInfo ? userInfo.phone : '' -} - -// 获取用户邮箱 -export const getUserEmail = () => { - const userInfo = getUserInfo() - return userInfo ? userInfo.email : '' -} - -// 获取用户头像 -export const getUserAvatar = () => { - const userInfo = getUserInfo() - return userInfo ? userInfo.avatar : '' -} - -// 获取用户昵称 -export const getUserNickname = () => { - const userInfo = getUserInfo() - return userInfo ? userInfo.nickname : '' -} - -// 获取用户真实姓名 -export const getUserRealName = () => { - const userInfo = getUserInfo() - return userInfo ? userInfo.realName : '' -} - -// 获取用户部门 -export const getUserDepartment = () => { - const userInfo = getUserInfo() - return userInfo ? userInfo.department : '' -} - -// 获取用户职位 -export const getUserPosition = () => { - const userInfo = getUserInfo() - return userInfo ? userInfo.position : '' -} - -// 获取用户创建时间 -export const getUserCreateTime = () => { - const userInfo = getUserInfo() - return userInfo ? userInfo.createTime : '' -} - -// 获取用户最后登录时间 -export const getUserLastLoginTime = () => { - const userInfo = getUserInfo() - return userInfo ? userInfo.lastLoginTime : '' -} - -// 更新用户信息 -export const updateUserInfo = (updates) => { - const userInfo = getUserInfo() - if (userInfo) { - const newUserInfo = { - ...userInfo, - ...updates - } - setUserInfo(newUserInfo) - } -} - -// 登录 -export const login = (token, userInfo) => { - console.log('auth.login 被调用,token:', token) - console.log('auth.login 被调用,userInfo:', userInfo) - setToken(token) - setUserInfo(userInfo) - console.log('token已保存,当前token:', getToken()) -} - -// 登出 -export const logout = () => { - clearAuth() - redirectToLogin() -} - -// 刷新token -export const refreshToken = async (newToken) => { - setToken(newToken) -} - -// 检查token是否过期 -export const isTokenExpired = () => { - const token = getToken() - if (!token) return true - - try { - // 简单的token过期检查,实际项目中应该解析JWT token - // 这里假设token包含过期时间信息 - const tokenData = JSON.parse(atob(token.split('.')[1])) - const currentTime = Math.floor(Date.now() / 1000) - return tokenData.exp < currentTime - } catch (error) { - console.error('解析token失败:', error) - return true - } -} - -// 自动刷新token -export const autoRefreshToken = async () => { - if (isTokenExpired()) { - // 这里应该调用后端API刷新token - // 暂时直接清除认证信息 - clearAuth() - redirectToLogin() - return false - } - return true -} - -// 获取认证头 -export const getAuthHeader = () => { - const token = getToken() - return token ? { 'Authorization': `Bearer ${token}` } : {} -} - -// 保存登录状态 -export const saveLoginState = (loginData) => { - const { token, userInfo, rememberMe = false } = loginData - - if (rememberMe) { - // 记住登录状态 - setToken(token) - setUserInfo(userInfo) - } else { - // 临时登录状态 - setToken(token) - setUserInfo(userInfo) - } -} - -// 获取登录状态 -export const getLoginState = () => { - return { - isLoggedIn: isLoggedIn(), - token: getToken(), - userInfo: getUserInfo() - } -} - -// 验证用户信息完整性 -export const validateUserInfo = () => { - const userInfo = getUserInfo() - if (!userInfo) return false - - const requiredFields = ['id', 'username', 'phone'] - return requiredFields.every(field => userInfo[field]) -} - -// 获取用户显示名称 -export const getUserDisplayName = () => { - const userInfo = getUserInfo() - if (!userInfo) return '未登录' - - return userInfo.realName || userInfo.nickname || userInfo.username || '未知用户' -} - -// 获取用户状态 -export const getUserStatus = () => { - const userInfo = getUserInfo() - return userInfo ? userInfo.status : 'unknown' -} - -// 检查用户是否激活 -export const isUserActive = () => { - const status = getUserStatus() - return status === 'active' -} - -// 检查用户是否被禁用 -export const isUserDisabled = () => { - const status = getUserStatus() - return status === 'disabled' -} - -export default { - getToken, - setToken, - clearToken, - getUserInfo, - setUserInfo, - clearUserInfo, - isLoggedIn, - clearAuth, - redirectToLogin, - checkAuth, - getUserPermissions, - hasPermission, - hasRole, - getUserId, - getUsername, - getUserPhone, - getUserEmail, - getUserAvatar, - getUserNickname, - getUserRealName, - getUserDepartment, - getUserPosition, - getUserCreateTime, - getUserLastLoginTime, - updateUserInfo, - login, - logout, - refreshToken, - isTokenExpired, - autoRefreshToken, - getAuthHeader, - saveLoginState, - getLoginState, - validateUserInfo, - getUserDisplayName, - getUserStatus, - isUserActive, - isUserDisabled -} diff --git a/mini_program/farm-monitor-dashboard/utils/index.js b/mini_program/farm-monitor-dashboard/utils/index.js deleted file mode 100644 index 57f1089..0000000 --- a/mini_program/farm-monitor-dashboard/utils/index.js +++ /dev/null @@ -1,357 +0,0 @@ -// utils/index.js - 工具函数 - -// 格式化时间 -export const formatTime = (time) => { - if (!time) return '' - - const now = new Date() - const targetTime = new Date(time) - const diff = now - targetTime - const minutes = Math.floor(diff / 60000) - const hours = Math.floor(minutes / 60) - const days = Math.floor(hours / 24) - - if (minutes < 1) return '刚刚' - if (minutes < 60) return `${minutes}分钟前` - if (hours < 24) return `${hours}小时前` - if (days < 7) return `${days}天前` - - return targetTime.toLocaleDateString() -} - -// 格式化日期 -export const formatDate = (date, format = 'YYYY-MM-DD') => { - if (!date) return '' - - const d = new Date(date) - const year = d.getFullYear() - const month = String(d.getMonth() + 1).padStart(2, '0') - const day = String(d.getDate()).padStart(2, '0') - const hours = String(d.getHours()).padStart(2, '0') - const minutes = String(d.getMinutes()).padStart(2, '0') - const seconds = String(d.getSeconds()).padStart(2, '0') - - return format - .replace('YYYY', year) - .replace('MM', month) - .replace('DD', day) - .replace('HH', hours) - .replace('mm', minutes) - .replace('ss', seconds) -} - -// 防抖函数 -export const debounce = (func, wait) => { - let timeout - return function executedFunction(...args) { - const later = () => { - clearTimeout(timeout) - func(...args) - } - clearTimeout(timeout) - timeout = setTimeout(later, wait) - } -} - -// 节流函数 -export const throttle = (func, limit) => { - let inThrottle - return function(...args) { - if (!inThrottle) { - func.apply(this, args) - inThrottle = true - setTimeout(() => inThrottle = false, limit) - } - } -} - -// 深拷贝 -export const deepClone = (obj) => { - if (obj === null || typeof obj !== 'object') return obj - if (obj instanceof Date) return new Date(obj.getTime()) - if (obj instanceof Array) return obj.map(item => deepClone(item)) - if (typeof obj === 'object') { - const clonedObj = {} - for (const key in obj) { - if (obj.hasOwnProperty(key)) { - clonedObj[key] = deepClone(obj[key]) - } - } - return clonedObj - } -} - -// 生成唯一ID -export const generateId = () => { - return Date.now().toString(36) + Math.random().toString(36).substr(2) -} - -// 验证手机号 -export const validatePhone = (phone) => { - const reg = /^1[3-9]\d{9}$/ - return reg.test(phone) -} - -// 验证邮箱 -export const validateEmail = (email) => { - const reg = /^[^\s@]+@[^\s@]+\.[^\s@]+$/ - return reg.test(email) -} - -// 验证身份证号 -export const validateIdCard = (idCard) => { - const reg = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/ - return reg.test(idCard) -} - -// 获取文件扩展名 -export const getFileExtension = (filename) => { - return filename.slice((filename.lastIndexOf('.') - 1 >>> 0) + 2) -} - -// 格式化文件大小 -export const formatFileSize = (bytes) => { - if (bytes === 0) return '0 B' - const k = 1024 - const sizes = ['B', 'KB', 'MB', 'GB', 'TB'] - const i = Math.floor(Math.log(bytes) / Math.log(k)) - return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i] -} - -// 获取URL参数 -export const getUrlParams = (url) => { - const params = {} - const urlObj = new URL(url) - urlObj.searchParams.forEach((value, key) => { - params[key] = value - }) - return params -} - -// 数组去重 -export const uniqueArray = (arr) => { - return [...new Set(arr)] -} - -// 对象数组去重 -export const uniqueObjectArray = (arr, key) => { - const seen = new Set() - return arr.filter(item => { - const value = item[key] - if (seen.has(value)) { - return false - } - seen.add(value) - return true - }) -} - -// 计算两个日期之间的天数 -export const daysBetween = (date1, date2) => { - const oneDay = 24 * 60 * 60 * 1000 - const firstDate = new Date(date1) - const secondDate = new Date(date2) - return Math.round(Math.abs((firstDate - secondDate) / oneDay)) -} - -// 获取当前时间戳 -export const getCurrentTimestamp = () => { - return Date.now() -} - -// 获取当前日期字符串 -export const getCurrentDateString = () => { - return new Date().toISOString().split('T')[0] -} - -// 获取当前时间字符串 -export const getCurrentTimeString = () => { - return new Date().toTimeString().split(' ')[0] -} - -// 检查是否为移动设备 -export const isMobile = () => { - return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) -} - -// 获取随机颜色 -export const getRandomColor = () => { - const colors = ['#3cc51f', '#52c41a', '#faad14', '#f5222d', '#1890ff', '#722ed1', '#13c2c2', '#eb2f96'] - return colors[Math.floor(Math.random() * colors.length)] -} - -// 数字千分位格式化 -export const formatNumber = (num) => { - return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',') -} - -// 金额格式化 -export const formatMoney = (amount, currency = '¥') => { - return currency + formatNumber(amount.toFixed(2)) -} - -// 获取状态文本 -export const getStatusText = (status, statusMap) => { - return statusMap[status] || '未知状态' -} - -// 获取状态颜色 -export const getStatusColor = (status, colorMap) => { - return colorMap[status] || '#909399' -} - -// 检查对象是否为空 -export const isEmpty = (obj) => { - if (obj === null || obj === undefined) return true - if (typeof obj === 'string') return obj.trim() === '' - if (Array.isArray(obj)) return obj.length === 0 - if (typeof obj === 'object') return Object.keys(obj).length === 0 - return false -} - -// 安全的JSON解析 -export const safeJsonParse = (str, defaultValue = null) => { - try { - return JSON.parse(str) - } catch (e) { - return defaultValue - } -} - -// 安全的JSON字符串化 -export const safeJsonStringify = (obj, defaultValue = '{}') => { - try { - return JSON.stringify(obj) - } catch (e) { - return defaultValue - } -} - -// 获取页面参数 -export const getPageParams = (options) => { - const params = {} - if (options && options.query) { - Object.keys(options.query).forEach(key => { - params[key] = options.query[key] - }) - } - return params -} - -// 设置页面标题 -export const setPageTitle = (title) => { - wx.setNavigationBarTitle({ - title: title - }) -} - -// 显示加载提示 -export const showLoading = (title = '加载中...') => { - wx.showLoading({ - title: title, - mask: true - }) -} - -// 隐藏加载提示 -export const hideLoading = () => { - wx.hideLoading() -} - -// 显示成功提示 -export const showSuccess = (title = '操作成功') => { - wx.showToast({ - title: title, - icon: 'success', - duration: 2000 - }) -} - -// 显示错误提示 -export const showError = (title = '操作失败') => { - wx.showToast({ - title: title, - icon: 'none', - duration: 2000 - }) -} - -// 显示确认对话框 -export const showConfirm = (content, title = '提示') => { - return new Promise((resolve) => { - wx.showModal({ - title: title, - content: content, - success: (res) => { - resolve(res.confirm) - } - }) - }) -} - -// 页面跳转 -export const navigateTo = (url) => { - wx.navigateTo({ url }) -} - -// 页面重定向 -export const redirectTo = (url) => { - wx.redirectTo({ url }) -} - -// 页面返回 -export const navigateBack = (delta = 1) => { - wx.navigateBack({ delta }) -} - -// 切换到tabBar页面 -export const switchTab = (url) => { - wx.switchTab({ url }) -} - -// 重新启动到指定页面 -export const reLaunch = (url) => { - wx.reLaunch({ url }) -} - -export default { - formatTime, - formatDate, - debounce, - throttle, - deepClone, - generateId, - validatePhone, - validateEmail, - validateIdCard, - getFileExtension, - formatFileSize, - getUrlParams, - uniqueArray, - uniqueObjectArray, - daysBetween, - getCurrentTimestamp, - getCurrentDateString, - getCurrentTimeString, - isMobile, - getRandomColor, - formatNumber, - formatMoney, - getStatusText, - getStatusColor, - isEmpty, - safeJsonParse, - safeJsonStringify, - getPageParams, - setPageTitle, - showLoading, - hideLoading, - showSuccess, - showError, - showConfirm, - navigateTo, - redirectTo, - navigateBack, - switchTab, - reLaunch -} diff --git a/mini_program/farm-monitor-wechat/README.md b/mini_program/farm-monitor-wechat/README.md deleted file mode 100644 index 90cac85..0000000 --- a/mini_program/farm-monitor-wechat/README.md +++ /dev/null @@ -1,263 +0,0 @@ -# 养殖端微信小程序 - 原生版本 - -## 项目简介 - -这是养殖管理系统的微信小程序原生版本,使用微信小程序原生开发框架,不依赖uniapp等第三方框架。 - -## 功能特性 - -### 🐄 牛只管理 -- 牛只信息录入和管理 -- 牛只转移和出栏 -- 牛只统计和查询 -- 批量操作支持 - -### 📱 设备管理 -- 智能耳标管理 -- 智能项圈管理 -- 智能脚环管理 -- 智能主机管理 -- 设备实时监控 - -### ⚠️ 预警中心 -- 智能耳标预警 -- 智能项圈预警 -- 预警统计和分析 -- 预警处理和管理 - -### 📍 电子围栏 -- 围栏设置和管理 -- 越界预警 -- 地图显示 - -### 👤 个人中心 -- 用户信息管理 -- 系统设置 -- 帮助和支持 - -## 技术栈 - -- **框架**: 微信小程序原生开发 -- **语言**: JavaScript ES6+ -- **样式**: WXSS -- **模板**: WXML -- **状态管理**: 小程序全局数据 -- **网络请求**: wx.request -- **UI组件**: 微信小程序原生组件 - -## 项目结构 - -``` -farm-monitor-wechat/ -├── app.js # 小程序入口文件 -├── app.json # 小程序全局配置 -├── app.wxss # 小程序全局样式 -├── sitemap.json # 站点地图配置 -├── project.config.json # 项目配置文件 -├── project.private.config.json # 私有配置文件 -├── pages/ # 页面目录 -│ ├── index/ # 首页 -│ ├── login/ # 登录页 -│ ├── home/ # 首页Tab -│ ├── cattle/ # 牛只管理 -│ ├── device/ # 设备管理 -│ ├── alert/ # 预警中心 -│ └── profile/ # 个人中心 -├── services/ # 服务层 -│ ├── api.js # API请求服务 -│ ├── authService.js # 认证服务 -│ ├── cattleService.js # 牛只管理服务 -│ ├── deviceService.js # 设备管理服务 -│ └── alertService.js # 预警服务 -├── components/ # 自定义组件 -├── utils/ # 工具函数 -├── images/ # 图片资源 -└── README.md # 项目说明 -``` - -## 开发环境 - -### 环境要求 -- 微信开发者工具 1.06.0+ -- Node.js 16.0+ -- 微信小程序账号 - -### 安装步骤 - -1. **克隆项目** - ```bash - git clone - cd farm-monitor-wechat - ``` - -2. **安装依赖** - ```bash - npm install - ``` - -3. **配置项目** - - 在微信开发者工具中打开项目 - - 修改 `app.json` 中的 `appid` - - 修改 `services/api.js` 中的 `baseUrl` - -4. **启动开发** - - 在微信开发者工具中点击"编译" - - 在模拟器中预览效果 - -## 配置说明 - -### 1. 小程序配置 (app.json) - -```json -{ - "pages": [...], - "tabBar": {...}, - "window": {...}, - "permission": {...} -} -``` - -### 2. API配置 (services/api.js) - -```javascript -const apiService = new ApiService() -apiService.baseUrl = 'http://your-api-domain.com/api' -``` - -### 3. 项目配置 (project.config.json) - -```json -{ - "appid": "wx-your-appid-here", - "projectname": "farm-monitor-wechat" -} -``` - -## 页面说明 - -### 主要页面 - -1. **首页 (pages/index)** - - 应用启动页 - - 用户登录引导 - -2. **登录页 (pages/login)** - - 密码登录 - - 短信验证码登录 - - 用户注册 - -3. **首页Tab (pages/home)** - - 数据统计展示 - - 快捷操作入口 - - 最近预警信息 - -4. **牛只管理 (pages/cattle)** - - 牛只列表 - - 牛只详情 - - 添加/编辑牛只 - -5. **设备管理 (pages/device)** - - 设备列表 - - 设备详情 - - 设备控制 - -6. **预警中心 (pages/alert)** - - 预警列表 - - 预警详情 - - 预警处理 - -7. **个人中心 (pages/profile)** - - 用户信息 - - 系统设置 - - 帮助支持 - -## API接口 - -### 认证接口 -- `POST /auth/login` - 用户登录 -- `POST /auth/sms-login` - 短信登录 -- `POST /auth/register` - 用户注册 -- `GET /auth/user-info` - 获取用户信息 - -### 牛只管理接口 -- `GET /cattle` - 获取牛只列表 -- `POST /cattle` - 添加牛只 -- `PUT /cattle/:id` - 更新牛只信息 -- `DELETE /cattle/:id` - 删除牛只 - -### 设备管理接口 -- `GET /device` - 获取设备列表 -- `GET /device/:id` - 获取设备详情 -- `POST /device` - 添加设备 -- `PUT /device/:id` - 更新设备信息 - -### 预警管理接口 -- `GET /smart-alerts/public` - 获取预警列表 -- `GET /smart-alerts/public/stats` - 获取预警统计 -- `POST /smart-alerts/public/:id/handle` - 处理预警 - -## 开发规范 - -### 1. 代码规范 -- 使用ES6+语法 -- 遵循微信小程序开发规范 -- 统一使用2空格缩进 -- 使用有意义的变量和函数名 - -### 2. 文件命名 -- 页面文件使用小写字母和连字符 -- 组件文件使用PascalCase -- 工具文件使用camelCase - -### 3. 注释规范 -- 文件头部添加文件说明 -- 函数添加JSDoc注释 -- 复杂逻辑添加行内注释 - -## 部署说明 - -### 1. 开发环境 -- 在微信开发者工具中直接运行 -- 使用测试API接口 - -### 2. 生产环境 -- 上传代码到微信小程序后台 -- 配置生产环境API接口 -- 提交审核发布 - -## 常见问题 - -### 1. 网络请求失败 -- 检查API接口地址是否正确 -- 确认服务器是否正常运行 -- 检查网络连接状态 - -### 2. 登录失败 -- 检查用户名密码是否正确 -- 确认API接口返回格式 -- 查看控制台错误信息 - -### 3. 页面显示异常 -- 检查数据绑定是否正确 -- 确认样式文件是否引入 -- 查看控制台错误信息 - -## 更新日志 - -### v1.0.0 (2024-01-01) -- 初始版本发布 -- 实现基础功能模块 -- 完成用户认证系统 -- 完成牛只管理功能 -- 完成设备管理功能 -- 完成预警中心功能 - -## 联系方式 - -- 项目负责人: [姓名] -- 邮箱: [email] -- 电话: [phone] - -## 许可证 - -本项目采用 MIT 许可证,详情请查看 [LICENSE](LICENSE) 文件。 diff --git a/mini_program/farm-monitor-wechat/app.js b/mini_program/farm-monitor-wechat/app.js deleted file mode 100644 index cf49902..0000000 --- a/mini_program/farm-monitor-wechat/app.js +++ /dev/null @@ -1,196 +0,0 @@ -/** - * 养殖端微信小程序 - 原生版本 - * @file app.js - * @description 小程序入口文件 - */ - -// 引入API服务 -const apiService = require('./services/api.js') - -App({ - /** - * 全局数据 - */ - globalData: { - version: '1.0.0', - platform: 'wechat', - isDevelopment: true, - userInfo: null, - token: null, - baseUrl: 'http://localhost:5350/api' - }, - - /** - * 小程序初始化 - */ - onLaunch: function(options) { - console.log('小程序启动', options) - - // 检查更新 - this.checkForUpdate() - - // 初始化用户信息 - this.initUserInfo() - - // 检查登录状态 - this.checkLoginStatus() - }, - - /** - * 小程序显示 - */ - onShow: function(options) { - console.log('小程序显示', options) - }, - - /** - * 小程序隐藏 - */ - onHide: function() { - console.log('小程序隐藏') - }, - - /** - * 小程序错误 - */ - onError: function(msg) { - console.error('小程序错误:', msg) - }, - - /** - * 检查更新 - */ - checkForUpdate: function() { - if (wx.canIUse('getUpdateManager')) { - const updateManager = wx.getUpdateManager() - - updateManager.onCheckForUpdate(function(res) { - console.log('检查更新结果:', res.hasUpdate) - }) - - updateManager.onUpdateReady(function() { - wx.showModal({ - title: '更新提示', - content: '新版本已经准备好,是否重启应用?', - success: function(res) { - if (res.confirm) { - updateManager.applyUpdate() - } - } - }) - }) - - updateManager.onUpdateFailed(function() { - console.log('新版本下载失败') - }) - } - }, - - /** - * 初始化用户信息 - */ - initUserInfo: function() { - try { - const userInfo = wx.getStorageSync('userInfo') - const token = wx.getStorageSync('token') - - if (userInfo) { - this.globalData.userInfo = userInfo - } - - if (token) { - this.globalData.token = token - } - - console.log('用户信息初始化完成:', userInfo) - } catch (error) { - console.error('初始化用户信息失败:', error) - } - }, - - /** - * 检查登录状态 - */ - checkLoginStatus: function() { - const token = this.globalData.token - const userInfo = this.globalData.userInfo - - if (token && userInfo) { - console.log('用户已登录') - // 验证token有效性 - this.validateToken() - } else { - console.log('用户未登录') - } - }, - - /** - * 验证token有效性 - */ - validateToken: function() { - apiService.validateToken() - .then(res => { - if (res.success) { - console.log('Token验证成功') - } else { - console.log('Token已过期,清除登录信息') - this.clearLoginInfo() - } - }) - .catch(error => { - console.error('Token验证失败:', error) - this.clearLoginInfo() - }) - }, - - /** - * 清除登录信息 - */ - clearLoginInfo: function() { - this.globalData.userInfo = null - this.globalData.token = null - - try { - wx.removeStorageSync('userInfo') - wx.removeStorageSync('token') - } catch (error) { - console.error('清除登录信息失败:', error) - } - }, - - /** - * 设置用户信息 - */ - setUserInfo: function(userInfo, token) { - this.globalData.userInfo = userInfo - this.globalData.token = token - - try { - wx.setStorageSync('userInfo', userInfo) - wx.setStorageSync('token', token) - } catch (error) { - console.error('保存用户信息失败:', error) - } - }, - - /** - * 获取用户信息 - */ - getUserInfo: function() { - return this.globalData.userInfo - }, - - /** - * 获取token - */ - getToken: function() { - return this.globalData.token - }, - - /** - * 检查是否已登录 - */ - isLoggedIn: function() { - return !!(this.globalData.userInfo && this.globalData.token) - } -}) diff --git a/mini_program/farm-monitor-wechat/app.json b/mini_program/farm-monitor-wechat/app.json deleted file mode 100644 index d56d6cf..0000000 --- a/mini_program/farm-monitor-wechat/app.json +++ /dev/null @@ -1,79 +0,0 @@ -{ - "pages": [ - "pages/index/index", - "pages/login/login", - "pages/home/home", - "pages/cattle/cattle", - "pages/cattle/add/add", - "pages/cattle/detail/detail", - "pages/cattle/transfer/transfer", - "pages/cattle/exit/exit", - "pages/device/device", - "pages/device/eartag/eartag", - "pages/device/collar/collar", - "pages/device/ankle/ankle", - "pages/device/host/host", - "pages/alert/alert", - "pages/alert/eartag/eartag", - "pages/alert/collar/collar", - "pages/fence/fence", - "pages/profile/profile" - ], - "tabBar": { - "color": "#7A7E83", - "selectedColor": "#3cc51f", - "borderStyle": "black", - "backgroundColor": "#ffffff", - "list": [ - { - "pagePath": "pages/home/home", - "iconPath": "images/home.png", - "selectedIconPath": "images/home-active.png", - "text": "首页" - }, - { - "pagePath": "pages/cattle/cattle", - "iconPath": "images/cattle.png", - "selectedIconPath": "images/cattle-active.png", - "text": "牛只管理" - }, - { - "pagePath": "pages/device/device", - "iconPath": "images/device.png", - "selectedIconPath": "images/device-active.png", - "text": "设备管理" - }, - { - "pagePath": "pages/alert/alert", - "iconPath": "images/alert.png", - "selectedIconPath": "images/alert-active.png", - "text": "预警中心" - }, - { - "pagePath": "pages/profile/profile", - "iconPath": "images/profile.png", - "selectedIconPath": "images/profile-active.png", - "text": "我的" - } - ] - }, - "window": { - "backgroundTextStyle": "light", - "navigationBarBackgroundColor": "#fff", - "navigationBarTitleText": "养殖管理系统", - "navigationBarTextStyle": "black", - "backgroundColor": "#f8f8f8" - }, - "networkTimeout": { - "request": 10000, - "downloadFile": 10000 - }, - "debug": true, - "permission": { - "scope.userLocation": { - "desc": "你的位置信息将用于养殖场定位和地图展示" - } - }, - "requiredBackgroundModes": ["location"], - "sitemapLocation": "sitemap.json" -} diff --git a/mini_program/farm-monitor-wechat/app.wxss b/mini_program/farm-monitor-wechat/app.wxss deleted file mode 100644 index eaed5ac..0000000 --- a/mini_program/farm-monitor-wechat/app.wxss +++ /dev/null @@ -1,309 +0,0 @@ -/** - * 养殖端微信小程序 - 全局样式 - * @file app.wxss - * @description 全局样式文件 - */ - -/* 全局样式重置 */ -page { - background-color: #f8f8f8; - font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', Helvetica, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', SimSun, sans-serif; - font-size: 28rpx; - line-height: 1.6; - color: #333; -} - -/* 容器样式 */ -.container { - padding: 20rpx; - min-height: 100vh; - box-sizing: border-box; -} - -/* 卡片样式 */ -.card { - background: #fff; - border-radius: 16rpx; - padding: 30rpx; - margin-bottom: 20rpx; - box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1); -} - -/* 按钮样式 */ -.btn { - display: flex; - align-items: center; - justify-content: center; - padding: 20rpx 40rpx; - border-radius: 8rpx; - font-size: 28rpx; - font-weight: 500; - border: none; - outline: none; - transition: all 0.3s ease; -} - -.btn-primary { - background: #3cc51f; - color: #fff; -} - -.btn-primary:hover { - background: #2db815; -} - -.btn-secondary { - background: #f0f0f0; - color: #666; -} - -.btn-danger { - background: #ff4757; - color: #fff; -} - -.btn-warning { - background: #ffa502; - color: #fff; -} - -.btn-small { - padding: 12rpx 24rpx; - font-size: 24rpx; -} - -.btn-large { - padding: 30rpx 60rpx; - font-size: 32rpx; -} - -/* 输入框样式 */ -.input { - width: 100%; - padding: 20rpx; - border: 2rpx solid #e0e0e0; - border-radius: 8rpx; - font-size: 28rpx; - background: #fff; - box-sizing: border-box; -} - -.input:focus { - border-color: #3cc51f; -} - -/* 列表样式 */ -.list { - background: #fff; - border-radius: 16rpx; - overflow: hidden; -} - -.list-item { - display: flex; - align-items: center; - padding: 30rpx; - border-bottom: 1rpx solid #f0f0f0; - transition: background-color 0.3s ease; -} - -.list-item:last-child { - border-bottom: none; -} - -.list-item:hover { - background: #f8f8f8; -} - -.list-item-content { - flex: 1; -} - -.list-item-title { - font-size: 30rpx; - font-weight: 500; - color: #333; - margin-bottom: 8rpx; -} - -.list-item-desc { - font-size: 24rpx; - color: #999; -} - -.list-item-arrow { - width: 24rpx; - height: 24rpx; - margin-left: 20rpx; -} - -/* 状态标签 */ -.status-tag { - display: inline-block; - padding: 8rpx 16rpx; - border-radius: 20rpx; - font-size: 22rpx; - font-weight: 500; -} - -.status-online { - background: #e8f5e8; - color: #3cc51f; -} - -.status-offline { - background: #ffe8e8; - color: #ff4757; -} - -.status-warning { - background: #fff3e0; - color: #ffa502; -} - -.status-normal { - background: #f0f0f0; - color: #666; -} - -/* 统计卡片 */ -.stats-card { - background: #fff; - border-radius: 16rpx; - padding: 30rpx; - margin-bottom: 20rpx; - box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1); -} - -.stats-title { - font-size: 28rpx; - color: #666; - margin-bottom: 20rpx; -} - -.stats-grid { - display: flex; - flex-wrap: wrap; - gap: 20rpx; -} - -.stats-item { - flex: 1; - min-width: 140rpx; - text-align: center; - padding: 20rpx; - background: #f8f8f8; - border-radius: 12rpx; -} - -.stats-number { - font-size: 36rpx; - font-weight: bold; - color: #333; - margin-bottom: 8rpx; -} - -.stats-label { - font-size: 24rpx; - color: #666; -} - -/* 空状态 */ -.empty-state { - text-align: center; - padding: 80rpx 40rpx; - color: #999; -} - -.empty-icon { - width: 120rpx; - height: 120rpx; - margin: 0 auto 20rpx; - opacity: 0.5; -} - -.empty-text { - font-size: 28rpx; - margin-bottom: 20rpx; -} - -.empty-desc { - font-size: 24rpx; - color: #ccc; -} - -/* 加载状态 */ -.loading { - display: flex; - align-items: center; - justify-content: center; - padding: 40rpx; - color: #999; -} - -.loading-icon { - width: 40rpx; - height: 40rpx; - margin-right: 20rpx; - animation: spin 1s linear infinite; -} - -@keyframes spin { - 0% { transform: rotate(0deg); } - 100% { transform: rotate(360deg); } -} - -/* 工具类 */ -.text-center { text-align: center; } -.text-left { text-align: left; } -.text-right { text-align: right; } - -.text-primary { color: #3cc51f; } -.text-secondary { color: #666; } -.text-danger { color: #ff4757; } -.text-warning { color: #ffa502; } -.text-muted { color: #999; } - -.bg-primary { background-color: #3cc51f; } -.bg-secondary { background-color: #f0f0f0; } -.bg-danger { background-color: #ff4757; } -.bg-warning { background-color: #ffa502; } - -.mt-10 { margin-top: 10rpx; } -.mt-20 { margin-top: 20rpx; } -.mt-30 { margin-top: 30rpx; } - -.mb-10 { margin-bottom: 10rpx; } -.mb-20 { margin-bottom: 20rpx; } -.mb-30 { margin-bottom: 30rpx; } - -.p-10 { padding: 10rpx; } -.p-20 { padding: 20rpx; } -.p-30 { padding: 30rpx; } - -.flex { display: flex; } -.flex-center { display: flex; align-items: center; justify-content: center; } -.flex-between { display: flex; align-items: center; justify-content: space-between; } -.flex-column { display: flex; flex-direction: column; } - -.flex-1 { flex: 1; } - -/* 响应式 */ -@media (max-width: 750rpx) { - .container { - padding: 15rpx; - } - - .card { - padding: 20rpx; - } - - .stats-grid { - gap: 15rpx; - } - - .stats-item { - min-width: 120rpx; - padding: 15rpx; - } -} diff --git a/mini_program/farm-monitor-wechat/create-missing-pages.js b/mini_program/farm-monitor-wechat/create-missing-pages.js deleted file mode 100644 index 00f21f7..0000000 --- a/mini_program/farm-monitor-wechat/create-missing-pages.js +++ /dev/null @@ -1,94 +0,0 @@ -/** - * 创建缺失页面的脚本 - * @file create-missing-pages.js - * @description 批量创建缺失的页面文件 - */ - -const fs = require('fs') -const path = require('path') - -// 需要创建的页面列表 -const pages = [ - 'pages/cattle/exit/exit', - 'pages/device/device', - 'pages/device/eartag/eartag', - 'pages/device/collar/collar', - 'pages/device/ankle/ankle', - 'pages/device/host/host', - 'pages/alert/eartag/eartag', - 'pages/alert/collar/collar', - 'pages/fence/fence' -] - -// 基础JS模板 -const jsTemplate = `/** - * 页面 - * @file {filename}.js - * @description 页面描述 - */ - -Page({ - data: { - loading: false - }, - - onLoad: function (options) { - console.log('页面加载', options) - }, - - onShow: function () { - console.log('页面显示') - } -})` - -// 基础WXML模板 -const wxmlTemplate = ` - - - 页面内容 - -` - -// 基础WXSS模板 -const wxssTemplate = `/* 页面样式 */ -.container { - min-height: 100vh; - background: #f8f8f8; - padding: 20rpx; -} - -.content { - background: #fff; - border-radius: 16rpx; - padding: 30rpx; - text-align: center; -}` - -// 创建页面的函数 -function createPage(pagePath) { - const dir = path.dirname(pagePath) - const filename = path.basename(pagePath) - - // 创建目录 - if (!fs.existsSync(dir)) { - fs.mkdirSync(dir, { recursive: true }) - } - - // 创建JS文件 - const jsContent = jsTemplate.replace('{filename}', filename) - fs.writeFileSync(`${pagePath}.js`, jsContent) - - // 创建WXML文件 - fs.writeFileSync(`${pagePath}.wxml`, wxmlTemplate) - - // 创建WXSS文件 - fs.writeFileSync(`${pagePath}.wxss`, wxssTemplate) - - console.log(`创建页面: ${pagePath}`) -} - -// 创建所有页面 -pages.forEach(createPage) - -console.log('所有页面创建完成!') - diff --git a/mini_program/farm-monitor-wechat/create-remaining-pages.js b/mini_program/farm-monitor-wechat/create-remaining-pages.js deleted file mode 100644 index 947371c..0000000 --- a/mini_program/farm-monitor-wechat/create-remaining-pages.js +++ /dev/null @@ -1,118 +0,0 @@ -/** - * 创建剩余页面的脚本 - * @file create-remaining-pages.js - * @description 批量创建剩余的页面文件 - */ - -const fs = require('fs') -const path = require('path') - -// 需要创建的页面列表 -const pages = [ - { path: 'pages/device/ankle/ankle', title: '智能脚环管理', icon: '🦶' }, - { path: 'pages/device/host/host', title: '智能主机管理', icon: '📡' }, - { path: 'pages/alert/eartag/eartag', title: '智能耳标预警', icon: '🏷️' }, - { path: 'pages/alert/collar/collar', title: '智能项圈预警', icon: '📿' }, - { path: 'pages/fence/fence', title: '电子围栏管理', icon: '📍' } -] - -// 基础JS模板 -const jsTemplate = `/** - * 页面 - * @file {filename}.js - * @description {title} - */ - -Page({ - data: { - loading: false - }, - - onLoad: function (options) { - console.log('{title}页面加载', options) - }, - - onShow: function () { - console.log('{title}页面显示') - } -})` - -// 基础WXML模板 -const wxmlTemplate = ` - - - {icon} - {title} - 功能开发中... - -` - -// 基础WXSS模板 -const wxssTemplate = `/* {title}页面样式 */ -.container { - min-height: 100vh; - background: #f8f8f8; - padding: 20rpx; -} - -.content { - background: #fff; - border-radius: 16rpx; - padding: 80rpx 30rpx; - text-align: center; -} - -.icon { - font-size: 120rpx; - margin-bottom: 30rpx; - opacity: 0.5; -} - -.title { - font-size: 32rpx; - color: #333; - margin-bottom: 15rpx; - font-weight: 500; -} - -.desc { - font-size: 26rpx; - color: #999; -}` - -// 创建页面的函数 -function createPage(pageInfo) { - const { path: pagePath, title, icon } = pageInfo - const dir = path.dirname(pagePath) - const filename = path.basename(pagePath) - - // 创建目录 - if (!fs.existsSync(dir)) { - fs.mkdirSync(dir, { recursive: true }) - } - - // 创建JS文件 - const jsContent = jsTemplate - .replace(/{filename}/g, filename) - .replace(/{title}/g, title) - fs.writeFileSync(`${pagePath}.js`, jsContent) - - // 创建WXML文件 - const wxmlContent = wxmlTemplate - .replace(/{title}/g, title) - .replace(/{icon}/g, icon) - fs.writeFileSync(`${pagePath}.wxml`, wxmlContent) - - // 创建WXSS文件 - const wxssContent = wxssTemplate - .replace(/{title}/g, title) - fs.writeFileSync(`${pagePath}.wxss`, wxssContent) - - console.log(`创建页面: ${pagePath}`) -} - -// 创建所有页面 -pages.forEach(createPage) - -console.log('所有剩余页面创建完成!') - diff --git a/mini_program/farm-monitor-wechat/images/README.md b/mini_program/farm-monitor-wechat/images/README.md deleted file mode 100644 index 0a522f8..0000000 --- a/mini_program/farm-monitor-wechat/images/README.md +++ /dev/null @@ -1,53 +0,0 @@ -# 图片资源说明 - -## 图片文件列表 - -### Tab图标 -- `home.png` - 首页图标(未选中) -- `home-active.png` - 首页图标(选中) -- `cattle.png` - 牛只管理图标(未选中) -- `cattle-active.png` - 牛只管理图标(选中) -- `device.png` - 设备管理图标(未选中) -- `device-active.png` - 设备管理图标(选中) -- `alert.png` - 预警中心图标(未选中) -- `alert-active.png` - 预警中心图标(选中) -- `profile.png` - 个人中心图标(未选中) -- `profile-active.png` - 个人中心图标(选中) - -### 应用图标 -- `logo.png` - 应用Logo -- `default-avatar.png` - 默认头像 - -## 图片规格要求 - -### Tab图标 -- 尺寸: 81px × 81px -- 格式: PNG -- 背景: 透明 -- 颜色: 灰色(未选中)/ 主题色(选中) - -### 应用Logo -- 尺寸: 1024px × 1024px -- 格式: PNG -- 背景: 透明或白色 -- 设计: 简洁明了,符合养殖主题 - -### 默认头像 -- 尺寸: 200px × 200px -- 格式: PNG -- 背景: 透明 -- 设计: 通用用户头像 - -## 使用说明 - -1. 将图片文件放置在 `images/` 目录下 -2. 确保文件名与代码中的引用一致 -3. 图片大小控制在合理范围内,避免影响加载速度 -4. 建议使用WebP格式以减小文件大小 - -## 注意事项 - -- 所有图片都需要适配不同分辨率的设备 -- 建议提供2x和3x的高清版本 -- 图片命名使用小写字母和连字符 -- 定期优化图片大小,提升加载性能 diff --git a/mini_program/farm-monitor-wechat/images/alert-active.png b/mini_program/farm-monitor-wechat/images/alert-active.png deleted file mode 100644 index 0a289d9..0000000 --- a/mini_program/farm-monitor-wechat/images/alert-active.png +++ /dev/null @@ -1 +0,0 @@ -data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg== diff --git a/mini_program/farm-monitor-wechat/images/alert.png b/mini_program/farm-monitor-wechat/images/alert.png deleted file mode 100644 index 0a289d9..0000000 --- a/mini_program/farm-monitor-wechat/images/alert.png +++ /dev/null @@ -1 +0,0 @@ -data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg== diff --git a/mini_program/farm-monitor-wechat/images/cattle-active.png b/mini_program/farm-monitor-wechat/images/cattle-active.png deleted file mode 100644 index 0a289d9..0000000 --- a/mini_program/farm-monitor-wechat/images/cattle-active.png +++ /dev/null @@ -1 +0,0 @@ -data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg== diff --git a/mini_program/farm-monitor-wechat/images/cattle.png b/mini_program/farm-monitor-wechat/images/cattle.png deleted file mode 100644 index 0a289d9..0000000 --- a/mini_program/farm-monitor-wechat/images/cattle.png +++ /dev/null @@ -1 +0,0 @@ -data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg== diff --git a/mini_program/farm-monitor-wechat/images/device-active.png b/mini_program/farm-monitor-wechat/images/device-active.png deleted file mode 100644 index 0a289d9..0000000 --- a/mini_program/farm-monitor-wechat/images/device-active.png +++ /dev/null @@ -1 +0,0 @@ -data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg== diff --git a/mini_program/farm-monitor-wechat/images/device.png b/mini_program/farm-monitor-wechat/images/device.png deleted file mode 100644 index 0a289d9..0000000 --- a/mini_program/farm-monitor-wechat/images/device.png +++ /dev/null @@ -1 +0,0 @@ -data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg== diff --git a/mini_program/farm-monitor-wechat/images/home-active.png b/mini_program/farm-monitor-wechat/images/home-active.png deleted file mode 100644 index e69de29..0000000 diff --git a/mini_program/farm-monitor-wechat/images/home.png b/mini_program/farm-monitor-wechat/images/home.png deleted file mode 100644 index 0a289d9..0000000 --- a/mini_program/farm-monitor-wechat/images/home.png +++ /dev/null @@ -1 +0,0 @@ -data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg== diff --git a/mini_program/farm-monitor-wechat/images/profile-active.png b/mini_program/farm-monitor-wechat/images/profile-active.png deleted file mode 100644 index 0a289d9..0000000 --- a/mini_program/farm-monitor-wechat/images/profile-active.png +++ /dev/null @@ -1 +0,0 @@ -data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg== diff --git a/mini_program/farm-monitor-wechat/images/profile.png b/mini_program/farm-monitor-wechat/images/profile.png deleted file mode 100644 index 0a289d9..0000000 --- a/mini_program/farm-monitor-wechat/images/profile.png +++ /dev/null @@ -1 +0,0 @@ -data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg== diff --git a/mini_program/farm-monitor-wechat/package.json b/mini_program/farm-monitor-wechat/package.json deleted file mode 100644 index 2f9058b..0000000 --- a/mini_program/farm-monitor-wechat/package.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "name": "farm-monitor-wechat", - "version": "1.0.0", - "description": "养殖端微信小程序 - 原生版本", - "main": "app.js", - "scripts": { - "dev": "echo '请在微信开发者工具中打开项目进行开发'", - "build": "echo '请在微信开发者工具中构建项目'", - "test": "echo '测试功能'" - }, - "keywords": [ - "微信小程序", - "养殖管理", - "物联网", - "智能设备" - ], - "author": "养殖管理系统开发团队", - "license": "MIT", - "engines": { - "node": ">=16.0.0" - }, - "repository": { - "type": "git", - "url": "https://github.com/your-org/farm-monitor-wechat.git" - }, - "bugs": { - "url": "https://github.com/your-org/farm-monitor-wechat/issues" - }, - "homepage": "https://github.com/your-org/farm-monitor-wechat#readme" -} diff --git a/mini_program/farm-monitor-wechat/pages/alert/alert.js b/mini_program/farm-monitor-wechat/pages/alert/alert.js deleted file mode 100644 index f9d4c79..0000000 --- a/mini_program/farm-monitor-wechat/pages/alert/alert.js +++ /dev/null @@ -1,379 +0,0 @@ -/** - * 预警中心页面 - * @file alert.js - * @description 预警中心列表页面 - */ - -const app = getApp() -const alertService = require('../../services/alertService.js') - -Page({ - /** - * 页面的初始数据 - */ - data: { - alertList: [], - loading: true, - refreshing: false, - hasMore: true, - page: 1, - limit: 20, - searchKeyword: '', - filterType: '', - filterLevel: '', - total: 0, - showFilter: false, - searchInput: '', - stats: { - total: 0, - unread: 0, - high: 0, - medium: 0, - low: 0 - } - }, - - /** - * 生命周期函数--监听页面加载 - */ - onLoad: function (options) { - console.log('预警中心页面加载', options) - this.loadAlertData() - }, - - /** - * 生命周期函数--监听页面显示 - */ - onShow: function () { - console.log('预警中心页面显示') - this.refreshData() - }, - - /** - * 页面相关事件处理函数--监听用户下拉动作 - */ - onPullDownRefresh: function () { - console.log('下拉刷新') - this.refreshData() - }, - - /** - * 页面上拉触底事件的处理函数 - */ - onReachBottom: function () { - console.log('上拉触底') - if (this.data.hasMore && !this.data.loading) { - this.loadMoreData() - } - }, - - /** - * 用户点击右上角分享 - */ - onShareAppMessage: function () { - return { - title: '预警中心', - path: '/pages/alert/alert' - } - }, - - /** - * 加载预警数据 - */ - loadAlertData: function(reset = true) { - if (reset) { - this.setData({ - loading: true, - page: 1, - hasMore: true - }) - } else { - this.setData({ - loading: true - }) - } - - // 并行加载统计数据和列表数据 - Promise.all([ - this.loadAlertStats(), - this.loadAlertList(reset) - ]).then(() => { - console.log('预警数据加载完成') - }).catch(error => { - console.error('预警数据加载失败:', error) - }).finally(() => { - this.setData({ - loading: false, - refreshing: false - }) - if (reset) { - wx.stopPullDownRefresh() - } - }) - }, - - /** - * 加载预警统计 - */ - loadAlertStats: function() { - return alertService.getAlertStats() - .then(res => { - console.log('预警统计加载成功', res) - this.setData({ - stats: { - total: res.data.totalAlerts || 0, - unread: res.data.unreadAlerts || 0, - high: res.data.highLevel || 0, - medium: res.data.mediumLevel || 0, - low: res.data.lowLevel || 0 - } - }) - }) - .catch(error => { - console.error('预警统计加载失败:', error) - }) - }, - - /** - * 加载预警列表 - */ - loadAlertList: function(reset = true) { - const params = { - page: this.data.page, - limit: this.data.limit, - search: this.data.searchKeyword, - alertType: this.data.filterType, - alertLevel: this.data.filterLevel - } - - return alertService.getAlertList(params) - .then(res => { - console.log('预警列表加载成功', res) - - const newList = res.data || [] - const alertList = reset ? newList : [...this.data.alertList, ...newList] - - this.setData({ - alertList: alertList, - total: res.total || 0, - hasMore: newList.length >= this.data.limit - }) - }) - .catch(error => { - console.error('预警列表加载失败:', error) - wx.showToast({ - title: error.message || '加载失败', - icon: 'none' - }) - }) - }, - - /** - * 刷新数据 - */ - refreshData: function() { - this.setData({ - refreshing: true - }) - this.loadAlertData(true) - }, - - /** - * 加载更多数据 - */ - loadMoreData: function() { - this.setData({ - page: this.data.page + 1 - }) - this.loadAlertData(false) - }, - - /** - * 切换筛选显示 - */ - toggleFilter: function() { - this.setData({ - showFilter: !this.data.showFilter, - searchInput: this.data.searchKeyword - }) - }, - - /** - * 搜索输入 - */ - onSearchInput: function(e) { - this.setData({ - searchInput: e.detail.value - }) - }, - - /** - * 执行搜索 - */ - doSearch: function() { - this.setData({ - searchKeyword: this.data.searchInput, - showFilter: false - }) - this.loadAlertData(true) - }, - - /** - * 取消搜索 - */ - cancelSearch: function() { - this.setData({ - showFilter: false, - searchInput: this.data.searchKeyword - }) - }, - - /** - * 清空搜索 - */ - clearSearch: function() { - this.setData({ - searchKeyword: '', - searchInput: '', - filterType: '', - filterLevel: '' - }) - this.loadAlertData(true) - }, - - /** - * 类型筛选 - */ - onTypeFilter: function(e) { - const type = e.currentTarget.dataset.type - this.setData({ - filterType: type - }) - this.loadAlertData(true) - }, - - /** - * 级别筛选 - */ - onLevelFilter: function(e) { - const level = e.currentTarget.dataset.level - this.setData({ - filterLevel: level - }) - this.loadAlertData(true) - }, - - /** - * 查看预警详情 - */ - viewAlertDetail: function(e) { - const alertId = e.currentTarget.dataset.id - wx.navigateTo({ - url: `/pages/alert/detail/detail?id=${alertId}` - }) - }, - - /** - * 处理预警 - */ - handleAlert: function(e) { - const alertId = e.currentTarget.dataset.id - const alertType = e.currentTarget.dataset.type - - wx.showModal({ - title: '处理预警', - content: '确定要处理此预警吗?', - success: (res) => { - if (res.confirm) { - this.confirmHandleAlert(alertId, alertType) - } - } - }) - }, - - /** - * 确认处理预警 - */ - confirmHandleAlert: function(alertId, alertType) { - wx.showLoading({ - title: '处理中...' - }) - - const handleData = { - action: 'acknowledged', - notes: '通过小程序处理', - handler: app.getUserInfo()?.nickName || '用户' - } - - alertService.handleAlert(alertId, handleData) - .then(res => { - console.log('处理预警成功', res) - wx.hideLoading() - wx.showToast({ - title: '处理成功', - icon: 'success' - }) - this.loadAlertData(true) - }) - .catch(error => { - console.error('处理预警失败:', error) - wx.hideLoading() - wx.showToast({ - title: error.message || '处理失败', - icon: 'none' - }) - }) - }, - - /** - * 获取预警类型文本 - */ - getAlertTypeText: function(type) { - const typeMap = { - 'battery': '低电量', - 'offline': '离线', - 'temperature': '温度异常', - 'movement': '运动异常', - 'wear': '脱落' - } - return typeMap[type] || type - }, - - /** - * 获取预警级别文本 - */ - getAlertLevelText: function(level) { - const levelMap = { - 'high': '高', - 'medium': '中', - 'low': '低' - } - return levelMap[level] || level - }, - - /** - * 获取预警级别颜色 - */ - getAlertLevelColor: function(level) { - const colorMap = { - 'high': 'red', - 'medium': 'orange', - 'low': 'green' - } - return colorMap[level] || 'gray' - }, - - /** - * 获取预警类型图标 - */ - getAlertTypeIcon: function(type) { - const iconMap = { - 'battery': '🔋', - 'offline': '📵', - 'temperature': '🌡️', - 'movement': '🏃', - 'wear': '⚠️' - } - return iconMap[type] || '⚠️' - } -}) diff --git a/mini_program/farm-monitor-wechat/pages/alert/alert.wxml b/mini_program/farm-monitor-wechat/pages/alert/alert.wxml deleted file mode 100644 index dfa2b70..0000000 --- a/mini_program/farm-monitor-wechat/pages/alert/alert.wxml +++ /dev/null @@ -1,221 +0,0 @@ - - - - - - - ⚠️ - {{stats.total}} - 总预警 - - - - 🔴 - {{stats.high}} - 高级 - - - - 🟡 - {{stats.medium}} - 中级 - - - - 🟢 - {{stats.low}} - 低级 - - - - - - - - - 🔍 - - - 筛选 - - - - - - - 预警类型 - - - 全部 - - - 低电量 - - - 离线 - - - 温度异常 - - - 运动异常 - - - 脱落 - - - - - - 预警级别 - - - 全部 - - - 高级 - - - 中级 - - - 低级 - - - - - - - - - - - - - 共 {{total}} 条预警 - {{alertList.length}} 条记录 - - - - - - 加载中... - - - - - - - - {{getAlertTypeIcon(item.alertType)}} - - - {{item.description}} - {{item.deviceName || item.collarNumber || item.eartagNumber}} - - - {{getAlertLevelText(item.alertLevel)}} - - - - - - 类型: - {{getAlertTypeText(item.alertType)}} - - - 时间: - {{item.alertTime}} - - - 电量: - {{item.battery}}% - - - 温度: - {{item.temperature}}°C - - - - - - - - - - - - 📭 - 暂无预警信息 - 系统运行正常,无预警数据 - - - - - - 加载中... - - - - 没有更多数据了 - - diff --git a/mini_program/farm-monitor-wechat/pages/alert/alert.wxss b/mini_program/farm-monitor-wechat/pages/alert/alert.wxss deleted file mode 100644 index a73da62..0000000 --- a/mini_program/farm-monitor-wechat/pages/alert/alert.wxss +++ /dev/null @@ -1,473 +0,0 @@ -/* 预警中心页面样式 */ -.container { - min-height: 100vh; - background: #f8f8f8; - padding-bottom: 120rpx; -} - -/* 统计卡片 */ -.stats-section { - padding: 30rpx; - background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); -} - -.stats-grid { - display: flex; - gap: 20rpx; -} - -.stats-card { - flex: 1; - background: rgba(255, 255, 255, 0.95); - border-radius: 16rpx; - padding: 30rpx 20rpx; - text-align: center; - box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.1); - backdrop-filter: blur(10rpx); -} - -.stats-icon { - font-size: 48rpx; - margin-bottom: 15rpx; -} - -.stats-number { - font-size: 36rpx; - font-weight: bold; - color: #333; - margin-bottom: 8rpx; -} - -.stats-label { - font-size: 24rpx; - color: #666; -} - -/* 搜索栏 */ -.search-bar { - background: #fff; - padding: 20rpx 30rpx; - display: flex; - align-items: center; - gap: 20rpx; - box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1); -} - -.search-input { - flex: 1; - position: relative; - display: flex; - align-items: center; -} - -.search-input .input { - width: 100%; - height: 70rpx; - background: #f5f5f5; - border: 2rpx solid #e0e0e0; - border-radius: 35rpx; - padding: 0 50rpx 0 20rpx; - font-size: 26rpx; - color: #333; - box-sizing: border-box; -} - -.search-input .input:focus { - border-color: #3cc51f; - background: #fff; -} - -.search-icon { - position: absolute; - right: 20rpx; - top: 50%; - transform: translateY(-50%); - font-size: 28rpx; - color: #999; - cursor: pointer; -} - -.search-actions { - display: flex; - gap: 15rpx; -} - -.action-btn { - padding: 15rpx 25rpx; - background: #3cc51f; - color: #fff; - border: none; - border-radius: 20rpx; - font-size: 24rpx; - font-weight: 500; - cursor: pointer; - transition: all 0.3s ease; -} - -.action-btn:active { - background: #2db815; -} - -/* 筛选条件 */ -.filter-bar { - background: #fff; - padding: 20rpx 30rpx; - border-top: 1rpx solid #f0f0f0; -} - -.filter-section { - margin-bottom: 25rpx; -} - -.filter-section:last-child { - margin-bottom: 0; -} - -.filter-title { - font-size: 26rpx; - color: #333; - margin-bottom: 15rpx; - font-weight: 500; -} - -.filter-options { - display: flex; - gap: 15rpx; - flex-wrap: wrap; -} - -.filter-option { - padding: 12rpx 24rpx; - background: #f5f5f5; - color: #666; - border-radius: 20rpx; - font-size: 24rpx; - cursor: pointer; - transition: all 0.3s ease; -} - -.filter-option.active { - background: #3cc51f; - color: #fff; -} - -.filter-actions { - display: flex; - justify-content: flex-end; - gap: 15rpx; - margin-top: 20rpx; -} - -/* 统计信息 */ -.stats-info { - background: #fff; - padding: 20rpx 30rpx; - display: flex; - justify-content: space-between; - border-bottom: 1rpx solid #f0f0f0; -} - -.stats-text { - font-size: 24rpx; - color: #666; -} - -/* 加载状态 */ -.loading { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - height: 400rpx; - color: #999; -} - -.loading-icon { - width: 60rpx; - height: 60rpx; - border: 4rpx solid #e0e0e0; - border-top: 4rpx solid #3cc51f; - border-radius: 50%; - animation: spin 1s linear infinite; - margin-bottom: 20rpx; -} - -@keyframes spin { - 0% { transform: rotate(0deg); } - 100% { transform: rotate(360deg); } -} - -/* 预警列表 */ -.alert-list { - padding: 20rpx; -} - -.alert-item { - background: #fff; - border-radius: 16rpx; - padding: 30rpx; - margin-bottom: 20rpx; - box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1); - transition: transform 0.3s ease; -} - -.alert-item:active { - transform: scale(0.98); -} - -.alert-header { - display: flex; - align-items: center; - margin-bottom: 20rpx; -} - -.alert-icon { - width: 60rpx; - height: 60rpx; - border-radius: 50%; - display: flex; - align-items: center; - justify-content: center; - margin-right: 20rpx; - font-size: 28rpx; -} - -.alert-icon.red { - background: #ffe8e8; - color: #ff4757; -} - -.alert-icon.orange { - background: #fff3e0; - color: #ffa502; -} - -.alert-icon.green { - background: #e8f5e8; - color: #3cc51f; -} - -.alert-icon.gray { - background: #f0f0f0; - color: #999; -} - -.alert-info { - flex: 1; -} - -.alert-title { - font-size: 28rpx; - font-weight: 500; - color: #333; - margin-bottom: 8rpx; - line-height: 1.4; -} - -.alert-device { - font-size: 22rpx; - color: #666; -} - -.alert-level { - padding: 8rpx 16rpx; - border-radius: 20rpx; - font-size: 20rpx; - font-weight: 500; -} - -.alert-level.red { - background: #ffe8e8; - color: #ff4757; -} - -.alert-level.orange { - background: #fff3e0; - color: #ffa502; -} - -.alert-level.green { - background: #e8f5e8; - color: #3cc51f; -} - -.alert-level.gray { - background: #f0f0f0; - color: #999; -} - -.alert-details { - margin-bottom: 25rpx; - padding: 20rpx; - background: #f8f8f8; - border-radius: 12rpx; -} - -.detail-item { - display: flex; - align-items: center; - margin-bottom: 12rpx; -} - -.detail-item:last-child { - margin-bottom: 0; -} - -.detail-label { - font-size: 24rpx; - color: #666; - width: 120rpx; - flex-shrink: 0; -} - -.detail-value { - font-size: 24rpx; - color: #333; - flex: 1; -} - -.alert-actions { - display: flex; - justify-content: flex-end; -} - -.alert-actions .action-btn { - padding: 15rpx 30rpx; - border-radius: 8rpx; - font-size: 24rpx; - font-weight: 500; - cursor: pointer; - transition: all 0.3s ease; -} - -.alert-actions .action-btn.handle { - background: #3cc51f; - color: #fff; -} - -.alert-actions .action-btn:active { - opacity: 0.7; -} - -/* 空状态 */ -.empty-state { - text-align: center; - padding: 120rpx 40rpx; - background: #fff; - margin: 20rpx; - border-radius: 16rpx; - box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1); -} - -.empty-icon { - font-size: 120rpx; - margin-bottom: 30rpx; - opacity: 0.5; -} - -.empty-text { - font-size: 32rpx; - color: #666; - margin-bottom: 15rpx; - font-weight: 500; -} - -.empty-desc { - font-size: 26rpx; - color: #999; - line-height: 1.6; -} - -/* 加载更多 */ -.load-more { - display: flex; - align-items: center; - justify-content: center; - padding: 40rpx; - color: #999; - font-size: 24rpx; -} - -.load-more .loading-icon { - width: 40rpx; - height: 40rpx; - margin-right: 15rpx; -} - -/* 响应式 */ -@media (max-width: 750rpx) { - .stats-section { - padding: 20rpx; - } - - .stats-grid { - gap: 15rpx; - } - - .stats-card { - padding: 25rpx 15rpx; - } - - .stats-icon { - font-size: 40rpx; - } - - .stats-number { - font-size: 32rpx; - } - - .search-bar { - padding: 15rpx 20rpx; - } - - .search-input .input { - height: 60rpx; - font-size: 24rpx; - } - - .action-btn { - padding: 12rpx 20rpx; - font-size: 22rpx; - } - - .filter-bar { - padding: 15rpx 20rpx; - } - - .filter-options { - gap: 10rpx; - } - - .filter-option { - padding: 10rpx 20rpx; - font-size: 22rpx; - } - - .alert-item { - padding: 25rpx; - } - - .alert-icon { - width: 50rpx; - height: 50rpx; - font-size: 24rpx; - } - - .alert-title { - font-size: 26rpx; - } - - .alert-device { - font-size: 20rpx; - } - - .detail-label, - .detail-value { - font-size: 22rpx; - } - - .alert-actions .action-btn { - padding: 12rpx 25rpx; - font-size: 22rpx; - } -} diff --git a/mini_program/farm-monitor-wechat/pages/alert/collar/collar.js b/mini_program/farm-monitor-wechat/pages/alert/collar/collar.js deleted file mode 100644 index c736687..0000000 --- a/mini_program/farm-monitor-wechat/pages/alert/collar/collar.js +++ /dev/null @@ -1,330 +0,0 @@ -/** - * 智能项圈预警页面 - * @file collar.js - * @description 智能项圈预警管理页面 - */ - -const app = getApp() -const alertService = require('../../../services/alertService.js') - -Page({ - /** - * 页面的初始数据 - */ - data: { - alertList: [], - loading: true, - refreshing: false, - hasMore: true, - page: 1, - limit: 20, - searchKeyword: '', - filterType: '', - filterLevel: '', - total: 0, - stats: { - total: 0, - unread: 0, - high: 0, - medium: 0, - low: 0 - } - }, - - /** - * 生命周期函数--监听页面加载 - */ - onLoad: function (options) { - console.log('智能项圈预警页面加载', options) - this.loadAlertData() - }, - - /** - * 生命周期函数--监听页面显示 - */ - onShow: function () { - console.log('智能项圈预警页面显示') - this.refreshData() - }, - - /** - * 页面相关事件处理函数--监听用户下拉动作 - */ - onPullDownRefresh: function () { - console.log('下拉刷新') - this.refreshData() - }, - - /** - * 页面上拉触底事件的处理函数 - */ - onReachBottom: function () { - console.log('上拉触底') - if (this.data.hasMore && !this.data.loading) { - this.loadMoreData() - } - }, - - /** - * 加载预警数据 - */ - loadAlertData: function(reset = true) { - if (reset) { - this.setData({ - loading: true, - page: 1, - hasMore: true - }) - } else { - this.setData({ - loading: true - }) - } - - // 并行加载统计数据和列表数据 - Promise.all([ - this.loadAlertStats(), - this.loadAlertList(reset) - ]).then(() => { - console.log('项圈预警数据加载完成') - }).catch(error => { - console.error('项圈预警数据加载失败:', error) - }).finally(() => { - this.setData({ - loading: false, - refreshing: false - }) - if (reset) { - wx.stopPullDownRefresh() - } - }) - }, - - /** - * 加载预警统计 - */ - loadAlertStats: function() { - return alertService.getCollarAlertStats() - .then(res => { - console.log('项圈预警统计加载成功', res) - this.setData({ - stats: { - total: res.data.totalAlerts || 0, - unread: res.data.unreadAlerts || 0, - high: res.data.highLevel || 0, - medium: res.data.mediumLevel || 0, - low: res.data.lowLevel || 0 - } - }) - }) - .catch(error => { - console.error('项圈预警统计加载失败:', error) - }) - }, - - /** - * 加载预警列表 - */ - loadAlertList: function(reset = true) { - const params = { - page: this.data.page, - limit: this.data.limit, - search: this.data.searchKeyword, - alertType: this.data.filterType, - alertLevel: this.data.filterLevel - } - - return alertService.getCollarAlerts(params) - .then(res => { - console.log('项圈预警列表加载成功', res) - - const newList = res.data || [] - const alertList = reset ? newList : [...this.data.alertList, ...newList] - - this.setData({ - alertList: alertList, - total: res.total || 0, - hasMore: newList.length >= this.data.limit - }) - }) - .catch(error => { - console.error('项圈预警列表加载失败:', error) - wx.showToast({ - title: error.message || '加载失败', - icon: 'none' - }) - }) - }, - - /** - * 刷新数据 - */ - refreshData: function() { - this.setData({ - refreshing: true - }) - this.loadAlertData(true) - }, - - /** - * 加载更多数据 - */ - loadMoreData: function() { - this.setData({ - page: this.data.page + 1 - }) - this.loadAlertData(false) - }, - - /** - * 搜索输入 - */ - onSearchInput: function(e) { - this.setData({ - searchKeyword: e.detail.value - }) - }, - - /** - * 执行搜索 - */ - onSearch: function() { - this.loadAlertData(true) - }, - - /** - * 类型筛选 - */ - onTypeFilter: function(e) { - const type = e.currentTarget.dataset.type - this.setData({ - filterType: type - }) - this.loadAlertData(true) - }, - - /** - * 级别筛选 - */ - onLevelFilter: function(e) { - const level = e.currentTarget.dataset.level - this.setData({ - filterLevel: level - }) - this.loadAlertData(true) - }, - - /** - * 查看预警详情 - */ - viewAlertDetail: function(e) { - const alertId = e.currentTarget.dataset.id - wx.navigateTo({ - url: `/pages/alert/collar-detail/detail?id=${alertId}` - }) - }, - - /** - * 处理预警 - */ - handleAlert: function(e) { - const alertId = e.currentTarget.dataset.id - const alertType = e.currentTarget.dataset.type - - wx.showModal({ - title: '处理预警', - content: '确定要处理此预警吗?', - success: (res) => { - if (res.confirm) { - this.confirmHandleAlert(alertId, alertType) - } - } - }) - }, - - /** - * 确认处理预警 - */ - confirmHandleAlert: function(alertId, alertType) { - wx.showLoading({ - title: '处理中...' - }) - - const handleData = { - action: 'acknowledged', - notes: '通过小程序处理', - handler: app.getUserInfo()?.nickName || '用户' - } - - alertService.handleAlert(alertId, handleData) - .then(res => { - console.log('处理预警成功', res) - wx.hideLoading() - wx.showToast({ - title: '处理成功', - icon: 'success' - }) - this.loadAlertData(true) - }) - .catch(error => { - console.error('处理预警失败:', error) - wx.hideLoading() - wx.showToast({ - title: error.message || '处理失败', - icon: 'none' - }) - }) - }, - - /** - * 获取预警类型文本 - */ - getAlertTypeText: function(type) { - const typeMap = { - 'battery': '低电量', - 'offline': '离线', - 'temperature': '温度异常', - 'movement': '运动异常', - 'wear': '脱落' - } - return typeMap[type] || type - }, - - /** - * 获取预警级别文本 - */ - getAlertLevelText: function(level) { - const levelMap = { - 'high': '高', - 'medium': '中', - 'low': '低' - } - return levelMap[level] || level - }, - - /** - * 获取预警级别颜色 - */ - getAlertLevelColor: function(level) { - const colorMap = { - 'high': 'red', - 'medium': 'orange', - 'low': 'green' - } - return colorMap[level] || 'gray' - }, - - /** - * 获取预警类型图标 - */ - getAlertTypeIcon: function(type) { - const iconMap = { - 'battery': '🔋', - 'offline': '📵', - 'temperature': '🌡️', - 'movement': '🏃', - 'wear': '⚠️' - } - return iconMap[type] || '⚠️' - } -}) \ No newline at end of file diff --git a/mini_program/farm-monitor-wechat/pages/alert/collar/collar.wxml b/mini_program/farm-monitor-wechat/pages/alert/collar/collar.wxml deleted file mode 100644 index d6e6664..0000000 --- a/mini_program/farm-monitor-wechat/pages/alert/collar/collar.wxml +++ /dev/null @@ -1,213 +0,0 @@ - - - - - - - ⚠️ - {{stats.total}} - 总预警 - - - - 🔴 - {{stats.high}} - 高级 - - - - 🟡 - {{stats.medium}} - 中级 - - - - 🟢 - {{stats.low}} - 低级 - - - - - - - - - 🔍 - - - - - - - 预警类型 - - - 全部 - - - 低电量 - - - 离线 - - - 温度异常 - - - 运动异常 - - - 脱落 - - - - - - 预警级别 - - - 全部 - - - 高级 - - - 中级 - - - 低级 - - - - - - - - 共 {{total}} 条预警 - {{alertList.length}} 条记录 - - - - - - 加载中... - - - - - - - - {{getAlertTypeIcon(item.alertType)}} - - - {{item.description}} - {{item.collarNumber || item.deviceName}} - - - {{getAlertLevelText(item.alertLevel)}} - - - - - - 类型: - {{getAlertTypeText(item.alertType)}} - - - 时间: - {{item.alertTime}} - - - 电量: - {{item.battery}}% - - - 温度: - {{item.temperature}}°C - - - - - - - - - - - - 📭 - 暂无预警信息 - 系统运行正常,无预警数据 - - - - - - 加载中... - - - - 没有更多数据了 - - \ No newline at end of file diff --git a/mini_program/farm-monitor-wechat/pages/alert/collar/collar.wxss b/mini_program/farm-monitor-wechat/pages/alert/collar/collar.wxss deleted file mode 100644 index 7f2767f..0000000 --- a/mini_program/farm-monitor-wechat/pages/alert/collar/collar.wxss +++ /dev/null @@ -1,441 +0,0 @@ -/* 智能项圈预警页面样式 */ -.container { - min-height: 100vh; - background: #f8f8f8; - padding-bottom: 120rpx; -} - -/* 统计卡片 */ -.stats-section { - padding: 30rpx; - background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); -} - -.stats-grid { - display: flex; - gap: 20rpx; -} - -.stats-card { - flex: 1; - background: rgba(255, 255, 255, 0.95); - border-radius: 16rpx; - padding: 30rpx 20rpx; - text-align: center; - box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.1); - backdrop-filter: blur(10rpx); -} - -.stats-icon { - font-size: 48rpx; - margin-bottom: 15rpx; -} - -.stats-number { - font-size: 36rpx; - font-weight: bold; - color: #333; - margin-bottom: 8rpx; -} - -.stats-label { - font-size: 24rpx; - color: #666; -} - -/* 搜索栏 */ -.search-bar { - background: #fff; - padding: 20rpx 30rpx; - margin: 20rpx; - border-radius: 16rpx; - box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1); -} - -.search-input { - position: relative; - display: flex; - align-items: center; -} - -.search-input .input { - width: 100%; - height: 70rpx; - background: #f5f5f5; - border: 2rpx solid #e0e0e0; - border-radius: 35rpx; - padding: 0 50rpx 0 20rpx; - font-size: 26rpx; - color: #333; - box-sizing: border-box; -} - -.search-input .input:focus { - border-color: #3cc51f; - background: #fff; -} - -.search-icon { - position: absolute; - right: 20rpx; - top: 50%; - transform: translateY(-50%); - font-size: 28rpx; - color: #999; - cursor: pointer; -} - -/* 筛选条件 */ -.filter-bar { - background: #fff; - margin: 0 20rpx 20rpx; - border-radius: 16rpx; - padding: 30rpx; - box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1); -} - -.filter-section { - margin-bottom: 25rpx; -} - -.filter-section:last-child { - margin-bottom: 0; -} - -.filter-title { - font-size: 26rpx; - color: #333; - margin-bottom: 15rpx; - font-weight: 500; -} - -.filter-options { - display: flex; - gap: 15rpx; - flex-wrap: wrap; -} - -.filter-option { - padding: 12rpx 24rpx; - background: #f5f5f5; - color: #666; - border-radius: 20rpx; - font-size: 24rpx; - cursor: pointer; - transition: all 0.3s ease; -} - -.filter-option.active { - background: #3cc51f; - color: #fff; -} - -/* 统计信息 */ -.stats-info { - background: #fff; - padding: 20rpx 30rpx; - margin: 0 20rpx 20rpx; - display: flex; - justify-content: space-between; - border-radius: 16rpx; - box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1); -} - -.stats-text { - font-size: 24rpx; - color: #666; -} - -/* 加载状态 */ -.loading { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - height: 400rpx; - color: #999; -} - -.loading-icon { - width: 60rpx; - height: 60rpx; - border: 4rpx solid #e0e0e0; - border-top: 4rpx solid #3cc51f; - border-radius: 50%; - animation: spin 1s linear infinite; - margin-bottom: 20rpx; -} - -@keyframes spin { - 0% { transform: rotate(0deg); } - 100% { transform: rotate(360deg); } -} - -/* 预警列表 */ -.alert-list { - padding: 0 20rpx; -} - -.alert-item { - background: #fff; - border-radius: 16rpx; - padding: 30rpx; - margin-bottom: 20rpx; - box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1); - transition: transform 0.3s ease; -} - -.alert-item:active { - transform: scale(0.98); -} - -.alert-header { - display: flex; - align-items: center; - margin-bottom: 20rpx; -} - -.alert-icon { - width: 60rpx; - height: 60rpx; - border-radius: 50%; - display: flex; - align-items: center; - justify-content: center; - margin-right: 20rpx; - font-size: 28rpx; -} - -.alert-icon.red { - background: #ffe8e8; - color: #ff4757; -} - -.alert-icon.orange { - background: #fff3e0; - color: #ffa502; -} - -.alert-icon.green { - background: #e8f5e8; - color: #3cc51f; -} - -.alert-icon.gray { - background: #f0f0f0; - color: #999; -} - -.alert-info { - flex: 1; -} - -.alert-title { - font-size: 28rpx; - font-weight: 500; - color: #333; - margin-bottom: 8rpx; - line-height: 1.4; -} - -.alert-device { - font-size: 22rpx; - color: #666; -} - -.alert-level { - padding: 8rpx 16rpx; - border-radius: 20rpx; - font-size: 20rpx; - font-weight: 500; -} - -.alert-level.red { - background: #ffe8e8; - color: #ff4757; -} - -.alert-level.orange { - background: #fff3e0; - color: #ffa502; -} - -.alert-level.green { - background: #e8f5e8; - color: #3cc51f; -} - -.alert-level.gray { - background: #f0f0f0; - color: #999; -} - -.alert-details { - margin-bottom: 25rpx; - padding: 20rpx; - background: #f8f8f8; - border-radius: 12rpx; -} - -.detail-item { - display: flex; - align-items: center; - margin-bottom: 12rpx; -} - -.detail-item:last-child { - margin-bottom: 0; -} - -.detail-label { - font-size: 24rpx; - color: #666; - width: 120rpx; - flex-shrink: 0; -} - -.detail-value { - font-size: 24rpx; - color: #333; - flex: 1; -} - -.alert-actions { - display: flex; - justify-content: flex-end; -} - -.alert-actions .action-btn { - padding: 15rpx 30rpx; - border-radius: 8rpx; - font-size: 24rpx; - font-weight: 500; - cursor: pointer; - transition: all 0.3s ease; -} - -.alert-actions .action-btn.handle { - background: #3cc51f; - color: #fff; -} - -.alert-actions .action-btn:active { - opacity: 0.7; -} - -/* 空状态 */ -.empty-state { - text-align: center; - padding: 120rpx 40rpx; - background: #fff; - margin: 20rpx; - border-radius: 16rpx; - box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1); -} - -.empty-icon { - font-size: 120rpx; - margin-bottom: 30rpx; - opacity: 0.5; -} - -.empty-text { - font-size: 32rpx; - color: #666; - margin-bottom: 15rpx; - font-weight: 500; -} - -.empty-desc { - font-size: 26rpx; - color: #999; - line-height: 1.6; -} - -/* 加载更多 */ -.load-more { - display: flex; - align-items: center; - justify-content: center; - padding: 40rpx; - color: #999; - font-size: 24rpx; -} - -.load-more .loading-icon { - width: 40rpx; - height: 40rpx; - margin-right: 15rpx; -} - -/* 响应式 */ -@media (max-width: 750rpx) { - .stats-section { - padding: 20rpx; - } - - .stats-grid { - gap: 15rpx; - } - - .stats-card { - padding: 25rpx 15rpx; - } - - .stats-icon { - font-size: 40rpx; - } - - .stats-number { - font-size: 32rpx; - } - - .search-bar, - .filter-bar, - .stats-info { - margin: 0 15rpx 15rpx; - padding: 20rpx; - } - - .search-input .input { - height: 60rpx; - font-size: 24rpx; - } - - .filter-options { - gap: 10rpx; - } - - .filter-option { - padding: 10rpx 20rpx; - font-size: 22rpx; - } - - .alert-item { - padding: 25rpx; - } - - .alert-icon { - width: 50rpx; - height: 50rpx; - font-size: 24rpx; - } - - .alert-title { - font-size: 26rpx; - } - - .alert-device { - font-size: 20rpx; - } - - .detail-label, - .detail-value { - font-size: 22rpx; - } - - .alert-actions .action-btn { - padding: 12rpx 25rpx; - font-size: 22rpx; - } -} \ No newline at end of file diff --git a/mini_program/farm-monitor-wechat/pages/alert/eartag/eartag.js b/mini_program/farm-monitor-wechat/pages/alert/eartag/eartag.js deleted file mode 100644 index c5250b3..0000000 --- a/mini_program/farm-monitor-wechat/pages/alert/eartag/eartag.js +++ /dev/null @@ -1,359 +0,0 @@ -/** - * 智能耳标预警页面 - * @file eartag.js - * @description 智能耳标预警管理页面 - */ - -const app = getApp() - -Page({ - /** - * 页面的初始数据 - */ - data: { - alertList: [], - loading: true, - refreshing: false, - hasMore: true, - page: 1, - limit: 20, - searchKeyword: '', - filterType: '', - filterLevel: '', - total: 0, - stats: { - total: 0, - battery: 0, - offline: 0, - temperature: 0, - movement: 0 - } - }, - - /** - * 生命周期函数--监听页面加载 - */ - onLoad: function (options) { - console.log('智能耳标预警页面加载', options) - this.loadAlertList() - }, - - /** - * 生命周期函数--监听页面显示 - */ - onShow: function () { - console.log('智能耳标预警页面显示') - this.loadAlertList() - }, - - /** - * 页面相关事件处理函数--监听用户下拉动作 - */ - onPullDownRefresh: function () { - console.log('下拉刷新') - this.refreshData() - }, - - /** - * 页面上拉触底事件的处理函数 - */ - onReachBottom: function () { - console.log('上拉触底') - if (this.data.hasMore && !this.data.loading) { - this.loadMoreData() - } - }, - - /** - * 加载预警列表 - */ - loadAlertList: function(reset = true) { - if (reset) { - this.setData({ - loading: true, - page: 1, - hasMore: true - }) - } else { - this.setData({ - loading: true - }) - } - - // 模拟数据加载 - setTimeout(() => { - const mockData = [ - { - id: '1', - deviceId: 'ET001', - deviceName: '耳标-001', - cattleId: 'C001', - cattleName: '牛只-001', - alertType: 'battery', - alertLevel: 'high', - message: '电量低于20%,需要充电', - battery: 15, - temperature: 38.5, - steps: 1250, - ySteps: 1200, - createTime: '2024-01-15 14:30:00', - status: 'unhandled', - location: 'A区-1号栏' - }, - { - id: '2', - deviceId: 'ET002', - deviceName: '耳标-002', - cattleId: 'C002', - cattleName: '牛只-002', - alertType: 'offline', - alertLevel: 'high', - message: '设备离线超过2小时', - battery: 0, - temperature: 0, - steps: 0, - ySteps: 0, - createTime: '2024-01-15 12:15:00', - status: 'handled', - location: 'A区-2号栏' - }, - { - id: '3', - deviceId: 'ET003', - deviceName: '耳标-003', - cattleId: 'C003', - cattleName: '牛只-003', - alertType: 'temperature', - alertLevel: 'medium', - message: '温度异常,超过40°C', - battery: 85, - temperature: 42.1, - steps: 2100, - ySteps: 2100, - createTime: '2024-01-15 16:45:00', - status: 'unhandled', - location: 'B区-1号栏' - }, - { - id: '4', - deviceId: 'ET004', - deviceName: '耳标-004', - cattleId: 'C004', - cattleName: '牛只-004', - alertType: 'movement', - alertLevel: 'low', - message: '运动异常,步数为0', - battery: 72, - temperature: 37.8, - steps: 0, - ySteps: 0, - createTime: '2024-01-15 18:20:00', - status: 'unhandled', - location: 'B区-2号栏' - } - ] - - const mockStats = { - total: 12, - battery: 3, - offline: 2, - temperature: 4, - movement: 3 - } - - const newList = reset ? mockData : [...this.data.alertList, ...mockData] - - this.setData({ - alertList: newList, - stats: mockStats, - total: mockData.length, - hasMore: false, - loading: false, - refreshing: false - }) - - if (reset) { - wx.stopPullDownRefresh() - } - }, 1000) - }, - - /** - * 刷新数据 - */ - refreshData: function() { - this.setData({ - refreshing: true - }) - this.loadAlertList(true) - }, - - /** - * 加载更多数据 - */ - loadMoreData: function() { - this.setData({ - page: this.data.page + 1 - }) - this.loadAlertList(false) - }, - - /** - * 搜索输入 - */ - onSearchInput: function(e) { - this.setData({ - searchKeyword: e.detail.value - }) - }, - - /** - * 执行搜索 - */ - onSearch: function() { - this.loadAlertList(true) - }, - - /** - * 预警类型筛选 - */ - onTypeFilter: function(e) { - const type = e.currentTarget.dataset.type - this.setData({ - filterType: type - }) - this.loadAlertList(true) - }, - - /** - * 预警级别筛选 - */ - onLevelFilter: function(e) { - const level = e.currentTarget.dataset.level - this.setData({ - filterLevel: level - }) - this.loadAlertList(true) - }, - - /** - * 查看预警详情 - */ - viewAlertDetail: function(e) { - const alertId = e.currentTarget.dataset.id - wx.navigateTo({ - url: `/pages/alert/detail/detail?id=${alertId}&type=eartag` - }) - }, - - /** - * 处理预警 - */ - handleAlert: function(e) { - const alertId = e.currentTarget.dataset.id - const alertMessage = e.currentTarget.dataset.message - - wx.showModal({ - title: '处理预警', - content: `确定要处理预警"${alertMessage}"吗?`, - success: (res) => { - if (res.confirm) { - this.confirmHandleAlert(alertId) - } - } - }) - }, - - /** - * 确认处理预警 - */ - confirmHandleAlert: function(alertId) { - wx.showLoading({ - title: '处理中...' - }) - - // 模拟处理 - setTimeout(() => { - wx.hideLoading() - wx.showToast({ - title: '处理成功', - icon: 'success' - }) - this.loadAlertList(true) - }, 1000) - }, - - /** - * 获取预警类型文本 - */ - getAlertTypeText: function(type) { - const typeMap = { - 'battery': '低电量', - 'offline': '离线', - 'temperature': '温度异常', - 'movement': '运动异常' - } - return typeMap[type] || '未知' - }, - - /** - * 获取预警级别文本 - */ - getAlertLevelText: function(level) { - const levelMap = { - 'high': '高', - 'medium': '中', - 'low': '低' - } - return levelMap[level] || '未知' - }, - - /** - * 获取预警级别颜色 - */ - getAlertLevelColor: function(level) { - const colorMap = { - 'high': 'red', - 'medium': 'orange', - 'low': 'yellow' - } - return colorMap[level] || 'gray' - }, - - /** - * 获取状态文本 - */ - getStatusText: function(status) { - const statusMap = { - 'unhandled': '未处理', - 'handled': '已处理', - 'ignored': '已忽略' - } - return statusMap[status] || '未知' - }, - - /** - * 获取状态颜色 - */ - getStatusColor: function(status) { - const colorMap = { - 'unhandled': 'red', - 'handled': 'green', - 'ignored': 'gray' - } - return colorMap[status] || 'gray' - }, - - /** - * 获取预警图标 - */ - getAlertIcon: function(type) { - const iconMap = { - 'battery': '🔋', - 'offline': '📶', - 'temperature': '🌡️', - 'movement': '🏃' - } - return iconMap[type] || '⚠️' - } -}) \ No newline at end of file diff --git a/mini_program/farm-monitor-wechat/pages/alert/eartag/eartag.wxml b/mini_program/farm-monitor-wechat/pages/alert/eartag/eartag.wxml deleted file mode 100644 index f01e799..0000000 --- a/mini_program/farm-monitor-wechat/pages/alert/eartag/eartag.wxml +++ /dev/null @@ -1,221 +0,0 @@ - - - - - 智能耳标预警概览 - - - ⚠️ - {{stats.total}} - 总预警 - - - 🔋 - {{stats.battery}} - 低电量 - - - 📶 - {{stats.offline}} - 离线 - - - 🌡️ - {{stats.temperature}} - 温度异常 - - - 🏃 - {{stats.movement}} - 运动异常 - - - - - - - - - 🔍 - - - - - - - 预警类型 - - - 全部 - - - 低电量 - - - 离线 - - - 温度异常 - - - 运动异常 - - - - - - 预警级别 - - - 全部 - - - 高 - - - 中 - - - 低 - - - - - - - - 共 {{total}} 条预警 - {{alertList.length}} 条记录 - - - - - - 加载中... - - - - - - - {{getAlertIcon(item.alertType)}} - - {{item.message}} - {{item.deviceName}} - {{item.cattleName}} - - - {{getAlertLevelText(item.alertLevel)}} - - - - - - - 预警类型: - {{getAlertTypeText(item.alertType)}} - - - 处理状态: - {{getStatusText(item.status)}} - - - - - 设备电量: - {{item.battery}}% - - - 设备温度: - {{item.temperature}}°C - - - - - 当前位置: - {{item.location}} - - - 预警时间: - {{item.createTime}} - - - - - - - - - - - - - - 暂无预警数据 - 当前没有智能耳标预警信息 - - - - - - 加载中... - - - - 没有更多数据了 - - \ No newline at end of file diff --git a/mini_program/farm-monitor-wechat/pages/alert/eartag/eartag.wxss b/mini_program/farm-monitor-wechat/pages/alert/eartag/eartag.wxss deleted file mode 100644 index 94f454a..0000000 --- a/mini_program/farm-monitor-wechat/pages/alert/eartag/eartag.wxss +++ /dev/null @@ -1,456 +0,0 @@ -/* 智能耳标预警页面样式 */ -.container { - min-height: 100vh; - background: #f8f8f8; - padding-bottom: 120rpx; -} - -/* 统计概览 */ -.stats-section { - background: linear-gradient(135deg, #ff4d4f 0%, #ff7875 100%); - padding: 40rpx 30rpx; - margin-bottom: 20rpx; -} - -.stats-title { - font-size: 32rpx; - font-weight: bold; - color: #fff; - margin-bottom: 30rpx; - text-align: center; -} - -.stats-grid { - display: flex; - gap: 15rpx; - flex-wrap: wrap; -} - -.stats-card { - flex: 1; - min-width: 120rpx; - background: rgba(255, 255, 255, 0.95); - border-radius: 16rpx; - padding: 25rpx 15rpx; - text-align: center; - box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.1); - backdrop-filter: blur(10rpx); -} - -.stats-icon { - font-size: 40rpx; - margin-bottom: 12rpx; -} - -.stats-number { - font-size: 32rpx; - font-weight: bold; - color: #333; - margin-bottom: 6rpx; -} - -.stats-label { - font-size: 22rpx; - color: #666; -} - -/* 搜索栏 */ -.search-bar { - background: #fff; - padding: 20rpx 30rpx; - box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1); -} - -.search-input { - position: relative; - display: flex; - align-items: center; -} - -.search-input .input { - width: 100%; - height: 70rpx; - background: #f5f5f5; - border: 2rpx solid #e0e0e0; - border-radius: 35rpx; - padding: 0 50rpx 0 20rpx; - font-size: 26rpx; - color: #333; - box-sizing: border-box; -} - -.search-input .input:focus { - border-color: #ff4d4f; - background: #fff; -} - -.search-icon { - position: absolute; - right: 20rpx; - top: 50%; - transform: translateY(-50%); - font-size: 28rpx; - color: #999; - cursor: pointer; -} - -/* 筛选条件 */ -.filter-bar { - background: #fff; - padding: 30rpx; - margin: 0 20rpx 20rpx; - border-radius: 16rpx; - box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1); -} - -.filter-section { - margin-bottom: 25rpx; -} - -.filter-section:last-child { - margin-bottom: 0; -} - -.filter-title { - font-size: 26rpx; - color: #333; - margin-bottom: 15rpx; - font-weight: 500; -} - -.filter-options { - display: flex; - gap: 15rpx; - flex-wrap: wrap; -} - -.filter-option { - padding: 12rpx 24rpx; - background: #f5f5f5; - color: #666; - border-radius: 20rpx; - font-size: 24rpx; - cursor: pointer; - transition: all 0.3s ease; -} - -.filter-option.active { - background: #ff4d4f; - color: #fff; -} - -/* 统计信息 */ -.stats-info { - background: #fff; - padding: 20rpx 30rpx; - display: flex; - justify-content: space-between; - border-bottom: 1rpx solid #f0f0f0; -} - -.stats-text { - font-size: 24rpx; - color: #666; -} - -/* 加载状态 */ -.loading { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - height: 400rpx; - color: #999; -} - -.loading-icon { - width: 60rpx; - height: 60rpx; - border: 4rpx solid #e0e0e0; - border-top: 4rpx solid #ff4d4f; - border-radius: 50%; - animation: spin 1s linear infinite; - margin-bottom: 20rpx; -} - -@keyframes spin { - 0% { transform: rotate(0deg); } - 100% { transform: rotate(360deg); } -} - -/* 预警列表 */ -.alert-list { - padding: 20rpx; -} - -.alert-item { - background: #fff; - border-radius: 16rpx; - padding: 30rpx; - margin-bottom: 20rpx; - box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1); - transition: transform 0.3s ease; -} - -.alert-item:active { - transform: scale(0.98); -} - -.alert-header { - display: flex; - align-items: center; - margin-bottom: 20rpx; -} - -.alert-icon { - width: 60rpx; - height: 60rpx; - border-radius: 50%; - display: flex; - align-items: center; - justify-content: center; - margin-right: 20rpx; - font-size: 28rpx; - background: #fff2f0; -} - -.alert-info { - flex: 1; -} - -.alert-title { - font-size: 28rpx; - font-weight: 500; - color: #333; - margin-bottom: 8rpx; - line-height: 1.4; -} - -.alert-device { - font-size: 22rpx; - color: #666; -} - -.alert-level { - padding: 8rpx 16rpx; - border-radius: 20rpx; - font-size: 20rpx; - font-weight: 500; -} - -.alert-level.red { - background: #ffe8e8; - color: #ff4757; -} - -.alert-level.orange { - background: #fff3e0; - color: #ffa502; -} - -.alert-level.yellow { - background: #fffbe6; - color: #faad14; -} - -.alert-level.gray { - background: #f0f0f0; - color: #999; -} - -.alert-details { - margin-bottom: 25rpx; - padding: 20rpx; - background: #f8f8f8; - border-radius: 12rpx; -} - -.detail-row { - display: flex; - margin-bottom: 12rpx; -} - -.detail-row:last-child { - margin-bottom: 0; -} - -.detail-item { - flex: 1; - display: flex; - align-items: center; -} - -.detail-label { - font-size: 24rpx; - color: #666; - margin-right: 8rpx; - flex-shrink: 0; -} - -.detail-value { - font-size: 24rpx; - color: #333; - flex: 1; -} - -.detail-value.red { - color: #ff4757; - font-weight: 500; -} - -.detail-value.green { - color: #3cc51f; - font-weight: 500; -} - -.detail-value.gray { - color: #999; - font-weight: 500; -} - -.alert-actions { - display: flex; - justify-content: flex-end; -} - -.alert-actions .action-btn { - padding: 15rpx 30rpx; - border-radius: 8rpx; - font-size: 24rpx; - font-weight: 500; - cursor: pointer; - transition: all 0.3s ease; -} - -.alert-actions .action-btn.handle { - background: #ff4d4f; - color: #fff; -} - -.alert-actions .action-btn:active { - opacity: 0.7; -} - -/* 空状态 */ -.empty-state { - text-align: center; - padding: 120rpx 40rpx; - background: #fff; - margin: 20rpx; - border-radius: 16rpx; - box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1); -} - -.empty-icon { - font-size: 120rpx; - margin-bottom: 30rpx; - opacity: 0.5; -} - -.empty-text { - font-size: 32rpx; - color: #666; - margin-bottom: 15rpx; - font-weight: 500; -} - -.empty-desc { - font-size: 26rpx; - color: #999; - line-height: 1.6; -} - -/* 加载更多 */ -.load-more { - display: flex; - align-items: center; - justify-content: center; - padding: 40rpx; - color: #999; - font-size: 24rpx; -} - -.load-more .loading-icon { - width: 40rpx; - height: 40rpx; - margin-right: 15rpx; -} - -/* 响应式 */ -@media (max-width: 750rpx) { - .stats-section { - padding: 30rpx 20rpx; - } - - .stats-grid { - gap: 12rpx; - } - - .stats-card { - padding: 20rpx 12rpx; - min-width: 100rpx; - } - - .stats-icon { - font-size: 36rpx; - } - - .stats-number { - font-size: 28rpx; - } - - .stats-label { - font-size: 20rpx; - } - - .search-bar { - padding: 15rpx 20rpx; - } - - .search-input .input { - height: 60rpx; - font-size: 24rpx; - } - - .filter-bar { - margin: 0 15rpx 15rpx; - padding: 25rpx; - } - - .filter-options { - gap: 10rpx; - } - - .filter-option { - padding: 10rpx 20rpx; - font-size: 22rpx; - } - - .alert-item { - padding: 25rpx; - } - - .alert-icon { - width: 50rpx; - height: 50rpx; - font-size: 24rpx; - } - - .alert-title { - font-size: 26rpx; - } - - .alert-device { - font-size: 20rpx; - } - - .detail-label, - .detail-value { - font-size: 22rpx; - } - - .alert-actions .action-btn { - padding: 12rpx 25rpx; - font-size: 22rpx; - } -} \ No newline at end of file diff --git a/mini_program/farm-monitor-wechat/pages/cattle/add/add.js b/mini_program/farm-monitor-wechat/pages/cattle/add/add.js deleted file mode 100644 index 14ed2ba..0000000 --- a/mini_program/farm-monitor-wechat/pages/cattle/add/add.js +++ /dev/null @@ -1,370 +0,0 @@ -/** - * 牛只添加页面 - * @file add.js - * @description 添加新牛只页面 - */ - -const app = getApp() - -Page({ - /** - * 页面的初始数据 - */ - data: { - formData: { - cattleId: '', - name: '', - breed: '', - gender: '', - birthDate: '', - weight: '', - healthStatus: 'healthy', - location: '', - description: '', - parentId: '', - parentName: '' - }, - // 计算后的索引值 - breedIndex: 0, - genderIndex: 0, - healthStatusIndex: 0, - locationIndex: 0, - parentIndex: 0, - breedOptions: [ - '荷斯坦牛', - '西门塔尔牛', - '夏洛莱牛', - '利木赞牛', - '安格斯牛', - '其他' - ], - genderOptions: [ - { value: 'male', label: '公牛' }, - { value: 'female', label: '母牛' }, - { value: 'calf', label: '犊牛' } - ], - healthStatusOptions: [ - { value: 'healthy', label: '健康' }, - { value: 'sick', label: '生病' }, - { value: 'pregnant', label: '怀孕' }, - { value: 'lactating', label: '泌乳期' } - ], - locationOptions: [ - 'A区-1号栏', - 'A区-2号栏', - 'A区-3号栏', - 'B区-1号栏', - 'B区-2号栏', - 'B区-3号栏', - 'C区-1号栏', - 'C区-2号栏', - 'C区-3号栏' - ], - submitting: false, - showParentPicker: false, - parentList: [] - }, - - /** - * 生命周期函数--监听页面加载 - */ - onLoad: function (options) { - console.log('牛只添加页面加载', options) - this.loadParentList() - this.generateCattleId() - }, - - /** - * 生成牛只ID - */ - generateCattleId: function() { - const now = new Date() - const year = now.getFullYear() - const month = String(now.getMonth() + 1).padStart(2, '0') - const day = String(now.getDate()).padStart(2, '0') - const random = String(Math.floor(Math.random() * 1000)).padStart(3, '0') - const cattleId = `C${year}${month}${day}${random}` - - this.setData({ - 'formData.cattleId': cattleId - }) - }, - - /** - * 计算索引值 - */ - calculateIndexes: function() { - const { formData, breedOptions, genderOptions, healthStatusOptions, locationOptions, parentList } = this.data - - const breedIndex = breedOptions.indexOf(formData.breed) - const genderIndex = genderOptions.findIndex(item => item.value === formData.gender) - const healthStatusIndex = healthStatusOptions.findIndex(item => item.value === formData.healthStatus) - const locationIndex = locationOptions.indexOf(formData.location) - const parentIndex = parentList.findIndex(item => item.id === formData.parentId) - - this.setData({ - breedIndex: breedIndex >= 0 ? breedIndex : 0, - genderIndex: genderIndex >= 0 ? genderIndex : 0, - healthStatusIndex: healthStatusIndex >= 0 ? healthStatusIndex : 0, - locationIndex: locationIndex >= 0 ? locationIndex : 0, - parentIndex: parentIndex >= 0 ? parentIndex : 0 - }) - }, - - /** - * 加载父代牛只列表 - */ - loadParentList: function() { - // 模拟数据 - const mockParents = [ - { id: 'C001', name: '牛只-001', breed: '荷斯坦牛', gender: 'female' }, - { id: 'C002', name: '牛只-002', breed: '西门塔尔牛', gender: 'male' }, - { id: 'C003', name: '牛只-003', breed: '夏洛莱牛', gender: 'female' } - ] - - this.setData({ - parentList: mockParents - }, () => { - // 数据加载完成后计算索引 - this.calculateIndexes() - }) - }, - - /** - * 输入框变化 - */ - onInputChange: function(e) { - const field = e.currentTarget.dataset.field - const value = e.detail.value - - this.setData({ - [`formData.${field}`]: value - }) - }, - - /** - * 选择品种 - */ - onBreedChange: function(e) { - const index = e.detail.value - this.setData({ - 'formData.breed': this.data.breedOptions[index], - breedIndex: index - }) - }, - - /** - * 选择性别 - */ - onGenderChange: function(e) { - const index = e.detail.value - this.setData({ - 'formData.gender': this.data.genderOptions[index].value, - genderIndex: index - }) - }, - - /** - * 选择健康状态 - */ - onHealthStatusChange: function(e) { - const index = e.detail.value - this.setData({ - 'formData.healthStatus': this.data.healthStatusOptions[index].value, - healthStatusIndex: index - }) - }, - - /** - * 选择位置 - */ - onLocationChange: function(e) { - const index = e.detail.value - this.setData({ - 'formData.location': this.data.locationOptions[index], - locationIndex: index - }) - }, - - /** - * 选择出生日期 - */ - onBirthDateChange: function(e) { - this.setData({ - 'formData.birthDate': e.detail.value - }) - }, - - /** - * 选择父代 - */ - onParentChange: function(e) { - const index = e.detail.value - const parent = this.data.parentList[index] - - this.setData({ - 'formData.parentId': parent.id, - 'formData.parentName': parent.name, - parentIndex: index - }) - }, - - /** - * 显示父代选择器 - */ - showParentPicker: function() { - this.setData({ - showParentPicker: true - }) - }, - - /** - * 隐藏父代选择器 - */ - hideParentPicker: function() { - this.setData({ - showParentPicker: false - }) - }, - - /** - * 表单验证 - */ - validateForm: function() { - const { formData } = this.data - - if (!formData.name.trim()) { - wx.showToast({ - title: '请输入牛只名称', - icon: 'none' - }) - return false - } - - if (!formData.breed) { - wx.showToast({ - title: '请选择品种', - icon: 'none' - }) - return false - } - - if (!formData.gender) { - wx.showToast({ - title: '请选择性别', - icon: 'none' - }) - return false - } - - if (!formData.birthDate) { - wx.showToast({ - title: '请选择出生日期', - icon: 'none' - }) - return false - } - - if (!formData.weight || isNaN(formData.weight) || formData.weight <= 0) { - wx.showToast({ - title: '请输入正确的体重', - icon: 'none' - }) - return false - } - - if (!formData.location) { - wx.showToast({ - title: '请选择位置', - icon: 'none' - }) - return false - } - - return true - }, - - /** - * 提交表单 - */ - onSubmit: function() { - if (!this.validateForm()) { - return - } - - this.setData({ - submitting: true - }) - - // 模拟提交 - setTimeout(() => { - this.setData({ - submitting: false - }) - - wx.showToast({ - title: '添加成功', - icon: 'success' - }) - - setTimeout(() => { - wx.navigateBack() - }, 1500) - }, 2000) - }, - - /** - * 重置表单 - */ - onReset: function() { - wx.showModal({ - title: '确认重置', - content: '确定要重置表单吗?', - success: (res) => { - if (res.confirm) { - this.setData({ - formData: { - cattleId: '', - name: '', - breed: '', - gender: '', - birthDate: '', - weight: '', - healthStatus: 'healthy', - location: '', - description: '', - parentId: '', - parentName: '' - } - }) - this.generateCattleId() - } - } - }) - }, - - /** - * 获取性别文本 - */ - getGenderText: function(gender) { - const genderMap = { - 'male': '公牛', - 'female': '母牛', - 'calf': '犊牛' - } - return genderMap[gender] || '未知' - }, - - /** - * 获取健康状态文本 - */ - getHealthStatusText: function(status) { - const statusMap = { - 'healthy': '健康', - 'sick': '生病', - 'pregnant': '怀孕', - 'lactating': '泌乳期' - } - return statusMap[status] || '未知' - } -}) \ No newline at end of file diff --git a/mini_program/farm-monitor-wechat/pages/cattle/add/add.wxml b/mini_program/farm-monitor-wechat/pages/cattle/add/add.wxml deleted file mode 100644 index 54ef39c..0000000 --- a/mini_program/farm-monitor-wechat/pages/cattle/add/add.wxml +++ /dev/null @@ -1,164 +0,0 @@ - - - - - 添加新牛只 - 请填写牛只基本信息 - - -
- - - 基本信息 - - - 牛只ID - {{formData.cattleId}} - - - - 牛只名称 - - - - - 品种 - - {{formData.breed || '请选择品种'}} - - - - - 性别 - - {{getGenderText(formData.gender) || '请选择性别'}} - - - - - 出生日期 - - {{formData.birthDate || '请选择出生日期'}} - - - - - 体重(kg) - - - - - - - 健康状态 - - - 健康状态 - - {{getHealthStatusText(formData.healthStatus)}} - - - - - 位置 - - {{formData.location || '请选择位置'}} - - - - - - - 父代信息 - - - 父代牛只 - - {{formData.parentName || '请选择父代牛只'}} - - - - - - - 备注信息 - - - 备注描述 -