<template> <!-- 站点管理 --> <div class="siteManage"> <div class="searchBox"> <n-space> <n-input v-model:value="filterInfo.query.searchStr" clearable placeholder="请输入站点名称或编号" /> <n-date-picker v-model:value="timeRange" type="datetimerange" clearable /> <n-button type="primary" @click="handleClick('search')"> <template #icon> <n-icon><Search /></n-icon> </template> 搜索 </n-button> <n-button type="primary" @click="handleClick('create')"> <template #icon> <n-icon><Add /></n-icon> </template> 新增 </n-button> </n-space> </div> <div class="tableBox"> <n-data-table ref="tableRef" :bordered="false" striped :max-height="700" :columns="columns" :data="tableData" :remote="true" :loading="tableLoading" :pagination="pagination" ></n-data-table> </div> <!-- 新增/编辑 --> <n-modal :title="dialogInfo.title[dialogInfo.type]" preset="card" :show-icon="false" :style="{ width: '600px' }" v-model:show="dialogInfo.visible" > <n-form v-if="dialogInfo.type === 'create' || dialogInfo.type === 'update'" ref="formRef" :label-width="150" :rules="formInfo.rules" :model="formInfo.data" label-placement="left" > <n-form-item label="站点名称:" path="stName"> <n-input v-model:value="formInfo.data.stName" placeholder="请输入站点名称" style="width: 100%" /> </n-form-item> <n-form-item label="站点编号:" path="stCode"> <n-input v-model:value="formInfo.data.stCode" placeholder="请输入站点编号" style="width: 100%" :disabled="dialogInfo.type === 'update'" /> </n-form-item> <n-form-item label="站点类型:" path="station"> <n-select v-model:value="formInfo.data.station" filterable multiple :options="listTypeInfo['stationList']" placeholder="请选择站点类型" /> </n-form-item> <n-form-item label="安装类型:" path="installationType"> <n-select v-model:value="formInfo.data.installationType" filterable :options="installationdataList" placeholder="请选择安装类型" /> </n-form-item> <n-form-item label="站点状态:" path="constructionStatus"> <n-select v-model:value="formInfo.data.constructionStatus" :options="listTypeInfo['statusList']" /> </n-form-item> <n-form-item label="知晓站点上线:" path="isKnow"> <n-select v-model:value="formInfo.data.isKnow" :options="listTypeInfo['isKnowList']" /> </n-form-item> <n-grid x-gap="12" :cols="2"> <n-gi> <n-form-item label="经度:" path="lon"> <n-input v-model:value="formInfo.data.lon" placeholder="请输入经度" style="width: 100%" /> </n-form-item> </n-gi> <n-gi> <n-form-item label="纬度:" path="lat"> <n-input v-model:value="formInfo.data.lat" placeholder="请输入纬度" style="width: 100%" /> </n-form-item> </n-gi> </n-grid> <n-form-item label="站点安装位置:" path="address"> <n-input v-model:value="formInfo.data.address" placeholder="请输入站点安装位置" style="width: 100%" /> </n-form-item> <n-form-item label="安装负责人:" path="person"> <n-input v-model:value="formInfo.data.person" placeholder="请输入安装负责人" style="width: 100%" /> </n-form-item> <n-form-item label="视频监控地址:" path="videoPath"> <n-select v-model:value="formInfo.data.videoPath" multiple :options="videoList" /> </n-form-item> <n-form-item label="现场安装图片(最多3张):" path="fileList"> <n-upload v-model:file-list="uploadList" accept=".jpg,.png,.jpeg,.svg,.gif" :max="3" list-type="image-card" @change="changeFile"> 点击上传 </n-upload> </n-form-item> </n-form> <template #action> <n-space justify="end"> <n-button @click="() => (dialogInfo.visible = false)">取消</n-button> <n-button type="primary" @click="handleClick('submit')" :loading="formInfo.loading">确定</n-button> </n-space> </template> </n-modal> <!-- 因子分配 --> <n-modal title="因子分配" preset="card" :show-icon="false" :style="{ width: '750px' }" v-model:show="dialogInfo.visible2"> <n-transfer ref="transfer" v-model:value="transferValue" :options="transferOptions" source-title="可分配因子" target-title="已分配因子" filterable style="width: 700px" /> <template #action> <n-space justify="end"> <n-button @click="() => (dialogInfo.visible2 = false)">取消</n-button> <n-button type="primary" @click="() => (dialogInfo.visible2 = false)">确定</n-button> </n-space> </template> </n-modal> </div> </template> <script> import { reactive, toRefs, ref, h, onMounted, computed, watch } from 'vue'; import { NButton, NTag, useMessage, useDialog } from 'naive-ui'; import { Search, Add } from '@vicons/ionicons5'; import { formatDate } from '@/utils/util'; import { useStore } from 'vuex'; import { stationbaseList, sysDicList, fileUpload, fileDelete, sysStationbaseSaveOrupdate, queryRiverWaterVideo, equipConfigList, } from '@/services'; export default { components: { Search, Add, }, setup() { const message = useMessage(); const dialog = useDialog(); const store = useStore(); const formRef = ref(); const allData = reactive({ // 搜索相关 filterInfo: { query: { searchStr: '', startDate: '', endDate: '', platformCode: '', }, }, uploadList: [], imageZG: [], videoList: [], timeRange: null, fileList: [], //图片列表 installationdataList: [], //安装类型列表 // 弹窗相关 dialogInfo: { title: { create: '新增', update: '编辑', }, type: '', visible: false, type2: '', visible2: false, }, // 表单相关 formInfo: { loading: false, data: { id: '', stName: '', stCode: '', station: [], stationType: '', installationType: '', constructionStatus: 0, isKnow: 1, address: '', person: '', videoPath: [], lat: '', lon: '', fileList: [], }, rules: { stName: { required: true, message: '请输入站点名称', trigger: 'blur', }, stCode: { required: true, message: '请输入站点编号', trigger: 'blur', }, station: { type: 'array', required: true, message: '请选择站点类型', trigger: 'change', }, installationType: { required: true, message: '请选择安装类型', trigger: 'change', }, address: { required: true, message: '请输入安装位置', trigger: 'blur', }, person: { required: true, message: '请输入安装负责人', trigger: 'blur', }, lat: { required: true, message: '请输入纬度', trigger: 'blur', }, lon: { required: true, message: '请输入经度', trigger: 'blur', }, }, }, //表格 columns: [ { title: '站点编号', key: 'stCode', align: 'center', ellipsis: { tooltip: true, }, }, { title: '站点名称', key: 'stName', align: 'center', ellipsis: { tooltip: true, }, }, { title: '站点类型', key: 'stationType', align: 'center', render(row) { return h( NTag, { bordered: false, }, { default: () => row.stationType || '--', } ); }, }, { title: '安装类型', key: 'installationType', align: 'center', ellipsis: { tooltip: true, }, render(row) { const arr = allData.installationdataList.filter((item) => item.value == row['installationType']); if (arr.length) { return h( NTag, { bordered: false, }, { default: () => arr[0].label, } ); } }, }, { title: '站点状态', key: 'constructionStatus', align: 'center', render(row) { return h( NTag, { bordered: false, color: { color: 'transparent', textColor: row.constructionStatus == 0 ? '#006DF7' : '#d03050', }, }, { default: () => (row.constructionStatus == 0 ? '启用' : '禁用'), } ); }, }, { title: '站点上线', key: 'isKnow', align: 'center', render(row) { return h( NTag, { bordered: false, color: { color: 'transparent', textColor: row.isKnow == 1 ? '#006DF7' : '#d03050', }, }, { default: () => (row.isKnow == 1 ? '知晓' : '不知晓'), } ); }, }, { title: '站点存储时间', key: 'ut', width: '150', align: 'center', ellipsis: { tooltip: true, }, }, { title: '安装人', key: 'person', align: 'center', ellipsis: { tooltip: true, }, }, { title: '关联因子', key: 'actions', width: '80', align: 'center', render(row) { const btn = allData.actionColumn2.map((item) => { return h( NButton, { text: true, size: item.size, // style: { // margin: "10px", // }, type: item.btnType, onClick: () => handleClick(item.type, row), }, { default: () => item.default } ); }); return btn; }, }, { title: '站点安装时间', key: 'createTime', width: '150', align: 'center', ellipsis: { tooltip: true, }, }, // { // title: "创建人", // key: "createUserName", // align: "center", // ellipsis: { // tooltip: true, // }, // }, // { // title: "更新人", // key: "updateUserName", // align: "center", // ellipsis: { // tooltip: true, // }, // }, { title: '更新时间', key: 'updateTime', align: 'center', ellipsis: { tooltip: true, }, }, { title: '创建时间', key: 'createTime', align: 'center', ellipsis: { tooltip: true, }, }, { title: '操作', key: 'actions', width: '80', align: 'center', render(row) { const btn = allData.actionColumn.map((item) => { return h( NButton, { text: true, size: item.size, style: { margin: '10px', }, type: item.btnType, onClick: () => handleClick(item.type, row), }, { default: () => item.default } ); }); return btn; }, }, ], tableData: [], tableLoading: false, actionColumn: [ { size: 'small', btnType: 'primary', type: 'update', default: '编辑', }, ], actionColumn2: [ { size: 'small', btnType: 'primary', type: 'Yinzi', default: '关联因子', }, ], // 下拉数据集合 listTypeInfo: { isKnowList: [ { label: '不知晓', value: 0 }, { label: '知晓', value: 1 }, ], statusList: [ { label: '启用', value: 0 }, { label: '禁用', value: 1 }, ], stationList: [], }, // 穿梭框 transferValue: ['DO', 'TP', 'pH', 'CODMN'], transferOptions: [], }); allData.filterInfo.query.platformCode = computed(() => { return store.getters.platformCode; }); //分页 const paginationReactive = reactive({ page: 1, pageSize: 10, showSizePicker: true, pageSizes: [10, 20, 50], showQuickJumper: true, pageCount: 0, itemCount: 0, onChange: (page) => { paginationReactive.page = page; getTableData(); }, onPageSizeChange: (pageSize) => { paginationReactive.pageSize = pageSize; paginationReactive.page = 1; getTableData(); }, }); // 图片上传处理逻辑 const changeFile = async (file) => { $loadingBar.start(); if (file.event) { // 文件上传 let formdata = new FormData(); formdata.append('files', file.file.file); let config = { headers: { 'Content-Type': 'multipart/form-data' }, }; let res = await fileUpload(formdata, config); if (res && res.code === 200) { if (res.data.length > 0) { let datas = res.data[0]; allData.formInfo.data.fileList.push(datas); let param = { fileNo: datas.fileNo, name: datas.fileOriginalName, url: datas.fileCloudStorageKey, status: 'success', }; allData.imageZG.push(param); } } else { allData.uploadList = []; let param = { id: file.file.id, name: file.file.name, status: 'error', }; allData.uploadList.push(param); } $loadingBar.finish(); } else { // 文件删除,根据文件名进行匹配 let fileIndex = null; allData.imageZG.map((item, index) => { if (file.file.name == item.name) { fileIndex = index; } }); let fileNos = []; fileNos.push(allData.imageZG[fileIndex].fileNo); let res = await fileDelete(fileNos); if (res && res.code === 200) { allData.formInfo.data.fileList.splice(fileIndex, 1); } } }; // 点击事件 const handleClick = (type, row) => { switch (type) { // 搜索 case 'search': paginationReactive.page = 1; getTableData(); break; //新增 case 'create': resetForm(); allData.dialogInfo.type = type; allData.dialogInfo.visible = true; break; // 编辑 case 'update': allData.dialogInfo.type = type; for (let key in row) { if (key in allData.formInfo.data) { if (key === 'stationType') { row[key] = row[key] !== null ? row[key].toString() : ''; } if (key === 'installationType') { row[key] = `${row[key]}`; } if (key == 'videoPath') { if (!!!row[key]) row[key] = ''; if (row[key] != '') { row[key] = row[key].split(','); } } allData.formInfo.data[key] = row[key]; } } // 处理站点类型 let sitecodelist = []; let arr = row.stationType ? row.stationType.split('-') : []; if (arr.length) { for (var el in arr) { allData.listTypeInfo.stationList.forEach((item) => { if (arr[el] === item.label) { sitecodelist.push(item.value); } }); } } allData.formInfo.data.station = sitecodelist; // 图片文件默认填充 allData.uploadList = []; allData.imageZG = []; if (row.fileList != null && row.fileList.length > 0) { row.fileList.map((item) => { let param = { id: item.id, name: item.tableName, status: 'finished', url: item.fileCloudStorageKey, }; allData.uploadList.push(param); }); } allData.imageZG = allData.uploadList; allData.dialogInfo.visible = true; break; // 表单提交 case 'submit': formRef.value.validate((errors) => { if (!errors) { submit(); } else { console.log(errors); } }); break; case 'Yinzi': allData.dialogInfo.visible2 = true; break; } }; // 表单提交 async function submit() { // 处理站点类型 let namelist = []; allData.formInfo.data.station.forEach((item) => { allData.listTypeInfo.stationList.forEach((site) => { if (item == site.value) { namelist.push(site.label); } }); }); allData.formInfo.data.stationType = namelist.join('-'); if (typeof allData.formInfo.data.videoPath != 'string') { allData.formInfo.data.videoPath = allData.formInfo.data.videoPath.join(); } let params = { data: allData.formInfo.data, }; allData.formInfo.loading = true; let result = await sysStationbaseSaveOrupdate(params); allData.formInfo.loading = false; if (result.code === 1) { allData.dialogInfo.visible = false; if (allData.dialogInfo.type === 'create') { paginationReactive.page = 1; } getTableData(); } else { return; } } // 重置表单 function resetForm() { allData.formInfo.data = { id: '', stName: '', stCode: '', station: [], stationType: '', installationType: '', constructionStatus: 0, isKnow: 1, address: '', person: '', videoPath: null, lat: '', lon: '', fileList: [], }; } // 获取表格数据 const getTableData = async () => { allData.filterInfo.query.startDate = allData.timeRange ? formatDate(allData.timeRange[0]) : ''; allData.filterInfo.query.endDate = allData.timeRange ? formatDate(allData.timeRange[1]) : ''; let pramas = { current: paginationReactive.page, size: paginationReactive.pageSize, data: allData.filterInfo.query, }; allData.tableLoading = true; let res = await stationbaseList(pramas); if (res && res.code == 1) { let datas = res.data; allData.tableData = res.data.list; paginationReactive.pageCount = datas.pages; paginationReactive.itemCount = datas.total; } allData.tableLoading = false; }; //获取站点类型及安装类型列表 const getDicType = async () => { let result = await sysDicList({ tableFieldType: 'installation_type' }); if (result.code === 0) { allData.installationdataList = result.list.map((item) => { return { label: item.name, value: item.code, }; }); } let result1 = await sysDicList({ tableFieldType: 'site_type' }); if (result1.code === 0) { allData.listTypeInfo.stationList = result1.list.map((item) => { return { label: item.name, value: item.code, }; }); } }; // 获取摄像头列表 const getAllVideo = async () => { let res = await queryRiverWaterVideo(); if (res && res.code == 1) { allData.videoList = res.data; } }; // 获取所有因子数据 const getAllYinZiData = async () => { let pramas = { current: 1, size: 10000, data: { searchStr: '' }, }; let res = await equipConfigList(pramas); if (res && res.code == 1) { allData.transferOptions = []; res.data.list.forEach((element) => { allData.transferOptions.push({ label: element.codeProperty + ' (' + element.codeAscll + ')', value: element.codeAscll, }); }); } }; watch( () => allData.dialogInfo.visible, (val) => { if (!val) { allData.fileList = []; allData.dialogInfo.type = ''; } } ); onMounted(() => { getDicType(); getAllVideo(); getTableData(); getAllYinZiData(); }); return { formRef, ...toRefs(allData), pagination: paginationReactive, getTableData, handleClick, getDicType, changeFile, getAllVideo, }; }, }; </script> <style lang="less" scoped> .tableBox { margin-top: 10px; } </style>