Files
fishery-app/src/home/updatePond.vue
2026-01-12 00:36:05 +08:00

662 lines
20 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="updatePond">
<scroll-view :scroll-y="true" :style="{ height: '100%' }">
<view class="body">
<nut-form ref="updateRef" :rules="rule" :model-value="formData">
<nut-form-item label="鱼塘名称" prop="pondName">
<nut-input
clearable
:cursor="formData.pondName.length"
input-align="right"
v-model="formData.pondName"
type="text"
:max-length="20"
placeholder="请输入鱼塘名称"
/>
</nut-form-item>
<nut-form-item label="养殖品种" prop="fishKindIds">
<view
@click="showFish = true"
:style="{
width: '100%',
minHeight: '60px',
justifyContent: ' flex-end',
}"
:class="fishListInfo ? 'c_222 view_f' : 'c_757575 view_f'"
>
<nut-ellipsis
direction="end"
:content="fishListInfo ? fishListInfo : '请选择养殖品种'"
:rows="3"
expand-text="展开"
collapse-text="收起"
:style="{ float: 'right' }"
></nut-ellipsis>
<Right color="#979797" />
</view>
</nut-form-item>
<nut-form-item label="密度" prop="density">
<nut-input
type="digit"
clearable
:cursor="String(formData.density).length"
input-align="right"
v-model="formData.density"
placeholder="请输入密度"
>
<template #right>
<text class="c_888">/</text>
</template>
</nut-input>
</nut-form-item>
<nut-form-item label="鱼塘面积" prop="area">
<nut-input
type="digit"
clearable
input-align="right"
:cursor="String(formData.area).length"
v-model="formData.area"
placeholder="请输入鱼塘面积"
>
<template #right>
<text class="c_888"></text>
</template>
</nut-input>
</nut-form-item>
<nut-form-item label="投苗日期" prop="placeTime">
<nut-input
clearable
input-align="right"
v-model="formData.placeTime"
type="text"
readonly
@click="show = true"
placeholder="请选择投苗日期"
>
<template #right>
<Right color="#979797" />
</template>
</nut-input>
</nut-form-item>
</nut-form>
<nut-config-provider :theme-vars="themeVars">
<nut-cell-group>
<nut-cell title="塘口设备" is-link @click="bandDevice">
<template #desc>
<text class="c_17B4B2">选择设备</text>
</template>
</nut-cell>
<nut-cell
v-for="item in detectorList"
:key="item.id"
:style="{
padding: 'var(--nut-cell-padding, 26rpx 32rpx) !important',
}"
>
<template #title>
<span class="font_30 c_222">{{ item.deviceName }}</span>
</template>
<template #icon>
<IconFont :name="rongjieyang" />
</template>
</nut-cell>
<nut-collapse v-for="item in controlList" :key="item.id">
<nut-collapse-item :name="item.id">
<template #title>
<view class="view_f">
<IconFont
:name="kongzhiqi"
:style="{
margin: 'var(--nut-cell-default-icon-margin, 0 8rpx 0 0rpx)',
}"
/>
<text class="font_30 c_222">{{ item.deviceName }}</text>
</view>
</template>
<nut-cell-group>
<nut-cell v-for="i in item.listSwitch" :key="i.id">
<template #title>
<span class="font_30 c_222">{{ i.switchName }}</span>
</template>
<template #icon>
<IconFont :name="kaiguan" />
</template>
</nut-cell>
</nut-cell-group>
</nut-collapse-item>
</nut-collapse>
</nut-cell-group>
</nut-config-provider>
<nut-button
block
shape="square"
type="primary"
size="large"
:style="{
fontWeight: 'bold',
fontSize: '14px !important',
borderRadius: '10px',
}"
@click="save"
:loading="isLoading"
>保存</nut-button
>
<nut-button
block
shape="square"
size="large"
color="#E22323"
plain
:style="{
fontWeight: 'bold',
fontSize: '14px !important',
borderRadius: '10px',
marginTop: '20rpx',
}"
:loading="d_isLoading"
@click="delPond"
v-if="Uid == rootuserid"
>删除塘口</nut-button
>
</view>
</scroll-view>
<!-- 日期选择器 -->
<nut-popup v-model:visible="show" position="bottom">
<nut-date-picker
v-model="val"
:min-date="min"
:max-date="max"
:three-dimensional="false"
@confirm="confirm"
@cancel="cancelDate"
></nut-date-picker>
</nut-popup>
<!-- 鱼类选择器 -->
<nut-popup v-model:visible="showFish" position="bottom" :style="{ height: '50%' }">
<Fish
@cancel="cancel"
@confirm="submit"
:fishIds="formData.fishKindIds"
:style="{ marginBottom: '20px' }"
/>
</nut-popup>
<!-- 绑定设备弹框 -->
<nut-dialog v-model:visible="bandDevShow" text-align="left" no-footer>
<view class="d_body" :style="{ paddingBottom: '0px' }">
<nut-row>
<nut-col :span="24">
<view class="d_title">选择设备</view>
</nut-col>
<nut-col :span="24">
<nut-divider class="divider" />
</nut-col>
<nut-col :span="24">
<next-tree
ref="qiantree"
:selectParent="false"
labelKey="deviceName"
valueKey="id"
:multiple="true"
:treeData="deviceList"
@confirm="onconfirm"
childrenKey="listSwitch"
border
@cancel="oncancel"
showChild
/>
</nut-col>
</nut-row>
</view>
</nut-dialog>
<!-- 弹出层提示 -->
<nut-dialog :content="msg" v-model:visible="showRes" no-footer>
<view :style="{ height: '100%' }">
<view class="d_body">
<nut-row>
<nut-col :span="24" class="d_title" :style="{ textAlign: 'center' }">
请选择鱼塘!
</nut-col>
</nut-row>
</view>
<view class="d_btn" :style="{ position: 'absolute' }">
<nut-row>
<nut-col :span="24" :style="{ border: '1px solid #eee', color: '#15BBC5' }">
<nut-button type="primary" shape="square" block @click="goHome"
>确定</nut-button
>
</nut-col>
</nut-row>
</view>
</view>
</nut-dialog>
<!-- 弹出层提示 -->
<nut-toast :msg="state.msg" v-model:visible="state.show" :type="state.type" />
</view>
</template>
<script setup lang="ts" name="UpdatePond">
import { UpdateFormType } from "./types";
import Fish from "@/components/other/fish";
import { PondUpdate, pondBaseInfo, pondDeviceInfo, PondDel, fishList } from "@/api/pond";
import { allDeviceList, bandDeviceToPond } from "@/api/device";
import { formatDate, sortByField } from "@/utils/tools";
import Taro from "@tarojs/taro";
import { IconFont, Right } from "@nutui/icons-vue-taro";
import nextTree from "@/components/tree/index";
import { stateType } from "@/utils/types";
import { imgUrl } from "@/utils/imgUrl";
definePageConfig({
navigationBarTitleText: "塘口设置",
});
const store: any = inject("store");
const kaiguan = `${imgUrl}kaiguan.png`;
const rongjieyang = `${imgUrl}rongjieyang.png`;
const kongzhiqi = `${imgUrl}kongzhiqi.png`;
// 塘口id
const instance: any = Taro.getCurrentInstance();
const id = instance.router.params.id;
const themeVars = ref({
// cellPadding: '5px 16px',
collapseItemPadding: "5px 16px",
cellBoxShadow: "0px",
collapseWrapperContentPadding: "0px 10px",
});
const formData: UpdateFormType = reactive({
id: undefined,
pondName: "",
fishKindIds: [],
area: 0,
density: 0,
placeTime: null,
});
const rule = reactive({
pondName: [{ required: true, message: "请输入鱼塘名称" }],
fishKindIds: [{ required: true, message: "请选择养殖品种", validator: kindValidator }],
});
const updateRef: any = ref(null);
const showRes = ref<boolean>(false);
const msg = ref<string>("设置成功");
/** 日期弹框相关 */
const show = ref<boolean>(false);
const min = new Date(2000, 0, 1);
const max = new Date(2100, 0, 1);
const val = ref(new Date());
const showFish = ref<boolean>(false);
const isLoading = ref<boolean>(false);
const d_isLoading = ref<boolean>(false);
const fishListInfo = ref("");
const allFishList = ref<any[]>([]);
const detectorList = ref([]);
const controlList = ref([]);
const bandDevShow = ref(false);
const bandDeviceList = ref<any[]>([]);
// 设备列表
const deviceList = ref<any[]>([]);
const state: stateType = reactive({
msg: "",
type: "text",
center: true,
show: false,
});
const Uid = Taro.getStorageSync("UserId");
const rootuserid = ref(store.getRootUserId);
/** -----------------method start----------------- */
Taro.useDidShow(() => {
// 先加载鱼类列表,然后再加载塔口信息
getAllFishList().then(() => {
info();
});
getDeviceList();
getDevicesList();
});
// 校验
function kindValidator(val) {
if (val.length > 0) {
return Promise.resolve();
} else {
return Promise.reject("请选择养殖品种");
}
}
// 取消选择鱼类
function cancel() {
showFish.value = false;
// fishListInfo.value = "";
// formData.fishKindIds = [];
}
// 确定选择鱼类
function submit(e) {
showFish.value = false;
formData.fishKindIds = e ? e.res : [];
fishListInfo.value = e ? e.fishInfo : "";
}
// 确定日期
function confirm(e) {
const s = e.selectedValue;
formData.placeTime = s[0] + "-" + s[1] + "-" + s[2];
val.value = new Date(s[0], s[1] - 1 > 0 ? s[1] - 1 : 0, s[2]);
show.value = false;
}
// 保存
function save() {
updateRef.value?.validate().then(({ valid, errors }) => {
if (valid) {
if (formData.id) {
// 将fishKindIds数组转换为字符串格式 "[1,2]"
let fishKindIdsStr = '';
if (Array.isArray(formData.fishKindIds) && formData.fishKindIds.length > 0) {
// 转换为数字数组然后转JSON字符串
const fishIds = formData.fishKindIds.map(id => Number(id));
fishKindIdsStr = JSON.stringify(fishIds);
}
const data = {
id: formData.id,
pondName: formData.pondName,
fishKindIds: fishKindIdsStr, // 使用字符串格式
area: formData.area,
density: formData.density,
placeTime: formData.placeTime ? formData.placeTime : null,
};
console.log('保存数据', data);
isLoading.value = true;
PondUpdate(data)
.then((res: any) => {
if (res.code == 200) {
state.show = true;
state.msg = "保存成功";
// 延迟返回首页,让用户看到成功提示
setTimeout(() => {
Taro.switchTab({
url: "/pages/main/home",
});
}, 1500);
}
})
.finally(() => {
isLoading.value = false;
});
}
} else {
console.warn("error:", errors);
}
});
}
// 获取所有鱼类列表
function getAllFishList() {
return fishList().then((res: any) => {
console.log('鱼类列表接口返回', res);
// 处理不同的返回格式
if (res.rows) {
// 直接返回 {total, rows} 格式
allFishList.value = res.rows || [];
console.log('鱼类列表加载完成(rows)', allFishList.value);
} else if (res.code == 200 && res.data) {
allFishList.value = res.data || [];
console.log('鱼类列表加载完成(code)', allFishList.value);
} else if (res.statusCode == 200 && res.data) {
allFishList.value = res.data || [];
console.log('鱼类列表加载完成(statusCode)', allFishList.value);
} else {
console.error('鱼类列表加载失败', res);
}
});
}
// 根据鱼类ID获取鱼类名称
function getFishNames(fishIds: any[]) {
const names: string[] = [];
console.log('查找鱼类名称', { fishIds, allFishList: allFishList.value });
fishIds.forEach((id: any) => {
const fish = allFishList.value.find((f: any) => f.id == id || f.id == String(id));
if (fish) {
names.push(fish.fishName);
}
});
console.log('鱼类名称结果', names.join(""));
return names.join("");
}
// 查看鱼塘详情
function info() {
if (!id) {
// 错误提示
msg.value = "请选择鱼塘";
showRes.value = true;
return;
}
pondBaseInfo({ id }).then((res: any) => {
if (res.code == 200) {
formData.id = res.data.id;
formData.pondName = res.data.pondName;
formData.area = res.data.area;
formData.density = res.data.density;
// 解析fishKindIds后端返回的是字符串
let fishIds = [];
try {
if (typeof res.data.fishKindIds === 'string') {
fishIds = JSON.parse(res.data.fishKindIds);
} else if (Array.isArray(res.data.fishKindIds)) {
fishIds = res.data.fishKindIds;
}
} catch (e) {
console.error('解析fishKindIds失败', e);
}
formData.fishKindIds = fishIds.map(id => String(id));
// 根据ID查找鱼类名称
fishListInfo.value = getFishNames(fishIds);
// 时间日期格式化
if (res.data.placeTime) {
val.value = new Date(res.data.placeTime);
formData.placeTime = formatDate(val.value);
}
}
});
}
// 返回首页
function goHome() {
Taro.switchTab({
url: "/pages/main/home",
});
}
// 弹出绑定设备列表
function bandDevice() {
if (detectorList.value.length == 0 && controlList.value.length == 0) {
state.show = true;
state.msg = "请先添加设备";
} else {
bandDevShow.value = true;
}
}
// 获取塘口下的设备列表
function getDeviceList() {
// 查询塘口下设备列表
pondDeviceInfo({ id }).then((res: any) => {
if (res.code == 200) {
detectorList.value = res.data.listDetector;
controlList.value = res.data.listController;
}
});
}
// 设备列表
function getDevicesList() {
allDeviceList({ type: 1 }).then((res: any) => {
if (res.code == 200) {
res.data.forEach((r: any) => {
r.open = true;
r.disabled = false;
r.checked = false;
// 判断是否在当前选中的港口id
if (r.pondInfo) {
if (id == r.pondInfo.id) {
r.checked = true;
} else {
r.disabled = true;
}
}
if (r.deviceType == 2) {
r.id = undefined;
// r.id = r.deviceName;
}
if (r.listSwitch && r.listSwitch.length > 0) {
r.listSwitch.forEach((rr) => {
rr.deviceName = rr.switchName;
rr.disabled = false;
rr.checked = false;
// 判断是否在当前选中的港口id
if (rr.pondInfo) {
if (id == rr.pondInfo.id) {
rr.checked = true;
} else {
rr.disabled = true;
}
}
});
}
});
const ids: any = [];
res.data.forEach((device, i) => {
if (device.deviceType === 2 && device.isOxygenUsed) {
ids.push(i);
}
});
if (ids.length > 0) {
ids.forEach((i) => {
let newDevice = { ...res.data[i], deviceType: 1, listSwitch: [] }; // 修改deviceType并清空listSwitch
newDevice.id = newDevice.kzId;
res.data.push(newDevice);
});
}
res.data.forEach((r) => {
r.open = true;
r.disabled = false;
r.checked = false;
// 判断是否在当前选中的港口id
if (r.pondInfo) {
if (id == r.pondInfo.id) {
r.checked = true;
} else {
r.disabled = true;
}
}
});
res.data.sort(sortByField("deviceType", true));
deviceList.value = res.data;
}
});
}
// 取消绑定设备选择
function oncancel() {
bandDevShow.value = false;
}
// 确定选择绑定的设备
function onconfirm(list) {
bandDeviceList.value = list.list;
const listDetectorId: any = [];
const listSwitchId: any = [];
list.list.forEach((res) => {
if (res.source.deviceType) {
if (res.source.id) {
listDetectorId.push(res.source.id);
}
} else {
listSwitchId.push(res.source.id);
}
});
// 确定提示框
Taro.showModal({
title: "提示",
content: "确认绑定选中的设备?",
success: function (res) {
if (res.confirm) {
const data = {
pondId: id,
listDetectorId,
listSwitchId,
};
bandDeviceToPond(data)
.then((res) => {
if (res.code == 200) {
state.show = true;
state.msg = "绑定成功";
getDeviceList();
}
})
.finally(() => {
bandDevShow.value = false;
});
} else if (res.cancel) {
bandDevShow.value = false;
}
},
});
}
// 删除塘口
function delPond() {
let msg = "确认删除塘口?";
let title = "提示";
if (detectorList.value.length == 0 && controlList.value.length == 0) {
msg = "确认删除塘口?";
} else {
title = "提示!!!";
msg = "塘口存在设备,确认要删除塘口?";
}
Taro.showModal({
title: title,
content: msg,
success: function (res) {
if (res.confirm) {
d_isLoading.value = true;
PondDel({ id })
.then((res) => {
if (res.code == 200) {
state.show = true;
state.msg = "删除成功";
// 返回首页
Taro.switchTab({
url: "/pages/main/home",
});
}
})
.finally(() => {
d_isLoading.value = false;
});
} else if (res.cancel) {
console.log("用户点击取消");
}
},
});
}
// 取消日期选择
function cancelDate() {
formData.placeTime = null;
show.value = false;
}
/** -----------------method end------------------- */
</script>
<style lang="scss">
.updatePond {
width: 100%;
height: 100%;
background-image: url("https://www.yuceyun.cn/wechat/bg.jpg");
background-color: #e5ebed;
background-repeat: no-repeat;
background-size: 100% 100%;
position: fixed;
margin: 0;
.body {
padding: 20px;
}
.nut-dialog {
padding: 0;
}
.nut-dialog__content {
margin: 0;
max-height: 100%;
}
}
</style>