Compare commits

...

3 Commits

3 changed files with 1164 additions and 17 deletions

View File

@ -1,11 +1,11 @@
import request from '@/utils/request'
// 查询羊只档案列表
// 羊只档案列表查询
export function listSheep_file(query) {
return request({
url: '/sheep_file/sheep_file/list',
method: 'get',
params: query
method: 'post', // 改为 POST
data: query // 使用 data 而不是 params
})
}
@ -26,6 +26,15 @@ export function delSheep_file(id) {
})
}
// 羊只档案导出
export function exportSheep_file(query) {
return request({
url: '/sheep_file/sheep_file/export',
method: 'post', // 改为 POST
data: query, // 使用 data 而不是 params
responseType: 'blob'
})
}
// 在群总数
@ -47,3 +56,22 @@ export function getVarietyStat() {
export function getLactationParityStat() {
return request({ url: '/sheep_file/sheep_file/stat/lactationParity', method: 'get' })
}
/**
* 新增API获取字段的唯一值列表
* 用于前端筛选条件中的下拉选项数据
*
* @param {string} fieldName 字段名数据库列名
* @returns 包含字段唯一值列表的Promise
*
* 使用示例
* getFieldValues('bs_manage_tags').then(values => {
* console.log(values); // ["AF00001", "AF00002", "AF00003"]
* });
*/
export function getFieldValues(fieldName) {
return request({
url: '/sheep_file/sheep_file/field/' + fieldName,
method: 'get'
})
}

View File

@ -0,0 +1,818 @@
<template>
<!-- 模板部分保持不变 -->
<div class="custom-filter">
<el-button type="primary" @click="openFilterDialog">
<i class="el-icon-search"></i>
筛选条件
</el-button>
<el-dialog
v-model="filterDialogVisible"
title="自定义筛选条件"
width="800px"
:close-on-click-modal="false"
>
<!-- 条件定义区域 -->
<div class="condition-definition">
<h4>添加筛选条件</h4>
<el-row :gutter="10" align="middle">
<el-col :span="6">
<el-select
v-model="currentCondition.field"
placeholder="选择字段"
@change="handleFieldChange"
clearable
>
<el-option
v-for="field in availableFields"
:key="field.value"
:label="field.label"
:value="field.value"
/>
</el-select>
</el-col>
<el-col :span="6">
<el-select
v-model="currentCondition.operator"
placeholder="选择条件"
:disabled="!currentCondition.field"
@change="handleOperatorChange"
>
<el-option
v-for="op in availableOperators"
:key="op.value"
:label="op.label"
:value="op.value"
/>
</el-select>
</el-col>
<el-col :span="10">
<div v-if="showValueInput">
<el-input
v-if="currentFieldType === 'text' && currentCondition.operator !== 'in'"
v-model="currentCondition.value"
:placeholder="`请输入${getCurrentFieldLabel()}`"
clearable
/>
<!-- 多选下拉框在列表中 -->
<el-select
v-else-if="currentCondition.operator === 'in'"
v-model="currentCondition.selectedOriginalValues"
multiple
filterable
:placeholder="`选择${getCurrentFieldLabel()}`"
style="width: 100%"
:loading="loadingFieldValues"
>
<el-option
v-for="item in fieldValues"
:key="item.originalValue"
:label="item.displayLabel"
:value="item.originalValue"
/>
</el-select>
<el-input-number
v-else-if="currentFieldType === 'number'"
v-model="currentCondition.value"
:placeholder="`请输入${getCurrentFieldLabel()}`"
controls-position="right"
style="width: 100%"
/>
<el-date-picker
v-else-if="currentFieldType === 'date'"
v-model="currentCondition.value"
type="date"
:placeholder="`选择${getCurrentFieldLabel()}`"
value-format="YYYY-MM-DD"
style="width: 100%"
/>
<el-select
v-else-if="currentFieldType === 'dict' && currentCondition.operator !== 'in'"
v-model="currentCondition.value"
:placeholder="`选择${getCurrentFieldLabel()}`"
style="width: 100%"
>
<el-option
v-for="item in getDictOptions(currentCondition.field)"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</div>
<div v-else-if="currentCondition.operator === 'null' || currentCondition.operator === 'notNull'">
<el-tag type="info">
{{ currentCondition.operator === 'null' ? '为空' : '不为空' }}
</el-tag>
</div>
</el-col>
<el-col :span="2">
<el-button
type="primary"
@click="addCondition"
:disabled="!canAddCondition"
icon="el-icon-plus"
>
添加
</el-button>
</el-col>
</el-row>
</div>
<div class="condition-list" v-if="conditions.length > 0">
<h4>已添加的条件</h4>
<div class="condition-item" v-for="(condition, index) in conditions" :key="index">
<span class="condition-text">
{{ getConditionText(condition) }}
</span>
<el-button
link
type="danger"
@click="removeCondition(index)"
icon="el-icon-delete"
>
删除
</el-button>
</div>
</div>
<div class="condition-list" v-else>
<el-empty description="暂无筛选条件" :image-size="80"></el-empty>
</div>
<template #footer>
<div class="dialog-footer">
<el-button @click="resetFilter">重置</el-button>
<el-button @click="cancelFilter">取消</el-button>
<el-button type="primary" @click="applyFilters" :disabled="conditions.length === 0">
保存条件
</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup>
import { ref, computed, getCurrentInstance } from 'vue'
import { getFieldValues } from '@/api/fileManagement/sheep_file'
const { proxy } = getCurrentInstance()
// 使 useDict Ref
const { sheep_gender, sheep_status, breed_type } = proxy.useDict('sheep_gender', 'sheep_status', 'breed_type')
//
const filterDialogVisible = ref(false)
const conditions = ref([])
const fieldValues = ref([])
const loadingFieldValues = ref(false)
//
const currentCondition = ref({
field: '',
operator: '',
value: '',
selectedOriginalValues: []
})
//
const availableFields = ref([
{ label: '耳号', value: 'bs_manage_tags', type: 'text' },
{ label: '电子耳号', value: 'electronic_tags', type: 'text' },
{ label: '牧场名称', value: 'dr_ranch', type: 'text' },
{ label: '羊舍名称', value: 'sheepfold_name', type: 'text' },
{ label: '品种', value: 'variety', type: 'text' },
{ label: '家系', value: 'family', type: 'text' },
{ label: '羊只类型', value: 'name', type: 'text' },
{ label: '性别', value: 'gender', type: 'dict' },
{ label: '出生日期', value: 'birthday', type: 'date' },
{ label: '日龄', value: 'day_age', type: 'number' },
{ label: '月龄', value: 'month_age', type: 'number' },
{ label: '胎次', value: 'parity', type: 'number' },
{ label: '出生体重', value: 'birth_weight', type: 'number' },
{ label: '断奶日期', value: 'weaning_date', type: 'date' },
{ label: '羊只状态', value: 'status_id', type: 'dict' },
{ label: '断奶体重', value: 'weaning_weight', type: 'number' },
{ label: '当前体重', value: 'current_weight', type: 'number' },
{ label: '断奶日龄', value: 'weaning_day_age', type: 'number' },
{ label: '断奶日增重', value: 'weaning_daily_gain', type: 'number' },
{ label: '繁殖状态', value: 'breed', type: 'text' },
{ label: '父亲耳号', value: 'father_manage_tags', type: 'text' },
{ label: '母亲耳号', value: 'mother_manage_tags', type: 'text' },
{ label: '受体耳号', value: 'receptor_manage_tags', type: 'text' },
{ label: '配种类型', value: 'mating_type_id', type: 'dict' },
{ label: '孕检日期', value: 'preg_date', type: 'date' },
{ label: '产羔日期', value: 'lambing_date', type: 'date' },
{ label: '产羔时怀孕天数', value: 'lambing_day', type: 'number' },
{ label: '配后天数', value: 'mating_day', type: 'number' },
{ label: '怀孕天数', value: 'gestation_day', type: 'number' },
{ label: '预产日期', value: 'expected_date', type: 'date' },
{ label: '产后天数', value: 'post_lambing_day', type: 'number' },
{ label: '泌乳天数', value: 'lactation_day', type: 'number' },
{ label: '空怀天数', value: 'anestrous_day', type: 'number' },
{ label: '配种次数', value: 'mating_counts', type: 'number' },
{ label: '累计配种次数', value: 'mating_total', type: 'number' },
{ label: '累计流产次数', value: 'miscarriage_counts', type: 'number' },
{ label: '体况评分', value: 'body', type: 'number' },
{ label: '乳房评分', value: 'breast', type: 'number' },
{ label: '入群日期', value: 'source_date', type: 'date' },
{ label: '修改日期', value: 'update_time', type: 'date' },
{ label: '创建日期', value: 'create_time', type: 'date' },
])
// - Ref
const dictMap = {
'gender': sheep_gender,
'status_id': sheep_status,
'mating_type_id': breed_type
}
console.log('字典数据详情:', {
sheep_gender: sheep_gender.value, // 访 .value
sheep_status: sheep_status.value,
breed_type: breed_type.value
})
//
const currentFieldType = computed(() => {
const field = availableFields.value.find(f => f.value === currentCondition.value.field)
return field ? field.type : 'text'
})
const showValueInput = computed(() => {
return currentCondition.value.operator &&
currentCondition.value.operator !== 'null' &&
currentCondition.value.operator !== 'notNull'
})
const canAddCondition = computed(() => {
const { field, operator, value, selectedOriginalValues } = currentCondition.value
if (!field || !operator) return false
if (showValueInput.value) {
if (operator === 'in') {
return selectedOriginalValues && selectedOriginalValues.length > 0
} else {
return value !== null && value !== undefined && value !== ''
}
}
return true
})
const availableOperators = computed(() => {
const fieldOperatorConfig = {
'bs_manage_tags': [
{ label: '在列表中', value: 'in' },
{ label: '为空', value: 'null' },
],
'electronic_tags': [
{ label: '在列表中', value: 'in' },
{ label: '为空', value: 'null' },
{ label: '不为空', value: 'notNull' }
],
'father_manage_tags': [
{ label: '在列表中', value: 'in' },
{ label: '为空', value: 'null' },
],
'mother_manage_tags': [
{ label: '在列表中', value: 'in' },
{ label: '为空', value: 'null' },
],
'receptor_manage_tags': [
{ label: '在列表中', value: 'in' },
{ label: '为空', value: 'null' },
],
'dr_ranch':[
{label:'在列表中',value:'in'},
{label: '为空', value: 'null' },
],
'sheepfold_name':[
{label:'在列表中',value:'in'},
{label: '为空', value: 'null' },
],
'variety':[
{label:'在列表中',value:'in'},
{label: '为空', value: 'null' },
],
'family':[
{label:'在列表中',value:'in'},
],
'name':[
{label:'在列表中',value:'in'},
{label: '为空', value: 'null' },
],
'day_age': 'number',
'month_age': 'number',
'parity': 'number',
'birth_weight': 'number',
'weaning_weight': 'number',
'current_weight': 'number',
'weaning_day_age': 'number',
'weaning_daily_gain': 'number',
'breed': [
{label:'在列表中',value:'in'},
{label: '为空', value: 'null' },
],
'birthday': 'date',
'weaning_date': 'date',
'gender':[
{label:'在列表中',value:'in'},
{label: '为空', value: 'null' },
],
'status_id':[
{label:'在列表中',value:'in'},
{label: '为空', value: 'null' },
],
'mating_type_id':[
{label:'在列表中',value:'in'},
{label: '为空', value: 'null' },
],
'preg_date':'date',
'lambing_date':'date',
'lambing_day':'number',
'mating_day':'number',
'gestation_day':'number',
'expected_date':'date',
'post_lambing_day':'number',
'lactation_day':'number',
'anestrous_day':'number',
'mating_counts':'number',
'mating_total':'number',
'miscarriage_counts':'number',
'body':'number',
'breast':'number',
'source_date':'date',
'update_time':'date',
'create_time':'date',
}
const currentField = currentCondition.value.field
if (fieldOperatorConfig[currentField]) {
if (Array.isArray(fieldOperatorConfig[currentField])) {
return fieldOperatorConfig[currentField]
} else if (typeof fieldOperatorConfig[currentField] === 'string') {
const type = fieldOperatorConfig[currentField]
return getDefaultOperatorsByType(type)
}
}
return getDefaultOperatorsByType(currentFieldType.value)
})
function getDefaultOperatorsByType(type) {
const operators = {
text: [
{ label: '等于', value: 'eq' },
{ label: '包含', value: 'like' },
{ label: '在列表中', value: 'in' },
{ label: '为空', value: 'null' },
{ label: '不为空', value: 'notNull' }
],
number: [
{ label: '等于', value: 'eq' },
{ label: '大于', value: 'gt' },
{ label: '小于', value: 'lt' },
{ label: '大于等于', value: 'ge' },
{ label: '小于等于', value: 'le' },
{ label: '为空', value: 'null' },
{ label: '不为空', value: 'notNull' }
],
date: [
{ label: '等于', value: 'eq' },
{ label: '大于', value: 'gt' },
{ label: '小于', value: 'lt' },
{ label: '大于等于', value: 'ge' },
{ label: '小于等于', value: 'le' },
{ label: '为空', value: 'null' },
],
dict: [
{ label: '等于', value: 'eq' },
{ label: '在列表中', value: 'in' },
{ label: '为空', value: 'null' },
{ label: '不为空', value: 'notNull' }
]
}
return operators[type] || operators.text
}
//
function openFilterDialog() {
filterDialogVisible.value = true
conditions.value = []
currentCondition.value = {
field: '',
operator: '',
value: '',
selectedOriginalValues: []
}
}
function getCurrentFieldLabel() {
const field = availableFields.value.find(f => f.value === currentCondition.value.field)
return field ? field.label : ''
}
/**
* 获取字典选项用于单选
*/
function getDictOptions(field) {
const dictRef = dictMap[field]
return dictRef ? dictRef.value : [] // 访 .value
}
/**
* 根据字典字段和原始值获取字典标签
*/
function getDictLabel(field, value) {
const dictRef = dictMap[field]
if (!dictRef) {
console.warn(`字段 ${field} 没有对应的字典`)
return String(value)
}
const dictData = dictRef.value // 访 .value
console.log(`字典转换: field=${field}, value=${value}, dictData=`, dictData)
if (!dictData || !Array.isArray(dictData) || dictData.length === 0) {
console.warn('字典数据无效,返回原始值')
return String(value)
}
//
const valueStr = String(value)
//
const option = dictData.find(item => {
//
return String(item.value) === valueStr
})
if (option) {
console.log(`找到匹配: ${value} -> ${option.label}`)
return option.label
} else {
console.warn(`未找到匹配的字典项: value=${value}`)
//
return String(value)
}
}
function getOperatorsByField(field, fieldType) {
const fieldOperatorConfig = {
'bs_manage_tags': [
{ label: '在列表中', value: 'in' },
{ label: '为空', value: 'null' },
],
'electronic_tags': [
{ label: '在列表中', value: 'in' },
{ label: '为空', value: 'null' },
{ label: '不为空', value: 'notNull' }
],
'father_manage_tags': [
{ label: '在列表中', value: 'in' },
{ label: '为空', value: 'null' },
],
'mother_manage_tags': [
{ label: '在列表中', value: 'in' },
{ label: '为空', value: 'null' },
],
'receptor_manage_tags': [
{ label: '在列表中', value: 'in' },
{ label: '为空', value: 'null' },
],
'dr_ranch':[
{label:'在列表中',value:'in'},
{label: '为空', value: 'null' },
],
'sheepfold_name':[
{label:'在列表中',value:'in'},
{label: '为空', value: 'null' },
],
'variety':[
{label:'在列表中',value:'in'},
{label: '为空', value: 'null' },
],
'family':[
{label:'在列表中',value:'in'},
],
'name':[
{label:'在列表中',value:'in'},
{label: '为空', value: 'null' },
],
'day_age': 'number',
'month_age': 'number',
'parity': 'number',
'birth_weight': 'number',
'weaning_weight': 'number',
'current_weight': 'number',
'weaning_day_age': 'number',
'weaning_daily_gain': 'number',
'breed':[
{label:'在列表中',value:'in'},
{label: '为空', value: 'null' },
],
'birthday': 'date',
'weaning_date': 'date',
'gender':[
{label:'在列表中',value:'in'},
{label: '为空', value: 'null' },
],
'status_id': 'dict',
'mating_type_id': 'dict'
}
if (fieldOperatorConfig[field]) {
if (Array.isArray(fieldOperatorConfig[field])) {
return fieldOperatorConfig[field]
} else if (typeof fieldOperatorConfig[field] === 'string') {
const type = fieldOperatorConfig[field]
return getDefaultOperatorsByType(type)
}
}
return getDefaultOperatorsByType(fieldType)
}
function getConditionText(condition) {
const field = availableFields.value.find(f => f.value === condition.field)
const operators = getOperatorsByField(condition.field, field ? field.type : 'text')
const operator = operators.find(op => op.value === condition.operator)
if (!field || !operator) {
console.warn('未知条件:', condition)
return '未知条件'
}
let valueText = ''
if (condition.operator === 'in') {
if (Array.isArray(condition.value)) {
if (field.type === 'dict') {
valueText = condition.value.map(originalValue =>
getDictLabel(condition.field, originalValue)
).join(', ')
} else {
valueText = condition.value.join(', ')
}
} else {
valueText = condition.value
}
} else if (condition.operator === 'null' || condition.operator === 'notNull') {
valueText = ''
} else {
if (field.type === 'dict') {
valueText = getDictLabel(condition.field, condition.value)
} else {
valueText = condition.value
}
}
let displayText = `${field.label} ${operator.label}`
if (valueText) {
displayText += ` ${valueText}`
}
return displayText
}
function handleFieldChange() {
currentCondition.value.operator = ''
currentCondition.value.value = ''
currentCondition.value.selectedOriginalValues = []
fieldValues.value = []
}
function handleOperatorChange() {
currentCondition.value.value = ''
currentCondition.value.selectedOriginalValues = []
if (currentCondition.value.operator === 'in') {
loadFieldValues()
}
}
async function loadFieldValues() {
if (!currentCondition.value.field) return
loadingFieldValues.value = true
try {
const response = await getFieldValues(currentCondition.value.field)
const rawValues = response.data || []
console.log('=== 字段值加载调试 ===')
console.log('字段:', currentCondition.value.field)
console.log('字段类型:', currentFieldType.value)
console.log('后端返回的原始值:', rawValues)
const dictRef = dictMap[currentCondition.value.field]
console.log('对应的字典引用:', dictRef)
console.log('对应的字典数据:', dictRef ? dictRef.value : '无')
//
fieldValues.value = rawValues.map(rawValue => {
// 使
if (currentFieldType.value === 'dict') {
const displayLabel = getDictLabel(currentCondition.value.field, rawValue)
console.log(`转换: ${rawValue} -> ${displayLabel}`)
return {
originalValue: rawValue,
displayLabel: displayLabel
}
} else {
// 使
return {
originalValue: rawValue,
displayLabel: String(rawValue)
}
}
})
console.log('最终字段值:', fieldValues.value)
console.log('========================')
} catch (error) {
console.error('获取字段值失败:', error)
proxy.$modal.msgError('获取字段值失败')
fieldValues.value = []
} finally {
loadingFieldValues.value = false
}
}
function addCondition() {
if (canAddCondition.value) {
const condition = JSON.parse(JSON.stringify(currentCondition.value))
if (condition.operator === 'in') {
condition.value = condition.selectedOriginalValues
delete condition.selectedOriginalValues
}
conditions.value.push(condition)
currentCondition.value = {
field: '',
operator: '',
value: '',
selectedOriginalValues: []
}
fieldValues.value = []
proxy.$modal.msgSuccess('条件添加成功')
}
}
function removeCondition(index) {
conditions.value.splice(index, 1)
proxy.$modal.msgSuccess('条件删除成功')
}
function cancelFilter() {
filterDialogVisible.value = false
conditions.value = []
}
// 1. applyFilters
function applyFilters() {
if (conditions.value.length === 0) {
proxy.$modal.msgWarning('请至少添加一个筛选条件')
return
}
const queryParams = {}
conditions.value.forEach(condition => {
const { field, operator, value } = condition
switch (operator) {
case 'eq':
queryParams[field] = value
break
case 'like':
queryParams[field] = value
break
case 'in':
if (Array.isArray(value) && value.length > 0) {
queryParams[field] = value.join(',')
}
break
case 'null':
queryParams[field] = 'IS_NULL'
break
case 'notNull':
queryParams[field] = 'NOT_NULL'
break
case 'gt':
queryParams[field] = `GT:${value}`
break
case 'lt':
queryParams[field] = `LT:${value}`
break
case 'ge':
queryParams[field] = `GE:${value}`
break
case 'le':
queryParams[field] = `LE:${value}`
break
}
})
//
emit('filter', queryParams)
filterDialogVisible.value = false
proxy.$modal.msgSuccess('筛选条件已保存')
}
// 2.
function resetFilter() {
conditions.value = []
currentCondition.value = {
field: '',
operator: '',
value: '',
selectedOriginalValues: []
}
fieldValues.value = []
proxy.$modal.msgSuccess('筛选条件已重置')
}
const emit = defineEmits(['filter'])
defineExpose({
openFilterDialog
})
</script>
<style scoped>
.condition-definition {
padding: 20px;
border: 1px solid #e4e7ed;
border-radius: 4px;
margin-bottom: 20px;
background-color: #fafafa;
}
.condition-definition h4 {
margin-top: 0;
margin-bottom: 15px;
color: #303133;
}
.condition-list {
max-height: 300px;
overflow-y: auto;
}
.condition-list h4 {
margin-top: 0;
margin-bottom: 10px;
color: #303133;
}
.condition-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 12px 15px;
margin: 8px 0;
background-color: #f5f7fa;
border-radius: 4px;
border-left: 4px solid #409eff;
}
.condition-text {
flex: 1;
font-size: 14px;
color: #606266;
}
.dialog-footer {
display: flex;
justify-content: flex-end;
align-items: center;
}
.custom-filter {
display: inline-block;
}
.dialog-footer {
display: flex;
justify-content: space-between;
align-items: center;
}
</style>

View File

@ -32,6 +32,15 @@
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<!-- 新增自定义筛选按钮 -->
<CustomFilter ref="customFilterRef" @filter="handleCustomFilter" />
<span v-if="isCustomFilterActive" style="color: #67c23a; margin-left: 5px;">
<i class="el-icon-success"></i> 筛选条件已激活
</span>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
@ -54,6 +63,24 @@
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<!-- 新增显示已应用的筛选条件 -->
<div v-if="appliedFilters.length > 0" class="applied-filters mb8">
<div class="filter-title">已应用筛选条件:</div>
<el-tag
v-for="(filter, index) in appliedFilters"
:key="index"
closable
@close="removeAppliedFilter(index)"
type="primary"
style="margin-right: 8px; margin-bottom: 8px;"
>
{{ filter.text }}
</el-tag>
<el-button link type="primary" @click="clearAllFilters" style="margin-left: 10px;">
清除所有
</el-button>
</div>
<div style="margin-bottom: 10px;">
<el-button type="info" plain icon="Setting" @click="openColumnDialog">显示列</el-button>
</div>
@ -346,6 +373,40 @@
<span style="font-weight: bold; color: #333;">当前体重</span>
</template>
</el-table-column>
<el-table-column
v-if="columns['weaningDayAge'].visible"
label="断奶日龄"
align="center"
prop="weaningDayAge"
width="120"
sortable
>
<template #header>
<span style="font-weight: bold; color: #333;">断奶日龄</span>
</template>
</el-table-column>
<el-table-column
v-if="columns['weaningDailyGain'].visible"
label="断奶日增重"
align="center"
prop="weaningDailyGain"
width="120"
sortable
>
<template #header>
<span style="font-weight: bold; color: #333;">断奶日增重</span>
</template>
</el-table-column>
<!-- <el-table-column
v-if="columns['breedStatusId'].visible"
label="繁育状态id"
@ -935,7 +996,9 @@
<el-checkbox label="weaningDate">断奶日期</el-checkbox>
<el-checkbox label="statusId">羊只状态</el-checkbox>
<el-checkbox label="weaningWeight">断奶体重</el-checkbox>
<el-checkbox label="currentWeight">当前体重</el-checkbox>
<el-checkbox label="currentWeight">当前体重</el-checkbox>\
<el-checkbox label="weaningDayAge">断奶日龄</el-checkbox>
<el-checkbox label="weaningDailyGain">断奶日增重</el-checkbox>
<!-- <el-checkbox label="breedStatusId">繁育状态id</el-checkbox> -->
<el-checkbox label="breed">繁殖状态</el-checkbox>
<!-- <el-checkbox label="bsFatherId">父号id</el-checkbox> -->
@ -993,12 +1056,20 @@
<script setup name="Sheep_file">
import { listSheep_file, getSheep_file } from "@/api/fileManagement/sheep_file"
//
import CustomFilter from '@/components/CustomFilter/index.vue'
//
const customFilterRef = ref()
const appliedFilters = ref([])
// 1.
const customFilterParams = ref({})
const isCustomFilterActive = ref(false)
const { proxy } = getCurrentInstance()
const { sheep_gender } = proxy.useDict('sheep_gender')
console.log('性别字典数据:', sheep_gender) //
const { breed_type } = proxy.useDict('breed_type')
const { controlled } = proxy.useDict('controlled')
const { source } = proxy.useDict('source')
@ -1014,7 +1085,7 @@ const total = ref(0)
const title = ref("")
const columnDialogVisible = ref(false)
const selectedColumns = ref([
'id', 'bsManageTags', 'ranchId', 'drRanch', 'sheepfoldId', 'sheepfoldName', 'electronicTags', 'varietyId', 'variety', 'family', 'name', 'gender', 'birthday', 'dayAge', 'monthAge', 'parity', 'birthWeight', 'weaningDate', 'statusId', 'weaningWeight', 'currentWeight', 'breedStatusId', 'breed', 'bsFatherId', 'fatherManageTags', 'bsMotherId', 'motherManageTags', 'receptorId', 'receptorManageTags', 'fatherFatherId', 'grandfatherManageTags', 'fatherMotherId', 'grandmotherManageTags', 'fatherId', 'maternalGrandfatherManageTags', 'motherId', 'maternalGrandmotherManageTags', 'matingDate', 'matingTypeId', 'pregDate', 'lambingDate', 'lambingDay', 'matingDay', 'gestationDay', 'expectedDate', 'postLambingDay', 'lactationDay', 'anestrousDay', 'matingCounts', 'matingTotal', 'miscarriageCounts', 'comment', 'controlled', 'body', 'breast', 'source', 'sourceDate', 'sourceRanchId', 'sourceRanch', 'updateBy', 'updateTime', 'createBy', 'createTime'
'id', 'bsManageTags', 'ranchId', 'drRanch', 'sheepfoldId', 'sheepfoldName', 'electronicTags', 'varietyId', 'variety', 'family', 'name', 'gender', 'birthday', 'dayAge', 'monthAge', 'parity', 'birthWeight', 'weaningDate', 'statusId', 'weaningWeight', 'currentWeight','weaningDayAge', 'weaningDailyGain','breedStatusId', 'breed', 'bsFatherId', 'fatherManageTags', 'bsMotherId', 'motherManageTags', 'receptorId', 'receptorManageTags', 'fatherFatherId', 'grandfatherManageTags', 'fatherMotherId', 'grandmotherManageTags', 'fatherId', 'maternalGrandfatherManageTags', 'motherId', 'maternalGrandmotherManageTags', 'matingDate', 'matingTypeId', 'pregDate', 'lambingDate', 'lambingDay', 'matingDay', 'gestationDay', 'expectedDate', 'postLambingDay', 'lactationDay', 'anestrousDay', 'matingCounts', 'matingTotal', 'miscarriageCounts', 'comment', 'controlled', 'body', 'breast', 'source', 'sourceDate', 'sourceRanchId', 'sourceRanch', 'updateBy', 'updateTime', 'createBy', 'createTime'
])
const isAllSelected = ref(false)
const columns = reactive({
@ -1039,6 +1110,8 @@ const columns = reactive({
statusId: { visible: true },
weaningWeight: { visible: true },
currentWeight: { visible: true },
weaningDayAge: { visible: true },
weaningDailyGain: { visible: true },
breedStatusId: { visible: true },
breed: { visible: true },
bsFatherId: { visible: true },
@ -1107,13 +1180,24 @@ const data = reactive({
const { queryParams, form, rules } = toRefs(data)
/** 查询羊只档案列表 */
function getList() {
// 5. getList
function getList(queryParamOverride = null) {
loading.value = true
listSheep_file(queryParams.value).then(response => {
//
const finalQueryParams = queryParamOverride || { ...queryParams.value }
//
if (isCustomFilterActive.value && Object.keys(customFilterParams.value).length > 0) {
Object.assign(finalQueryParams, customFilterParams.value)
}
listSheep_file(finalQueryParams).then(response => {
sheep_fileList.value = response.rows
total.value = response.total
loading.value = false
}).catch(() => {
loading.value = false
})
}
@ -1141,6 +1225,8 @@ function reset() {
statusId: null,
weaningWeight: null,
currentWeight: null,
weaningDayAge: null,
weaningDailyGain:null,
breedStatusId: null,
breed: null,
bsFatherId: null,
@ -1191,13 +1277,38 @@ function reset() {
/** 搜索建议功能 */
function handleQuery() {
queryParams.value.pageNum = 1
getList()
//
const finalQueryParams = { ...queryParams.value }
//
if (isCustomFilterActive.value && Object.keys(customFilterParams.value).length > 0) {
Object.assign(finalQueryParams, customFilterParams.value)
}
//
loading.value = true
listSheep_file(finalQueryParams).then(response => {
sheep_fileList.value = response.rows
total.value = response.total
loading.value = false
}).catch(() => {
loading.value = false
})
}
/** 重置按钮操作 */
// 4. resetQuery
function resetQuery() {
proxy.resetForm("queryRef")
handleQuery()
//
customFilterParams.value = {}
appliedFilters.value = []
isCustomFilterActive.value = false
//
queryParams.value.pageNum = 1
getList()
}
//
@ -1218,11 +1329,16 @@ function handleDelete(row) {
}).catch(() => {})
}
/** 导出按钮操作 */
// 8. handleExport
function handleExport() {
proxy.download('sheep_file/sheep_file/export', {
...queryParams.value
}, `sheep_file_${new Date().getTime()}.xlsx`)
const exportParams = { ...queryParams.value }
//
if (isCustomFilterActive.value && Object.keys(customFilterParams.value).length > 0) {
Object.assign(exportParams, customFilterParams.value)
}
proxy.download('sheep_file/sheep_file/export', exportParams, `sheep_file_${new Date().getTime()}.xlsx`)
}
//
@ -1266,12 +1382,175 @@ function confirmColumnSettings() {
//
function resetColumnSettings() {
selectedColumns.value = [
'id', 'bsManageTags', 'ranchId', 'drRanch', 'sheepfoldId', 'sheepfoldName', 'electronicTags', 'varietyId', 'variety', 'family', 'name', 'gender', 'birthday', 'dayAge', 'monthAge', 'parity', 'birthWeight', 'weaningDate', 'statusId', 'weaningWeight', 'currentWeight', 'breedStatusId', 'breed', 'bsFatherId', 'fatherManageTags', 'bsMotherId', 'motherManageTags', 'receptorId', 'receptorManageTags', 'fatherFatherId', 'grandfatherManageTags', 'fatherMotherId', 'grandmotherManageTags', 'fatherId', 'maternalGrandfatherManageTags', 'motherId', 'maternalGrandmotherManageTags', 'matingDate', 'matingTypeId', 'pregDate', 'lambingDate', 'lambingDay', 'matingDay', 'gestationDay', 'expectedDate', 'postLambingDay', 'lactationDay', 'anestrousDay', 'matingCounts', 'matingTotal', 'miscarriageCounts', 'comment', 'controlled', 'body', 'breast', 'source', 'sourceDate', 'sourceRanchId', 'sourceRanch', 'updateBy', 'updateTime', 'createBy', 'createTime'
'id', 'bsManageTags', 'ranchId', 'drRanch', 'sheepfoldId', 'sheepfoldName', 'electronicTags', 'varietyId', 'variety', 'family', 'name', 'gender', 'birthday', 'dayAge', 'monthAge', 'parity', 'birthWeight', 'weaningDate', 'statusId', 'weaningWeight', 'currentWeight','weaningDayAge', 'weaningDailyGain','breedStatusId', 'breed', 'bsFatherId', 'fatherManageTags', 'bsMotherId', 'motherManageTags', 'receptorId', 'receptorManageTags', 'fatherFatherId', 'grandfatherManageTags', 'fatherMotherId', 'grandmotherManageTags', 'fatherId', 'maternalGrandfatherManageTags', 'motherId', 'maternalGrandmotherManageTags', 'matingDate', 'matingTypeId', 'pregDate', 'lambingDate', 'lambingDay', 'matingDay', 'gestationDay', 'expectedDate', 'postLambingDay', 'lactationDay', 'anestrousDay', 'matingCounts', 'matingTotal', 'miscarriageCounts', 'comment', 'controlled', 'body', 'breast', 'source', 'sourceDate', 'sourceRanchId', 'sourceRanch', 'updateBy', 'updateTime', 'createBy', 'createTime'
]
updateColumnVisibility()
localStorage.setItem('selectedColumns', JSON.stringify(selectedColumns.value))
}
/**
* 处理自定义筛选
*/
/**
* 处理自定义筛选
*/
//
function handleCustomFilter(filterParams) {
console.log('接收到筛选参数:', filterParams)
//
appliedFilters.value = Object.keys(filterParams).map(field => {
const fieldConfig = availableFields.find(f => f.value === field)
const value = filterParams[field]
let text = ''
if (!fieldConfig) {
text = `${field}: ${value}`
} else if (value === 'IS_NULL') {
text = `${fieldConfig.label}: 为空`
} else if (value === 'NOT_NULL') {
text = `${fieldConfig.label}: 不为空`
} else if (value.startsWith('GT:')) {
text = `${fieldConfig.label} > ${value.substring(3)}`
} else if (value.startsWith('LT:')) {
text = `${fieldConfig.label} < ${value.substring(3)}`
} else if (value.startsWith('GE:')) {
text = `${fieldConfig.label}${value.substring(3)}`
} else if (value.startsWith('LE:')) {
text = `${fieldConfig.label}${value.substring(3)}`
} else if (value.includes(',')) {
const values = value.split(',')
if (['gender', 'status_id', 'mating_type_id'].includes(field)) {
const dictLabels = values.map(v => getDictLabel(field, v)).join(', ')
text = `${fieldConfig.label} 在 [${dictLabels}] 中`
} else {
text = `${fieldConfig.label} 在 [${value}] 中`
}
} else {
if (['gender', 'status_id', 'mating_type_id'].includes(field)) {
const dictLabel = getDictLabel(field, value)
text = `${fieldConfig.label}: ${dictLabel}`
} else {
text = `${fieldConfig.label}: ${value}`
}
}
return { field, value, text }
})
//
customFilterParams.value = filterParams
isCustomFilterActive.value = Object.keys(filterParams).length > 0
}
/**
* 获取字典标签
*/
function getDictLabel(field, value) {
let dictOptions = []
//
if (field === 'gender') {
dictOptions = sheep_gender.value || []
} else if (field === 'status_id') {
dictOptions = sheep_status.value || []
} else if (field === 'mating_type_id') {
dictOptions = breed_type.value || []
} else if (field === 'controlled') {
dictOptions = controlled.value || []
} else if (field === 'source') {
dictOptions = source.value || []
}
if (!dictOptions || !Array.isArray(dictOptions) || dictOptions.length === 0) {
return String(value)
}
//
const valueStr = String(value)
const item = dictOptions.find(item => String(item.value) === valueStr)
return item ? item.label : String(value)
}
/**
* 移除单个筛选条件
*/
// 6. removeAppliedFilter
function removeAppliedFilter(index) {
const filter = appliedFilters.value[index]
//
if (customFilterParams.value[filter.field]) {
delete customFilterParams.value[filter.field]
}
appliedFilters.value.splice(index, 1)
//
if (appliedFilters.value.length === 0) {
isCustomFilterActive.value = false
}
}
/**
* 清除所有筛选条件
*/
// 7. clearAllFilters
function clearAllFilters() {
customFilterParams.value = {}
appliedFilters.value = []
isCustomFilterActive.value = false
//
}
//
const availableFields = [
{ label: '耳号', value: 'bs_manage_tags' },
{ label: '电子耳号', value: 'electronic_tags'},
{ label: '牧场名称', value: 'dr_ranch' },
{ label: '羊舍名称', value: 'sheepfold_name'},
{ label: '品种', value: 'variety'},
{ label: '家系', value: 'family' },
{ label: '羊只类型', value: 'name'},
{ label: '性别', value: 'gender'},
{ label: '出生日期', value: 'birthday'},
{ label: '日龄', value: 'day_age'},
{ label: '月龄', value: 'month_age'},
{ label: '胎次', value: 'parity'},
{ label: '出生体重', value: 'birth_weight' },
{ label: '断奶日期', value: 'weaning_date' },
{ label: '羊只状态', value: 'status_id' },
{ label: '断奶体重', value: 'weaning_weight' },
{ label: '当前体重', value: 'current_weight' },
{ label: '断奶日龄', value: 'weaning_day_age' },
{ label: '断奶日增重', value: 'weaning_daily_gain' },
{ label: '繁殖状态', value: 'breed' },
{ label: '父亲耳号', value: 'father_manage_tags' },
{ label: '母亲耳号', value: 'mother_manage_tags'},
{ label: '受体耳号', value: 'receptor_manage_tags' },
{ label: '配种类型', value: 'mating_type_id' },
{ label: '孕检日期', value: 'preg_date'},
{ label: '产羔日期', value: 'lambing_date'},
{ label: '产羔时怀孕天数', value: 'lambing_day'},
{ label: '配后天数', value: 'mating_day' },
{ label: '怀孕天数', value: 'gestation_day'},
{ label: '预产日期', value: 'expected_date'},
{ label: '产后天数', value: 'post_lambing_day'},
{ label: '泌乳天数', value: 'lactation_day'},
{ label: '空怀天数', value: 'anestrous_day' },
{ label: '配种次数', value: 'mating_counts' },
{ label: '累计配种次数', value: 'mating_total'},
{ label: '累计流产次数', value: 'miscarriage_counts' },
{ label: '体况评分', value: 'body' },
{ label: '乳房评分', value: 'breast'},
{ label: '入群日期', value: 'source_date' },
{ label: '修改日期', value: 'update_time'},
{ label: '创建日期', value: 'create_time'},
]
getList()
</script>
@ -1283,4 +1562,26 @@ getList()
margin: 5px;
width: calc(30% - 20px);
}
.applied-filters {
padding: 12px 16px;
background-color: #f8f9fa;
border-radius: 4px;
border: 1px solid #e9ecef;
}
.filter-title {
font-weight: 600;
margin-bottom: 8px;
color: #495057;
}
.filter-active-tip {
display: inline-flex;
align-items: center;
margin-left: 8px;
font-size: 12px;
color: #67c23a;
}
</style>