修改bug。新增牛只,超链接
This commit is contained in:
@@ -129,32 +129,61 @@
|
||||
<a-row :gutter="16">
|
||||
<a-col :span="8">
|
||||
<a-form-item label="品系" name="strain">
|
||||
<a-input
|
||||
<a-select
|
||||
v-model:value="formData.strain"
|
||||
placeholder="请输入品系"
|
||||
@input="handleFieldChange('strain', $event.target.value)"
|
||||
@change="handleFieldChange('strain', $event.target.value)"
|
||||
/>
|
||||
placeholder="请选择品系"
|
||||
:loading="cattleUsersLoading"
|
||||
@change="handleFieldChange('strain', $event)"
|
||||
show-search
|
||||
:filter-option="filterOption"
|
||||
>
|
||||
<a-select-option
|
||||
v-for="user in cattleUsers"
|
||||
:key="user.id"
|
||||
:value="user.id"
|
||||
>
|
||||
{{ user.name }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="8">
|
||||
<a-form-item label="品种" name="varieties">
|
||||
<a-input
|
||||
<a-select
|
||||
v-model:value="formData.varieties"
|
||||
placeholder="请输入品种"
|
||||
@input="handleFieldChange('varieties', $event.target.value)"
|
||||
@change="handleFieldChange('varieties', $event.target.value)"
|
||||
/>
|
||||
placeholder="请选择品种"
|
||||
:loading="cattleTypesLoading"
|
||||
@change="handleFieldChange('varieties', $event)"
|
||||
show-search
|
||||
:filter-option="filterOption"
|
||||
>
|
||||
<a-select-option
|
||||
v-for="type in cattleTypes"
|
||||
:key="type.id"
|
||||
:value="type.id"
|
||||
>
|
||||
{{ type.name }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="8">
|
||||
<a-form-item label="类别" name="cate">
|
||||
<a-input
|
||||
<a-select
|
||||
v-model:value="formData.cate"
|
||||
placeholder="请输入类别"
|
||||
@input="handleFieldChange('cate', $event.target.value)"
|
||||
@change="handleFieldChange('cate', $event.target.value)"
|
||||
/>
|
||||
placeholder="请选择类别"
|
||||
@change="handleFieldChange('cate', $event)"
|
||||
show-search
|
||||
:filter-option="filterCateOption"
|
||||
>
|
||||
<a-select-option
|
||||
v-for="(name, value) in cateOptions"
|
||||
:key="value"
|
||||
:value="parseInt(value)"
|
||||
>
|
||||
{{ name }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
@@ -368,15 +397,29 @@ const animals = ref([])
|
||||
const farms = ref([])
|
||||
const pens = ref([])
|
||||
const batches = ref([])
|
||||
const cattleUsers = ref([]) // 品系数据(cattle_user表)
|
||||
const cattleTypes = ref([]) // 品种数据(cattle_type表)
|
||||
const loading = ref(false)
|
||||
const farmsLoading = ref(false)
|
||||
const pensLoading = ref(false)
|
||||
const batchesLoading = ref(false)
|
||||
const cattleUsersLoading = ref(false)
|
||||
const cattleTypesLoading = ref(false)
|
||||
const modalVisible = ref(false)
|
||||
const submitLoading = ref(false)
|
||||
const isEdit = ref(false)
|
||||
const formRef = ref()
|
||||
|
||||
// 类别选项(预定义映射)
|
||||
const cateOptions = ref({
|
||||
1: '犊牛',
|
||||
2: '育成母牛',
|
||||
3: '架子牛',
|
||||
4: '青年牛',
|
||||
5: '基础母牛',
|
||||
6: '育肥牛'
|
||||
})
|
||||
|
||||
// 分页相关
|
||||
const pagination = ref({
|
||||
current: 1,
|
||||
@@ -474,19 +517,38 @@ const columns = [
|
||||
title: '品系',
|
||||
dataIndex: 'strain', // 映射iot_cattle.strain,显示用途名称
|
||||
key: 'strain',
|
||||
width: 120
|
||||
width: 120,
|
||||
customRender: ({ text }) => {
|
||||
const user = cattleUsers.value.find(u => u.id === text)
|
||||
return user ? user.name : text || '-'
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '品种',
|
||||
dataIndex: 'varieties', // 映射iot_cattle.varieties
|
||||
key: 'varieties',
|
||||
width: 120
|
||||
width: 120,
|
||||
customRender: ({ text }) => {
|
||||
const type = cattleTypes.value.find(t => t.id === text)
|
||||
return type ? type.name : text || '-'
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '类别',
|
||||
dataIndex: 'cate', // 映射iot_cattle.cate
|
||||
key: 'cate',
|
||||
width: 100
|
||||
width: 100,
|
||||
customRender: ({ text }) => {
|
||||
const cateMap = {
|
||||
1: '犊牛',
|
||||
2: '育成母牛',
|
||||
3: '架子牛',
|
||||
4: '青年牛',
|
||||
5: '基础母牛',
|
||||
6: '育肥牛'
|
||||
}
|
||||
return cateMap[text] || text || '-'
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '出生体重(kg)',
|
||||
@@ -611,6 +673,38 @@ const fetchBatches = async (farmId = null) => {
|
||||
}
|
||||
}
|
||||
|
||||
// 获取品系列表(cattle_user表)
|
||||
const fetchCattleUsers = async () => {
|
||||
try {
|
||||
cattleUsersLoading.value = true
|
||||
const response = await api.get('/cattle-user')
|
||||
if (response.success) {
|
||||
cattleUsers.value = response.data
|
||||
console.log('获取品系列表成功:', cattleUsers.value.length, '条记录')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取品系列表失败:', error)
|
||||
} finally {
|
||||
cattleUsersLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 获取品种和类别列表(cattle_type表)
|
||||
const fetchCattleTypes = async () => {
|
||||
try {
|
||||
cattleTypesLoading.value = true
|
||||
const response = await api.get('/cattle-type')
|
||||
if (response.success) {
|
||||
cattleTypes.value = response.data
|
||||
console.log('获取品种列表成功:', cattleTypes.value.length, '条记录')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取品种列表失败:', error)
|
||||
} finally {
|
||||
cattleTypesLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 字段变化监听函数
|
||||
const handleFieldChange = (fieldName, value) => {
|
||||
console.log(`字段 ${fieldName} 变化:`, value)
|
||||
@@ -625,6 +719,54 @@ const handleFieldChange = (fieldName, value) => {
|
||||
formData[fieldName] = value
|
||||
}
|
||||
|
||||
// 下拉框过滤选项方法
|
||||
const filterOption = (input, option) => {
|
||||
return option.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}
|
||||
|
||||
// 类别下拉框过滤选项方法
|
||||
const filterCateOption = (input, option) => {
|
||||
return option.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}
|
||||
|
||||
// 绑定耳标到iot_jbq_client表
|
||||
const bindEarTag = async (earNumber, cattleId) => {
|
||||
try {
|
||||
console.log('开始绑定耳标:', earNumber, '到牛只ID:', cattleId)
|
||||
|
||||
// 查找对应的耳标设备
|
||||
const response = await api.get('/iot-jbq-client', {
|
||||
params: { cid: earNumber }
|
||||
})
|
||||
|
||||
if (response.success && response.data && response.data.length > 0) {
|
||||
const device = response.data[0]
|
||||
console.log('找到耳标设备:', device)
|
||||
|
||||
// 更新设备的绑定状态
|
||||
const updateResponse = await api.put(`/iot-jbq-client/${device.id}`, {
|
||||
bandge_status: 1, // 1表示已绑定
|
||||
bound_cattle_id: cattleId,
|
||||
bound_ear_number: earNumber
|
||||
})
|
||||
|
||||
if (updateResponse.success) {
|
||||
console.log('耳标绑定成功')
|
||||
message.success('耳标绑定成功')
|
||||
} else {
|
||||
console.error('耳标绑定失败:', updateResponse.message)
|
||||
message.warning('牛只档案创建成功,但耳标绑定失败')
|
||||
}
|
||||
} else {
|
||||
console.warn('未找到对应的耳标设备:', earNumber)
|
||||
message.warning('牛只档案创建成功,但未找到对应的耳标设备')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('耳标绑定失败:', error)
|
||||
message.warning('牛只档案创建成功,但耳标绑定失败')
|
||||
}
|
||||
}
|
||||
|
||||
// 处理动物类型选择变化
|
||||
const handleTypeChange = (value) => {
|
||||
console.log('=== 动物类型变化 ===')
|
||||
@@ -775,6 +917,8 @@ const openModal = () => {
|
||||
// 加载必需数据
|
||||
const loadRequiredData = () => {
|
||||
fetchFarms()
|
||||
fetchCattleUsers()
|
||||
fetchCattleTypes()
|
||||
}
|
||||
|
||||
// 提交表单(使用iot_cattle API)
|
||||
@@ -789,11 +933,20 @@ const handleSubmit = async () => {
|
||||
console.log('是否编辑模式:', isEdit.value);
|
||||
console.log('原始表单数据:', JSON.parse(JSON.stringify(formData)));
|
||||
|
||||
// 处理日期格式
|
||||
// 检查必填字段
|
||||
const requiredFields = ['earNumber', 'sex', 'strain', 'varieties', 'cate', 'birthWeight', 'birthday', 'orgId'];
|
||||
const missingFields = requiredFields.filter(field => !formData[field] && formData[field] !== 0);
|
||||
if (missingFields.length > 0) {
|
||||
console.error('缺少必填字段:', missingFields);
|
||||
message.error(`缺少必填字段: ${missingFields.join(', ')}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// 处理日期格式 - 转换为时间戳(秒)
|
||||
const submitData = {
|
||||
...formData,
|
||||
birthday: formData.birthday ? formData.birthday.format('YYYY-MM-DD') : null,
|
||||
weightCalculateTime: formData.weightCalculateTime ? formData.weightCalculateTime.format('YYYY-MM-DD') : null
|
||||
birthday: formData.birthday ? Math.floor(formData.birthday.valueOf() / 1000) : null,
|
||||
weightCalculateTime: formData.weightCalculateTime ? Math.floor(formData.weightCalculateTime.valueOf() / 1000) : null
|
||||
}
|
||||
|
||||
// 如果是新增操作,移除id字段
|
||||
@@ -815,6 +968,11 @@ const handleSubmit = async () => {
|
||||
console.log('服务器响应:', response);
|
||||
|
||||
if (response.success) {
|
||||
// 如果创建成功且有耳标号,尝试绑定耳标
|
||||
if (!isEdit.value && formData.earNumber) {
|
||||
await bindEarTag(formData.earNumber, response.data.id)
|
||||
}
|
||||
|
||||
message.success(isEdit.value ? '更新牛只档案成功' : '创建牛只档案成功')
|
||||
modalVisible.value = false
|
||||
await fetchAnimals()
|
||||
@@ -1210,6 +1368,8 @@ onMounted(() => {
|
||||
fetchFarms()
|
||||
fetchPens()
|
||||
fetchBatches()
|
||||
fetchCattleUsers()
|
||||
fetchCattleTypes()
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
@@ -119,18 +119,32 @@
|
||||
</template>
|
||||
</a-input>
|
||||
<a-select
|
||||
v-model="searchType"
|
||||
placeholder="围栏类型"
|
||||
class="type-filter"
|
||||
@change="handleSearch"
|
||||
v-model="selectedFenceName"
|
||||
placeholder="选择围栏名称"
|
||||
class="fence-name-select"
|
||||
@change="handleFenceNameSelect"
|
||||
allowClear
|
||||
show-search
|
||||
:filter-option="filterFenceNameOption"
|
||||
:loading="fenceNamesLoading"
|
||||
>
|
||||
<a-select-option value="">全部类型</a-select-option>
|
||||
<a-select-option value="grazing">放牧区</a-select-option>
|
||||
<a-select-option value="safety">安全区</a-select-option>
|
||||
<a-select-option value="restricted">限制区</a-select-option>
|
||||
<a-select-option value="collector">收集区</a-select-option>
|
||||
<a-select-option
|
||||
v-for="fence in fenceList"
|
||||
:key="fence.id"
|
||||
:value="fence.name"
|
||||
>
|
||||
{{ fence.name }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
|
||||
<a-button
|
||||
type="default"
|
||||
@click="clearAllSearch"
|
||||
class="clear-search-btn"
|
||||
:disabled="!searchValue && !selectedFenceName && !searchType"
|
||||
>
|
||||
清除搜索
|
||||
</a-button>
|
||||
</div>
|
||||
<div class="fence-stats">
|
||||
<a-statistic
|
||||
@@ -264,6 +278,8 @@ const submitting = ref(false)
|
||||
const fenceModalVisible = ref(false)
|
||||
const searchValue = ref('')
|
||||
const searchType = ref('')
|
||||
const selectedFenceName = ref('')
|
||||
const fenceNamesLoading = ref(false)
|
||||
const selectedFence = ref(null)
|
||||
const editingFence = ref(null)
|
||||
|
||||
@@ -306,8 +322,13 @@ let allMarkers = []
|
||||
const filteredFenceList = computed(() => {
|
||||
let filtered = fenceList.value
|
||||
|
||||
// 按名称和描述搜索
|
||||
if (searchValue.value) {
|
||||
// 按围栏名称选择过滤
|
||||
if (selectedFenceName.value) {
|
||||
filtered = filtered.filter(fence => fence.name === selectedFenceName.value)
|
||||
}
|
||||
|
||||
// 按名称和描述搜索(当没有选择具体围栏名称时)
|
||||
if (searchValue.value && !selectedFenceName.value) {
|
||||
const searchLower = searchValue.value.toLowerCase()
|
||||
filtered = filtered.filter(fence =>
|
||||
fence.name.toLowerCase().includes(searchLower) ||
|
||||
@@ -700,7 +721,7 @@ const handleFenceSubmit = async () => {
|
||||
// 保存围栏
|
||||
const result = await api.electronicFence.createFence(fenceData)
|
||||
|
||||
if (result && result.id) {
|
||||
if (result && result.data && result.data.id) {
|
||||
// 保存坐标点
|
||||
const pointsData = drawingState.currentPoints.map((point, index) => ({
|
||||
lng: point.lng,
|
||||
@@ -709,10 +730,16 @@ const handleFenceSubmit = async () => {
|
||||
description: `围栏点${index + 1}`
|
||||
}))
|
||||
|
||||
await api.electronicFencePoints.createPoints({
|
||||
fence_id: result.id,
|
||||
points: pointsData
|
||||
})
|
||||
try {
|
||||
await api.electronicFencePoints.createPoints({
|
||||
fence_id: result.data.id,
|
||||
points: pointsData
|
||||
})
|
||||
console.log('坐标点创建成功')
|
||||
} catch (pointError) {
|
||||
console.error('坐标点创建失败:', pointError)
|
||||
message.warning('围栏创建成功,但坐标点保存失败: ' + pointError.message)
|
||||
}
|
||||
|
||||
console.log('围栏创建成功:', result)
|
||||
message.success('围栏创建成功')
|
||||
@@ -1090,6 +1117,27 @@ const handleSearch = () => {
|
||||
// 搜索逻辑在计算属性中处理
|
||||
}
|
||||
|
||||
// 处理围栏名称选择
|
||||
const handleFenceNameSelect = (value) => {
|
||||
selectedFenceName.value = value
|
||||
// 清空文本搜索,避免冲突
|
||||
if (value) {
|
||||
searchValue.value = ''
|
||||
}
|
||||
}
|
||||
|
||||
// 过滤围栏名称选项
|
||||
const filterFenceNameOption = (input, option) => {
|
||||
return option.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}
|
||||
|
||||
// 清除所有搜索条件
|
||||
const clearAllSearch = () => {
|
||||
searchValue.value = ''
|
||||
selectedFenceName.value = ''
|
||||
searchType.value = ''
|
||||
}
|
||||
|
||||
// 初始化
|
||||
onMounted(() => {
|
||||
console.log('电子围栏组件已挂载')
|
||||
@@ -1233,15 +1281,26 @@ onMounted(() => {
|
||||
|
||||
.search-section {
|
||||
margin-bottom: 15px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
margin-bottom: 10px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.fence-name-select {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.type-filter {
|
||||
width: 100%;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.clear-search-btn {
|
||||
width: 100%;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.fence-stats {
|
||||
|
||||
Reference in New Issue
Block a user