Files
estate/src/views/system/Sdb/SdbElectricityDevice/index.vue
2026-04-27 11:20:48 +08:00

572 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>
<div class="h-full flex flex-col p-2">
<pageheader></pageheader>
<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" label-width="100px" :model="queryParams" :inline="true">
<el-form-item label="设备状态" prop="status">
<el-select v-model="queryParams.status">
<el-option v-for="(item, index) in com_waterdevice_on_status" :key="index" :label="item.label" :value="item.value"></el-option>
</el-select>
</el-form-item>
<el-form-item label="分合状态" prop="status">
<el-select v-model="queryParams.status">
<el-option
v-for="(item, index) in com_electricity_readrecord_status"
:key="index"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="房间号" prop="houseName">
<el-input v-model="queryParams.houseName" placeholder="请输入房间号" clearable @keyup.enter="handleQuery" />
</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 class="flex-1" shadow="never">
<template #header>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleMarkqrcode" v-hasPermi="['waterRecord:waterRecord:add']"
>批量生成条形码</el-button
>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="Upload">批量更新固件</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<el-table v-loading="loading" border :data="ElectricityDeviceList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="电表设备编码" align="center" prop="deviceCode" />
<el-table-column label="设备状态" width="100" align="center" prop="status">
<template #default="scope">
<dict-tag :options="com_waterdevice_on_status" :value="scope.row.status"></dict-tag>
</template>
</el-table-column>
<el-table-column label="分合状态" width="100" align="center">
<template #default="scope">
<div class="readRecord" v-if="scope.row.waterRecord">
<DictTag :options="com_electricity_readrecord_status" :value="scope.row.waterRecord.status"></DictTag>
</div>
<span v-else>-----</span>
</template>
</el-table-column>
<el-table-column label="户号" align="center" prop="houseName" />
<el-table-column label="余额" width="100" align="center" prop="elePrice">
<template #defaul="scope">
<span v-if="scope.row.electricityRecord">{{ scope.row.electricityRecord.balance }}</span>
<span v-else>-----</span>
</template>
</el-table-column>
<el-table-column label="条形码" width="140" align="center" prop="deleted">
<template #default="scope">
<el-image
v-if="scope.row.url && scope.row.url.includes('http')"
:src="scope.row.url"
:preview-src-list="[scope.row.url]"
style="width: 90px; height: 30px; border-radius: 4px; margin-right: 5px"
fit="cover"
preview-teleported
>
<template #toolbar>
<el-icon @click="download(scope.row.url)"><Download /></el-icon>
</template>
</el-image>
<span v-else>暂未生成</span>
</template>
</el-table-column>
<el-table-column label="抄表时间" align="center">
<template #default="scope">
<span>{{ scope.row.waterRecord ? scope.row.waterRecord.readTime : '--' }}</span>
</template>
</el-table-column>
<!-- <el-table-column label="操作" align="center" fixed="right" class-name="small-padding fixed-width">
<template #default="scope">
<el-button link type="primary" @click="handleRecode(scope.row)">充值记录</el-button>
<el-button link type="primary" @click="handleQrCode(scope.row)">生成条码</el-button>
<el-button link type="primary" @click="handleOpenDialog('usedWater', scope.row)">用电量</el-button>
<el-button link type="primary" @click="handleOpenDialog('Upload', scope.row)">更新固件</el-button>
<el-button link type="primary" @click="handleOpenDialog('UpdateHouse', scope.row)" v-hasPermi="['system:waterDevice:edit']"
>修改</el-button
>
</template>
</el-table-column> -->
<el-table-column label="操作" align="center" fixed="right" class-name="small-padding fixed-width">
<template #default="scope">
<el-row>
<el-col :span="24" class="flex flex-items-center">
<el-button link type="primary" @click="handleRecode(scope.row)">充值记录</el-button>
<el-button link type="primary" @click="handleQrCode(scope.row)">生成条码</el-button>
<el-dropdown style="vertical-align: text-top">
<el-button link type="primary">
<div>
更多<el-icon><arrow-down /></el-icon>
</div>
</el-button>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item>
<div @click="handleOpenDialog('usedWater', scope.row)">用电量</div>
</el-dropdown-item>
<el-dropdown-item>
<div @click="handleOpenDialog('Upload', scope.row)">更新固件</div>
</el-dropdown-item>
<el-dropdown-item>
<div @click="handleOpenDialog('UpdateHouse', scope.row)" v-hasPermi="['system:waterDevice:edit']">修改</div>
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</el-col>
</el-row>
</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 v-if="dialogType === 'usedWater'" ref="UsedWaterformRef" :model="UsedWaterform" label-width="100px">
<el-form-item label="设备编号" prop="deviceCode"> {{ UsedWaterform.deviceCode }} </el-form-item>
<el-form-item label="开始时间" prop="startTime">
<el-date-picker
format="YYYY-MM-DD HH:MM:ss"
value-format="YYYY-MM-DD HH:MM:ss"
v-model="UsedWaterform.startTime"
type="datetime"
placeholder="开始时间"
/>
</el-form-item>
<el-form-item label="结束时间" prop="endTime">
<el-date-picker
format="YYYY-MM-DD HH:MM:ss"
value-format="YYYY-MM-DD HH:MM:ss"
v-model="UsedWaterform.endTime"
type="datetime"
placeholder="结束时间"
/>
</el-form-item>
<el-form-item>
<el-button :loading="buttonLoading" type="primary" @click="submitForm">搜索</el-button>
</el-form-item>
</el-form>
<el-form v-else-if="dialogType === 'Upload'" ref="UploadFileformRef" :model="UploadFileform" :rules="UploadFileformRules" label-width="100px">
<el-form-item label="上传更新文件" prop="file">
<el-upload
ref="uploadRef"
accept=".bin"
:action="uploadUrl"
name="file"
:headers="headerToken()"
:show-file-list="true"
class="upload-demo"
:on-success="handleAvatarSuccess"
:before-upload="beforeAvatarUpload"
>
<div class="uploadFileBox flex flex-items-center">
<el-icon>
<upload></upload>
</el-icon>
<div style="margin-left: 10px">上传文件</div>
</div>
<template #tip>
<div class="el-upload__tip">文件格式必须是 bin 格式</div>
</template>
</el-upload>
</el-form-item>
<el-form-item>
<el-button @click="unSubmit">取消</el-button>
<el-button :loading="buttonLoading" type="primary" @click="submitForm">更新到设备</el-button>
</el-form-item>
</el-form>
<el-form v-else-if="dialogType === 'UpdateHouse'" ref="EditHouseformRef" :model="EditHouseform" :rules="EditHouseformRules" label-width="100px">
<el-form-item label="更新户号" prop="houseId">
<el-cascader v-model="userHousepath" :options="treedata" @change="handleChange" />
</el-form-item>
<el-form-item>
<el-button @click="unSubmit">取消</el-button>
<el-button :loading="buttonLoading" type="primary" @click="submitForm">更新到设备</el-button>
</el-form-item>
</el-form>
<div v-show="!usedWaterInfo" class="usedWaterbox">
<div class="useditem">查询用电量开始时间</div>
<div class="useditem value">{{ UsedWaterInfo.startTime }}</div>
<div class="useditem">查询用电量结束时间</div>
<div class="useditem value">{{ UsedWaterInfo.endTime }}</div>
<div class="useditem">用电量</div>
<div class="useditem value">{{ UsedWaterInfo.count }}</div>
</div>
</el-dialog>
</div>
</template>
<script setup name="WaterDevice" lang="ts">
import {
ElectricityDeviceMakerQrcode,
getElectricityDeviceTimeRangeUsedWater,
listElectricityDevice,
updateElectricityDevice
} from '@/api/system/SdbElectricityDevice/index';
import { ElectricityDeviceVO } from '@/api/system/SdbElectricityDevice/type';
import { useHouseStore } from '@/store/modules/house';
import { useUserStore } from '@/store/modules/user';
import { Upload } from '@element-plus/icons-vue';
import { CascaderValue, tourEmits, UploadProps, UploadRawFile } from 'element-plus';
const huhao = 3096371295;
const uploadUrl = import.meta.env.VITE_APP_BASE_API + '/electricityDevice/upload';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { com_waterdevice_on_status } = toRefs<any>(proxy?.useDict('com_waterdevice_on_status'));
const { com_electricity_readrecord_status } = toRefs<any>(proxy?.useDict('com_electricity_readrecord_status'));
const ElectricityDeviceList = ref<ElectricityDeviceVO[]>([]);
const buttonLoading = ref(false);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref<{ id: string; deviceCode: string }[]>([]);
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const queryFormRef = ref<ElFormInstance>();
const dialog = reactive<DialogOption>({
visible: false,
title: ''
});
const data = reactive({
queryParams: {
pageNum: 1,
pageSize: 10,
deviceCode: undefined,
houseName: undefined,
status: undefined
}
});
const { queryParams } = toRefs(data);
/** 查询电 设备列表 */
const getList = async () => {
loading.value = true;
const res = await listElectricityDevice(queryParams.value);
ElectricityDeviceList.value = res.rows;
total.value = res.total;
loading.value = false;
};
// ! 用电量 =============================================================================
const usedWaterInfo = ref(true);
const UsedWaterformRef = ref(null);
const UsedWaterform = ref({
deviceCode: '',
startTime: '',
endTime: ''
});
const UsedWaterInfo = ref({
count: '',
startTime: '',
endTime: ''
});
// ! =======================================================================================
// ? 上传固件 ==============================================================================================
const UploadFileformRef = ref(null);
const uploadRef = ref(null);
const UploadFileform = ref({
id: '',
deviceCode: '',
file: ''
});
const UploadFileformRules = {
file: [{ required: true, message: '更新文件不能为空', trigger: 'blur' }]
};
// 携带token
function headerToken() {
const useStore = useUserStore();
return {
Authorization: 'Bearer ' + useStore.token
};
}
const beforeAvatarUpload: UploadProps['beforeUpload'] = (rawFile: UploadRawFile) => {
// 1. 校验后缀
console.log(rawFile);
if (!rawFile.name.endsWith('.bin')) {
ElMessage.warning('请上传 .bin 后缀的文件');
return false;
}
// 2. 校验文件类型bin 文件类型)
if (rawFile.type !== 'application/octet-stream' && rawFile.type !== '') {
ElMessage.warning('文件类型不正确,请上传标准 bin 文件');
return false;
}
// 3. 校验文件大小(不能空)
if (rawFile.size === 0) {
ElMessage.warning('上传 bin 文件不能为空');
return false;
}
return true;
};
const handleAvatarSuccess: UploadProps['onSuccess'] = (response: any) => {
UploadFileform.value.file = response.data.url;
};
// ? 上传固件 ==============================================================================================
// * 编辑房屋 ==============================================================================================
// 编辑房屋
const EditHouseformRef = ref(null);
const EditHouseformRules = {
file: [{ required: true, message: '更新文件不能为空', trigger: 'blur' }]
};
const EditHouseform = ref({
id: '',
deviceCode: '',
houseId: ''
});
// * 编辑房屋 ==============================================================================================
/** 批量生成 条形码 */
function handleMarkqrcode() {
if (ids.value.length > 0) {
ElectricityDeviceMakerQrcode(ids.value).then((res) => {
ElMessage.success('批量生成成功');
getList();
});
} else {
ElMessage.warning('请选择设备');
}
}
/** 多选框选中数据 */
const handleSelectionChange = (selection: ElectricityDeviceVO[]) => {
ids.value = selection.map((item) => {
return {
id: item.id,
deviceCode: item.deviceCode
};
});
single.value = selection.length != 1;
multiple.value = !selection.length;
};
// TODO 生成条码
/** 生成二维码 */
const handleQrCode = (row: ElectricityDeviceVO) => {
// 1.电表 2.电表
ElectricityDeviceMakerQrcode([
{
id: row.id,
deviceCode: row.deviceCode
}
]).then(() => {
ElMessage.success('生成成功');
getList();
});
};
// * house
const treedata = ref([]);
const houseStore = useHouseStore();
const userHousepath = ref<CascaderValue>([]);
function handleChange(val: CascaderValue) {
userHousepath.value = val;
EditHouseform.value.houseId = val[2];
}
// * house
const dialogType = ref<'usedWater' | 'Upload' | 'UpdateHouse'>('usedWater');
/** 用电量 更新固件 */
const handleOpenDialog = (type: 'usedWater' | 'Upload' | 'UpdateHouse', row: ElectricityDeviceVO) => {
reset();
dialog.visible = true;
dialogType.value = type;
dialog.title = type === 'usedWater' ? '用电量' : type === 'UpdateHouse' ? '编辑户号' : '更新固件';
if (type === 'usedWater') {
UsedWaterform.value.deviceCode = row.deviceCode;
UsedWaterform.value.startTime = new Date().toLocaleString();
UsedWaterform.value.endTime = new Date().toLocaleString();
usedWaterInfo.value = true;
} else if (type === 'Upload') {
UploadFileform.value.file = '';
UploadFileform.value.deviceCode = row.deviceCode;
UploadFileform.value.id = row.id;
} else if (type === 'UpdateHouse') {
EditHouseform.value.id = row.id;
EditHouseform.value.deviceCode = row.deviceCode;
EditHouseform.value.houseId = '';
getTree();
}
};
function getTree() {
treedata.value = [];
houseStore.getCurrentVilageTreeHouse().then((res) => {
treedata.value = res;
userHousepath.value = [];
});
}
/** 电表 启停*/
// TODO 修改水电表 启停
const handleChangeWater = (val: string, row: ElectricityDeviceVO) => {};
// TODO 修改电表户号
/** 提交按钮 */
const submitForm = () => {
if (dialogType.value === 'usedWater') {
UsedWaterformRef.value?.validate(async (valid: boolean) => {
if (valid) {
buttonLoading.value = true;
await getElectricityDeviceTimeRangeUsedWater(UsedWaterform.value)
.then((res) => {
UsedWaterInfo.value.endTime = res.data.endTime;
UsedWaterInfo.value.startTime = res.data.startTime;
UsedWaterInfo.value.count = res.data.count;
})
.finally(() => (buttonLoading.value = false));
proxy?.$modal.msgSuccess('操作成功');
usedWaterInfo.value = false;
}
});
} else if (dialogType.value === 'UpdateHouse') {
EditHouseformRef.value?.validate(async (valid: boolean) => {
if (valid) {
buttonLoading.value = true;
await updateElectricityDevice(EditHouseform.value).finally(() => (buttonLoading.value = false));
proxy?.$modal.msgSuccess('操作成功');
getList();
unSubmit();
}
});
}
};
const unSubmit = () => {
reset();
dialog.visible = false;
dialog.title = '';
uploadRef?.value.clearFiles();
};
/** 表单重置 */
const reset = () => {
usedWaterInfo.value = true;
UsedWaterform.value = {
deviceCode: '',
startTime: '',
endTime: ''
};
UsedWaterInfo.value = {
count: '',
startTime: '',
endTime: ''
};
EditHouseform.value = {
houseId: '',
deviceCode: '',
id: ''
};
UploadFileform.value.file = '';
// 上传 清空
UploadFileformRef.value?.resetFields();
// 使用电量 清空
EditHouseformRef.value?.resetFields();
// 使用电量 清空
UsedWaterformRef.value?.resetFields();
};
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.value.pageNum = 1;
getList();
};
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value?.resetFields();
handleQuery();
};
const router = useRouter();
// TODO 充值记录 查询
/** 充值记录 */
const handleRecode = (row: ElectricityDeviceVO) => {
// 1.电表 2.电表
router.push({
path: '/equipment/TopupRecord2',
query: {
type: '2',
houseName: row.houseName,
deviceCode: row.deviceCode,
id: row.id
}
});
};
onMounted(() => {
getList();
});
const download = (url: string) => {
console.log(url);
if (!url) return;
if (!url.includes('http')) return;
// 创建一个隐藏的 a 标签,直接跳转下载
const link = document.createElement('a');
link.href = url;
link.download = ''; // 自动获取文件名
link.target = '_blank';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
};
</script>
<style lang="scss" scoped>
.el-table {
height: calc(100% - 80px);
}
.usedWaterbox {
width: 100%;
border: 1px solid #eef0ff;
.useditem {
height: 42px;
line-height: 42px;
background-color: rgba(26, 117, 255, 0.1);
color: rgba(16, 16, 16, 1);
font-size: 14px;
padding: 0 10px;
&.value {
background-color: #fff;
}
}
}
.uploadFileBox {
width: 276px;
height: 35px;
line-height: 20px;
border-radius: 4px 4px 4px 4px;
background-color: rgba(255, 255, 255, 1);
color: rgba(16, 16, 16, 1);
border: 1px solid #ccc;
padding-left: 20px;
font-size: 14px;
}
</style>