Files
zhyc-sheep-ui/src/views/produce/manage_sheep/changeEar/index.vue
2026-03-05 21:39:44 +08:00

587 lines
21 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"
style="height: calc(100vh - 84px); display: flex; flex-direction: column; overflow: hidden;">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="事件日期" style="width: 300px">
<el-date-picker v-model="daterangeEventDate" type="daterange" range-separator="-" start-placeholder="开始日期"
end-placeholder="结束日期" value-format="YYYY-MM-DD" />
</el-form-item>
<el-form-item label="耳号" prop="manageTagsList">
<div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap;">
<!-- 主选择器不展示已选标签 -->
<el-select v-model="queryParams.manageTagsList" multiple filterable remote reserve-keyword
placeholder="输入耳号搜索" :remote-method="searchEarNumber" :loading="earLoading" allow-create
default-first-option collapse-tags :max-collapse-tags="0" style="width:300px" @change="handleEarChange">
<el-option v-for="item in earOptions" :key="item" :label="item" :value="item" />
</el-select>
<!-- 批量粘贴框 -->
<el-input v-model="pasteText" 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.manageTagsList && queryParams.manageTagsList.length" type="info" effect="plain"
size="large">
已选: {{ queryParams.manageTagsList.length }}
</el-tag>
<!-- 一键清空 -->
<el-button type="danger" plain :icon="Delete" @click="clearEarNumbers"
v-if="queryParams.manageTagsList && queryParams.manageTagsList.length">
清空全部
</el-button>
</div>
<!-- 已选耳号展示区可折叠 -->
<div v-if="queryParams.manageTagsList && queryParams.manageTagsList.length" class="selected-ear-numbers">
<el-tag v-for="tag in displayedEarTags" :key="tag" closable @close="removeEarNumber(tag)" style="margin:4px"
type="success">
{{ tag }}
</el-tag>
<el-button v-if="queryParams.manageTagsList.length > defaultShowCount" type="primary" link
@click="toggleExpand">
{{ isExpanded ? '收起' : `展开剩余 ${queryParams.manageTagsList.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="newTag">
<el-input v-model="queryParams.newTag" placeholder="请输入新耳号" clearable @keyup.enter="handleQuery"
style="max-width: 160px;" />
</el-form-item>
<el-form-item label="旧耳号" prop="oldTag">
<el-input v-model="queryParams.oldTag" placeholder="请输入旧耳号" clearable @keyup.enter="handleQuery"
style="max-width: 160px;" />
</el-form-item>
<el-form-item label="技术员" prop="technician">
<el-select v-model="queryParams.technician" placeholder="请选择技术员" clearable filterable style="max-width: 160px">
<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="inGroup">
<el-select v-model="queryParams.inGroup" placeholder="全部" clearable style="width:120px">
<el-option label="全部" :value="0" />
<el-option label="在群" :value="1" />
<el-option label="离群" :value="2" />
</el-select>
</el-form-item>
<el-form-item label="耳号类型" prop="earType">
<el-select v-model="queryParams.earType" placeholder="请选择耳号类型" style="min-width:150px" clearable>
<el-option label="电子耳号" :value="0"></el-option>
<el-option label="管理耳号" :value="1"></el-option>
</el-select>
</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="['changeEar:changeEar:add']">新增</el-button>
</el-col>
<!-- <el-col :span="1.5">
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate"
v-hasPermi="['changeEar:changeEar:edit']">修改</el-button>
</el-col> -->
<el-col :span="1.5">
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete"
v-hasPermi="['changeEar:changeEar:remove']">删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="handleExport"
v-hasPermi="['changeEar:changeEar:export']">导出</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<div style="flex: 1; overflow: hidden;">
<el-table v-loading="loading" :data="changeEarList" @selection-change="handleSelectionChange" height="100%"
style="width: 100%">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="耳号" align="center" prop="manageTags" />
<el-table-column label="品种" align="center" prop="varietyName" />
<el-table-column label="事件类型" align="center" prop="eventType" />
<el-table-column label="事件日期" align="center" prop="eventDate">
<template #default="scope">
<span>{{ parseTime(scope.row.eventDate, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="耳号类型" align="center" prop="earType">
<template #default="scope">
{{ scope.row.earType === 0 ? '电子耳号' : '管理耳号' }}
</template>
</el-table-column>
<el-table-column label="新耳号" align="center" prop="newTag" />
<el-table-column label="旧耳号" align="center" prop="oldTag" />
<el-table-column label="羊舍" align="center" prop="sheepfoldName" />
<el-table-column label="技术员" align="center" prop="technician" />
<el-table-column label="创建人" align="center" prop="createBy" />
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d} {h}:{i}') }}</span>
</template>
</el-table-column>
<el-table-column label="备注" align="center" prop="comment" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<!-- <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)"
v-hasPermi="['changeEar:changeEar:edit']">修改</el-button> -->
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)"
v-hasPermi="['changeEar:changeEar:remove']">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
<div style="flex-shrink: 0; padding: 10px 0;">
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize" @pagination="getList" :page-sizes="[20, 50, 100, 200, 500, 1000, 2000]" />
</div>
<!-- 添加或修改修改电子耳号记录对话框 -->
<el-dialog :title="title" v-model="open" width="500px" append-to-body>
<el-form ref="changeEarRef" :model="form" :rules="rules" label-width="80px">
<el-form-item label="耳号" prop="earNumber">
<el-input v-model="form.earNumber" placeholder="请输入管理耳号或电子耳号" @change="fetchOldTag" :disabled="!isAddMode" />
</el-form-item>
<el-form-item label="耳号类型" prop="earType">
<el-select v-model="form.earType" placeholder="请选择耳号类型" @change="fetchOldTag" :disabled="!isAddMode">
<el-option label="电子耳号" :value="0"></el-option>
<el-option label="管理耳号" :value="1"></el-option>
</el-select>
</el-form-item>
<el-form-item label="新耳号" prop="newTag" @blur="checkNewTagExists">
<el-input v-model="form.newTag" placeholder="请输入新耳号/电子耳号" @blur="checkNewTagExists" :disabled="!isAddMode" />
</el-form-item>
<el-form-item label="旧耳号" prop="oldTag">
<el-input v-model="form.oldTag" placeholder="自动获取" disabled />
</el-form-item>
<el-form-item label="技术员" prop="technician">
<el-select v-model="form.technician" placeholder="请选择技术员" :disabled="!isAddMode" clearable filterable
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-form-item label="事件日期" prop="eventDate">
<el-date-picker v-model="form.eventDate" type="date" placeholder="请选择事件日期" value-format="YYYY-MM-DD"
:disabled="!isAddMode" />
</el-form-item>
<el-form-item label="备注" prop="comment">
<el-input v-model="form.comment" type="textarea" placeholder="请输入内容" :disabled="!isAddMode" />
</el-form-item>
</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>
</div>
</template>
<script setup name="ChangeEar">
import { listChangeEar, getChangeEar, delChangeEar, addChangeEar, updateChangeEar, getSheepByEarNumber, checkTagExists, searchEarNumbers } from "@/api/produce/manage_sheep/changeEar"
import { listSheepfold_management as listSheepfold } from '@/api/fileManagement/sheepfold_management'
import dayjs from 'dayjs'
import { nextTick } from 'vue'
import { Plus, Delete, ArrowUp, ArrowDown } from '@element-plus/icons-vue'
import { getUserByPost } from '@/api/common/user'
const { proxy } = getCurrentInstance()
// 技术员下拉选项
const technicalOptions = ref([])
// 获取技术员列表岗位编码techs
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(() => {
technicalOptions.value = []
})
}
const changeEarList = ref([])
const open = 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 daterangeCreateTime = ref([])
const isAddMode = ref(true);
const daterangeEventDate = ref([]);
const pasteText = ref('') // 批量粘贴输入框
const isExpanded = ref(false) // 折叠状态
const defaultShowCount = 2 // 默认展示条数
/* 计算:控制实际展示的耳号列表 */
const displayedEarTags = computed(() => {
const list = queryParams.value.manageTagsList || []
if (isExpanded.value || list.length <= defaultShowCount) return list
return list.slice(0, defaultShowCount)
})
const data = reactive({
form: {
technician: null,
eventDate: null
},
queryParams: {
pageNum: 1,
pageSize: 20,
manageTags: null,
// sheepfoldId: null,
technician: null,
earType: null,
newTag: null,
oldTag: null,
createTime: null,
earType: null,
inGroup: 0
},
rules: {
earNumber: [
{ required: true, message: "请输入管理耳号或电子耳号", trigger: "blur" }
],
earType: [
{ required: true, message: "请选择耳号类型", trigger: "change" }
],
newTag: [
{ required: true, message: "请输入新耳号", trigger: "blur" }
],
technician: [
{ required: true, message: "请输入技术员", trigger: "blur" }
],
eventDate: [
{ required: true, message: "请选择事件日期", trigger: "change" }
]
}
})
const { queryParams, form, rules } = toRefs(data)
const earOptions = ref([])
const earLoading = ref(false)
/** 查询修改电子耳号记录列表 */
async function getList() {
loading.value = true;
queryParams.value.params = {};
if (queryParams.value.manageTags) {
queryParams.value.params["manageTags"] = queryParams.value.manageTags;
}
// if (queryParams.value.sheepfoldId) {
// queryParams.value.params["sheepfoldId"] = queryParams.value.sheepfoldId;
// }
if (daterangeCreateTime.value && daterangeCreateTime.value.length > 0) {
queryParams.value.params["beginCreateTime"] = daterangeCreateTime.value[0];
queryParams.value.params["endCreateTime"] = daterangeCreateTime.value[1];
}
if (daterangeEventDate.value && daterangeEventDate.value.length > 0) {
queryParams.value.params["beginEventDate"] = daterangeEventDate.value[0];
queryParams.value.params["endEventDate"] = daterangeEventDate.value[1];
}
if (queryParams.value.technician) { // ✅ 新增
queryParams.value.params["technician"] = queryParams.value.technician
}
const response = await listChangeEar(queryParams.value);
changeEarList.value = response.rows.map(item => {
item.earTypeName = item.earType === 0 ? '电子耳号' : '管理耳号';
return item;
});
total.value = response.total;
loading.value = false;
}
// 取消按钮
function cancel() {
open.value = false
reset()
}
// 表单重置
function reset() {
form.value = {
manageTags: null,
earType: null,
newTag: null,
oldTag: null,
technician: null,
eventDate: null,
comment: null,
createBy: null,
createTime: null
}
proxy.resetForm("changeEarRef")
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1
getList()
}
/** 重置按钮操作 */
function resetQuery() {
daterangeCreateTime.value = []
daterangeEventDate.value = []
// queryParams.value.sheepfoldName = null
queryParams.value.technician = null
queryParams.value.manageTags = null
queryParams.value.newTag = null
queryParams.value.oldTag = null
queryParams.value.earType = null
queryParams.value.manageTagsList = []
queryParams.value.inGroup = 0
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()
isAddMode.value = true
open.value = true
title.value = '添加耳号记录'
form.value.eventDate = dayjs().format('YYYY-MM-DD')
}
// 修改按钮操作
function handleUpdate(row) {
reset();
isAddMode.value = false;
const _id = row.id || ids.value;
getChangeEar(_id).then(response => {
response.data.earNumber = response.data.manageTags;
form.value = response.data;
open.value = true;
title.value = "修改电子耳号记录";
});
}
// 提交表单
function submitForm() {
proxy.$refs["changeEarRef"].validate(valid => {
if (valid) {
if (!form.value.id) {
if (!form.value.sheepId) {
proxy.$modal.msgError('未找到对应的羊只,请检查耳号');
return;
}
}
if (form.value.id) {
updateChangeEar(form.value).then(() => {
proxy.$modal.msgSuccess("修改成功");
open.value = false;
getList();
});
} else {
addChangeEar(form.value).then(() => {
proxy.$modal.msgSuccess("新增成功");
open.value = false;
getList();
});
}
}
});
}
//校验新耳号
function checkNewTagExists() {
if (!form.value.newTag || form.value.earType === null) {
console.log("新耳号或耳号类型为空");
return;
}
const tagValue = form.value.newTag.trim();
if (!tagValue) {
console.log("新耳号为空");
return;
}
console.log("调用后端接口,参数:", { tag: tagValue, earType: form.value.earType });
checkTagExists(tagValue, form.value.earType).then(res => {
console.log("后端返回结果:", res);
if (res.data.exists) {
proxy.$modal.msgError('该耳号已存在,请更换');
form.value.newTag = '';
}
}).catch(error => {
console.error('校验耳号失败:', error);
proxy.$modal.msgWarning('校验耳号失败,请重试');
});
}
//查询旧耳号
function fetchOldTag() {
const earNumber = form.value.earNumber.trim();
const earType = form.value.earType;
if (!earNumber || earType === null) {
form.value.oldTag = '';
form.value.sheepId = null;
return;
}
getSheepByEarNumber(earNumber, earType).then(response => {
const data = response.data;
const sheep = data.sheep;
const oldTag = data.oldTag;
if (!sheep || !sheep.id) {
form.value.oldTag = '';
form.value.sheepId = null;
proxy.$modal.warning("未找到对应的羊只");
return;
}
form.value.oldTag = oldTag;
form.value.sheepId = sheep.id;
}).catch(error => {
console.error("查询失败:", error);
form.value.oldTag = '';
form.value.sheepId = null;
proxy.$modal.error("查询耳号失败,请重试");
});
}
/** 删除按钮操作 */
function handleDelete(row) {
const _ids = row.id || ids.value
proxy.$modal.confirm('是否确认删除这条记录数据').then(function () {
return delChangeEar(_ids)
}).then(() => {
getList()
proxy.$modal.msgSuccess("删除成功")
}).catch(() => { })
}
/** 导出按钮操作 */
function handleExport() {
queryParams.value.ids = ids.value;
try {
proxy.download('changeEar/changeEar/export', { ...queryParams.value }, `改耳号记录${Date.now()}.xlsx`);
} finally {
queryParams.value.ids = null;
}
}
//加载羊舍数据
const sheepfoldOptions = ref([])
function getSheepfoldOptions() {
listSheepfold({ pageNum: 1, pageSize: 9999 }).then(res => {
sheepfoldOptions.value = res.rows
})
}
// 搜索耳号的方法(用于下拉框远程搜索)
const searchEarNumber = async (query) => {
if (!query || query.trim() === '') {
earOptions.value = []
return
}
earLoading.value = true
try {
// 调用API搜索耳号
const res = await searchEarNumbers(query.trim())
if (res.code === 200 && Array.isArray(res.data)) {
earOptions.value = res.data
} else {
earOptions.value = []
}
} catch (error) {
console.error('搜索耳号失败:', error)
earOptions.value = []
proxy.$modal.msgError('搜索耳号失败')
} finally {
earLoading.value = false
}
}
/* 粘贴事件 */
function handlePaste() {
nextTick(() => handlePasteSubmit())
}
/* 批量提交 */
function handlePasteSubmit() {
if (!pasteText.value || !pasteText.value.trim()) return
const separators = /[\p{White_Space},\n\r\t]+/u
const raw = pasteText.value.trim().split(separators).filter(v => v)
const exist = new Set(queryParams.value.manageTagsList || [])
const adds = []
const dups = []
raw.forEach(v => {
if (!exist.has(v)) { adds.push(v); exist.add(v) }
else dups.push(v)
})
if (adds.length) {
queryParams.value.manageTagsList = [...(queryParams.value.manageTagsList || []), ...adds]
proxy.$modal.msgSuccess(`成功添加 ${adds.length} 个耳号,当前共 ${queryParams.value.manageTagsList.length}` +
(dups.length > 0 ? `,已忽略 ${dups.length} 个重复耳号` : ''))
} else if (dups.length > 0) {
proxy.$modal.msgWarning('所有耳号均已存在')
}
pasteText.value = ''
}
/* 切换展开/收起 */
function toggleExpand() {
isExpanded.value = !isExpanded.value
}
/* 选择器变化时去重 */
function handleEarChange(val) {
queryParams.value.manageTagsList = [...new Set(val)]
}
/* 一键清空 */
function clearEarNumbers() {
queryParams.value.manageTagsList = []
pasteText.value = ''
isExpanded.value = false
}
/* 删除单个耳号 */
function removeEarNumber(tag) {
const idx = queryParams.value.manageTagsList.indexOf(tag)
if (idx > -1) queryParams.value.manageTagsList.splice(idx, 1)
}
onMounted(() => {
getSheepfoldOptions();
getList();
fetchTechnicalList();
});
</script>
<style scoped>
.selected-ear-numbers {
margin-bottom: 16px;
padding: 10px;
background: #f5f7fa;
border-radius: 4px;
}
</style>