fix: 新增功能修改及完善。

This commit is contained in:
tianyongbao
2025-10-16 00:29:26 +08:00
parent abe6f38f6e
commit 3377df781a
26 changed files with 3243 additions and 55 deletions

View File

@@ -47,9 +47,9 @@
>删除</el-button
>
</el-col>
<el-col :span="1.5">
<!-- <el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['fishery:aquUser:export']">导出</el-button>
</el-col>
</el-col> -->
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
@@ -64,8 +64,13 @@
<el-table-column label="区县" align="center" prop="district" /> -->
<el-table-column label="报警电话" align="center" prop="warnPhoneJson" />
<el-table-column label="展示标题" align="center" prop="title" />
<el-table-column label="操作" align="center" fixed="right" class-name="small-padding fixed-width">
<el-table-column label="创建时间" align="center" prop="createTime" />
<el-table-column label="修改时间" align="center" prop="updateTime" />
<el-table-column label="操作" align="center" fixed="right" width="200" class-name="small-padding fixed-width">
<template #default="scope">
<el-tooltip content="查看塘口" placement="top">
<el-button link type="primary" icon="View" @click="handleViewPonds(scope.row)"></el-button>
</el-tooltip>
<el-tooltip content="修改" placement="top">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['fishery:aquUser:edit']"></el-button>
</el-tooltip>
@@ -78,7 +83,7 @@
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
</el-card>
<!-- 添加或修改养殖用户对话框 -->
<!-- 添加或修改养殖账号对话框 -->
<el-dialog :title="dialog.title" v-model="dialog.visible" width="850px" append-to-body>
<el-form ref="aquUserFormRef" :model="form" :rules="rules" :inline="true" label-width="120px">
<el-form-item label="用户名" prop="userName">
@@ -137,12 +142,44 @@
</div>
</template>
</el-dialog>
<!-- 用户塘口信息对话框 -->
<el-dialog :title="pondDialog.title" v-model="pondDialog.visible" width="1000px" append-to-body>
<el-table :data="userPondList" border max-height="500px">
<el-table-column label="塘口名称" align="center" prop="pondName" />
<el-table-column label="鱼品种列表" align="center" prop="fishKindNames" />
<el-table-column label="面积(亩)" align="center" prop="area" />
<el-table-column label="密度(尾/亩)" align="center" prop="density" />
<el-table-column label="投苗日期" align="center" prop="placeTime" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.placeTime, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
</el-table>
<div v-if="userPondList.length === 0" class="text-center py-8 text-gray-500">
该用户暂无塘口信息
</div>
<template #footer>
<div class="dialog-footer">
<el-button @click="pondDialog.visible = false"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup name="AquUser" lang="ts">
import { listAquUser, getAquUser, delAquUser, addAquUser, updateAquUser } from '@/api/fishery/aquUser';
import { listPond } from '@/api/fishery/pond';
import { AquUserVO, AquUserQuery, AquUserForm } from '@/api/fishery/aquUser/types';
import { PondVO } from '@/api/fishery/pond/types';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
@@ -163,6 +200,14 @@ const dialog = reactive<DialogOption>({
title: ''
});
// 塘口信息相关
const pondDialog = reactive<DialogOption>({
visible: false,
title: ''
});
const userPondList = ref<PondVO[]>([]);
const currentUserId = ref<string | number>('');
const initFormData: AquUserForm = {
id: undefined,
userName: undefined,
@@ -204,7 +249,7 @@ const data = reactive<PageData<AquUserForm, AquUserQuery>>({
const { queryParams, form, rules } = toRefs(data);
/** 查询养殖用户列表 */
/** 查询养殖账号列表 */
const getList = async () => {
loading.value = true;
const res = await listAquUser(queryParams.value);
@@ -248,7 +293,7 @@ const handleSelectionChange = (selection: AquUserVO[]) => {
const handleAdd = () => {
reset();
dialog.visible = true;
dialog.title = '添加养殖用户';
dialog.title = '添加养殖账号';
};
/** 修改按钮操作 */
@@ -258,7 +303,7 @@ const handleUpdate = async (row?: AquUserVO) => {
const res = await getAquUser(_id);
Object.assign(form.value, res.data);
dialog.visible = true;
dialog.title = '修改养殖用户';
dialog.title = '修改养殖账号';
};
/** 提交按钮 */
@@ -281,7 +326,7 @@ const submitForm = () => {
/** 删除按钮操作 */
const handleDelete = async (row?: AquUserVO) => {
const _ids = row?.id || ids.value;
await proxy?.$modal.confirm('是否确认删除养殖用户编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
await proxy?.$modal.confirm('是否确认删除养殖账号编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
await delAquUser(_ids);
proxy?.$modal.msgSuccess('删除成功');
await getList();
@@ -298,6 +343,22 @@ const handleExport = () => {
);
};
/** 查看用户塘口信息 */
const handleViewPonds = async (row: AquUserVO) => {
currentUserId.value = row.id;
pondDialog.title = `${row.userName} 的塘口信息`;
// 根据用户ID查询塘口列表
const res = await listPond({
pageNum: 1,
pageSize: 1000,
userId: row.id
});
userPondList.value = res.rows || [];
pondDialog.visible = true;
};
onMounted(() => {
getList();
});

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,459 @@
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div v-show="showSearch" class="mb-[10px]">
<el-card shadow="hover">
<el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="90px">
<el-form-item label="用户信息" prop="params.userKeyword">
<el-input v-model="queryParams.params.userKeyword" placeholder="请输入用户名或手机号" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="设备类型" prop="deviceType">
<el-select v-model="queryParams.deviceType" placeholder="请选择设备类型" clearable >
<el-option v-for="dict in aqu_device_type" :key="dict.value" :label="dict.label" :value="dict.value"/>
</el-select>
</el-form-item>
<el-form-item label="设备编号" prop="serialNum">
<el-input v-model="queryParams.serialNum" placeholder="请输入设备编号" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="绑定/解绑" prop="isBind">
<el-select v-model="queryParams.isBind" placeholder="请选择绑定/解绑" clearable >
<el-option v-for="dict in is_bind" :key="dict.value" :label="dict.label" :value="dict.value"/>
</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-card>
</div>
</transition>
<el-card shadow="never">
<template #header>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['fishery:deviceBindRecord:add']">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['fishery:deviceBindRecord:edit']">修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['fishery:deviceBindRecord:remove']">删除</el-button>
</el-col>
<!-- <el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['fishery:deviceBindRecord:export']">导出</el-button>
</el-col> -->
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<el-table v-loading="loading" border :data="deviceBindRecordList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="用户名" align="center" prop="userName"/>
<el-table-column label="手机号" align="center" prop="mobilePhone" />
<el-table-column label="设备类型" align="center" prop="deviceType">
<template #default="scope">
<dict-tag :options="aqu_device_type" :value="scope.row.deviceType"/>
</template>
</el-table-column>
<el-table-column label="设备编号" align="center" prop="serialNum" />
<el-table-column label="绑定/解绑" align="center" prop="isBind">
<template #default="scope">
<dict-tag :options="is_bind" :value="scope.row.isBind"/>
</template>
</el-table-column>
<el-table-column label="操作时间" align="center" prop="createTime" />
<el-table-column label="操作" align="center" fixed="right" class-name="small-padding fixed-width">
<template #default="scope">
<el-tooltip content="修改" placement="top">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['fishery:deviceBindRecord:edit']"></el-button>
</el-tooltip>
<el-tooltip content="删除" placement="top">
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['fishery:deviceBindRecord:remove']"></el-button>
</el-tooltip>
</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" />
</el-card>
<!-- 添加或修改设备绑定记录对话框 -->
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
<el-form ref="deviceBindRecordFormRef" :model="form" :rules="rules" label-width="120px">
<el-form-item label="用户" prop="userId">
<el-input
:value="selectedUser ? `${selectedUser.userName} (${selectedUser.mobilePhone})` : ''"
placeholder="请选择用户"
readonly
@click="openUserSelect"
style="cursor: pointer;"
>
<template #append>
<el-button icon="Search" @click="openUserSelect">选择</el-button>
</template>
</el-input>
</el-form-item>
<el-form-item label="设备类型" prop="deviceType">
<el-select v-model="form.deviceType" placeholder="请选择设备类型" style="width: 100%">
<el-option
v-for="dict in aqu_device_type"
:key="dict.value"
:label="dict.label"
:value="parseInt(dict.value)"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="设备编号" prop="serialNum">
<el-input v-model="form.serialNum" placeholder="请输入设备编号" />
</el-form-item>
<el-form-item label="物联网IotId" prop="iotId">
<el-input v-model="form.iotId" placeholder="请输入物联网IotId" />
</el-form-item>
<el-form-item label="绑定/解绑" prop="isBind">
<el-select v-model="form.isBind" placeholder="请选择绑定/解绑" style="width: 100%">
<el-option
v-for="dict in is_bind"
:key="dict.value"
:label="dict.label"
:value="parseInt(dict.value)"
></el-option>
</el-select>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
<!-- 用户选择对话框 -->
<el-dialog title="选择用户" v-model="userSelectVisible" width="900px" append-to-body>
<!-- 搜索条件 -->
<el-form :model="userQueryParams" :inline="true" class="mb-4">
<el-form-item label="用户名">
<el-input
v-model="userQueryParams.userName"
placeholder="请输入用户名"
clearable
style="width: 180px"
@keyup.enter="handleUserQuery"
/>
</el-form-item>
<el-form-item label="手机号">
<el-input
v-model="userQueryParams.mobilePhone"
placeholder="请输入手机号"
clearable
style="width: 180px"
@keyup.enter="handleUserQuery"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleUserQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetUserQuery">重置</el-button>
</el-form-item>
</el-form>
<!-- 用户表格 -->
<el-table
:data="aquUserList"
highlight-current-row
height="400px"
border
>
<el-table-column label="用户名" align="center" prop="userName" />
<el-table-column label="手机号" align="center" prop="mobilePhone" />
<el-table-column label="省份" align="center" prop="province" />
<el-table-column label="城市" align="center" prop="city" />
<el-table-column label="区县" align="center" prop="district" />
<el-table-column label="操作" align="center" width="100">
<template #default="scope">
<el-button
type="primary"
size="small"
@click="handleUserSelect(scope.row)"
>
选择
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<pagination
v-show="userTotal > 0"
:total="userTotal"
v-model:page="userQueryParams.pageNum"
v-model:limit="userQueryParams.pageSize"
@pagination="handleUserPaginationChange"
class="mt-4"
/>
<template #footer>
<div class="dialog-footer">
<el-button @click="cancelUserSelect"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup name="DeviceBindRecord" lang="ts">
import { listDeviceBindRecord, getDeviceBindRecord, delDeviceBindRecord, addDeviceBindRecord, updateDeviceBindRecord } from '@/api/fishery/deviceBindRecord';
import { DeviceBindRecordVO, DeviceBindRecordQuery, DeviceBindRecordForm } from '@/api/fishery/deviceBindRecord/types';
import { listAquUser } from '@/api/fishery/aquUser';
import { AquUserVO } from '@/api/fishery/aquUser/types';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { is_bind, aqu_device_type } = toRefs<any>(proxy?.useDict('is_bind', 'aqu_device_type'));
const deviceBindRecordList = ref<DeviceBindRecordVO[]>([]);
const buttonLoading = ref(false);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref<Array<string | number>>([]);
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
// 用户选择相关
const aquUserList = ref<AquUserVO[]>([]);
const selectedUser = ref<AquUserVO | null>(null);
const userSelectVisible = ref(false);
const userQueryParams = reactive<{
pageNum: number;
pageSize: number;
userName?: string;
mobilePhone?: string;
}>({
pageNum: 1,
pageSize: 10,
userName: undefined,
mobilePhone: undefined
});
const userTotal = ref(0);
const queryFormRef = ref<ElFormInstance>();
const deviceBindRecordFormRef = ref<ElFormInstance>();
const dialog = reactive<DialogOption>({
visible: false,
title: ''
});
const initFormData: DeviceBindRecordForm = {
id: undefined,
iotId: undefined,
deviceType: undefined,
serialNum: undefined,
userId: undefined,
isBind: undefined,
}
const data = reactive<PageData<DeviceBindRecordForm, DeviceBindRecordQuery>>({
form: {...initFormData},
queryParams: {
pageNum: 1,
pageSize: 10,
iotId: undefined,
deviceType: undefined,
serialNum: undefined,
userId: undefined,
isBind: undefined,
params: {
}
},
rules: {
id: [
{ required: true, message: "主键id不能为空", trigger: "blur" }
],
iotId: [
{ required: true, message: "物联网IotId不能为空", trigger: "blur" }
],
deviceType: [
{ required: true, message: "设备类型不能为空", trigger: "change" }
],
serialNum: [
{ required: true, message: "设备编号不能为空", trigger: "blur" }
],
userId: [
{ required: true, message: "用户id不能为空", trigger: "blur" }
],
isBind: [
{ required: true, message: "绑定/解绑不能为空", trigger: "change" }
],
}
});
const { queryParams, form, rules } = toRefs(data);
/** 查询设备绑定记录列表 */
const getList = async () => {
loading.value = true;
const res = await listDeviceBindRecord(queryParams.value);
deviceBindRecordList.value = res.rows;
total.value = res.total;
loading.value = false;
}
/** 取消按钮 */
const cancel = () => {
reset();
dialog.visible = false;
}
/** 表单重置 */
const reset = () => {
form.value = {...initFormData};
selectedUser.value = null; // 清空用户选择
deviceBindRecordFormRef.value?.resetFields();
}
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.value.pageNum = 1;
getList();
}
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value?.resetFields();
handleQuery();
}
/** 多选框选中数据 */
const handleSelectionChange = (selection: DeviceBindRecordVO[]) => {
ids.value = selection.map(item => item.id);
single.value = selection.length != 1;
multiple.value = !selection.length;
}
/** 新增按钮操作 */
const handleAdd = () => {
reset();
selectedUser.value = null; // 清空用户选择
dialog.visible = true;
dialog.title = "添加设备绑定记录";
}
/** 修改按钮操作 */
const handleUpdate = async (row?: DeviceBindRecordVO) => {
reset();
const _id = row?.id || ids.value[0]
const res = await getDeviceBindRecord(_id);
Object.assign(form.value, res.data);
// 回显用户信息
if (form.value.userId) {
try {
const userRes = await listAquUser({
pageNum: 1,
pageSize: 1000
});
const userList = userRes.rows || userRes.data || [];
const user = userList.find(u => u.id.toString() === form.value.userId.toString());
if (user) {
selectedUser.value = user;
} else {
console.warn('未找到用户ID:', form.value.userId);
selectedUser.value = null;
}
} catch (error) {
console.error('加载用户信息失败:', error);
selectedUser.value = null;
}
} else {
selectedUser.value = null;
}
dialog.visible = true;
dialog.title = "修改设备绑定记录";
}
/** 提交按钮 */
const submitForm = () => {
deviceBindRecordFormRef.value?.validate(async (valid: boolean) => {
if (valid) {
buttonLoading.value = true;
if (form.value.id) {
await updateDeviceBindRecord(form.value).finally(() => buttonLoading.value = false);
} else {
await addDeviceBindRecord(form.value).finally(() => buttonLoading.value = false);
}
proxy?.$modal.msgSuccess("操作成功");
dialog.visible = false;
await getList();
}
});
}
/** 删除按钮操作 */
const handleDelete = async (row?: DeviceBindRecordVO) => {
const _ids = row?.id || ids.value;
await proxy?.$modal.confirm('是否确认删除设备绑定记录编号为"' + _ids + '"的数据项?').finally(() => loading.value = false);
await delDeviceBindRecord(_ids);
proxy?.$modal.msgSuccess("删除成功");
await getList();
}
/** 导出按钮操作 */
const handleExport = () => {
proxy?.download('fishery/deviceBindRecord/export', {
...queryParams.value
}, `deviceBindRecord_${new Date().getTime()}.xlsx`)
}
/** 获取用户列表 */
const getAquUserList = async () => {
const res = await listAquUser(userQueryParams);
aquUserList.value = res.rows || res.data || [];
userTotal.value = res.total || 0;
};
/** 打开用户选择对话框 */
const openUserSelect = () => {
userQueryParams.pageNum = 1;
userQueryParams.userName = undefined;
userQueryParams.mobilePhone = undefined;
getAquUserList();
userSelectVisible.value = true;
};
/** 搜索用户 */
const handleUserQuery = () => {
userQueryParams.pageNum = 1;
getAquUserList();
};
/** 重置用户搜索 */
const resetUserQuery = () => {
userQueryParams.pageNum = 1;
userQueryParams.userName = undefined;
userQueryParams.mobilePhone = undefined;
getAquUserList();
};
/** 用户分页改变 */
const handleUserPaginationChange = () => {
getAquUserList();
};
/** 选择用户 */
const handleUserSelect = (user: AquUserVO) => {
selectedUser.value = user;
form.value.userId = user.id;
userSelectVisible.value = false;
};
/** 取消选择用户 */
const cancelUserSelect = () => {
userSelectVisible.value = false;
};
onMounted(() => {
getList();
});
</script>

View File

@@ -35,9 +35,9 @@
>删除</el-button
>
</el-col>
<el-col :span="1.5">
<!-- <el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['fishery:deviceThreshold:export']">导出</el-button>
</el-col>
</el-col> -->
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
@@ -48,7 +48,8 @@
<el-table-column label="阈值名称" align="center" prop="thresholdName" />
<el-table-column label="最大值" align="center" prop="limitUpper" />
<el-table-column label="最小值" align="center" prop="limitLower" />
<el-table-column label="备注" align="center" prop="remark" />
<el-table-column label="创建时间" align="center" prop="createTime" />
<el-table-column label="修改时间" align="center" prop="updateTime" />
<el-table-column label="操作" align="center" fixed="right" class-name="small-padding fixed-width">
<template #default="scope">
<el-tooltip content="修改" placement="top">

View File

@@ -0,0 +1,153 @@
<template>
<div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div v-show="showSearch" class="mb-[10px]">
<el-card shadow="hover">
<el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="90px">
<el-form-item label="设备编号" prop="serialNum">
<el-input v-model="queryParams.serialNum" placeholder="请输入设备编号" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="设备类型" prop="deviceType">
<el-select v-model="queryParams.deviceType" placeholder="请选择设备类型" clearable @change="handleQuery">
<el-option
v-for="dict in aqu_device_type"
:key="dict.value"
:label="dict.label"
:value="parseInt(dict.value)"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="用户信息" prop="params.userKeyword">
<el-input v-model="queryParams.params.userKeyword" placeholder="请输入用户名或手机号" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="是否过期" prop="params.isExpired">
<el-select v-model="queryParams.params.isExpired" placeholder="请选择是否过期" clearable @change="handleQuery">
<el-option
v-for="dict in is_expired"
:key="dict.value"
:label="dict.label"
:value="parseInt(dict.value)"
></el-option>
</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-card>
</div>
</transition>
<el-card shadow="never">
<template #header>
<el-row :gutter="10" class="mb8">
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<el-table v-loading="loading" border :data="deviceList">
<el-table-column label="设备编号" align="center" prop="serialNum" />
<el-table-column label="设备名称" align="center" prop="deviceName" />
<el-table-column label="塘口名称" align="center" prop="pondName" />
<el-table-column label="设备类型" align="center" prop="deviceType">
<template #default="scope">
<dict-tag :options="aqu_device_type" :value="scope.row.deviceType"/>
</template>
</el-table-column>
<el-table-column label="用户名" align="center" prop="userName" />
<el-table-column label="手机号" align="center" prop="mobilePhone" />
<el-table-column label="物联网卡号" align="center" prop="iccId" width="190"/>
<el-table-column label="绑定时间" align="center" prop="bindTime">
<template #default="scope">
<span>{{ parseTime(scope.row.bindTime, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="到期时间" align="center" prop="deadTime">
<template #default="scope">
<span :style="{
color: scope.row.expiredDays > 0 && scope.row.expiredDays < 60 ? 'red' :
scope.row.expiredDays >= 60 ? '#E6A23C' : ''
}">{{ parseTime(scope.row.deadTime, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="到期情况" align="center" prop="expiredDays">
<template #default="scope">
<span
v-if="scope.row.expiredDays > 0"
:style="{
color: scope.row.expiredDays < 60 ? 'red' : '#E6A23C'
}">已过期{{ scope.row.expiredDays }}</span>
<span v-else-if="scope.row.expiredDays < 0">剩余{{ Math.abs(scope.row.expiredDays) }}</span>
<span v-else>今天到期</span>
</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" />
</el-card>
</div>
</template>
<script setup name="DeviceValidity" lang="ts">
import { listDevice } from '@/api/fishery/device';
import { DeviceVO, DeviceQuery } from '@/api/fishery/device/types';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { aqu_device_type, is_expired } = toRefs<any>(proxy?.useDict('aqu_device_type', 'is_expired'));
const deviceList = ref<DeviceVO[]>([]);
const loading = ref(true);
const showSearch = ref(true);
const total = ref(0);
const queryFormRef = ref<ElFormInstance>();
const data = reactive<PageData<{}, DeviceQuery>>({
form: {},
queryParams: {
pageNum: 1,
pageSize: 10,
userId: undefined,
serialNum: undefined,
deviceName: undefined,
deviceType: undefined,
bindTime: undefined,
pondId: undefined,
iccId: undefined,
category: undefined,
params: {
isExpired: 1,
expiredFlag: 1
}
},
rules: {}
});
const { queryParams } = toRefs(data);
/** 查询设备管理列表 */
const getList = async () => {
loading.value = true;
const res = await listDevice(queryParams.value);
deviceList.value = res.rows;
total.value = res.total;
loading.value = false;
}
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.value.pageNum = 1;
getList();
}
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value?.resetFields();
handleQuery();
}
onMounted(() => {
getList();
});
</script>

View File

@@ -35,16 +35,16 @@
>删除</el-button
>
</el-col>
<el-col :span="1.5">
<!-- <el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['fishery:fish:export']">导出</el-button>
</el-col>
</el-col> -->
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<el-table v-loading="loading" border :data="fishList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="主键Id" align="center" prop="id" v-if="true" />
<!-- <el-table-column label="主键Id" align="center" prop="id" v-if="true" /> -->
<el-table-column label="鱼类类型" align="center" prop="fishType">
<template #default="scope">
<dict-tag :options="fish_type" :value="scope.row.fishType" />

View File

@@ -4,12 +4,12 @@
<div v-show="showSearch" class="mb-[10px]">
<el-card shadow="hover">
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
<el-form-item label="用户名称/手机号" prop="userName">
<el-input v-model="queryParams.userId" placeholder="请输入用户id" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="塘口名称" prop="pondName">
<el-input v-model="queryParams.pondName" placeholder="请输入塘口名称" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="用户信息" prop="params.userKeyword">
<el-input v-model="queryParams.params.userKeyword" placeholder="请输入用户名或手机号" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="投苗日期" prop="time">
<el-date-picker
v-model="queryParams.time"
@@ -45,26 +45,34 @@
>删除</el-button
>
</el-col>
<el-col :span="1.5">
<!-- <el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['fishery:pond:export']">导出</el-button>
</el-col>
</el-col> -->
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<el-table v-loading="loading" border :data="pondList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="用户id" align="center" prop="userId" />
<el-table-column label="塘口名称" align="center" prop="pondName" />
<el-table-column label="鱼品种列表" align="center" prop="fishKindIds" />
<el-table-column label="面积" align="center" prop="area" />
<el-table-column label="密度" align="center" prop="density" />
<el-table-column label="投苗日期" align="center" prop="placeTime" width="180">
<el-table-column label="用户名" align="center" prop="userName" />
<el-table-column label="手机号" align="center" prop="mobilePhone" />
<el-table-column label="鱼品种列表" align="center" prop="fishKindNames" />
<el-table-column label="面积(亩)" align="center" prop="area" />
<el-table-column label="密度(尾/亩)" align="center" prop="density" />
<el-table-column label="投苗日期" align="center" prop="placeTime" width="120">
<template #default="scope">
<span>{{ parseTime(scope.row.placeTime, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="夜间防止误关" align="center" prop="keepNightOpen" />
<el-table-column label="夜间防止误关" align="center" prop="keepNightOpen">
<template #default="scope">
<dict-tag :options="open_close" :value="scope.row.keepNightOpen" />
</template>
</el-table-column>
<el-table-column label="创建时间" align="center" prop="createTime" width="160"/>
<el-table-column label="修改时间" align="center" prop="updateTime" width="160"/>
<el-table-column label="操作" align="center" fixed="right" class-name="small-padding fixed-width">
<template #default="scope">
<el-tooltip content="修改" placement="top">
@@ -79,30 +87,96 @@
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
</el-card>
<!-- 添加或修改塘口管理对话框 -->
<!-- 添加或修改塘口对话框 -->
<el-dialog :title="dialog.title" v-model="dialog.visible" width="550px" append-to-body>
<el-form ref="pondFormRef" :model="form" :rules="rules" label-width="110px">
<el-form-item label="用户id" prop="userId">
<el-input v-model="form.userId" placeholder="请输入用户id" />
<el-form-item label="用户" prop="userId">
<el-input
:value="selectedUser ? `${selectedUser.userName} (${selectedUser.mobilePhone})` : ''"
placeholder="请选择用户"
readonly
@click="openUserSelect"
style="cursor: pointer;"
>
<template #append>
<el-button icon="Search" @click="openUserSelect">选择</el-button>
</template>
</el-input>
</el-form-item>
<el-form-item label="塘口名称" prop="pondName">
<el-input v-model="form.pondName" placeholder="请输入塘口名称" />
</el-form-item>
<el-form-item label="鱼品种列表" prop="fishKindIds">
<el-input v-model="form.fishKindIds" placeholder="请输入鱼品种列表" />
<div class="fish-selector">
<el-input
v-model="selectedFishNames"
placeholder="请选择鱼品种"
readonly
@click="openFishSelect"
style="cursor: pointer;"
>
<template #suffix>
<div class="input-suffix">
<span v-if="selectedFishList.length > 0" class="count-badge">
{{ selectedFishList.length }}
</span>
<el-icon class="select-icon"><ArrowDown /></el-icon>
</div>
</template>
</el-input>
<!-- 简洁的已选择项目展示 -->
<div v-if="selectedFishList.length > 0" class="selected-items">
<div class="selected-summary">
<span class="summary-text">已选择 {{ selectedFishList.length }} 个品种</span>
<el-button
type="text"
size="small"
@click="clearAllFish"
class="clear-btn"
>
清空
</el-button>
</div>
<div class="selected-list-compact">
<span
v-for="(fish, index) in selectedFishList.slice(0, 5)"
:key="fish.id"
class="fish-item"
>
{{ fish.fishName }}<span v-if="index < Math.min(4, selectedFishList.length - 1)"></span>
</span>
<span v-if="selectedFishList.length > 5" class="more-indicator">
... 及另外{{ selectedFishList.length - 5 }}个品种
</span>
</div>
</div>
</div>
</el-form-item>
<el-form-item label="面积" prop="area">
<el-input v-model="form.area" placeholder="请输入面积" />
<el-input v-model="form.area" placeholder="请输入面积">
<template #append></template>
</el-input>
</el-form-item>
<el-form-item label="密度" prop="density">
<el-input v-model="form.density" placeholder="请输入密度" />
<el-input v-model="form.density" placeholder="请输入密度">
<template #append>/</template>
</el-input>
</el-form-item>
<el-form-item label="投苗日期" prop="placeTime">
<el-date-picker clearable v-model="form.placeTime" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择投苗日期">
<el-date-picker clearable v-model="form.placeTime" type="date" value-format="YYYY-MM-DD" placeholder="请选择投苗日期">
</el-date-picker>
</el-form-item>
<el-form-item label="夜间防止误关" prop="keepNightOpen">
<el-input v-model="form.keepNightOpen" placeholder="请输入夜间防止误关" />
<el-select v-model="form.keepNightOpen" placeholder="请选择夜间防止误关">
<el-option
v-for="dict in open_close"
:key="dict.value"
:label="dict.label"
:value="parseInt(dict.value)"
/>
</el-select>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入备注" />
@@ -110,8 +184,198 @@
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
<!-- 鱼品种选择对话框 -->
<el-dialog title="选择鱼品种" v-model="fishSelectVisible" width="1200px" append-to-body>
<el-row :gutter="20">
<!-- 左侧鱼类搜索和列表 -->
<el-col :span="16">
<!-- Tab页签 -->
<el-tabs v-model="activeTab" @tab-change="handleTabChange" class="mb-4">
<el-tab-pane label="全部" name="all"></el-tab-pane>
<el-tab-pane
v-for="dict in fish_type"
:key="dict.value"
:label="dict.label"
:name="dict.value"
></el-tab-pane>
</el-tabs>
<!-- 搜索条件 -->
<el-form :model="fishQueryParams" :inline="true" class="mb-4">
<el-form-item label="鱼类名称">
<el-input
v-model="fishQueryParams.fishName"
placeholder="请输入鱼类名称"
clearable
style="width: 200px"
@keyup.enter="handleFishQuery"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleFishQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetFishQuery">重置</el-button>
</el-form-item>
</el-form>
<!-- 鱼品种表格 -->
<el-table
ref="fishTableRef"
:data="fishList"
@selection-change="handleSelectAllFish"
height="350px"
border
v-loading="loading"
>
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="鱼类名称" align="center" prop="fishName" />
<el-table-column label="鱼类类型" align="center" prop="fishType" width="100">
<template #default="scope">
<dict-tag :options="fish_type" :value="scope.row.fishType" />
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="80">
<template #default="scope">
<el-button
type="primary"
size="small"
@click="quickAddFish(scope.row)"
:disabled="selectedFishList.some(item => item.id === scope.row.id)"
>
添加
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 数据统计 -->
<div class="mt-2 text-sm text-gray-500">
当前显示 {{ fishList.length }} 条数据
</div>
</el-col>
<!-- 右侧已选择的鱼类 -->
<el-col :span="8">
<div class="selected-fish-panel">
<div class="panel-header">
<h4>已选择的鱼类 ({{ selectedFishList.length }})</h4>
<el-button
type="danger"
size="small"
@click="clearAllFish"
v-show="selectedFishList.length > 0"
>
清空
</el-button>
</div>
<div class="selected-list">
<div
v-for="fish in selectedFishList"
:key="fish.id"
class="selected-item"
>
<span class="fish-name">{{ fish.fishName }}</span>
<dict-tag :options="fish_type" :value="fish.fishType" size="small" class="ml-2" />
<el-button
type="danger"
size="small"
icon="Close"
circle
@click="removeFish(fish.id)"
class="ml-2"
/>
</div>
<el-empty
v-if="selectedFishList.length === 0"
description="请选择鱼类"
:image-size="100"
/>
</div>
</div>
</el-col>
</el-row>
<template #footer>
<div class="dialog-footer">
<span class="selected-count">已选择 {{ selectedFishList.length }} 个鱼类</span>
<el-button type="primary" @click="confirmFishSelect" :disabled="selectedFishList.length === 0"> </el-button>
<el-button @click="cancelFishSelect"> </el-button>
</div>
</template>
</el-dialog>
<!-- 用户选择对话框 -->
<el-dialog title="选择用户" v-model="userSelectVisible" width="900px" append-to-body>
<!-- 搜索条件 -->
<el-form :model="userQueryParams" :inline="true" class="mb-4">
<el-form-item label="用户名">
<el-input
v-model="userQueryParams.userName"
placeholder="请输入用户名"
clearable
style="width: 180px"
@keyup.enter="handleUserQuery"
/>
</el-form-item>
<el-form-item label="手机号">
<el-input
v-model="userQueryParams.mobilePhone"
placeholder="请输入手机号"
clearable
style="width: 180px"
@keyup.enter="handleUserQuery"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleUserQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetUserQuery">重置</el-button>
</el-form-item>
</el-form>
<!-- 用户表格 -->
<el-table
:data="aquUserList"
highlight-current-row
height="400px"
border
>
<el-table-column label="用户名" align="center" prop="userName" />
<el-table-column label="手机号" align="center" prop="mobilePhone" />
<el-table-column label="省份" align="center" prop="province" />
<el-table-column label="城市" align="center" prop="city" />
<el-table-column label="区县" align="center" prop="district" />
<el-table-column label="操作" align="center" width="100">
<template #default="scope">
<el-button
type="primary"
size="small"
@click="handleUserSelect(scope.row)"
>
选择
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<pagination
v-show="userTotal > 0"
:total="userTotal"
v-model:page="userQueryParams.pageNum"
v-model:limit="userQueryParams.pageSize"
@pagination="handleUserPaginationChange"
class="mt-4"
/>
<template #footer>
<div class="dialog-footer">
<el-button @click="cancelUserSelect"> </el-button>
</div>
</template>
</el-dialog>
@@ -120,12 +384,47 @@
<script setup name="Pond" lang="ts">
import { listPond, getPond, delPond, addPond, updatePond } from '@/api/fishery/pond';
import { listFish, getFish } from '@/api/fishery/fish';
import { listAquUser } from '@/api/fishery/aquUser';
import { PondVO, PondQuery, PondForm } from '@/api/fishery/pond/types';
import { FishVO } from '@/api/fishery/fish/types';
import { AquUserVO } from '@/api/fishery/aquUser/types';
import dayjs from 'dayjs';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { fish_type,open_close } = toRefs<any>(proxy?.useDict('fish_type','open_close'));
const pondList = ref<PondVO[]>([]);
const fishList = ref<FishVO[]>([]);
const selectedFishList = ref<FishVO[]>([]);
const originalSelectedFishList = ref<FishVO[]>([]); // 备份的选择列表,用于取消操作
const fishSelectVisible = ref(false);
// 用户选择相关
const aquUserList = ref<AquUserVO[]>([]);
const selectedUser = ref<AquUserVO | null>(null);
const userSelectVisible = ref(false);
const userQueryParams = reactive<{
pageNum: number;
pageSize: number;
userName?: string;
mobilePhone?: string;
}>({
pageNum: 1,
pageSize: 10,
userName: undefined,
mobilePhone: undefined
});
const userTotal = ref(0);
const fishQueryParams = reactive<{
fishType?: number;
fishName?: string;
}>({
fishType: undefined,
fishName: undefined
});
const fishTotal = ref(0); // 鱼类数据总数
const activeTab = ref<string>('all'); // 当前激活的tab
const buttonLoading = ref(false);
const loading = ref(true);
const showSearch = ref(true);
@@ -136,6 +435,7 @@ const total = ref(0);
const queryFormRef = ref<ElFormInstance>();
const pondFormRef = ref<ElFormInstance>();
const fishTableRef = ref<ElTableInstance>();
const dialog = reactive<DialogOption>({
visible: false,
@@ -173,13 +473,263 @@ const data = reactive<PageData<PondForm, PondQuery>>({
fishKindIds: [{ required: true, message: '鱼品种列表不能为空', trigger: 'blur' }],
area: [{ required: true, message: '面积不能为空', trigger: 'blur' }],
density: [{ required: true, message: '密度不能为空', trigger: 'blur' }],
keepNightOpen: [{ required: true, message: '夜间防止误关不能为空', trigger: 'blur' }]
keepNightOpen: [{ required: true, message: '夜间防止误关不能为空', trigger: 'change' }]
}
});
const { queryParams, form, rules } = toRefs(data);
/** 查询塘口管理列表 */
// 鱼品种相关状态
const selectedFishNames = computed(() => {
const count = selectedFishList.value.length;
if (count === 0) return '';
// 简洁显示,不显示具体名称
return `已选择 ${count} 个鱼类品种`;
});
// 获取完整的鱼类名称列表用于tooltip显示
const fullFishNames = computed(() => {
return selectedFishList.value.map(fish => fish.fishName).join('、');
});
const parseFishIds = (fishKindIds: any): string[] => {
if (!fishKindIds) return [];
try {
// 解析JSON数组格式"[29,31,34,4,2]"
const parsed = JSON.parse(fishKindIds.toString());
if (Array.isArray(parsed)) {
return parsed.map(id => id.toString());
}
} catch (error) {
console.warn('fishKindIds格式错误:', fishKindIds);
}
return [];
};
// 获取当前页面中已选中的项目
const getCurrentPageSelection = () => {
return fishList.value.filter(fish =>
selectedFishList.value.some(selected => selected.id === fish.id)
);
};
/** 根据ID列表获取鱼类信息 */
const getFishByIds = async (fishIds: string[]) => {
if (fishIds.length === 0) return [];
try {
// 方案1如果鱼类数量不多使用并发单个查询
if (fishIds.length <= 20) {
const promises = fishIds.map(id => getFish(id).catch(() => null));
const results = await Promise.all(promises);
return results.filter(res => res !== null).map(res => res.data);
}
// 方案2鱼类数量较多时使用分批查询
const allFishList: FishVO[] = [];
let pageNum = 1;
let hasMore = true;
const foundIds = new Set<string>();
// 分批获取所有鱼类数据,直到找齐所需的鱼类
while (hasMore && foundIds.size < fishIds.length) {
const res = await listFish({
pageNum: pageNum,
pageSize: 100, // 每次获取100条
fishType: undefined,
fishName: undefined
});
const fishData = res.rows || res.data || [];
// 筛选出需要的鱼类
const neededFish = fishData.filter(fish => {
const fishIdStr = fish.id.toString();
if (fishIds.includes(fishIdStr) && !foundIds.has(fishIdStr)) {
foundIds.add(fishIdStr);
return true;
}
return false;
});
allFishList.push(...neededFish);
// 判断是否还需要继续获取
hasMore = fishData.length === 100 && foundIds.size < fishIds.length;
pageNum++;
// 安全限制,避免无限循环
if (pageNum > 50) break;
}
return allFishList;
} catch (error) {
console.error('获取鱼类信息失败:', error);
return [];
}
};
const getFishList = async () => {
const res = await listFish({
pageNum: 1,
pageSize: 1000, // 获取所有数据
fishType: fishQueryParams.fishType,
fishName: fishQueryParams.fishName
});
fishList.value = res.rows || res.data || [];
fishTotal.value = res.total || 0;
// 数据加载完成后,设置当前页面的选中状态
await nextTick();
const currentPageSelection = getCurrentPageSelection();
if (fishTableRef.value && currentPageSelection.length > 0) {
// 清空当前选中状态
fishTableRef.value.clearSelection();
// 设置已选择的项目
currentPageSelection.forEach(fish => {
fishTableRef.value!.toggleRowSelection(fish, true);
});
}
};
/** 鱼类分页改变 */
const handleFishPaginationChange = () => {
getFishList();
};
/** 搜索鱼品种 */
const handleFishQuery = () => {
getFishList();
};
/** 重置鱼品种搜索 */
const resetFishQuery = () => {
fishQueryParams.fishType = undefined;
fishQueryParams.fishName = undefined;
activeTab.value = 'all';
getFishList();
};
/** 切换tab */
const handleTabChange = (tabName: string) => {
activeTab.value = tabName;
if (tabName === 'all') {
fishQueryParams.fishType = undefined;
} else {
fishQueryParams.fishType = parseInt(tabName);
}
fishQueryParams.fishName = undefined; // 切换tab时清空名称搜索
getFishList();
};
/** 全选/反选鱼类 */
const handleSelectAllFish = (selection: FishVO[]) => {
// 先移除当前页面中的所有项目
const currentPageIds = fishList.value.map(fish => fish.id);
selectedFishList.value = selectedFishList.value.filter(fish => !currentPageIds.includes(fish.id));
// 再添加当前页面选中的项目
selectedFishList.value.push(...selection);
};
/** 快速添加单个鱼类 */
const quickAddFish = (fish: FishVO) => {
if (!selectedFishList.value.find(item => item.id === fish.id)) {
selectedFishList.value.push(fish);
}
};
/** 移除已选择的鱼类 */
const removeFish = (fishId: string | number) => {
selectedFishList.value = selectedFishList.value.filter(fish => fish.id !== fishId);
};
/** 清空所有已选择的鱼类 */
const clearAllFish = async () => {
selectedFishList.value = [];
// 清空表格选中状态
if (fishTableRef.value) {
fishTableRef.value.clearSelection();
}
};
/** 打开鱼品种选择对话框 */
const openFishSelect = () => {
// 备份当前选择状态,用于取消操作
originalSelectedFishList.value = [...selectedFishList.value];
// 仅重置搜索条件,不清空已选择的鱼类
fishQueryParams.fishType = undefined;
fishQueryParams.fishName = undefined;
activeTab.value = 'all';
getFishList();
fishSelectVisible.value = true;
};
/** 确认选择鱼品种 */
const confirmFishSelect = () => {
// 统一保存为JSON数组格式新增和编辑都使用此格式
const fishIds = selectedFishList.value.map(fish => fish.id);
form.value.fishKindIds = JSON.stringify(fishIds);
fishSelectVisible.value = false;
};
/** 取消选择鱼品种 */
const cancelFishSelect = () => {
// 取消时恢复到原有选择状态
selectedFishList.value = [...originalSelectedFishList.value];
fishSelectVisible.value = false;
};
/** 获取用户列表 */
const getAquUserList = async () => {
const res = await listAquUser(userQueryParams);
aquUserList.value = res.rows || res.data || [];
userTotal.value = res.total || 0;
};
/** 打开用户选择对话框 */
const openUserSelect = () => {
// 重置搜索条件
userQueryParams.pageNum = 1;
userQueryParams.userName = undefined;
userQueryParams.mobilePhone = undefined;
getAquUserList();
userSelectVisible.value = true;
};
/** 搜索用户 */
const handleUserQuery = () => {
userQueryParams.pageNum = 1;
getAquUserList();
};
/** 重置用户搜索 */
const resetUserQuery = () => {
userQueryParams.pageNum = 1;
userQueryParams.userName = undefined;
userQueryParams.mobilePhone = undefined;
getAquUserList();
};
/** 用户分页改变 */
const handleUserPaginationChange = () => {
getAquUserList();
};
/** 选择用户 */
const handleUserSelect = (user: AquUserVO) => {
selectedUser.value = user;
form.value.userId = user.id;
userSelectVisible.value = false;
};
/** 取消选择用户 */
const cancelUserSelect = () => {
userSelectVisible.value = false;
};
/** 查询塘口列表 */
const getList = async () => {
loading.value = true;
const timeRange = queryParams.value.time;
@@ -189,8 +739,8 @@ const getList = async () => {
st = dayjs(timeRange[0]).format('YYYY-MM-DD');
et = dayjs(timeRange[1]).format('YYYY-MM-DD');
}
queryParams.value.startTime = st;
queryParams.value.endTime = et;
queryParams.value.params.startTime = st;
queryParams.value.params.endTime = et;
const res = await listPond(queryParams.value);
pondList.value = res.rows;
total.value = res.total;
@@ -206,6 +756,8 @@ const cancel = () => {
/** 表单重置 */
const reset = () => {
form.value = { ...initFormData };
// 注释掉清空选择列表,保持弹窗独立性
// selectedFishList.value = [];
pondFormRef.value?.resetFields();
};
@@ -231,8 +783,10 @@ const handleSelectionChange = (selection: PondVO[]) => {
/** 新增按钮操作 */
const handleAdd = () => {
reset();
selectedFishList.value = []; // 新增时清空选择列表
selectedUser.value = null; // 清空用户选择
dialog.visible = true;
dialog.title = '添加塘口管理';
dialog.title = '添加塘口';
};
/** 修改按钮操作 */
@@ -241,8 +795,41 @@ const handleUpdate = async (row?: PondVO) => {
const _id = row?.id || ids.value[0];
const res = await getPond(_id);
Object.assign(form.value, res.data);
// 解析JSON数组格式的鱼类ID
if (form.value.fishKindIds) {
const fishIds = parseFishIds(form.value.fishKindIds);
selectedFishList.value = await getFishByIds(fishIds);
} else {
selectedFishList.value = [];
}
// 回显用户信息 - 优化加载逻辑
if (form.value.userId) {
try {
// 先加载用户列表使用较大的pageSize确保包含目标用户
const userRes = await listAquUser({
pageNum: 1,
pageSize: 1000
});
const userList = userRes.rows || userRes.data || [];
const user = userList.find(u => u.id.toString() === form.value.userId.toString());
if (user) {
selectedUser.value = user;
} else {
console.warn('未找到用户ID:', form.value.userId);
selectedUser.value = null;
}
} catch (error) {
console.error('加载用户信息失败:', error);
selectedUser.value = null;
}
} else {
selectedUser.value = null;
}
dialog.visible = true;
dialog.title = '修改塘口管理';
dialog.title = '修改塘口';
};
/** 提交按钮 */
@@ -265,7 +852,7 @@ const submitForm = () => {
/** 删除按钮操作 */
const handleDelete = async (row?: PondVO) => {
const _ids = row?.id || ids.value;
await proxy?.$modal.confirm('是否确认删除塘口管理编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
await proxy?.$modal.confirm('是否确认删除塘口编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
await delPond(_ids);
proxy?.$modal.msgSuccess('删除成功');
await getList();
@@ -286,3 +873,154 @@ onMounted(() => {
getList();
});
</script>
<style scoped>
.selected-fish-panel {
border: 1px solid #dcdfe6;
border-radius: 4px;
height: 450px;
display: flex;
flex-direction: column;
}
.panel-header {
padding: 12px 16px;
border-bottom: 1px solid #ebeef5;
display: flex;
justify-content: space-between;
align-items: center;
background-color: #f5f7fa;
}
.panel-header h4 {
margin: 0;
font-size: 14px;
color: #303133;
}
.selected-list {
flex: 1;
overflow-y: auto;
padding: 8px;
}
.selected-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 8px 12px;
margin-bottom: 6px;
background-color: #f0f9ff;
border: 1px solid #b3d8ff;
border-radius: 4px;
font-size: 13px;
}
.fish-name {
flex: 1;
color: #303133;
}
.selected-count {
color: #606266;
margin-right: auto;
font-size: 14px;
}
.dialog-footer {
display: flex;
justify-content: flex-end;
align-items: center;
gap: 10px;
}
/* 鱼品种选择器样式 */
.fish-selector {
width: 100%;
}
.input-suffix {
display: flex;
align-items: center;
gap: 8px;
padding-right: 8px;
}
.count-badge {
background: #409eff;
color: white;
border-radius: 10px;
padding: 2px 8px;
font-size: 12px;
min-width: 16px;
text-align: center;
}
.select-icon {
color: #c0c4cc;
font-size: 14px;
}
.selected-items {
margin-top: 8px;
border: 1px solid #e4e7ed;
border-radius: 4px;
background: #f9f9f9;
}
.selected-summary {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 12px;
border-bottom: 1px solid #ebeef5;
background: #f5f7fa;
}
.summary-text {
font-size: 13px;
color: #606266;
font-weight: 500;
}
.clear-btn {
color: #f56c6c;
padding: 0;
font-size: 12px;
}
.clear-btn:hover {
color: #f78989;
}
.selected-list-compact {
padding: 10px 12px;
line-height: 1.5;
color: #303133;
font-size: 14px;
}
.fish-item {
color: #409eff;
font-weight: 500;
}
.more-indicator {
color: #909399;
font-style: italic;
}
.selected-fish-tags {
max-height: 100px;
overflow-y: auto;
padding: 8px;
border: 1px solid #dcdfe6;
border-radius: 4px;
background-color: #f5f7fa;
}
.selected-fish-tags .el-tag {
margin-right: 6px;
margin-bottom: 4px;
}
</style>