const { DataTypes } = require('sequelize') const BaseModel = require('./BaseModel') const { sequelize } = require('../config/database-simple') /** * 电子围栏模型 */ class ElectronicFence extends BaseModel { static init(sequelize) { return super.init({ id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true, comment: '围栏ID' }, name: { type: DataTypes.STRING(100), allowNull: false, comment: '围栏名称' }, type: { type: DataTypes.ENUM('collector', 'grazing', 'safety'), allowNull: false, defaultValue: 'collector', comment: '围栏类型: collector-采集器电子围栏, grazing-放牧围栏, safety-安全围栏' }, description: { type: DataTypes.TEXT, allowNull: true, comment: '围栏描述' }, coordinates: { type: DataTypes.JSON, allowNull: false, comment: '围栏坐标点数组' }, center_lng: { type: DataTypes.DECIMAL(10, 7), allowNull: false, comment: '围栏中心经度' }, center_lat: { type: DataTypes.DECIMAL(10, 7), allowNull: false, comment: '围栏中心纬度' }, area: { type: DataTypes.DECIMAL(10, 4), allowNull: true, comment: '围栏面积(平方米)' }, grazing_status: { type: DataTypes.ENUM('grazing', 'not_grazing'), allowNull: false, defaultValue: 'not_grazing', comment: '放牧状态: grazing-放牧中, not_grazing-未放牧' }, inside_count: { type: DataTypes.INTEGER, allowNull: false, defaultValue: 0, comment: '安全区域内动物数量' }, outside_count: { type: DataTypes.INTEGER, allowNull: false, defaultValue: 0, comment: '安全区域外动物数量' }, is_active: { type: DataTypes.BOOLEAN, allowNull: false, defaultValue: true, comment: '是否启用' }, farm_id: { type: DataTypes.INTEGER, allowNull: true, comment: '关联农场ID' }, created_by: { type: DataTypes.INTEGER, allowNull: true, comment: '创建人ID' }, updated_by: { type: DataTypes.INTEGER, allowNull: true, comment: '更新人ID' } }, { sequelize, modelName: 'ElectronicFence', tableName: 'electronic_fences', timestamps: true, createdAt: 'created_at', updatedAt: 'updated_at', comment: '电子围栏表', indexes: [ { name: 'idx_fence_name', fields: ['name'] }, { name: 'idx_fence_type', fields: ['type'] }, { name: 'idx_fence_center', fields: ['center_lng', 'center_lat'] }, { name: 'idx_fence_active', fields: ['is_active'] } ] }) } /** * 定义关联关系 */ static associate(models) { // 围栏与农场关联(可选) this.belongsTo(models.Farm, { foreignKey: 'farm_id', as: 'farm' }) } /** * 获取围栏类型文本 */ getTypeText() { const typeMap = { 'collector': '采集器电子围栏', 'grazing': '放牧围栏', 'safety': '安全围栏' } return typeMap[this.type] || '未知类型' } /** * 获取放牧状态文本 */ getGrazingStatusText() { const statusMap = { 'grazing': '放牧中', 'not_grazing': '未放牧' } return statusMap[this.grazing_status] || '未知状态' } /** * 计算围栏面积(简化计算) */ calculateArea() { if (!this.coordinates || this.coordinates.length < 3) { return 0 } // 使用Shoelace公式计算多边形面积 let area = 0 const coords = this.coordinates for (let i = 0; i < coords.length; i++) { const j = (i + 1) % coords.length area += coords[i].lng * coords[j].lat area -= coords[j].lng * coords[i].lat } // 转换为平方米(粗略计算) return Math.abs(area) * 111000 * 111000 / 2 } /** * 计算围栏中心点 */ calculateCenter() { if (!this.coordinates || this.coordinates.length === 0) { return { lng: 0, lat: 0 } } let lngSum = 0 let latSum = 0 this.coordinates.forEach(coord => { lngSum += coord.lng latSum += coord.lat }) return { lng: lngSum / this.coordinates.length, lat: latSum / this.coordinates.length } } /** * 检查点是否在围栏内 */ isPointInside(lng, lat) { if (!this.coordinates || this.coordinates.length < 3) { return false } let inside = false const coords = this.coordinates for (let i = 0, j = coords.length - 1; i < coords.length; j = i++) { if (((coords[i].lat > lat) !== (coords[j].lat > lat)) && (lng < (coords[j].lng - coords[i].lng) * (lat - coords[i].lat) / (coords[j].lat - coords[i].lat) + coords[i].lng)) { inside = !inside } } return inside } /** * 转换为前端格式 */ toFrontendFormat() { return { id: this.id, name: this.name, type: this.getTypeText(), description: this.description, coordinates: this.coordinates, center: { lng: this.center_lng, lat: this.center_lat }, area: this.area, grazingStatus: this.getGrazingStatusText(), insideCount: this.inside_count, outsideCount: this.outside_count, isActive: this.is_active, createdAt: this.created_at, updatedAt: this.updated_at } } } // 初始化模型 ElectronicFence.init(sequelize) module.exports = ElectronicFence