羊只分组页面下拉框调整为嵌套查询,羊舍管理添加可视化

This commit is contained in:
wyt 2025-08-20 18:42:55 +08:00
parent 8624037266
commit d8c918768a
4 changed files with 218 additions and 10 deletions

View File

@ -61,3 +61,12 @@ export function addByEarTags(data) {
data
})
}
// 树形分组
export const listGroupTree = () =>
request({
url: '/sheep_grouping/sheep_grouping/group/tree',
method: 'get'
})

View File

@ -55,3 +55,11 @@ export function checkSheepfoldNoExist(ranchId, sheepfoldTypeId, sheepfoldNo) {
}
})
}
// 获取树形座位图(牧场 → 类型 → 羊舍 → 排栏)
export function getSeatMap() {
return request({
url: '/sheepfold_management/sheepfold_management/seatMap',
method: 'get'
})
}

View File

@ -18,7 +18,7 @@
/>
</el-form-item>
<el-form-item label="分组" prop="groupId">
<el-select
<!-- <el-select
v-model="queryParams.groupId"
placeholder="请选择分组"
clearable
@ -30,8 +30,15 @@
:label="g.groupName"
:value="g.groupId"
/>
</el-select>
</el-form-item>
</el-select> -->
<el-tree-select v-model="queryParams.groupId" :data="groupTree" style="width: 180px;"
:props="{ value: 'groupId', label: 'groupName', children: 'children' }"
value-key="groupId" placeholder="请选择"
check-strictly
clearable
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
@ -134,14 +141,27 @@
<el-input type="textarea" :rows="4" v-model="form.earTags" :disabled="form.earTagsDisabled" placeholder="请输入耳号,多个耳号用逗号或换行分隔"/>
</el-form-item>
<el-form-item label="分组" prop="groupId">
<el-select v-model="form.groupId" placeholder="请选择分组" clearable>
<!-- <el-select v-model="form.groupId" placeholder="请选择分组" clearable>
<el-option
v-for="g in leafGroupOptions"
:key="g.groupId"
:label="g.groupName"
:value="g.groupId"
/>
</el-select>
</el-select> -->
<el-tree-select
v-model="form.groupId"
:data="groupTree"
style="width: 180px"
:props="{ value: 'groupId', label: 'groupName', children: 'children' }"
value-key="groupId"
placeholder="请选择分组"
clearable
check-strictly
:select-leaf-only="true"
/>
</el-form-item>
</el-form>
<template #footer>
@ -159,6 +179,7 @@ import { listSheep_grouping, getSheep_grouping, delSheep_grouping, addSheep_grou
import {listLeafGroup} from "@/api/fileManagement/group_management"
import {listSheep_grouping_join} from "@/api/fileManagement/sheep_grouping"
import { addByEarTags } from '@/api/fileManagement/sheep_grouping'
import { listGroupTree } from '@/api/fileManagement/sheep_grouping'
const { proxy } = getCurrentInstance()
@ -173,6 +194,8 @@ const total = ref(0)
const title = ref("")
const leafGroupOptions = ref([])
const { sheep_gender } = proxy.useDict('sheep_gender')
// data
const groupTree = ref([])
const data = reactive({
form: {
@ -390,17 +413,33 @@ loadLeafGroups()
getList()
// //
// function loadLeafGroups() {
// listLeafGroup().then(res => {
// leafGroupOptions.value = res.data
// })
// }
//
function loadLeafGroups() {
listLeafGroup().then(res => {
leafGroupOptions.value = res.data
listGroupTree().then(res => {
groupTree.value = res.data
console.log(groupTree.value)
})
}
// groupId
// function getGroupName(id) {
// const group = leafGroupOptions.value.find(g => g.groupId === id)
// return group ? group.groupName : ''
// }
function getGroupName(id) {
const group = leafGroupOptions.value.find(g => g.groupId === id)
return group ? group.groupName : ''
const flatten = (arr) =>
arr.reduce((acc, cur) => acc.concat(cur, flatten(cur.children || [])), [])
const node = flatten(groupTree.value).find(n => n.groupId === id)
return node ? node.groupName : ''
}
</script>

View File

@ -103,6 +103,86 @@
@pagination="getList"
/>
<!-- ===== 图形化展示区域 ===== -->
<el-divider>牧场羊舍示意图</el-divider>
<el-collapse
v-model="activeNames"
accordion
style="margin-top: 16px; max-width: 100%; overflow-x: auto"
>
<!-- 一级牧场 -->
<el-collapse-item
v-for="ranch in seatMapTree"
:key="ranch.ranchId"
:title="ranch.ranchName"
:name="ranch.ranchId"
>
<!-- 二级羊舍类型 -->
<el-collapse accordion>
<el-collapse-item
v-for="type in ranch.types"
:key="type.typeId"
:title="`${type.typeName} (${type.folds.length}个)`"
>
<!-- 三级羊舍卡片 -->
<el-row :gutter="16">
<el-col
v-for="fold in type.folds"
:key="fold.foldNo"
:xs="24"
:sm="12"
:md="8"
:lg="6"
:xl="4"
style="margin-bottom: 16px"
>
<el-card shadow="hover">
<template #header>
<span>{{ fold.foldNo }}{{type.typeName}}</span>
</template>
<!-- 四级 -->
<div
v-for="row in fold.rows"
:key="row.rowNo"
class="seat-block"
>
<div class="row-label">{{ row.rowNo }}</div>
<div class="seat-row">
<!-- 五级栏位 -->
<div
v-for="col in row.columns"
:key="col"
class="seat"
:class="{ occupied: isOccupied(fold.foldNo, row.rowNo, col) }"
@click="toggleSeat(fold.foldNo, row.rowNo, col)"
>
{{ col }}
</div>
</div>
</div>
</el-card>
</el-col>
</el-row>
</el-collapse-item>
</el-collapse>
</el-collapse-item>
</el-collapse>
<!-- 添加或修改羊舍管理对话框 -->
<el-dialog :title="title" v-model="open" width="500px" append-to-body>
<el-form ref="sheepfold_managementRef" :model="form" :rules="rules" label-width="80px">
@ -190,7 +270,7 @@
</template>
<script setup name="Sheepfold_management">
import { listSheepfold_management, getSheepfold_management, delSheepfold_management, addSheepfold_management, updateSheepfold_management,checkSheepfoldNoExist } from "@/api/fileManagement/sheepfold_management"
import { getSeatMap,listSheepfold_management, getSheepfold_management, delSheepfold_management, addSheepfold_management, updateSheepfold_management,checkSheepfoldNoExist } from "@/api/fileManagement/sheepfold_management"
const { proxy } = getCurrentInstance()
const { bas_sheepfold_type, da_ranch } = proxy.useDict('bas_sheepfold_type', 'da_ranch')
@ -206,6 +286,7 @@ const total = ref(0)
const title = ref("")
const sheepfoldNoExists = ref(false) //
const data = reactive({
form: {
id: null,
@ -388,6 +469,7 @@ function submitForm() {
proxy.$modal.msgSuccess("修改成功")
open.value = false
getList()
loadSeatMap();
})
} else {
// -
@ -423,6 +505,7 @@ function submitForm() {
proxy.$modal.msgSuccess(`新增成功,共添加${requests.length}条记录`)
open.value = false
getList()
loadSeatMap()
})
.catch(error => {
proxy.$modal.msgError("部分记录添加失败:" + error.message)
@ -439,6 +522,7 @@ function handleDelete(row) {
return delSheepfold_management(_ids)
}).then(() => {
getList()
loadSeatMap();
proxy.$modal.msgSuccess("删除成功")
}).catch(() => {})
}
@ -450,7 +534,45 @@ function handleExport() {
}, `sheepfold_management_${new Date().getTime()}.xlsx`)
}
/* ===== 图形化展示所需变量和方法 ===== */
const activeNames = ref([]) //
const seatMapTree = ref([]) //
const loadSeatMap = () => {
getSeatMap()
.then(res => (seatMapTree.value = res.data))
.catch(err => proxy.$modal.msgError('加载座位图失败:' + err.message))
}
/* 演示:点击栏位切换颜色 */
const occupied = ref(new Set())
const isOccupied = (foldNo, rowNo, col) =>
occupied.value.has(`${foldNo}-${rowNo}-${col}`)
const toggleSeat = (foldNo, rowNo, col) => {
const key = `${foldNo}-${rowNo}-${col}`
occupied.value.has(key)
? occupied.value.delete(key)
: occupied.value.add(key)
}
/* 页面加载时拉取数据 */
onMounted(() => {
getList()
loadSeatMap()
})
getList()
</script>
@ -462,4 +584,34 @@ getList()
border-radius: 4px;
background-color: #f5f7fa;
}
/* ===== 图形化展示样式 ===== */
.seat-block {
margin-bottom: 8px;
}
.row-label {
font-weight: bold;
margin-bottom: 4px;
}
.seat-row {
display: flex;
flex-wrap: wrap;
gap: 4px;
}
.seat {
width: 32px;
height: 32px;
border: 1px solid #dcdfe6;
border-radius: 4px;
display: flex;
align-items: center;
justify-content: center;
font-size: 12px;
cursor: pointer;
background: #f2f6fc;
}
.seat.occupied {
background: #67c23a;
color: #fff;
}
</style>