Merge remote-tracking branch 'origin/main'

This commit is contained in:
zyk
2026-03-07 11:22:59 +08:00
12 changed files with 316 additions and 72 deletions

View File

@@ -1,11 +1,11 @@
import request from '@/utils/request' import request from '@/utils/request'
// 增加模糊搜索耳号 API // 【修改】增加 sheepfoldId 过滤参数
export function searchEarNumbers(query) { export function searchEarNumbers(query, sheepfoldId) {
return request({ return request({
url: '/saleRecord/saleRecord/searchEarNumbers', url: '/saleRecord/saleRecord/searchEarNumbers',
method: 'get', method: 'get',
params: { query } params: { query, sheepfoldId }
}) })
} }
@@ -82,3 +82,12 @@ export function getSheepInfo(bsManageTags) {
params: { bsManageTags } params: { bsManageTags }
}) })
} }
// 【新增】查询已销售的羊只耳号(用于查询栏)
export function searchSoldEarNumbers(query) {
return request({
url: '/saleRecord/saleRecord/searchSoldEarNumbers',
method: 'get',
params: { query }
})
}

View File

@@ -605,12 +605,27 @@ function loadSheepTypeList() {
}); });
} }
function searchEarNumber(query) { const searchEarNumber = async (query) => {
if (!query) { earOptions.value = []; return } if (!query || query.trim() === '') {
earOptions.value = []
return
}
earLoading.value = true earLoading.value = true
searchEarNumbers(query.trim()).then(res => { try {
earOptions.value = res.data || [] const res = await searchEarNumbers(query.trim())
}).finally(() => earLoading.value = false) 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() { function handlePaste() {
nextTick(() => handlePasteSubmit()) nextTick(() => handlePasteSubmit())

View File

@@ -522,12 +522,27 @@ function loadVarietyOptions() {
}) })
} }
function searchEarNumber(query) { const searchEarNumber = async (query) => {
if (!query) { earOptions.value = []; return } if (!query || query.trim() === '') {
earOptions.value = []
return
}
earLoading.value = true earLoading.value = true
searchEarNumbers(query.trim()).then(res => { try {
earOptions.value = res.data || [] const res = await searchEarNumbers(query.trim())
}).finally(() => earLoading.value = false) 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 clearEarNumbers() { function clearEarNumbers() {

View File

@@ -540,12 +540,27 @@ function loadVarietyOptions() {
varietyOptions.value = res.rows; varietyOptions.value = res.rows;
}) })
} }
function searchEarNumber(query) { const searchEarNumber = async (query) => {
if (!query) { earOptions.value = []; return } if (!query || query.trim() === '') {
earOptions.value = []
return
}
earLoading.value = true earLoading.value = true
searchEarNumbers(query.trim()).then(res => { try {
earOptions.value = res.data || [] const res = await searchEarNumbers(query.trim())
}).finally(() => earLoading.value = false) 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 clearEarNumbers() { function clearEarNumbers() {
queryParams.value.manageTagsList = [] queryParams.value.manageTagsList = []

View File

@@ -454,13 +454,27 @@ function getSheepfoldOptions() {
sheepfoldOptions.value = res.rows sheepfoldOptions.value = res.rows
}) })
} }
/* 远程搜耳号 */ const searchEarNumber = async (query) => {
function searchEarNumber(query) { if (!query || query.trim() === '') {
if (!query) { earOptions.value = []; return } earOptions.value = []
return
}
earLoading.value = true earLoading.value = true
searchEarNumbers(query.trim()).then(res => { try {
earOptions.value = res.data || [] const res = await searchEarNumbers(query.trim())
}).finally(() => earLoading.value = false) 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
}
} }
/* 清空所有耳号 */ /* 清空所有耳号 */

View File

@@ -497,12 +497,29 @@ function getSheepfoldOptions() {
sheepfoldOptions.value = res.rows sheepfoldOptions.value = res.rows
}) })
} }
function searchEarNumber(query) { // 搜索耳号的方法(用于下拉框远程搜索)
if (!query) { earOptions.value = []; return } const searchEarNumber = async (query) => {
if (!query || query.trim() === '') {
earOptions.value = []
return
}
earLoading.value = true earLoading.value = true
searchEarNumbers(query.trim()).then(res => { try {
earOptions.value = res.data || [] // 调用API搜索耳号
}).finally(() => earLoading.value = false) 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() { function handlePaste() {

View File

@@ -467,12 +467,29 @@ function getSheepfoldOptions() {
sheepfoldOptions.value = res.rows sheepfoldOptions.value = res.rows
}) })
} }
function searchEarNumber(query) { // 搜索耳号的方法(用于下拉框远程搜索)
if (!query) { earOptions.value = []; return } const searchEarNumber = async (query) => {
if (!query || query.trim() === '') {
earOptions.value = []
return
}
earLoading.value = true earLoading.value = true
searchEarNumbers(query.trim()).then(res => { try {
earOptions.value = res.data || [] // 调用API搜索耳号
}).finally(() => earLoading.value = false) 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() { function handlePaste() {

View File

@@ -629,7 +629,29 @@ function handleQuery() {
queryParams.value.pageNum = 1; queryParams.value.pageNum = 1;
getList(); getList();
} }
// 搜索耳号的方法(用于下拉框远程搜索)
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 = []
} finally {
earLoading.value = false
}
}
//重置搜索框 //重置搜索框
function resetQuery() { function resetQuery() {
daterangeTransDate.value = []; daterangeTransDate.value = [];

View File

@@ -769,12 +769,29 @@ function handleDelete(row) {
}) })
} }
function searchEarNumber(query) { // 搜索耳号的方法(用于下拉框远程搜索)
if (!query) { earOptions.value = []; return } const searchEarNumber = async (query) => {
if (!query || query.trim() === '') {
earOptions.value = []
return
}
earLoading.value = true earLoading.value = true
searchEarNumbers(query.trim()).then(res => { try {
earOptions.value = res.data || [] // 调用API搜索耳号
}).finally(() => earLoading.value = false) 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
}
} }
async function handleRanchChange(ranchName) { async function handleRanchChange(ranchName) {
if (!ranchName) { if (!ranchName) {

View File

@@ -559,12 +559,27 @@ function filterSheepfold(query) {
fold.sheepfoldName.includes(query) fold.sheepfoldName.includes(query)
) )
} }
function searchEarNumber(query) { const searchEarNumber = async (query) => {
if (!query) { earOptions.value = []; return } if (!query || query.trim() === '') {
earOptions.value = []
return
}
earLoading.value = true earLoading.value = true
searchEarNumbers(query.trim()).then(res => { try {
earOptions.value = res.data || [] const res = await searchEarNumbers(query.trim())
}).finally(() => earLoading.value = false) 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 clearEarNumbers() { function clearEarNumbers() {
queryParams.value.manageTagsList = [] queryParams.value.manageTagsList = []

View File

@@ -508,12 +508,27 @@ const fetchTechnicalList = () => {
technicalOptions.value = [] technicalOptions.value = []
}) })
} }
function searchEarNumber(query) { const searchEarNumber = async (query) => {
if (!query) { earOptions.value = []; return } if (!query || query.trim() === '') {
earOptions.value = []
return
}
earLoading.value = true earLoading.value = true
searchEarNumbers(query.trim()).then(res => { try {
earOptions.value = res.data || [] const res = await searchEarNumbers(query.trim())
}).finally(() => earLoading.value = false) 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 clearEarNumbers() { function clearEarNumbers() {
queryParams.value.manageTagsList = [] queryParams.value.manageTagsList = []

View File

@@ -29,10 +29,22 @@
reserve-keyword reserve-keyword
placeholder="输入耳号搜索,支持多选" placeholder="输入耳号搜索,支持多选"
:remote-method="searchEarNumberMethod" :remote-method="searchEarNumberMethod"
:loading="earNumberLoading" @focus="handleQueryEarNumberFocus" :loading="earNumberLoading"
style="width: 100%" style="width: 100%"
clearable clearable
> >
<el-option
v-if="earNumberLoading"
label="正在加载数据..."
value="__loading__"
disabled
/>
<el-option
v-else-if="earNumberQueryOptions.length === 0"
label="暂无已销售记录"
value="__empty__"
disabled
/>
<el-option <el-option
v-for="item in earNumberQueryOptions" v-for="item in earNumberQueryOptions"
:key="item" :key="item"
@@ -257,13 +269,35 @@
<el-select <el-select
v-model="form.bsManageTagsList" v-model="form.bsManageTagsList"
multiple multiple
filterable filterable
allow-create remote
allow-create
reserve-keyword
default-first-option default-first-option
placeholder="手动输入或选择" placeholder="请输入耳号任意部分进行搜索"
:remote-method="formSearchEarNumberMethod"
:loading="formEarNumberLoading"
style="width: 100%" style="width: 100%"
@change="handleTagChange"> @change="handleTagChange"
<el-option v-for="tag in earTagOptions" :key="tag" :label="tag" :value="tag" /> @focus="handleEarNumberFocus">
<el-option
v-if="formEarNumberLoading"
label="正在加载数据..."
value="__loading__"
disabled
/>
<el-option
v-else-if="earTagOptions.length === 0"
:label="form.sheepfoldId ? '该羊舍暂无羊只' : '暂无匹配数据'"
value="__empty__"
disabled
/>
<el-option
v-for="tag in earTagOptions"
:key="tag"
:label="tag"
:value="tag"
/>
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
@@ -455,13 +489,14 @@
import { ref, reactive, toRefs, computed, getCurrentInstance, onMounted } from 'vue' import { ref, reactive, toRefs, computed, getCurrentInstance, onMounted } from 'vue'
import { import {
listSaleRecord, getSaleRecord, delSaleRecord, addSaleRecord, updateSaleRecord, listSaleRecord, getSaleRecord, delSaleRecord, addSaleRecord, updateSaleRecord,
getSheepInfo, listSheepInventory, searchEarNumbers getSheepInfo, listSheepInventory, searchEarNumbers, searchSoldEarNumbers // <- 引入新增的 API
} from '@/api/sale/saleRecord/saleRecord' } from '@/api/sale/saleRecord/saleRecord'
import { listSheepfold_management } from '@/api/fileManagement/sheepfold_management' import { listSheepfold_management } from '@/api/fileManagement/sheepfold_management'
import { listUser } from '@/api/system/user' import { listUser } from '@/api/system/user'
import { listCustomer } from '@/api/sale/customer/customer' import { listCustomer } from '@/api/sale/customer/customer'
import { regionData } from 'element-china-area-data' import { regionData } from 'element-china-area-data'
const formEarNumberLoading = ref(false)
const { proxy } = getCurrentInstance() const { proxy } = getCurrentInstance()
const { disease_type } = proxy.useDict('disease_type') const { disease_type } = proxy.useDict('disease_type')
@@ -609,20 +644,35 @@ function handleQueryAreaChange(val) {
} }
} }
// 【新增】远程搜索耳号方法 // 2. 【修改】顶部搜索耳号查询方法
function searchEarNumberMethod(query) { function searchEarNumberMethod(query) {
if (query !== '') { earNumberLoading.value = true
earNumberLoading.value = true // 这里允许传入空字符串后端会返回前50条已售耳号
searchEarNumbers(query).then(res => { searchSoldEarNumbers(query).then(res => {
earNumberQueryOptions.value = res.data || [] earNumberQueryOptions.value = res.data || []
earNumberLoading.value = false earNumberLoading.value = false
}).catch(() => { }).catch(() => {
earNumberQueryOptions.value = []
earNumberLoading.value = false
})
} else {
earNumberQueryOptions.value = [] earNumberQueryOptions.value = []
} earNumberLoading.value = false
})
}
// 【新增】表单内的耳号远程搜索方法
function formSearchEarNumberMethod(query) {
formEarNumberLoading.value = true
// 将表单当前选中的羊舍ID传给后端。如果没有选此处会传 null/undefined后端将查询全库
searchEarNumbers(query, form.value.sheepfoldId).then(res => {
earTagOptions.value = res.data || []
formEarNumberLoading.value = false
}).catch(() => {
earTagOptions.value = []
formEarNumberLoading.value = false
})
}
// 【新增】下拉框获取焦点时如果还没数据加载一下默认数据前50条
function handleEarNumberFocus() {
formSearchEarNumberMethod('')
} }
// 【新增】移除单个查询耳号 // 【新增】移除单个查询耳号
@@ -649,6 +699,8 @@ function handleSheepfoldChange(val) {
console.error("获取耳号失败", err) console.error("获取耳号失败", err)
}) })
} }
// 切换羊舍后,立刻用空关键字查一下该羊舍下的耳号,更新下拉列表
formSearchEarNumberMethod('')
} }
function handleTagChange(tags) { function handleTagChange(tags) {
@@ -776,10 +828,23 @@ function handleDelete(row) {
}).catch(() => {}) }).catch(() => {})
} }
// 【修改】导出功能:支持勾选导出与全量导出
function handleExport() { function handleExport() {
proxy.download('saleRecord/saleRecord/export', { // 组装要传给后端的查询参数
...queryParams.value const exportParams = { ...queryParams.value }
}, `saleRecord_${new Date().getTime()}.xlsx`) let msg = "是否确认导出所有符合查询条件的销售记录?"
// 如果用户在表格中勾选了数据就把勾选的ID集合塞进参数里并改变提示语
if (ids.value.length > 0) {
exportParams.exportIds = ids.value
msg = `是否确认导出选中的 ${ids.value.length} 条销售记录?`
}
// 给用户一个明确的二次确认弹窗
proxy.$modal.confirm(msg).then(() => {
// 确认后调用导出接口,附带时间戳作为文件名
proxy.download('saleRecord/saleRecord/export', exportParams, `羊只销售记录_${new Date().getTime()}.xlsx`)
}).catch(() => {})
} }
function cancel() { function cancel() {
@@ -804,6 +869,14 @@ function diseaseTypeFormat(row) {
// 如果静态选项 label 和 value 一样,则直接返回即可 // 如果静态选项 label 和 value 一样,则直接返回即可
return row.diseaseType return row.diseaseType
} }
// 3. 【新增】输入框获取焦点时,如果还没数据,自动查询
function handleQueryEarNumberFocus() {
// 为了防止每次点击都发请求,判断如果没有输入内容且下拉框为空,才去查默认数据
if (earNumberQueryOptions.value.length === 0) {
searchEarNumberMethod('')
}
}
</script> </script>
<style scoped> <style scoped>