feat(ear-tag): 新增耳标登记功能

- 添加耳标登记页面,支持新增和编辑功能
- 实现养殖场、养殖舍、养殖栏的级联选择- 添加耳标信息的详细录入,包括生物芯片耳标号、电子耳标号等
-优化列表页面,增加搜索和筛选功能
- 重构表格组件,支持更多列类型和操作
This commit is contained in:
aixianling
2024-12-25 12:12:47 +08:00
parent 06fa7b636e
commit ee15427e88
5 changed files with 156 additions and 82 deletions

View File

@@ -1,7 +1,21 @@
<script>
import {mapState} from "vuex"
import AiSelect from "dui/packages/basic/AiSelect.vue";
const columns = [
{label: "序号", type: "index"},
{label: "生物芯片耳标号", prop: "biochipEarNumber"},
{label: "电子耳标号", prop: "electronicEarNumber"},
{label: "原厂耳标号", prop: "originalEarNumber"},
{label: "戴耳标照片", prop: "picture", upload: 1},
{label: "品种", prop: "variety", select: 1, dict: "variety"},
{label: "类别", prop: "category", select: 1, dict: "category"},
{label: "日龄/天", prop: "age", edit: 1},
{label: "体重/公斤", prop: "weight", edit: 1},
]
export default {
name: "etAdd",
components: {AiSelect},
props: {
instance: Function,
permissions: Function,
@@ -10,10 +24,18 @@ export default {
data() {
return {
detail: {},
columns,
}
},
computed: {
isAuditing: v => v.detail.auditStatus == 1
...mapState(["user"]),
userinfo: v => v.user.info || {},
isAdd: v => !v.$route.query.id,
isEdit: v => v.$route.query.edit == 1,
pageTitle: v => {
const appName = v.$parent.menuName || v.$parent.$options.label
return v.$route.query.id ? v.isEdit ? `编辑${appName}` : `${appName}详情` : `新增${appName}`
},
},
methods: {
back(params = {}) {
@@ -21,26 +43,29 @@ export default {
},
getDetail() {
const {id} = this.$route.query
this.instance.post("/api/user/auth/page", null, {params: {id}}).then(res => {
return this.instance.post("/api/breed/earTag/page", {id}).then(res => {
if (res?.data?.records) {
const detail = res.data.records[0] || {}
let {picture = "{}"} = detail
picture = JSON.parse(picture)
this.detail = {...detail, ...picture}
return this.detail = {...detail}
}
})
},
getNeedCerts(type) {
return this.$parent.certificates.filter(e => !e.permit || e.permit.includes(type))
},
handleAudit(auditStatus) {
const auditLabels = {
2: "同意通过", 3: "驳回"
getList() {
const {penId} = this.detail
this.instance.post("/api/breed/earTag/getEarTagByPenId", null, {params: {penId}}).then(res => {
if (res?.data) {
this.$set(this.detail, 'detailList', res.data)
}
this.$confirm(`是否要${auditLabels[auditStatus]}认证?`).then(() => {
this.instance.post("/api/user/audit", null, {params:{
id: this.detail.id, auditStatus
}}).then(res => {
})
},
handleDelete(index) {
this.$confirm("确定删除该条数据?").then(() => {
this.detail.splice(index, 1)
})
},
submit() {
this.$refs.detail.validate().then(() => {
this.instance.post("/api/breed/earTag/addOrEdit", this.detail).then(res => {
if (res?.code == 0) {
this.$confirm("是否要返回列表?", "提交成功").then(() => this.back())
}
@@ -49,32 +74,90 @@ export default {
}
},
created() {
this.dict.load("auditStatus")
this.dict.load("auditStatus", "category", "variety")
this.getDetail()
}
}
</script>
<template>
<ai-page title="认证材料" class="etAdd" showBack content-string="detail">
<el-form size="small" label-position="top" :model="detail" ref="detail">
<ai-card title="认证材料">
<div class="grid">
<el-form-item v-for="(op,i) in getNeedCerts(detail.type)" :key="i" v-bind="op" :rules="{required:true,message:`请上传${op.label}`,trigger:'change'}">
<el-image :src="detail[op.prop]" :preview-src-list="[detail[op.prop]]"/>
<ai-page :title="pageTitle" class="etAdd" showBack content-string="blank">
<el-form size="small" label-width="120px" :model="detail" ref="detail">
<ai-card title="基础信息">
<div class="grid c-3">
<template v-if="isAdd">
<el-form-item label="养殖场" prop="farmId">
<ai-select v-model="detail.farmId" :instance="instance" :action="`/api/siteUser/querySiteByUserId?userId=${userinfo.id}`" :prop="{label:'name'}"/>
</el-form-item>
<el-form-item label="养殖舍" prop="houseId">
<ai-select v-model="detail.houseId" :instance="instance" :action="`/api/siteUser/querySiteById?id=${detail.farmId||-1}`" :prop="{label:'name'}"/>
</el-form-item>
<el-form-item label="养殖栏" prop="penId">
<ai-select v-model="detail.penId" @change="getList" :instance="instance" :action="`/api/siteUser/querySiteById?id=${detail.houseId||-1}`" :prop="{label:'name'}"/>
</el-form-item>
</template>
<template v-else>
<el-form-item label="养殖场" prop="farmId">
<b v-text="detail.farmName"/>
</el-form-item>
<el-form-item label="养殖舍" prop="houseId">
<b v-text="detail.houseName"/>
</el-form-item>
<el-form-item label="养殖栏" prop="penId">
<b v-text="detail.penName"/>
</el-form-item>
</template>
</div>
</ai-card>
<ai-card title="耳标录入">
<ai-table v-if="isAdd" :tableData="detail.detailList" :colConfigs="columns" :isShowPagination="!1">
<el-table-column slot="options" label="操作" fixed="right" align="center">
<template slot-scope="{row,$index}">
<div class="table-options">
<el-button type="text" class="deleteBtn" @click="handleDelete($index)">删除</el-button>
</div>
</template>
</el-table-column>
</ai-table>
<div class="grid" v-else>
<el-form-item label="生物芯片耳标号">
<b v-text="detail.biochipEarNumber"/>
</el-form-item>
<el-form-item label="电子耳标号" prop="electronicEarNumber">
<el-input v-if="isEdit" v-model="detail.electronicEarNumber" placeholder="请输入" clearable/>
<b v-else v-text="detail.electronicEarNumber"/>
</el-form-item>
<el-form-item label="原厂耳标号" prop="originalEarNumber">
<el-input v-if="isEdit" v-model="detail.originalEarNumber" placeholder="请输入" clearable/>
<b v-else v-text="detail.originalEarNumber"/>
</el-form-item>
<el-form-item label="戴耳标照片" class="row">
<el-image :src="detail.picture" :preview-src-list="[detail.picture]"/>
</el-form-item>
<el-form-item label="品种" prop="variety">
<ai-select v-if="isEdit" v-model="detail.variety" dict="variety"/>
<b v-else v-text="detail.variety"/>
</el-form-item>
<el-form-item label="类别" prop="category">
<ai-select v-if="isEdit" v-model="detail.category" dict="category"/>
<b v-else v-text="detail.category"/>
</el-form-item>
<el-form-item label="日龄/天">
<el-input v-if="isEdit" v-model.number="detail.age" placeholder="请输入" clearable/>
<b v-else v-text="detail.age"/>
</el-form-item>
<el-form-item label="体重/公斤">
<el-input v-if="isEdit" v-model.number="detail.weight" placeholder="请输入" clearable/>
<b v-else v-text="detail.weight"/>
</el-form-item>
</div>
</ai-card>
<ai-card title="备注说明">
<div v-text="detail.remark"/>
</ai-card>
</el-form>
<div slot="footer">
<template v-if="isAuditing">
<el-button type="primary" @click="handleAudit(2)">同意</el-button>
<el-button type="danger" @click="handleAudit(3)">拒绝</el-button>
<template v-if="isEdit||isAdd">
<el-button type="primary" @click="submit">提交</el-button>
</template>
<el-button @click="back">关闭</el-button>
<el-button @click="back">返回</el-button>
</div>
</ai-page>
</template>

View File

@@ -1,5 +1,5 @@
<script>
import AiSearchBar from "dui/packages/layout/AiSearchBar.vue";
import {mapState} from "vuex"
const columns = [
{label: "序号", type: "index"},
@@ -12,7 +12,6 @@ const columns = [
]
export default {
name: "etList",
components: {AiSearchBar},
props: {
instance: Function,
dict: Object,
@@ -28,6 +27,19 @@ export default {
form: {}
}
},
computed: {
...mapState(['user']),
userinfo: v => v.user.info || {}
},
watch: {
search: {
deep: true,
handler() {
this.page.pageNum = 1
this.getTableData()
}
}
},
methods: {
getTableData() {
this.instance.post("/api/breed/earTag/page", {...this.page, ...this.search}).then(res => {
@@ -49,7 +61,7 @@ export default {
}
},
created() {
this.dict.load("auditStatus")
this.dict.load("auditStatus", "category", "variety")
this.getTableData()
}
}
@@ -59,14 +71,14 @@ export default {
<ai-page class="etList" title="耳标登记">
<ai-search-bar>
<template #left>
<ai-select placeholder="所属机构" v-model="search.userId" dict="authStatus"/>
<ai-select placeholder="养殖场" v-model="search.farmId" dict="authStatus"/>
<ai-select placeholder="养殖舍" v-model="search.houseId" dict="authStatus"/>
<ai-select placeholder="养殖栏" v-model="search.penId" dict="authStatus"/>
<ai-select placeholder="全部机构" v-model="search.userId" :instance="instance" :action="`/api/breed/earTag/getOrgList`" :prop="{label:'name'}"/>
<ai-select placeholder="全部养殖场" v-model="search.farmId" :instance="instance" :action="`/api/siteUser/querySiteByUserId?userId=${search.userId||''}`" :prop="{label:'name'}"/>
<ai-select placeholder="全部养殖舍" v-model="search.houseId" :instance="instance" :action="`/api/siteUser/querySiteById?id=${search.farmId||-1}`" :prop="{label:'name'}"/>
<ai-select placeholder="全部养殖栏" v-model="search.penId" :instance="instance" :action="`/api/siteUser/querySiteById?id=${search.houseId||-1}`" :prop="{label:'name'}"/>
<el-input placeholder="戴标员" v-model="search.userName" dict="authStatus" size="small" clearable/>
<el-input placeholder="生物芯片耳标号" v-model="search.biochipEarNumber" dict="authStatus" size="small" clearable/>
<ai-select placeholder="类别" v-model="search.category" dict="authStatus"/>
<ai-select placeholder="品种" v-model="search.variety" dict="authStatus"/>
<ai-select placeholder="全部类别" v-model="search.category" dict="category"/>
<ai-select placeholder="全部品种" v-model="search.variety" dict="variety"/>
<ai-search label="登记日期">
<el-date-picker v-model="search.beginDate" type="datetime" placeholder="开始日期" size="small"/>
<el-date-picker v-model="search.endDate" type="datetime" placeholder="结束日期" size="small"/>
@@ -76,14 +88,10 @@ export default {
<el-input placeholder="最大日龄" v-model="search.endAge" size="small" clearable/>
</ai-search>
</template>
<template #right>
<el-input size="small" placeholder="搜索账号" v-model="search.name" clearable
@change="page.pageNum=1, getTableData()" @getList="getTableData"/>
</template>
</ai-search-bar>
<ai-search-bar>
<template #left>
<el-button type="primary" icon="iconfont iconAdd" @clicl="$router.push({hash:'#add'})">新增</el-button>
<el-button type="primary" icon="iconfont iconAdd" @click="$router.push({hash:'#add'})">新增</el-button>
</template>
</ai-search-bar>
<ai-table :tableData="tableData" :colConfigs="columns" :dict="dict" @getList="getTableData"
@@ -91,8 +99,8 @@ export default {
<el-table-column slot="options" label="操作" fixed="right" align="center">
<template slot-scope="{row}">
<div class="table-options">
<el-button type="text">查看</el-button>
<el-button type="text">编辑</el-button>
<el-button type="text" @click="$router.push({hash:'#add',query:{id:row.id}})">查看</el-button>
<el-button type="text" @click="$router.push({hash:'#add',query:{id:row.id,edit:1}})">编辑</el-button>
<el-button type="text" class="deleteBtn" @click="handleDelete(row.id)">删除</el-button>
</div>
</template>

View File

@@ -21,33 +21,17 @@
:is="colConfig.component"
:col-config="colConfig">
</component>
<el-table-column
v-else-if="colConfig.dict"
:key="colConfig.id"
v-bind="colConfig">
<span slot-scope="{row}" :style="{color:colConfig.color||dict.getColor(colConfig.dict, row[colConfig.prop])}">
{{ dict.getLabel(colConfig.dict, row[colConfig.prop]) }}
</span>
</el-table-column>
<el-table-column
v-else-if="colConfig.openType"
:key="colConfig.id"
v-bind="colConfig">
<template v-slot="{row}">
<ai-open-data :type="colConfig.openType" :openid="row[colConfig.prop]"/>
</template>
</el-table-column>
<el-table-column
v-else-if="colConfig.type"
:key="colConfig.id"
v-bind="colConfig"
:width="colConfig.width || 100"/>
<el-table-column v-else v-bind="colConfig" :key="colConfig.id"
:show-overflow-tooltip="colConfig['show-overflow-tooltip'] != false">
<template slot-scope="scope">
<render-slot v-if="colConfig.render" :render="colConfig.render" :row="scope.row" :index="scope.$index"
:column="colConfig"/>
<span v-else>{{ getValue(colConfig, scope.row) }}</span>
<el-table-column v-else-if="colConfig.type" v-bind="colConfig" :width="colConfig.width||80" align="center"/>
<el-table-column v-else v-bind="colConfig">
<template slot-scope="{row,$index}">
<span v-if="colConfig.dict" :style="{color:colConfig.color||dict.getColor(colConfig.dict, row[colConfig.prop])}" v-text="dict.getLabel(colConfig.dict, row[colConfig.prop])"/>
<render-slot v-else-if="colConfig.render" :render="colConfig.render" :row="row" :index="$index" :column="colConfig"/>
<el-input v-else-if="colConfig.edit==1" v-model="row[colConfig.prop]" :index="$index"/>
<el-input v-else-if="colConfig.num==1" v-model.number="row[colConfig.prop]" :index="$index"/>
<ai-select v-else-if="colConfig.select==1" v-model="row[colConfig.prop]" v-bind="colConfig"/>
<ai-uploader v-else-if="colConfig.upload==1" v-model="row[colConfig.prop]" v-bind="colConfig"/>
<ai-open-data v-else-if="colConfig.openType" :type="colConfig.openType" :openid="row[colConfig.prop]"/>
<span v-else>{{ getValue(colConfig, row) }}</span>
</template>
</el-table-column>
</template>
@@ -88,6 +72,7 @@
<script>
import moment from 'dayjs'
import dict from "../../lib/js/dict"
import AiUploader from "./AiUploader.vue";
export default {
name: 'AiTable',
@@ -121,6 +106,7 @@ export default {
}
},
components: {
AiUploader,
renderSlot: {
functional: true,
props: {

View File

@@ -70,6 +70,11 @@ export default {
}
&.blank {
width: 100%;
overflow-y: auto;
}
&.hasFooter {
padding-bottom: 64px;
}

View File

@@ -3,7 +3,7 @@
<div ref="AiSearchBarZone" class="searchLeftZone">
<slot name="left"/>
</div>
<div class="searchRightZone" ref="searchRightZone">
<div class="searchRightZone" ref="searchRightZone" v-if="$slots.right">
<slot name="right"/>
</div>
<ai-pull-down v-if="!isSingleRow" v-model="expand"/>
@@ -30,14 +30,6 @@ export default {
}
},
methods: {
handlePullDown(style) {
this.searchBarStyle = style
if (style.height == 'auto') {
this.searchBarStyle.marginBottom = '16px'
} else {
this.searchBarStyle.marginBottom = '0'
}
},
initSize() {
this.height = this.$refs?.AiSearchBarZone?.offsetHeight
this.rightHeight = this.$refs?.searchRightZone?.offsetHeight + 12