This commit is contained in:
ll
2026-03-04 20:48:44 +08:00
6 changed files with 900 additions and 1031 deletions

View File

@@ -58,4 +58,30 @@ export function getDonorFemaleList() {
url: '/embryo/flush/donorFemaleList',
method: 'get'
})
}
// 获取供体公羊下拉列表
export function getDonorMaleList() {
return request({
url: '/embryo/flush/donorMaleList',
method: 'get'
})
}
// 根据耳号获取基础信息
export function getSheepInfo(manageTag) {
return request({
url: '/embryo/flush/getSheepInfo',
method: 'get',
params: { manageTag }
})
}
// 计算胚胎品种
export function calculateEmbryoVariety(maleVariety, femaleVariety) {
return request({
url: '/embryo/flush/calculateVariety',
method: 'get',
params: { maleVariety, femaleVariety }
})
}

View File

@@ -18,22 +18,63 @@ export function getBreedPlanGenerate(id) {
}
// 筛选符合条件的母羊
export function selectEligibleEwe() {
export function selectEligibleEwe(params) {
return request({
url: '/mating_plan/generate/selectEwe',
method: 'get'
method: 'get',
params
})
}
// 筛选符合条件的公羊
export function selectEligibleRam() {
export function selectEligibleRam(params) {
return request({
url: '/mating_plan/generate/selectRam',
method: 'get'
method: 'get',
params
})
}
// 自动生成配种计划
/**
* 导出已选母羊/公羊配对表按轮询自动配对用户可在Excel中调整后再导入
* @param {Object} data - { eweIds: [], ramIds: [] }
*/
export function exportSelectedPairs(data) {
return request({
url: '/mating_plan/generate/exportPairs',
method: 'post',
data,
responseType: 'blob'
})
}
/**
* 解析上传的配对Excel返回预览数据不生成计划
* 使用 FormData 上传文件
* @param {FormData} formData - 包含 file 字段的表单数据
*/
export function parsePairsFromExcel(formData) {
return request({
url: '/mating_plan/generate/parsePairs',
method: 'post',
data: formData,
headers: { 'Content-Type': 'multipart/form-data' }
})
}
/**
* 根据导入的配对数据生成配种计划
* @param {Object} data - { planType: 1, pairs: [{eweEarNo, ramEarNo, eweId, ramId}] }
*/
export function generateBreedPlanFromPairs(data) {
return request({
url: '/mating_plan/generate/generateFromPairs',
method: 'post',
data
})
}
// 自动生成配种计划(按比例分配,原有逻辑)
export function autoGenerateBreedPlan(data) {
return request({
url: '/mating_plan/generate/auto',
@@ -85,24 +126,15 @@ export function viewBreedPlan(id) {
})
}
// 导出配种计划详情
// 导出配种计划详情已审批计划的详细Excel
export function exportBreedPlanDetails(id) {
return request({
url: '/mating_plan/generate/export/' + id,
method: 'get',
method: 'post',
responseType: 'blob'
})
}
// 修改配种计划详情
export function updateBreedPlan(data) {
return request({
url: '/mating_plan/generate/update',
method: 'put',
data: data
})
}
// 删除配种计划生成
export function delBreedPlanGenerate(id) {
return request({
@@ -114,9 +146,18 @@ export function delBreedPlanGenerate(id) {
// 模糊查询母羊耳号列表
export function searchEarNumbers(query) {
return request({
url: '/mating_plan/generate/search_ear_numbers', // 根据实际路径修改
url: '/mating_plan/generate/search_ear_numbers',
method: 'get',
params: { query }
})
}
// 下载配对模板(空白模板,只有表头)
export function downloadPairTemplate() {
return request({
url: '/mating_plan/generate/exportPairs',
method: 'post',
data: { eweIds: [], ramIds: [] },
responseType: 'blob'
})
}

View File

@@ -1,8 +1,9 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="80px">
<el-form class="sticky-search-form" model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="80px">
<el-form-item label="耳号" prop="allEarNumbers">
<!-- 给每个 el-form-item 添加 sticky-item -->
<el-form-item label="耳号" prop="allEarNumbers" class="sticky-item">
<div style="display: flex; align-items: center; gap: 10px; flex-wrap: wrap;">
<!-- 主选择器不显示已选标签 -->
<el-select
@@ -99,14 +100,15 @@
</div>
</el-form-item>
<el-form-item label="是否在群" prop="isInHerd">
<!-- 其他表单项也添加 sticky-item -->
<el-form-item label="是否在群" prop="isInHerd" class="sticky-item">
<el-select v-model="queryParams.isInHerd" placeholder="请选择" clearable style="width: 240px">
<el-option label="是" value="1" />
<el-option label="否" value="0" />
</el-select>
</el-form-item>
<el-form-item label="断奶日期" style="width: 340px">
<el-form-item label="断奶日期" style="width: 340px" class="sticky-item">
<el-date-picker
v-model="daterangeTime"
value-format="YYYY-MM-DD"
@@ -118,7 +120,7 @@
></el-date-picker>
</el-form-item>
<el-form-item label="羊只类别" prop="sheepCategory">
<el-form-item label="羊只类别" prop="sheepCategory" class="sticky-item">
<el-select v-model="queryParams.sheepCategory" placeholder="请选择羊只类别" clearable style="width: 240px">
<el-option label="种公羊" value="种公羊"></el-option>
<el-option label="基础母羊" value="基础母羊"></el-option>
@@ -127,21 +129,22 @@
</el-select>
</el-form-item>
<el-form-item label="性别" prop="gender">
<el-form-item label="性别" prop="gender" class="sticky-item">
<el-select v-model="queryParams.gender" placeholder="请选择性别" clearable style="width: 240px">
<el-option label="公" value="公"></el-option>
<el-option label="母" value="母"></el-option>
</el-select>
</el-form-item>
<el-form-item label="是否留养" prop="status">
<el-form-item label="是否留养" prop="status" class="sticky-item">
<el-select v-model="queryParams.status" placeholder="请选择是否留养" clearable style="width: 240px">
<el-option label="留养" value="1"></el-option>
<el-option label="不留养" value="0"></el-option>
</el-select>
</el-form-item>
<el-form-item>
<!-- 搜索按钮不放 sticky或者也可以放 -->
<el-form-item class="sticky-item">
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
@@ -633,19 +636,37 @@ 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;
}
/* 核心样式:让每个表单项粘性定位 */
.sticky-search-form {
position: relative;
}
.sticky-item {
position: sticky;
top: 0; /* 粘在视口顶部 */
background: #fff; /* 白色背景,避免透明 */
z-index: 100;
padding: 10px;
margin-bottom: 10px;
border-radius: 4px;
box-shadow: 0 1px 3px rgba(0,0,0,0.1); /* 轻微阴影区分 */
align-self: flex-start; /* 重要:在 flex 布局中保持粘性 */
}
/* 保持原有样式 */
.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;
@@ -660,15 +681,6 @@ getList()
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;

View File

@@ -96,10 +96,10 @@
<el-table-column label="A" align="center" prop="gradeA" width="60" />
<el-table-column label="B" align="center" prop="gradeB" width="60" />
<el-table-column label="C" align="center" prop="gradeC" width="60" />
<el-table-column label="D" align="center" prop="gradeD" width="60" />
<el-table-column label="16细胞(D级)" align="center" prop="gradeD" width="90" />
<el-table-column label="2/4细胞" align="center" prop="cell24" width="70" />
<el-table-column label="8细胞" align="center" prop="cell8" width="60" />
<el-table-column label="16细胞" align="center" prop="cell16" width="70" />
<el-table-column label="16细胞" align="center" prop="cell16" width="80" />
<el-table-column label="未受精" align="center" prop="unfertilized" width="70" />
<el-table-column label="退化" align="center" prop="degenerated" width="60" />
<el-table-column label="冲胚数" align="center" prop="totalEmbryo" width="70" />
@@ -178,7 +178,22 @@
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="供体父号" prop="donorMaleNo">
<el-input v-model="form.donorMaleNo" placeholder="自动填充/可修改" />
<el-select
v-model="form.donorMaleNo"
filterable
clearable
placeholder="请选择供体公羊"
@change="handleDonorMaleChange"
style="width: 100%">
<el-option
v-for="item in donorMaleOptions"
:key="item.manageTag"
:label="item.manageTag"
:value="item.manageTag">
<span>{{ item.manageTag }}</span>
<span style="float: right; color: #8492a6; font-size: 12px">{{ item.variety }}</span>
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
@@ -229,9 +244,10 @@
</el-form-item>
</el-col>
</el-row>
<!-- 新增行放置16细胞(D级) -->
<el-row :gutter="20">
<el-col :span="6">
<el-form-item label="D级" prop="gradeD" label-width="60px">
<el-form-item label="16细胞(D级)" prop="gradeD" label-width="90px">
<el-input-number v-model="form.gradeD" :min="0" @change="calculateTotal" style="width: 100%" />
</el-form-item>
</el-col>
@@ -251,17 +267,17 @@
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="16细胞" prop="cell16" label-width="60px">
<el-form-item label="16细胞" prop="cell16" label-width="65px">
<el-input-number v-model="form.cell16" :min="0" @change="calculateTotal" style="width: 100%" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="6">
<el-form-item label="未受精" prop="unfertilized" label-width="60px">
<el-input-number v-model="form.unfertilized" :min="0" @change="calculateTotal" style="width: 100%" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="6">
<el-form-item label="退化" prop="degenerated" label-width="60px">
<el-input-number v-model="form.degenerated" :min="0" @change="calculateTotal" style="width: 100%" />
@@ -300,8 +316,10 @@
<el-col :span="6">
<el-form-item label="胚胎类型" prop="embryoType">
<el-select v-model="form.embryoType" placeholder="请选择" style="width: 100%">
<el-option label="体内供体" value="体内供体" />
<el-option label="体外供体" value="体外供体" />
<el-option label="体内胚胎冻胚" value="体内胚胎冻胚" />
<el-option label="体内胚胎鲜胚" value="体内胚胎鲜胚" />
<el-option label="体外胚胎冻胚" value="体外胚胎冻胚" />
<el-option label="体外胚胎鲜胚" value="体外胚胎鲜胚" />
</el-select>
</el-form-item>
</el-col>
@@ -357,7 +375,8 @@
</template>
<script setup name="Flush">
import { listFlush, getFlush, delFlush, addFlush, updateFlush, getDonorInfo, getDonorFemaleList } from "@/api/embryo/flush"
import { listFlush, getFlush, delFlush, addFlush, updateFlush, getDonorInfo, getDonorFemaleList, getDonorMaleList, getSheepInfo,
calculateEmbryoVariety} from "@/api/embryo/flush"
const { proxy } = getCurrentInstance()
@@ -372,6 +391,7 @@ const total = ref(0)
const title = ref("")
const dateRange = ref([])
const donorFemaleOptions = ref([])
const donorMaleOptions = ref([])
// 保存配种日期用于计算胎龄
const matingDateCache = ref(null)
@@ -427,6 +447,16 @@ function loadDonorFemaleList() {
})
}
/** 加载供体公羊下拉列表 */
function loadDonorMaleList() {
getDonorMaleList().then(response => {
donorMaleOptions.value = response.data || []
}).catch(error => {
console.error('加载供体公羊列表失败:', error)
donorMaleOptions.value = []
})
}
// 取消按钮
function cancel() {
open.value = false
@@ -460,7 +490,7 @@ function reset() {
recipientCnt: 0,
embryoType: null,
embryoSource: '自繁',
destination: '遗弃',
destination: '移植',
storageMethod: '胚胎保存液',
flushOperator: null,
collectOperator: null,
@@ -496,6 +526,7 @@ function handleSelectionChange(selection) {
function handleAdd() {
reset()
loadDonorFemaleList()
loadDonorMaleList()
open.value = true
title.value = "添加冲胚记录"
}
@@ -504,6 +535,7 @@ function handleAdd() {
function handleUpdate(row) {
reset()
loadDonorFemaleList()
loadDonorMaleList()
const _id = row.id || ids.value
getFlush(_id).then(response => {
form.value = response.data
@@ -520,22 +552,17 @@ function handleFlushTimeChange(val) {
/** 供体母羊选择变化 */
function handleDonorFemaleChange(val) {
if (!val) {
if (!val) { /* 清空逻辑... */ return; }
getDonorInfo(val).then(response => {
console.log("后端返回的数据:", response.data); // 检查这里是否有 embryoVariety 字段
const info = response.data || {};
// 确保这些字段名与后端 result.put(...) 的 Key 一致
form.value.donorFemaleVariety = info.donorFemaleVariety || null;
form.value.donorMaleNo = info.donorMaleNo || null; // 匹配成功后会自动填入
form.value.donorMaleVariety = info.donorMaleVariety || null;
form.value.embryoVariety = info.embryoVariety || null; // 自动计算后的品种
form.value.ranchId = info.ranchId || null;
form.value.ranchName = info.ranchName || null;
matingDateCache.value = info.matingDate || null;
calculateEmbryoAge(); // 计算胎龄
});
// 清空相关字段
form.value.donorFemaleVariety = null
form.value.donorMaleNo = null
form.value.donorMaleVariety = null
form.value.embryoVariety = null
form.value.ranchId = null
form.value.ranchName = null
matingDateCache.value = null
calculateEmbryoAge();
updateEmbryoVariety();
return
}
// 调用接口获取关联信息
@@ -552,11 +579,13 @@ function handleDonorFemaleChange(val) {
matingDateCache.value = info.matingDate || null
// 计算胎龄
calculateEmbryoAge()
calculateEmbryoAge();
// 重点:拿到母羊信息后,如果公羊品种也有了,直接更新胚胎品种
updateEmbryoVariety();
}).catch(error => {
console.error('获取供体母羊关联信息失败:', error)
proxy.$modal.msgError('获取供体母羊信息失败')
})
});
}
/** 计算胎龄 */
@@ -567,6 +596,8 @@ function calculateEmbryoAge() {
const diffTime = flushDate.getTime() - matingDate.getTime()
const diffDays = Math.floor(diffTime / (1000 * 60 * 60 * 24))
form.value.embryoAge = diffDays > 0 ? diffDays : 0
} else {
form.value.embryoAge = null
}
}
@@ -583,7 +614,7 @@ function calculateTotal() {
const unfertilized = form.value.unfertilized || 0
const degenerated = form.value.degenerated || 0
// 有效胚 = A+ + A + B + C + D
// 有效胚 = A+ + A + B + C + D(16细胞)
form.value.validEmbryo = gradeAPlus + gradeA + gradeB + gradeC + gradeD
// 冲胚数 = 所有数量总和
@@ -631,5 +662,42 @@ function handleExport() {
}, `冲胚记录_${new Date().getTime()}.xlsx`)
}
/** 供体父号下拉选择变化处理 */
function handleDonorMaleChange(val) {
if (!val) {
form.value.donorMaleVariety = null;
updateEmbryoVariety();
return;
}
// 直接从已加载的下拉列表中查找品种,无需再次请求接口
const found = donorMaleOptions.value.find(item => item.manageTag === val);
if (found) {
form.value.donorMaleVariety = found.variety;
} else {
// 兜底:下拉列表中未找到时仍走接口
getSheepInfo(val).then(response => {
if (response.data) {
form.value.donorMaleVariety = response.data.variety;
}
});
}
updateEmbryoVariety();
}
/** 统一的胚胎品种计算调用 */
function updateEmbryoVariety() {
const maleVar = form.value.donorMaleVariety;
const femaleVar = form.value.donorFemaleVariety;
if (maleVar && femaleVar) {
calculateEmbryoVariety(maleVar, femaleVar).then(response => {
form.value.embryoVariety = response.data;
});
} else {
form.value.embryoVariety = null;
}
}
getList()
</script>

View File

@@ -99,7 +99,11 @@
<el-col :span="12">
<el-form-item label="客户名称" prop="custName">
<el-input v-model="form.custName" placeholder="请输入客户名称" />
<!-- <el-input v-model="form.custName" placeholder="请输入客户名称" /> -->
<el-select v-model="form.custName" placeholder="请选择客户" filterable clearable style="width: 100%"
@change="handleCustomerChange">
<el-option v-for="item in userDict" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
</el-col>
@@ -239,14 +243,14 @@
<script setup name="Sale">
import { listSale, getSale, delSale, addSale, updateSale } from "@/api/frozen/sale"
import { reactive } from "vue"
import { onMounted, reactive } from "vue"
import { ref } from "vue"
import { getSaleCodeDict } from "../../../api/frozen/sale"
import { computed } from "vue"
import { listCustomer } from "../../../api/sale/customer/customer"
import { computed } from 'vue'
const { proxy } = getCurrentInstance()
const { frozen_sale_item_type } = proxy.useDict('frozen_sale_item_type')
const saleList = ref([])
const ddSaleItemList = ref([])
const open = ref(false)
@@ -316,6 +320,26 @@
})
}
// =============== 用户字典数据 =================
const userDict = ref([])
const userMap = computed(() => {
return new Map(userDict.value.map(u => [u.id, u]))
})
const handleCustomerChange = (val) => {
const user = userMap.value.get(val)
if (user) {
form.value.custPhone = user.phone || ''
form.value.custAddr = (user.province + user.city + user.district + user.address) || ''
} else {
form.value.custPhone = ''
form.value.custAddr = ''
}
}
// =============== End =================
// 取消按钮
function cancel() {
open.value = false
@@ -465,4 +489,10 @@
}, `sale_${new Date().getTime()}.xlsx`)
}
getList()
onMounted(() => {
// 加载客户列表
listCustomer({ pageNum: 1, pageSize: 1000 }).then(r => {
userDict.value = r.rows
})
})
</script>

File diff suppressed because it is too large Load Diff