소스 검색

增加单井巡查模板编辑器,单井信息管理完善模板配置

chenwen 2 년 전
부모
커밋
a236dc5d6a
5개의 변경된 파일506개의 추가작업 그리고 2개의 파일을 삭제
  1. 3 0
      package.json
  2. 50 0
      src/api/singleLayoutTemp.js
  3. 98 0
      src/components/layouttmp/LayoutTmp.vue
  4. 331 0
      src/pages/base/SingleLayoutTemp.vue
  5. 24 2
      src/pages/base/WellEdit.vue

+ 3 - 0
package.json

@@ -7,12 +7,15 @@
     "serve": "vite preview"
   },
   "dependencies": {
+    "@createjs/easeljs": "^2.0.0-beta.4",
     "@element-plus/icons-vue": "^2.0.10",
     "axios": "^1.3.4",
+    "echarts": "^5.4.2",
     "element-plus": "^2.3.3",
     "pinia": "^2.0.32",
     "v-contextmenu": "^3.0.0",
     "vue": "^3.2.47",
+    "vue-drag-resize": "^1.5.4",
     "vue-i18n": "^9.2.2",
     "vue-router": "^4.1.6",
     "vuedraggable": "^4.1.0"

+ 50 - 0
src/api/singleLayoutTemp.js

@@ -0,0 +1,50 @@
+import request from '../utils/request';
+
+const api={}
+
+
+
+api.loadTempList=()=>{
+	return request({
+	    url: '/base/temp/loadTypeAll',
+	    method: 'post',
+		data:{tempType:'single'}
+	});
+}
+
+
+api.save=(data)=>{
+	return request({
+	    url: '/base/temp/update',
+	    method: 'post',
+		data:  data
+	});
+}
+
+api.saveAs=(data)=>{
+	return request({
+	    url: '/base/temp/add',
+	    method: 'post',
+		data:  data
+	});
+}
+
+
+
+api.del = (tempId) => {
+	    return request({
+	        url: '/base/temp/delete',
+	        method: 'post',
+			data:  {tempId}
+	    });
+}
+
+api.getTempDtl = (tempId) => {
+	    return request({
+	        url: '/base/temp/get',
+	        method: 'post',
+			data:  {tempId}
+	    });
+}
+
+export  default api

+ 98 - 0
src/components/layouttmp/LayoutTmp.vue

@@ -0,0 +1,98 @@
+<template>
+	<VueDragResize 
+	:isActive="false" 
+	w="auto" 
+	h="auto"  
+	:snapToGrid="true" 
+	:gridX="10" 
+	:gridY="10" 
+	v-for="(el,index) in modelValue"
+	:key="el.code"
+	:isResizable="el.elType!='single'"
+	:parentLimitation="true"
+	:x="el.left||0"
+	:y="el.top||0"
+	@resizestop="(newRect)=>{resize(newRect,el)}" 
+	@dragstop="(newRect)=>{resize(newRect,el)}"
+	
+	>
+	
+		<div class="single" v-if="el.elType=='single'" :style="{width:el.width+'px',height:el.height+'px'}">
+			<div class="single-header">{{el.name}}</div>
+			<div class="single-body"></div>
+		</div>
+		<div class="multi" v-else-if="el.elType=='multi'" :style="{width:el.width+'px',height:el.height+'px'}">
+			{{el.name}}
+		</div>
+		
+		<div class="wellName" v-else-if="el.elType=='wellName'" :style="{width:el.width+'px',height:el.height+'px'}">
+			{{el.name}}
+		</div>
+	
+	</VueDragResize>
+	
+</template>
+
+<script setup>
+	import {ref,reactive,toRaw,onMounted } from 'vue'
+	import VueDragResize from 'vue-drag-resize/src'
+	
+	const emit=defineEmits(['update:modelValue'])
+	
+	const props=defineProps({
+		modelValue:{
+			type:Array,
+			required:true
+		}
+	})
+	
+	const resize=(newRect,el)=>{
+		//console.log(el,tag)
+		//console.log(newRect)
+		let {width,height,left,top}=newRect
+		Object.assign(el,{width,height,left,top})
+		emit('update:modelValue',props.modelValue) 
+	}
+	
+	/**
+	const activeHandle=(el,activeTag)=>{  
+		el['active']=activeTag
+	}**/
+</script>
+
+<style scoped>
+	.single,.multi{
+		box-sizing: border-box;
+		width: 100%;
+		height: 100%;
+		padding: 0px;
+		background-color: #f0f9ff;
+		border:1px solid #e3f1f8;
+		border-radius: 5px;
+	}
+	.single .single-header{
+		background-color:#5085ff;
+		height: 50%;
+		
+		border-top-left-radius: 5px;
+		border-top-right-radius: 5px;
+		color:#fff;
+		text-align: center;
+		
+		font-size: 14px;
+		display: flex;
+		flex-flow: row nowrap;
+		justify-content: center;
+		align-items: center;
+	}
+	
+	.multi{
+		text-align: center;
+		font-size: 14px;
+	}
+	
+	.wellName{
+		padding: 0px;
+		border-bottom: 1px solid #5085ff;
+	}
+</style>

+ 331 - 0
src/pages/base/SingleLayoutTemp.vue

@@ -0,0 +1,331 @@
+<template>
+	<div class="page-container" >
+		<div class="edit-box">
+			
+			<LayoutTmp v-model="layoutELModels"></LayoutTmp>
+			
+		</div>
+		
+		<VueDragResize
+		:isActive="false" 
+		:w="320" 
+		:h="300"
+		:x="60"
+		:isResizable="false"
+		:parentLimitation="false"
+		key="ctr-panel"
+		>
+			<el-card class="ctr-panel">
+				<el-button-group>
+					<el-button type="primary" icon="Folder" @click="saveTemp('save')">保存</el-button>
+					<el-button type="primary" icon="FolderAdd" @click="saveTemp('saveAs')">另存为</el-button>
+					<el-button type="primary" icon="Delete" @click="delTemp">删除</el-button>
+				</el-button-group>
+				<el-select v-model="formModel.tempId" placeholder="选择单井模板" style="width:100%;margin-top:10px;" @change="changeTempHandle">
+					<el-option value="new" label="空白模板"/>
+					<el-option
+					  v-for="item in tempList"
+					  :key="item.tempId"
+					  :label="item.tempName"
+					  :value="item.tempId"
+					/>
+				</el-select>
+				
+				<el-collapse  accordion>
+					<el-collapse-item title="单值元素" name="1">
+						 <el-tag v-for="(el,index) in elOpts?.single" :key="index" @click="selEL(el)" :effect="el?.checked?'dark':'light'">{{el?.name}}</el-tag>
+					</el-collapse-item>
+					<el-collapse-item title="多值元素" name="2">
+						<el-tag v-for="(el,index) in elOpts?.multi" :key="index" @click="selEL(el)" :effect="el?.checked?'dark':'light'">{{el?.name}}</el-tag>
+					</el-collapse-item>
+					<el-collapse-item title="其它元素" name="3">
+						<el-tag v-for="(el,index) in elOpts?.oth" :key="index" @click="selEL(el)" :effect="el?.checked?'dark':'light'">{{el?.name}}</el-tag>
+					</el-collapse-item>
+				</el-collapse>
+			</el-card>
+		</VueDragResize>
+	
+		
+	</div>
+</template>
+
+<script setup>
+	import {ref,reactive,toRaw,onMounted } from 'vue'
+	import paramMgrAPI from '../../api/paramMgr.js'
+	import LayoutTmp from '../../components/layouttmp/LayoutTmp.vue'
+	import VueDragResize from 'vue-drag-resize/src'
+	import api from '../../api/singleLayoutTemp.js'
+	import {ElMessageBox,ElMessage} from 'element-plus'
+	
+	const formModel = reactive({
+		  tempId:null
+	})
+	
+	const layoutELModels=ref([])
+	
+	const tempList=ref([])
+		
+	const elOpts=reactive({
+		single:[],
+		multi:[],
+		oth:[
+			{code:'wellName',name:'井名标题',elType:'wellName'}
+		]
+	})
+	
+	
+	
+	
+	//选择布局元素
+	const selEL=(el)=>{
+		el['checked']=!el['checked']
+		synLayoutEL(el)
+	}
+	
+	//同步更新layoutel
+	const synLayoutEL=(srcEL)=>{
+		if(!srcEL.checked){
+			let finedIdx=null
+			layoutELModels.value.forEach((item,index)=>{
+				if(item&&item.code==srcEL.code){
+					finedIdx=index
+					return false
+				}
+			})
+			if(finedIdx!=null){
+				layoutELModels.value.splice(finedIdx,1)
+			}
+			
+		}
+		else{
+			let initVal={
+				width: 120,
+				height: 60,
+				top: 0,
+				left: 100,
+				name:srcEL.name,
+				code:srcEL.code,
+				elType:srcEL.elType
+			}
+			if(srcEL.elType=="multi"){
+				initVal.width=400
+				initVal.height=220
+			}
+			else if(srcEL.elType=="wellName"){
+				initVal.width=120
+				initVal.height=30
+			}
+			layoutELModels.value.push(initVal)
+		}
+	}
+	
+	onMounted(()=>{
+		loadParamType()
+		loadTempList()
+	})
+	
+	const loadParamType=()=>{
+		paramMgrAPI.loadAll().then(resp=>{
+			if(resp.code==0){
+				let tmp
+				resp.data.forEach(param=>{
+					param['name']=param.paramName
+					param['code']=param.paramCode
+					param['elType']='single'
+					tmp=elOpts.single
+					if(param.paramCode.indexOf('diagram')>=0){
+						param['elType']='multi'
+						tmp=elOpts.multi
+					}
+					tmp.push(param)
+					
+				})
+			}
+		}).catch(error=>{
+			console.log(error)
+		})
+	}
+	
+	const resetPage=()=>{
+		layoutELModels.value=[]
+		elOpts.single.forEach((item,index)=>{ 
+			item.checked=false
+		})
+		elOpts.multi.forEach((item,index)=>{
+			item.checked=false
+		})
+		elOpts.oth.forEach((item,index)=>{
+			item.checked=false
+		})
+	}
+	
+	const initElOptsCheck=(checkMap)=>{
+		elOpts.single.forEach((item,index)=>{
+			item.checked=checkMap[item.code]
+		})
+		elOpts.multi.forEach((item,index)=>{
+			item.checked=checkMap[item.code]
+		})
+		elOpts.oth.forEach((item,index)=>{
+			item.checked=checkMap[item.code]
+		})
+	}
+	
+	//选择模板后,加载明细
+	const changeTempHandle=(val)=>{
+		resetPage()
+		api.getTempDtl(val).then(resp=>{
+			if(resp.code!=0){
+				ElMessage.error(err||'加载模板明细失败')
+				return
+			}
+			if(resp.data&&resp.data.tempContent){
+				let elModels=JSON.parse(resp.data.tempContent)
+				let mapping={}
+				elModels.forEach((item,index)=>{
+					mapping[item.code]=true
+					layoutELModels.value.push(item)
+				})
+				initElOptsCheck(mapping)
+				
+			}
+			
+		}).catch(err=>{
+			   
+		   }
+		)
+	}
+	
+	//加载库中模板
+	const loadTempList=()=>{
+		api.loadTempList().then(resp=>{
+			if(resp.code==0){
+				tempList.value=resp.data
+			}
+		}).catch(error=>{
+			
+		})
+	}
+	
+	
+	//获取要保存的数据
+	const getSaveData=()=>{
+		let tempName=''
+		if(tempList.value&&tempList.value.length>0){
+			let chkedtemp=tempList.value.filter(temp=>temp.tempId==formModel.tempId)
+			tempName=chkedtemp&&chkedtemp.length>0?chkedtemp[0].tempName:null
+		}
+		return {tempName,tempId:formModel.tempId,tempContent:JSON.stringify(layoutELModels.value),tempType:'single'}
+	}
+	
+	const saveTemp=(tag)=>{
+		if(tag==="save"){
+			api.save(getSaveData()).then(resp=>{
+				if(resp.code!=0){
+					ElMessage.error(resp.msg)
+					return
+				}
+				ElMessage.success('操作成功')
+			}).catch(err=>{
+				ElMessage.error(err||'操作失败')
+			})
+		}
+		else if(tag==="saveAs"){
+			return ElMessageBox.prompt('创建新模板',null,{
+			   		   showCancelButton:true,
+			   		   showInput:true,
+					   inputType:'text',
+					   inputPlaceholder:'请输入模板名称',
+					   inputPattern:/\S+/,
+					   inputErrorMessage:'模板名称不能为空',
+					   closeOnClickModal:false
+					}).then(({value })=>{
+						let saveData=getSaveData()
+						saveData['tempName']=value 
+						api.saveAs(saveData).then(resp=>{
+							if(resp.code!=0){
+								ElMessage.error(resp.msg||'操作失败')
+							}
+							else{
+								ElMessage.success('操作成功')
+								loadTempList()
+								formModel.tempId=resp.data
+							}
+						})
+						
+					})
+					.catch(err => {
+						console.log('cancel save as '+err)
+					})
+		}
+	}
+	
+	//删除模板
+	const delTemp=()=>{
+		if(formModel.tempId==null){
+			ElMessage.error('还未选择模板')
+			return
+		}
+		ElMessageBox.confirm(
+			'确定要删除该模板吗?',
+			'操作确认',
+			{
+				confirmButtonText:'确定',
+				cancelButtonText:'取消',
+				type: 'warning'
+			}
+		).then(()=>{
+			api.del(formModel.tempId).then(resp=>{
+				if(resp.code!=0){
+					ElMessage.error(resp.msg)
+					return
+				}
+				ElMessage.success('操作成功')
+				formModel.tempId=null
+				resetPage()
+				loadTempList()
+				
+			}).catch(err=>{
+				ElMessage.error(err||'操作失败')
+			})
+		}).catch(()=>{
+			console.log('cancel del')
+		})
+	}
+	  
+</script>
+
+<style scoped>
+	.page-container{
+		position: relative;
+		left:0px;
+		top:0px;
+		
+		height: 100%;
+	}
+	.edit-box{
+		width:100%;
+		height: 100%;
+		box-sizing: border-box;
+		position: relative;
+		
+		
+	}
+	
+	
+	.item2 {
+	  margin-bottom: 18px;
+	}
+	.ctr-panel{
+	  width: 300px;
+	  position: absolute;
+	  top:0px;
+	  right: 10px;
+	}
+	.ctr-panel .el-tag{
+		width:70px;
+		margin:0px 5px 5px 0px;
+		cursor:pointer;
+	}
+	
+</style>

+ 24 - 2
src/pages/base/WellEdit.vue

@@ -48,7 +48,14 @@
 				</el-col>
 				<el-col :sm="24" :md="12" :lg="8">
 					<el-form-item label="巡查模板" prop="patrolStdTemp">
-					  <el-input v-model="formModel.patrolStdTemp" autocomplete="off" placeholder="请选择巡查模板" class="edit-form-item" clearable/>
+						<el-select v-model="formModel.patrolStdTemp" placeholder="选择巡查模板">
+							<el-option
+							  v-for="item in tempList"
+							  :key="item.tempId"
+							  :label="item.tempName"
+							  :value="item.tempId"
+							/>
+						</el-select>
 					</el-form-item>
 				</el-col>
 				<el-col :sm="24" :md="12" :lg="8">
@@ -97,6 +104,7 @@
 <script setup>
 	import {reactive,ref,toRaw,onMounted,watch,useAttrs } from 'vue'
 	import stationAPI from "../../api/station.js"
+	import tempAPI from '../../api/singleLayoutTemp.js'
 	import {useHomeStore} from "@/store/home.js"
 	import {ElMessageBox,ElMessage} from 'element-plus'
 	
@@ -134,11 +142,25 @@
 			{required:true,message:'巡查标准模板还未选择',trigger:'blur'},
 			]
 	})
-	
+	const tempList=ref([])
 	const wellSortOpts=ref([])
 	const wellTypeOpts=ref([])
 	const gatherDevices=ref([])
 	
+	onMounted(()=>{
+		loadLayoutTemps()
+	})
+	
+	const loadLayoutTemps=()=>{
+		tempAPI.loadTempList().then(resp=>{
+			if(resp.code==0){
+				tempList.value=resp.data
+			}
+		}).catch(error=>{
+			console.log(error)
+		})
+	}
+	
 	let initFormDone=false
 	
 	const initForm=async ()=>{