Files
zhyc-sheep-ui/src/views/produce/other/fixHoof/index.vue

526 lines
18 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="68px">
<el-form-item label="事件日期" style="width: 308px">
<el-date-picker v-model="daterangeEventDate" value-format="YYYY-MM-DD" type="daterange" range-separator="-"
start-placeholder="开始日期" end-placeholder="结束日期" />
</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:260px" @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:260px" @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.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.length">
清空全部
</el-button>
</div>
<div v-if="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="sheepfold">
<el-select v-model="queryParams.sheepfold" placeholder="请选择羊舍" style="min-width:150px" clearable>
<el-option v-for="item in sheepfoldOptions" :key="item.id" :label="item.sheepfoldName" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item label="品种" prop="varietyId">
<el-select v-model="queryParams.varietyId" placeholder="请选择品种" style="min-width:150px" clearable>
<el-option v-for="item in varietyOptions" :key="item.id" :label="item.variety" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item label="是否在群" prop="isDelete">
<el-select v-model="queryParams.isDelete" placeholder="全部" clearable style="min-width:120px">
<el-option label="全部" value="" />
<el-option label="在群" :value="0" />
<el-option label="离群" :value="1" />
</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="['fixHoof:fixHoof:add']">新增</el-button>
</el-col>
<!-- 按需添加 是否需要修改功能 -->
<!-- <el-col :span="1.5">
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate"
v-hasPermi="['fixHoof:fixHoof:edit']">修改</el-button>
</el-col> -->
<el-col :span="1.5">
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete"
v-hasPermi="['fixHoof:fixHoof:remove']">删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="handleExport"
v-hasPermi="['fixHoof:fixHoof:export']">导出</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList" />
</el-row>
<!-- 列表 -->
<el-table v-loading="loading" :data="fixHoofList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="耳号" align="center" prop="manageTags" />
<el-table-column label="事件类型" align="center" prop="eventType" width="120" />
<el-table-column label="事件日期" align="center" prop="eventDate" width="130">
<template #default="scope">
<span>{{ parseTime(scope.row.eventDate, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="羊舍" align="center" prop="sheepfoldName" />
<el-table-column label="品种" align="center" prop="varietyName" />
<el-table-column label="备注" align="center" prop="comment" />
<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" class-name="small-padding fixed-width">
<template #default="scope">
<!-- 按需添加 是否需要修改功能 -->
<!-- <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)"
v-hasPermi="['fixHoof:fixHoof:edit']">修改</el-button> -->
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)"
v-hasPermi="['fixHoof:fixHoof:remove']">删除</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" @pagination="getList" :page-sizes="[20, 50, 100, 200, 500, 1000, 2000]" />
<!-- 弹窗 -->
<el-dialog :title="title" v-model="open" width="500px" append-to-body>
<el-form ref="fixHoofRef" :model="form" :rules="rules" label-width="80px">
<el-form-item label="耳号" prop="manageTags">
<div style="display: flex; align-items: center; gap: 8px;">
<el-select v-model="form.manageTags" placeholder="请输入或选择耳号" multiple filterable allow-create
style="width: 100%; flex:1;" @change="loadSheepInfo">
<el-option v-for="sheep in sheepOptions" :key="sheep.id" :label="sheep.manageTags"
:value="sheep.manageTags" />
</el-select>
<span v-if="form.manageTags?.length > 0" class="tag-count">
已选 {{ form.manageTags.length }}
</span>
</div>
</el-form-item>
<el-form-item label="羊舍" prop="sheepfolds">
<el-select v-model="form.sheepfold" filterable style="width: 100%" @change="loadSheepBySheepfold">
<el-option v-for="fold in sheepfoldOptions" :key="fold.id" :label="fold.sheepfoldName" :value="fold.id" />
</el-select>
</el-form-item>
<el-form-item label="技术员" prop="technician">
<el-input v-model="form.technician" placeholder="请输入技术员" />
</el-form-item>
<el-form-item label="事件日期" prop="eventDate">
<el-date-picker v-model="form.eventDate" value-format="YYYY-MM-DD" type="date" placeholder="请选择事件日期"
clearable />
</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="FixHoof">
import { listFixHoof, getFixHoof, delFixHoof, addFixHoof, updateFixHoof, checkSheepByManageTags, getVarietyOptions, getSheepBySheepfoldId, searchEarNumbers } from '@/api/produce/other/fixHoof'
import { listSheepfold_management as listSheepfold } from '@/api/fileManagement/sheepfold_management'
import { Plus, Delete, ArrowUp, ArrowDown } from '@element-plus/icons-vue'
import { nextTick } from 'vue'
import dayjs from 'dayjs'
const { proxy } = getCurrentInstance()
const fixHoofList = 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 varietyOptions = ref([])
const sheepOptions = ref([])
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: {
sheepfold: null,
manageTags: [],
tagDetails: {},
eventDate: null,
},
queryParams: {
pageNum: 1,
pageSize: 20,
sheepId: null,
sheepfold: null,
varietyId: null,
technician: null,
createTime: null,
manageTagsList: [],
isDelete: null
},
rules: {
manageTags: [
{ required: true, message: '请输入管理耳号', trigger: 'blur' }
],
sheepfold: [
{ required: true, message: '请选择羊舍', trigger: 'change' }
],
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)
//根据羊舍获取羊只
function loadSheepBySheepfold() {
const currentSheepfoldId = form.value.sheepfold;
if (!currentSheepfoldId) {
sheepOptions.value = [];
return;
}
getSheepBySheepfoldId(currentSheepfoldId)
.then(res => {
const newSheepList = res.data || [];
sheepOptions.value = newSheepList.map(sheep => ({
id: sheep.id,
manageTags: sheep.manageTags,
sheepfoldId: currentSheepfoldId
}));
})
.catch(error => {
console.error('加载新羊舍耳号失败', error);
proxy.$modal.msgError('切换羊舍失败,请重试');
sheepOptions.value = [];
});
}
async function loadSheepInfo() {
const tags = form.value.manageTags;
if (!tags || tags.length === 0) return;
const tagDetails = {};
const validResults = [];
const validTags = [];
for (const tag of tags) {
try {
const { data: sheepData } = await checkSheepByManageTags(tag.trim());
if (!sheepData) {
validResults.push(false);
proxy.$modal.msgError(`耳号 ${tag} 不存在`);
} else {
validResults.push(true);
validTags.push(tag);
tagDetails[tag] = {
comment: sheepData.comment || '',
varietyId: sheepData.varietyId,
sheepfoldId: sheepData.sheepfoldId,
sheepId: sheepData.id
};
}
} catch (error) {
console.error('获取耳号信息失败:', error);
proxy.$modal.msgError(`耳号 ${tag} 验证失败`);
validResults.push(false);
}
}
if (validResults.includes(false)) {
form.value.manageTags = tags.filter((_, index) => validResults[index]);
proxy.$message.warning('部分耳号不合法,已过滤');
}
form.value.tagDetails = tagDetails;
if (validTags.length > 0) {
const firstValidTag = validTags[0];
const firstSheepfoldId = tagDetails[firstValidTag].sheepfoldId;
form.value.sheepfold = firstSheepfoldId;
}
}
//获取修蹄列表
function getList() {
loading.value = true
const q = { ...queryParams.value }
if (q.sheepId === '') q.sheepId = null
if (q.sheepfold === '') q.sheepfold = null
if (q.varietyId === '') q.varietyId = null
q.params = {}
if (daterangeCreateTime.value?.length) {
q.params.beginCreateTime = daterangeCreateTime.value[0]
q.params.endCreateTime = daterangeCreateTime.value[1]
}
if (daterangeEventDate.value?.length) {
q.params.beginEventDate = daterangeEventDate.value[0]
q.params.endEventDate = daterangeEventDate.value[1]
}
listFixHoof(q).then(res => {
fixHoofList.value = res.rows
total.value = res.total
loading.value = false
})
getVarietyOptions({ pageNum: 1, pageSize: 9999 }).then(res => {
varietyOptions.value = res.rows || []
})
}
//取消
function cancel() {
open.value = false
reset()
}
//重置
function reset() {
form.value = {
id: null,
sheepfold: null,
manageTags: [],
varietyId: null,
varietyName: null,
eventDate: null
}
sheepOptions.value = [];
proxy.resetForm('fixHoofRef')
}
//搜索
function handleQuery() {
queryParams.value.pageNum = 1
getList()
}
//重置
function resetQuery() {
daterangeCreateTime.value = []
daterangeEventDate.value = []
queryParams.value.varietyId = null
queryParams.value.manageTagsList = []
queryParams.value.isDelete = null
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()
open.value = true
title.value = '添加修蹄'
form.value.eventDate = dayjs().format('YYYY-MM-DD')
}
//修改
function handleUpdate(row) {
reset()
const _id = row.id || ids.value
getFixHoof(_id).then(res => {
const fixHoofData = res.data;
fixHoofData.manageTags = fixHoofData.manageTags ? [fixHoofData.manageTags] : [];
form.value = fixHoofData;
open.value = true
title.value = '修改修蹄'
})
}
//提交
function submitForm() {
proxy.$refs.fixHoofRef.validate(valid => {
if (!valid) return;
const allTags = form.value.manageTags;
const tagDetails = form.value.tagDetails || {};
if (!allTags || allTags.length === 0) {
proxy.$modal.msgError('请选择至少一个耳号');
return;
}
const fixHoofList = allTags.map(tag => {
const details = tagDetails[tag] || {};
return {
...form.value,
manageTags: tag,
comment: details.comment || '',
sheepId: details.sheepId,
varietyId: details.varietyId,
sheepfold: details.sheepfoldId || form.value.sheepfold
};
});
addFixHoof(fixHoofList)
.then(() => {
proxy.$modal.msgSuccess('操作成功');
open.value = false;
getList();
})
.catch(error => {
proxy.$modal.msgError(`处理失败:${error.message}`);
});
});
}
//删除
function handleDelete(row) {
const _ids = row.id || ids.value
proxy.$modal.confirm(`是否确认删除这条记录数据`).then(() => {
return delFixHoof(_ids)
}).then(() => {
getList()
proxy.$modal.msgSuccess('删除成功')
})
}
//导出
function handleExport() {
proxy.download('/produce/other/fixHoof/export', { ...queryParams.value }, `fixHoof_${new Date().getTime()}.xlsx`)
}
//加载羊舍数据
const sheepfoldOptions = ref([])
function getSheepfoldOptions() {
listSheepfold({ pageNum: 1, pageSize: 9999 }).then(res => {
sheepfoldOptions.value = res.rows
})
}
function searchEarNumber(query) {
if (!query) { earOptions.value = []; return }
earLoading.value = true
searchEarNumbers(query.trim()).then(res => {
earOptions.value = res.data || []
}).finally(() => earLoading.value = false)
}
function clearEarNumbers() {
queryParams.value.manageTagsList = []
}
function removeEarNumber(tag) {
const idx = queryParams.value.manageTagsList.indexOf(tag)
if (idx > -1) queryParams.value.manageTagsList.splice(idx, 1)
}
function handlePaste() {
nextTick(() => handlePasteSubmit())
}
function handlePasteSubmit() {
if (!pasteText.value.trim()) return
const separators = /[\s,\n\r\t]+/
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} 个耳号${dups.length ? `,已忽略 ${dups.length} 个重复` : ''}`)
} else if (dups.length) {
proxy.$modal.msgWarning('所有耳号均已存在')
}
pasteText.value = ''
}
function toggleExpand() {
isExpanded.value = !isExpanded.value
}
function handleEarChange(val) {
queryParams.value.manageTagsList = [...new Set(val)]
}
onMounted(() => {
getSheepfoldOptions()
getVarietyOptions()
getList()
})
</script>
<style scoped>
.tag-count {
color: #606266;
background-color: #f5f7fa;
padding: 2px 8px;
border-radius: 12px;
font-size: 12px;
}
.selected-ear-numbers {
max-height: 150px;
overflow-y: auto;
padding: 8px;
background: #f5f7fa;
border-radius: 4px;
border: 1px dashed #dcdfe6;
display: flex;
flex-wrap: wrap;
align-items: center;
}
.selected-ear-numbers::-webkit-scrollbar {
width: 6px;
}
.selected-ear-numbers::-webkit-scrollbar-thumb {
background-color: #dcdfe6;
border-radius: 3px;
}
</style>