Files
zhyc-sheep-ui/src/views/breed/lambing_records/index.vue
2026-03-05 14:58:45 +08:00

1269 lines
46 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="80px">
<el-form-item label="耳号" prop="allEarNumbers">
<div style="display: flex; align-items: center; gap: 10px; flex-wrap: wrap;">
<el-select
v-model="queryParams.allEarNumbers"
multiple
filterable
remote
reserve-keyword
placeholder="输入耳号搜索"
:remote-method="searchEarNumber"
:loading="earNumberLoading"
allow-create
default-first-option
collapse-tags
:max-collapse-tags="0"
style="width: 300px"
@change="handleEarNumberChange"
>
<el-option
v-for="item in earNumberOptions"
:key="item"
:label="item"
:value="item"
/>
</el-select>
<el-input
v-model="pasteInput"
placeholder="或粘贴多个耳号(空格/换行/逗号分隔)"
style="width: 300px"
@paste="handlePaste"
@keyup.enter="handlePasteSubmit"
clearable
>
<template #append>
<el-button @click="handlePasteSubmit" :icon="Plus">添加</el-button>
</template>
</el-input>
<el-tag
v-if="queryParams.allEarNumbers && queryParams.allEarNumbers.length > 0"
type="info"
effect="plain"
size="large"
>
已选: {{ queryParams.allEarNumbers.length }}
</el-tag>
<el-button
type="danger"
plain
@click="clearAllEarNumbers"
v-if="queryParams.allEarNumbers && queryParams.allEarNumbers.length > 0"
:icon="Delete"
>
清空全部
</el-button>
</div>
<div
v-if="queryParams.allEarNumbers && queryParams.allEarNumbers.length > 0"
class="selected-ear-numbers-display"
style="margin-top: 10px;"
>
<el-tag
v-for="(tag, index) in displayedEarNumbers"
:key="tag"
closable
@close="handleRemoveEarNumber(tag)"
style="margin: 4px;"
type="success"
>
{{ tag }}
</el-tag>
<el-button
v-if="queryParams.allEarNumbers.length > defaultShowCount"
type="primary"
link
@click="toggleExpand"
style="margin-left: 8px;"
>
{{ isExpanded ? '收起' : `展开剩余 ${queryParams.allEarNumbers.length - defaultShowCount}` }}
<el-icon class="el-icon--right">
<component :is="isExpanded ? ArrowUp : ArrowDown" />
</el-icon>
</el-button>
</div>
</el-form-item>
<el-form-item label="母羊品种" prop="femaleBreed">
<el-input
v-model="queryParams.femaleBreed"
placeholder="请输入母羊品种"
clearable
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="胎次" prop="parity">
<el-input
v-model="queryParams.parity"
placeholder="请输入胎次"
clearable
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="技术员" prop="technician">
<el-select
v-model="queryParams.technician"
placeholder="请选择技术员"
filterable
clearable
style="width: 200px"
@change="handleQuery"
>
<el-option
v-for="item in technicalOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="所在牧场" prop="farm">
<el-input
v-model="queryParams.farm"
placeholder="请输入所在牧场"
clearable
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="配种日期" prop="breedingDate">
<el-date-picker
v-model="queryParams.breedingDate"
type="daterange"
range-separator=""
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="YYYY-MM-DD">
</el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="Plus"
@click="handleAdd"
v-hasPermi="['breed:lambing_records:add']"
>新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="Edit"
:disabled="single"
@click="handleUpdate"
v-hasPermi="['breed:lambing_records:edit']"
>修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="Delete"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['breed:lambing_records:remove']"
>删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="Download"
@click="handleExport"
v-hasPermi="['breed:lambing_records:export']"
>导出</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="lambing_recordsList" @selection-change="handleSelectionChange" row-key="id">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="母羊耳号" align="center" prop="femaleEarNumber" width="120" fixed="left" />
<el-table-column label="母羊品种" align="center" prop="femaleBreed" width="100" />
<el-table-column label="事件类型" align="center" width="90">
<template #default>
<el-tag type="success" size="small">产羔</el-tag>
</template>
</el-table-column>
<el-table-column label="产羔日期" align="center" prop="createTime" width="110">
<template #default="scope">
<span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="配种类型" align="center" prop="breedType" width="140">
<template #default="scope">
<span>{{ getBreedTypeLabel(scope.row.breedType) }}</span>
</template>
</el-table-column>
<el-table-column label="配种日期" align="center" prop="breedingDate" width="110">
<template #default="scope">
<span>{{ parseTime(scope.row.breedingDate, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="胎次" align="center" prop="parity" width="80" />
<el-table-column label="公羊耳号" align="center" prop="maleEarNumber" width="120" />
<el-table-column label="公羊品种" align="center" prop="maleBreed" width="120" />
<!-- 供体信息胚胎移植时有值 -->
<el-table-column label="供体母羊" align="center" prop="donorEwe" width="120" />
<el-table-column label="供体母羊品种" align="center" prop="donorEweBreed" width="120" />
<el-table-column label="供体公羊" align="center" prop="donorRam" width="120" />
<el-table-column label="供体公羊品种" align="center" prop="donorRamBreed" width="120" />
<el-table-column label="移胚数" align="center" prop="embryoCount" width="90" />
<el-table-column label="产羔数量" align="center" prop="lambsBorn" width="90" />
<el-table-column label="活羔数量" align="center" prop="survival" width="90" />
<el-table-column label="折损数" align="center" prop="loss" width="80">
<template #default="scope">
<span>{{ (scope.row.lambsBorn || 0) - (scope.row.survival || 0) }}</span>
</template>
</el-table-column>
<el-table-column label="羔羊品种" align="center" prop="lambBreedId" width="110">
<template #default="scope">
<span>{{ getVarietyName(scope.row.lambBreedId) }}</span>
</template>
</el-table-column>
<template v-for="n in 8" :key="'lambcols'+n">
<el-table-column :label="'羔羊耳号'+n" align="center" width="130">
<template #default="scope">
<span>{{ scope.row.lambDetails && scope.row.lambDetails[n-1] ? scope.row.lambDetails[n-1].lambEarNumber : '' }}</span>
</template>
</el-table-column>
<el-table-column :label="'羔羊'+n+'出生重'" align="center" width="100">
<template #default="scope">
<span>{{ scope.row.lambDetails && scope.row.lambDetails[n-1] ? scope.row.lambDetails[n-1].birthWeight : '' }}</span>
</template>
</el-table-column>
</template>
<el-table-column label="技术员" align="center" prop="technician" width="100" />
<el-table-column label="月龄" align="center" prop="monthAge" width="80" />
<el-table-column label="产羔评分" align="center" prop="score" width="90" />
<el-table-column label="公羔数量" align="center" prop="maleCount" width="90" />
<el-table-column label="母羔数量" align="center" prop="femaleCount" width="90" />
<el-table-column label="留养公羔数量" align="center" prop="retainedMaleCount" width="130" />
<el-table-column label="留养母羔数量" align="center" prop="retainedFemaleCount" width="130" />
<el-table-column label="未留养公羔数量" align="center" prop="unretainedMaleCount" width="140" />
<el-table-column label="未留养母羔数量" align="center" prop="unretainedFemaleCount" width="140" />
<el-table-column label="产羔时怀孕天数" align="center" prop="pregnancyDays" width="140" />
<el-table-column label="当前羊舍" align="center" prop="currentShed" width="100" />
<el-table-column label="创建人" align="center" prop="createBy" width="100" />
<el-table-column label="创建日期" align="center" prop="createTime" width="110">
<template #default="scope">
<span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="所在牧场" align="center" prop="farm" width="100" />
<el-table-column label="备注" align="center" prop="comment" width="120" show-overflow-tooltip />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="200" fixed="right">
<template #default="scope">
<el-button link type="primary" icon="View" @click="handleLambDetail(scope.row)" size="small">产羔详情</el-button>
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['breed:lambing_records:edit']" size="small">修改</el-button>
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['breed:lambing_records:remove']" size="small">删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total>0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
:page-sizes="[20,50,100,200, 500, 1000, 2000]"
@pagination="getList"
/>
<el-dialog :title="title" v-model="open" width="900px" append-to-body>
<el-form ref="lambing_recordsRef" :model="form" :rules="rules" label-width="120px">
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="母羊耳号" prop="femaleEarNumber">
<el-input
v-model="form.femaleEarNumber"
placeholder="请输入母羊耳号"
@blur="handleEarNumberBlur"
@input="handleEarNumberInput"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="胎次" prop="parity">
<el-input v-model="form.parity" placeholder="请输入胎次" readonly />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="事件类型">
<el-input value="产羔" readonly />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="产羔日期" prop="createTime">
<el-date-picker
clearable
v-model="form.createTime"
type="date"
value-format="YYYY-MM-DD"
placeholder="请选择产羔日期"
style="width:100%">
</el-date-picker>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="配种类型">
<el-input :value="getBreedTypeLabel(form.breedType)" placeholder="配种类型" readonly />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="公羊耳号" prop="maleEarNumber">
<el-input v-model="form.maleEarNumber" placeholder="公羊耳号" readonly />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="配种日期" prop="breedingDate">
<el-input v-model="form.breedingDate" placeholder="配种日期" readonly />
</el-form-item>
</el-col>
</el-row>
<!-- 供体信息胚胎移植时显示 -->
<template v-if="isEmbryoTransfer">
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="供体母羊">
<el-input v-model="form.donorEwe" placeholder="供体母羊耳号" readonly />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="供体母羊品种">
<el-input v-model="form.donorEweBreed" placeholder="供体母羊品种" readonly />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="供体公羊">
<el-input v-model="form.donorRam" placeholder="供体公羊耳号" readonly />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="供体公羊品种">
<el-input v-model="form.donorRamBreed" placeholder="供体公羊品种" readonly />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="移胚数">
<el-input v-model="form.embryoCount" placeholder="移胚数" readonly />
</el-form-item>
</el-col>
</el-row>
</template>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="怀孕天数" prop="pregnancyDays">
<el-input v-model="form.pregnancyDays" placeholder="怀孕天数" readonly />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="技术员" prop="technician">
<el-select
v-model="form.technician"
placeholder="请选择技术员"
filterable
clearable
style="width: 100%"
>
<el-option
v-for="item in technicalOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="产羔数量" prop="lambsBorn">
<el-input
v-model.number="form.lambsBorn"
placeholder="请输入产羔数量"
type="number"
@input="handleLambsBornChange"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="活羔数量" prop="survival">
<el-input v-model.number="form.survival" placeholder="请输入活羔数量" type="number" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="产羔评分" prop="score">
<el-input v-model.number="form.score" placeholder="请输入产羔评分" type="number" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="24">
<el-form-item label="备注" prop="comment">
<el-input v-model="form.comment" type="textarea" placeholder="请输入备注" />
</el-form-item>
</el-col>
</el-row>
<div v-if="queryParams.femaleEarNumbers && queryParams.femaleEarNumbers.length > 0" class="selected-ear-numbers">
<span style="margin-right: 10px; color: #606266;">已选择耳号</span>
<el-tag
v-for="earNumber in queryParams.femaleEarNumbers"
:key="earNumber"
closable
@close="removeEarNumber(earNumber)"
style="margin-right: 8px;"
>
{{ earNumber }}
</el-tag>
</div>
<div v-if="form.lambsBorn > 0 && showLambForms">
<el-divider content-position="left">羔羊信息录入</el-divider>
<div v-for="(lamb, index) in lambForms" :key="index" class="lamb-form-item">
<div class="lamb-form-header">
<span class="lamb-title">{{ index + 1 }}只羔羊</span>
</div>
<el-row :gutter="20" class="lamb-form-content">
<el-col :span="8">
<el-form-item :label="`羔羊耳号`" :prop="`lambForms.${index}.lambEarNumber`">
<el-input v-model="lamb.lambEarNumber" placeholder="请输入羔羊耳号"
@input="handleLambEarNumberInput(index)"/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item :label="`性别`" :prop="`lambForms.${index}.gender`">
<el-select v-model="lamb.gender" placeholder="请选择性别">
<el-option label="公" value="male"></el-option>
<el-option label="母" value="female"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item :label="`是否留养`" :prop="`lambForms.${index}.isRetained`">
<el-switch
v-model="lamb.isRetained"
active-text=""
inactive-text="">
</el-switch>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20" class="lamb-form-content">
<el-col :span="8">
<el-form-item :label="`体重(kg)`" :prop="`lambForms.${index}.birthWeight`">
<el-input v-model.number="lamb.birthWeight" placeholder="请输入体重" type="number" step="0.1" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item :label="`品种`" :prop="`lambForms.${index}.lambBreed`">
<el-select
v-model="lamb.lambBreed"
placeholder="请选择品种"
filterable
clearable
style="width: 100%"
>
<el-option
v-for="variety in varietyList"
:key="variety.id"
:label="variety.variety"
:value="variety.id"
></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item :label="`家系`" :prop="`lambForms.${index}.lineage`">
<el-input v-model="lamb.lineage" placeholder="请输入家系" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20" class="lamb-form-content">
<el-col :span="8">
<el-form-item :label="`生日`" :prop="`lambForms.${index}.birthday`">
<el-date-picker
v-model="lamb.birthday"
type="date"
value-format="YYYY-MM-DD"
placeholder="请选择生日">
</el-date-picker>
</el-form-item>
</el-col>
</el-row>
</div>
</div>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
<el-dialog title="产羔详情" v-model="detailOpen" width="1000px" append-to-body>
<el-descriptions :column="3" border>
<el-descriptions-item label="母羊耳号">{{ detailData.femaleEarNumber }}</el-descriptions-item>
<el-descriptions-item label="母羊品种">{{ detailData.femaleBreed }}</el-descriptions-item>
<el-descriptions-item label="胎次">{{ detailData.parity }}</el-descriptions-item>
<el-descriptions-item label="公羊耳号">{{ detailData.maleEarNumber }}</el-descriptions-item>
<el-descriptions-item label="公羊品种">{{ detailData.maleBreed }}</el-descriptions-item>
<el-descriptions-item label="配种日期">{{ parseTime(detailData.breedingDate, '{y}-{m}-{d}') }}</el-descriptions-item>
<template v-if="detailData.donorEwe || detailData.donorRam">
<el-descriptions-item label="供体母羊">{{ detailData.donorEwe || '-' }}</el-descriptions-item>
<el-descriptions-item label="供体母羊品种">{{ detailData.donorEweBreed || '-' }}</el-descriptions-item>
<el-descriptions-item label="供体公羊">{{ detailData.donorRam || '-' }}</el-descriptions-item>
<el-descriptions-item label="供体公羊品种">{{ detailData.donorRamBreed || '-' }}</el-descriptions-item>
<el-descriptions-item label="移胚数">{{ detailData.embryoCount || '-' }}</el-descriptions-item>
</template>
<el-descriptions-item label="产羔数量">{{ detailData.lambsBorn }}</el-descriptions-item>
<el-descriptions-item label="活羔数量">{{ detailData.survival }}</el-descriptions-item>
<el-descriptions-item label="技术员">{{ detailData.technician }}</el-descriptions-item>
</el-descriptions>
<el-divider content-position="left">羔羊信息</el-divider>
<el-table :data="lambDetailList" border>
<el-table-column label="序号" type="index" width="60" align="center" />
<el-table-column label="羔羊耳号" prop="lambEarNumber" align="center" />
<el-table-column label="羔羊品种" prop="lambBreed" align="center">
<template #default="scope">
<span>{{ getVarietyName(scope.row.lambBreed) }}</span>
</template>
</el-table-column>
<el-table-column label="性别" prop="gender" align="center">
<template #default="scope">
<el-tag :type="getGenderDisplay(scope.row.gender).type">
{{ getGenderDisplay(scope.row.gender).label }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="出生重(kg)" prop="birthWeight" align="center" />
<el-table-column label="是否留养" prop="isRetained" align="center">
<template #default="scope">
<el-tag :type="scope.row.isRetained ? 'success' : 'danger'">
{{ scope.row.isRetained ? '是' : '否' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="家系" prop="lineage" align="center" />
<el-table-column label="生日" prop="birthday" align="center">
<template #default="scope">
<span>{{ parseTime(scope.row.birthday, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
</el-table>
</el-dialog>
</div>
</template>
<script setup name="Lambing_records">
import { listLambing_records, getLambing_records, delLambing_records, addLambing_records, updateLambing_records, getLambDetail, getVarietyList, getBreedingInfo,searchEarNumbers } from "@/api/breed/lambing_records"
import { getUserByPost } from '@/api/common/user' // 新增引入
import { ref, computed, nextTick } from 'vue'
import { ArrowUp, ArrowDown, Plus, Delete } from '@element-plus/icons-vue'
// 响应式数据
const pasteInput = ref('') // 批量粘贴输入框
const earNumberOptions = ref([]) // 耳号下拉选项
const earNumberLoading = ref(false) // 耳号加载状态
const isExpanded = ref(false) // 控制耳号展开/折叠状态
const defaultShowCount = 2 // 默认显示的耳号数量
// 新增:技术员选项
const technicalOptions = ref([])
// 计算属性:控制显示的耳号列表
const displayedEarNumbers = computed(() => {
if (!queryParams.value.allEarNumbers || queryParams.value.allEarNumbers.length === 0) {
return []
}
// 如果展开或总数<=2显示全部否则只显示前2个
if (isExpanded.value || queryParams.value.allEarNumbers.length <= defaultShowCount) {
return queryParams.value.allEarNumbers
} else {
return queryParams.value.allEarNumbers.slice(0, defaultShowCount)
}
})
const { proxy } = getCurrentInstance()
// 新增:耳号搜索相关状
const lambing_recordsList = ref([])
const open = ref(false)
const detailOpen = ref(false)
const loading = ref(true)
const showSearch = ref(true)
const ids = ref([])
const single = ref(true)
const multiple = ref(true)
const total = ref(0)
const title = ref("")
const showLambForms = ref(false)
const lambForms = ref([])
const detailData = ref({})
const lambDetailList = ref([])
const varietyList = ref([]) // 品种列表
// 是否胚胎移植有供体母羊或供体公羊信息时为true
const isEmbryoTransfer = computed(() => {
return !!(form.value.donorEwe || form.value.donorRam)
})
const data = reactive({
form: {},
queryParams: {
pageNum: 1,
pageSize: 10,
femaleEarNumber: [],
femaleBreed: null,
sheepId: null,
parity: null,
lambsBorn: null,
survival: null,
technician: null,
score: null,
comment: null,
createBy: null,
createTime: null,
farm: null,
breedingDate: []
},
rules: {
femaleEarNumber: [
{ required: true, message: "母羊耳号不能为空", trigger: "blur" }
],
lambsBorn: [
{ required: true, message: "产羔数量不能为空", trigger: "blur" }
]
}
})
// 品种 ID 常量定义 (对应 ScEmbryoFlushServiceImpl)
const VARIETY_IDS = {
HUYANG: 1, // 湖羊
DONGFULISHENG: 2, // 东佛里生
HUIJIAO: 3, // 回交
JIZA_1: 4, // 级杂一代
JIZA_2: 5, // 级杂二代
JIZA_3: 6, // 级杂三代
SHIDAI_1: 7, // 一世代
SHIDAI_2: 8, // 二世代
SHIDAI_3: 9, // 三世代
SHIDAI_4: 10 // 四世代
};
/** * 品种计算核心逻辑 (参考后端 calculateEmbryoVarietyById)
* @param {number} maleId 公羊品种ID
* @param {number} femaleId 母羊品种ID
* @returns {number|null} 羔羊品种ID
*/
function calculateLambBreedId(maleId, femaleId) {
if (!maleId || !femaleId) return null;
// 湖羊 x 湖羊 -> 湖羊
if (maleId === VARIETY_IDS.HUYANG && femaleId === VARIETY_IDS.HUYANG) return VARIETY_IDS.HUYANG;
// 东佛里生 x 东佛里生 -> 东佛里生
if (maleId === VARIETY_IDS.DONGFULISHENG && femaleId === VARIETY_IDS.DONGFULISHENG) return VARIETY_IDS.DONGFULISHENG;
// 东佛里生 x 湖羊 -> 级杂一代
if (maleId === VARIETY_IDS.DONGFULISHENG && femaleId === VARIETY_IDS.HUYANG) return VARIETY_IDS.JIZA_1;
// 东佛里生 x 级杂一代 -> 级杂二代
if (maleId === VARIETY_IDS.DONGFULISHENG && femaleId === VARIETY_IDS.JIZA_1) return VARIETY_IDS.JIZA_2;
// 东佛里生 x 级杂二代 -> 级杂三代
if (maleId === VARIETY_IDS.DONGFULISHENG && femaleId === VARIETY_IDS.JIZA_2) return VARIETY_IDS.JIZA_3;
// 东佛里生 x 级杂三代 -> 东佛里生
if (maleId === VARIETY_IDS.DONGFULISHENG && femaleId === VARIETY_IDS.JIZA_3) return VARIETY_IDS.DONGFULISHENG;
// 湖羊 x 级杂三代 -> 回交
if (maleId === VARIETY_IDS.HUYANG && femaleId === VARIETY_IDS.JIZA_3) return VARIETY_IDS.HUIJIAO;
// 湖羊 x 回交 -> 回交
if (maleId === VARIETY_IDS.HUYANG && femaleId === VARIETY_IDS.HUIJIAO) return VARIETY_IDS.HUIJIAO;
// 世代计算规则
const isMaleCapable = (maleId >= 3 && maleId <= 10);
if (isMaleCapable) {
if (femaleId === VARIETY_IDS.JIZA_2) return VARIETY_IDS.SHIDAI_1;
if (femaleId === VARIETY_IDS.SHIDAI_1) return VARIETY_IDS.SHIDAI_2;
if (femaleId === VARIETY_IDS.SHIDAI_2) return VARIETY_IDS.SHIDAI_3;
if (femaleId === VARIETY_IDS.SHIDAI_3) return VARIETY_IDS.SHIDAI_4;
}
return null;
}
const { queryParams, form, rules } = toRefs(data)
// 新增:获取技术员列表
const fetchTechnicalList = () => {
getUserByPost({ postCode: "techs" })
.then(res => {
if (res.code === 200 && Array.isArray(res.data)) {
technicalOptions.value = res.data.map(item => ({
value: item.nickName,
label: item.nickName
}))
} else {
technicalOptions.value = []
}
})
.catch(err => {
technicalOptions.value = []
})
}
/** 处理粘贴事件 */
function handlePaste(event) {
nextTick(() => {
handlePasteSubmit()
})
}
/** 处理粘贴内容提交 */
function handlePasteSubmit() {
if (!pasteInput.value || pasteInput.value.trim() === '') {
return
}
// 支持多种分隔符: 空格、换行、逗号、制表符
const separators = /[\s,\n\r\t]+/
const earNumbers = pasteInput.value
.trim()
.split(separators)
.filter(item => item.trim() !== '')
.map(item => item.trim())
if (earNumbers.length === 0) {
return
}
// 去重并添加到已选列表
const existingSet = new Set(queryParams.value.allEarNumbers || [])
const newEarNumbers = []
const duplicates = []
earNumbers.forEach(earNumber => {
if (!existingSet.has(earNumber)) {
newEarNumbers.push(earNumber)
existingSet.add(earNumber)
} else {
duplicates.push(earNumber)
}
})
// 添加新耳号
if (newEarNumbers.length > 0) {
queryParams.value.allEarNumbers = [
...(queryParams.value.allEarNumbers || []),
...newEarNumbers
]
const message = `成功添加 ${newEarNumbers.length} 个耳号,当前共 ${queryParams.value.allEarNumbers.length}` +
(duplicates.length > 0 ? `,已忽略 ${duplicates.length} 个重复耳号` : '')
proxy.$modal.msgSuccess(message)
} else if (duplicates.length > 0) {
proxy.$modal.msgWarning(`所有耳号均已存在,当前共 ${queryParams.value.allEarNumbers.length}`)
}
// 清空输入框
pasteInput.value = ''
}
/** 远程搜索耳号 */
function searchEarNumber(query) {
if (query !== '') {
earNumberLoading.value = true
const queries = query.trim().split(/[\s,]+/).filter(q => q)
if (queries.length === 1) {
// 单个耳号模糊搜索
searchEarNumbers(query).then(response => {
earNumberOptions.value = response.data || []
earNumberLoading.value = false
}).catch(() => {
earNumberOptions.value = []
earNumberLoading.value = false
})
} else {
// 多个耳号直接作为选项
earNumberOptions.value = queries
earNumberLoading.value = false
}
} else {
earNumberOptions.value = []
}
}
/** 耳号选择变化处理 */
function handleEarNumberChange(value) {
queryParams.value.allEarNumbers = [...new Set(value)]
console.log(`已选择 ${queryParams.value.allEarNumbers.length} 个耳号:`, queryParams.value.allEarNumbers)
}
/** 切换展开/收起状态 */
function toggleExpand() {
isExpanded.value = !isExpanded.value
}
/** 移除单个耳号 */
function handleRemoveEarNumber(tag) {
const index = queryParams.value.allEarNumbers.indexOf(tag)
if (index > -1) {
queryParams.value.allEarNumbers.splice(index, 1)
proxy.$modal.msgSuccess('已移除该耳号')
}
// 如果删除后剩余<=2个自动收起
if (queryParams.value.allEarNumbers.length <= defaultShowCount) {
isExpanded.value = false
}
}
/** 清空所有耳号 */
function clearAllEarNumbers() {
proxy.$modal.confirm('确定要清空所有已选择的耳号吗?').then(() => {
queryParams.value.allEarNumbers = []
pasteInput.value = ''
earNumberOptions.value = []
isExpanded.value = false // 重置展开状态
proxy.$modal.msgSuccess('已清空所有耳号')
}).catch(() => {})
}
/** 获取品种列表 */
function getVarietyData() {
return getVarietyList().then(response => {
console.log('品种列表数据:', response)
varietyList.value = response.rows || []
console.log('处理后的品种列表:', varietyList.value)
}).catch(error => {
console.error('获取品种列表失败:', error)
varietyList.value = []
})
}
/** 新增:清空所有耳号 */
function clearEarNumbers() {
queryParams.value.femaleEarNumbers = []
}
/** 新增:移除单个耳号 */
function removeEarNumber(earNumber) {
const index = queryParams.value.femaleEarNumbers.indexOf(earNumber)
if (index > -1) {
queryParams.value.femaleEarNumbers.splice(index, 1)
}
}
/** 根据品种ID获取品种名称 */
function getVarietyName(varietyId) {
if (!varietyId) return '-'
const id = typeof varietyId === 'string' ? parseInt(varietyId) : varietyId
const variety = varietyList.value.find(item => item.id === id)
return variety ? variety.variety : `未知品种(${varietyId})`
}
/** 性别转换函数 - 前端显示转后端数值 */
function genderToNumber(gender) {
if (gender === 'male') return 2
if (gender === 'female') return 1
return gender
}
/** 性别显示函数 - 后端数值转前端显示 */
function getGenderDisplay(gender) {
if (gender === 2 || gender === 'male') {
return { label: '公', type: 'primary' }
} else if (gender === 1 || gender === 'female') {
return { label: '母', type: 'success' }
}
return { label: '未知', type: 'info' }
}
/** 配种类型标签映射 */
function getBreedTypeLabel(breedType) {
const map = {
'1': '供体母羊配种',
'2': '同期发情人工授精',
'3': '本交',
'4': '自然发情人工授精',
'5': '胚胎移植'
}
if (breedType == null || breedType === '') return '-'
return map[String(breedType)] || String(breedType)
}
/** 母羊耳号输入处理 */
function handleEarNumberInput() {
// 清空相关联动字段
form.value.sheepId = null
form.value.parity = null
form.value.maleEarNumber = null
form.value.breedingDate = null
form.value.pregnancyDays = null
form.value.technician = null
form.value.donorEwe = null
form.value.donorEweBreed = null
form.value.donorRam = null
form.value.donorRamBreed = null
form.value.embryoCount = null
form.value.breedType = null
}
/** 母羊耳号失焦处理 - 自动查询配种信息 */
function handleEarNumberBlur() {
const earNumber = form.value.femaleEarNumber;
if (!earNumber || earNumber.trim() === '') return;
// 调用API查询配种信息
getBreedingInfo(earNumber.trim()).then(response => {
if (response.code === 200 && response.data) {
const breedingData = response.data
// 填充表单数据
form.value.sheepId = breedingData.sheep_id
form.value.parity = breedingData.parity
form.value.maleEarNumber = breedingData.male_ear_number || '未找到公羊'
form.value.breedingDate = breedingData.breeding_date
form.value.pregnancyDays = breedingData.pregnancy_days
form.value.technician = breedingData.technician || ''
// 供体信息(胚胎移植时有值)
form.value.donorEwe = breedingData.donor_ewe || null
form.value.donorEweBreed = breedingData.donor_ewe_breed || null
form.value.donorRam = breedingData.donor_ram || null
form.value.donorRamBreed = breedingData.donor_ram_breed || null
form.value.embryoCount = breedingData.embryo_count || null
form.value.breedType = breedingData.breed_type || null
const mVariety = varietyList.value.find(v => v.variety === breedingData.male_breed);
const fVariety = varietyList.value.find(v => v.variety === breedingData.female_breed);
// 临时存储这些信息,用于初始化羔羊列表
form.value._calculatedLambBreedId = calculateLambBreedId(mVariety?.id, fVariety?.id);
form.value._fatherLineage = breedingData.male_lineage || ''; // 确保后端返回了家系字段
if (lambForms.value && lambForms.value.length > 0) {
lambForms.value.forEach(lamb => {
lamb.lineage = form.value._fatherLineage;
lamb.lambBreed = form.value._calculatedLambBreedId;
});
}
proxy.$modal.msgSuccess("已自动匹配父母品种及家系信息");
proxy.$modal.msgSuccess("已自动填充配种信息")
} else {
proxy.$modal.msgWarning(response.msg || "未找到该母羊的配种记录")
// 清空相关字段
form.value.sheepId = null
form.value.parity = null
form.value.maleEarNumber = null
form.value.breedingDate = null
form.value.pregnancyDays = null
}
}).catch(error => {
console.error('查询配种信息失败:', error)
proxy.$modal.msgError("查询配种信息失败")
})
}
/** 查询产羔记录列表 */
function getList() {
loading.value = true
listLambing_records(queryParams.value).then(response => {
const rows = response.rows || []
total.value = response.total
// 批量加载每行的羔羊详情
const promises = rows.map(row =>
getLambDetail(row.id).then(res => {
row.lambDetails = res.data || []
}).catch(() => { row.lambDetails = [] })
)
Promise.all(promises).then(() => {
lambing_recordsList.value = rows
loading.value = false
})
}).catch(() => { loading.value = false })
}
// 取消按钮
function cancel() {
open.value = false
reset()
}
// 表单重置
function reset() {
form.value = {
id: null,
femaleEarNumber: null,
sheepId: null,
parity: null,
maleEarNumber: null,
breedingDate: null,
allEarNumbers: [], // ✅ 添加这一行!
pregnancyDays: null,
lambsBorn: null,
survival: null,
technician: null,
score: null,
comment: null,
createBy: null,
createTime: null,
donorEwe: null,
donorEweBreed: null,
donorRam: null,
donorRamBreed: null,
embryoCount: null,
breedType: null
}
showLambForms.value = false
lambForms.value = []
proxy.resetForm("lambing_recordsRef")
}
/** 搜索按钮操作 */
/** 搜索按钮操作 - 修改 */
function handleQuery() {
queryParams.value.pageNum = 1
getList()
}
/** 重置按钮操作 - 修改 */
function resetQuery() {
queryParams.value.allEarNumbers = [] // ✅ 添加这一行
earNumberOptions.value = [] // ✅ 添加这一行
isExpanded.value = false
proxy.resetForm("queryRef")
handleQuery()
}
// 多选框选中数据
function handleSelectionChange(selection) {
ids.value = selection.map(item => item.id)
single.value = selection.length != 1
multiple.value = !selection.length
}
/** 新增按钮操作 */
function handleAdd() {
reset()
// 默认产羔日期为今天
form.value.createTime = new Date().toISOString().split('T')[0]
open.value = true
title.value = "添加产羔记录"
}
/** 修改按钮操作 */
function handleUpdate(row) {
reset()
const _id = row.id || ids.value
getLambing_records(_id).then(response => {
form.value = response.data
open.value = true
title.value = "修改产羔记录"
// 如果是修改,不显示羔羊录入表单
showLambForms.value = false
})
}
/** 产羔数量变化处理 */
function handleLambsBornChange() {
const count = parseInt(form.value.lambsBorn) || 0;
if (count > 0 && count <= 10) {
showLambForms.value = true;
lambForms.value = Array.from({ length: count }, () => ({
lambEarNumber: '',
gender: '',
isRetained: true, // 默认留养
birthWeight: null,
lambBreed: form.value._calculatedLambBreedId, // 自动填充计算出的品种
lineage: form.value._fatherLineage, // 随父亲家系
birthday: form.value.createTime || new Date().toISOString().split('T')[0] // 随产羔日期
}));
} else {
showLambForms.value = false;
lambForms.value = [];
}
}
/** 查看产羔详情 */
function handleLambDetail(row) {
detailData.value = row
// 调用API获取羔羊详情列表
getLambDetail(row.id).then(response => {
lambDetailList.value = response.data || []
detailOpen.value = true
})
}
/** 提交按钮 */
function submitForm() {
proxy.$refs["lambing_recordsRef"].validate(valid => {
if (valid) {
const submitData = { ...form.value }
// 处理日期格式
if (submitData.createTime && typeof submitData.createTime === 'string') {
if (submitData.createTime.length === 10) {
submitData.createTime = submitData.createTime + ' 00:00:00'
}
}
// 处理羔羊详情
if (showLambForms.value && lambForms.value.length > 0) {
// 过滤掉空的羔羊信息
const validLambDetails = lambForms.value.filter(lamb =>
lamb.lambEarNumber && lamb.lambEarNumber.trim() !== ''
)
// 处理羔羊详情的日期格式和数据类型
validLambDetails.forEach(lamb => {
if (lamb.birthday && typeof lamb.birthday === 'string' && lamb.birthday.length === 10) {
// 保持日期格式为 YYYY-MM-DD后端会自动处理
}
// 确保体重为数字类型
if (lamb.birthWeight && typeof lamb.birthWeight === 'string') {
lamb.birthWeight = parseFloat(lamb.birthWeight)
}
// 性别转换:'male' -> 1, 'female' -> 0
lamb.gender = genderToNumber(lamb.gender)
// 品种ID已经是数字无需转换
})
submitData.lambDetails = validLambDetails
}
if (form.value.id != null) {
updateLambing_records(submitData).then(response => {
proxy.$modal.msgSuccess("修改成功")
open.value = false
getList()
})
} else {
addLambing_records(submitData).then(response => {
proxy.$modal.msgSuccess("新增成功")
open.value = false
getList()
})
}
}
})
}
/** 监听羔羊耳号输入,自动识别性别 */
function handleLambEarNumberInput(index) {
const lamb = lambForms.value[index]
const earNumber = lamb.lambEarNumber
// 确保耳号长度至少有2位
if (earNumber && earNumber.length >= 2) {
// 获取第二个字符并转大写
const secondChar = earNumber.charAt(1).toUpperCase()
if (secondChar === 'F') {
lamb.gender = 'female' // 对应 <el-option label="母" value="female">
} else if (secondChar === 'M') {
lamb.gender = 'male' // 对应 <el-option label="公" value="male">
}
}
}
/** 删除按钮操作 */
function handleDelete(row) {
const _ids = row.id || ids.value
proxy.$modal.confirm('是否确认删除产羔记录编号为"' + _ids + '"的数据项?').then(function() {
return delLambing_records(_ids)
}).then(() => {
getList()
proxy.$modal.msgSuccess("删除成功")
}).catch(() => {})
}
/** 导出按钮操作 */
function handleExport() {
proxy.download('breed/lambing_records/export', {
...queryParams.value
}, `lambing_records_${new Date().getTime()}.xlsx`)
}
// 页面初始化
onMounted(() => {
fetchTechnicalList() // 初始化加载技术员列表
console.log('页面初始化开始')
getVarietyData() // 先获取品种列表
.then(() => {
console.log('品种列表加载完成,开始获取产羔记录')
getList() // 然后获取产羔记录列表
})
})
</script>
<style scoped>
/* 已选耳号展示区样式 */
.selected-ear-numbers-display {
max-height: 150px;
overflow-y: auto;
padding: 8px;
background-color: #f5f7fa;
border-radius: 4px;
border: 1px dashed #dcdfe6;
display: flex;
flex-wrap: wrap;
align-items: center;
}
.selected-ear-numbers-display::-webkit-scrollbar {
width: 6px;
height: 6px;
}
.selected-ear-numbers-display::-webkit-scrollbar-thumb {
background-color: #dcdfe6;
border-radius: 3px;
}
.selected-ear-numbers-display::-webkit-scrollbar-track {
background-color: #f5f7fa;
}
.selected-ear-numbers-display .el-tag {
margin: 4px;
cursor: pointer;
}
.selected-ear-numbers-display .el-tag:hover {
opacity: 0.8;
}
/* 隐藏 el-select 的下拉箭头(可选) */
:deep(.el-select__caret) {
display: none;
}
</style>