xiaxin 1 year ago
parent
commit
8c801e15c4
42 changed files with 1594 additions and 128 deletions
  1. 4 0
      .hbuilderx/launch.json
  2. 3 0
      components/Collapse/CustomCollapse.vue
  3. 99 0
      components/Modal/CustomModal.vue
  4. 132 0
      components/Modal/CustomToast.vue
  5. 325 0
      components/OpenLayerMap/Draw.vue
  6. 91 36
      components/Recorder/CustomRecorder.vue
  7. 270 0
      components/Select/CustomMultiSelect.vue
  8. 1 1
      manifest.json
  9. 1 0
      package.json
  10. 32 10
      pages.json
  11. 37 0
      pages/drawMap/index.vue
  12. 28 26
      pages/index/components/inspectionFunc.vue
  13. 62 42
      pages/index/index.vue
  14. 11 4
      pages/index/pages/Deploy/index.vue
  15. 349 0
      pages/index/pages/InspectionPlan/index.vue
  16. 4 0
      pages/index/pages/MyFlow/components/DataList.vue
  17. 4 4
      pages/waterMarkCamera/WaterMarkCamera.nvue
  18. 1 0
      static/images/components/modal/bg.svg
  19. 1 0
      static/images/components/modal/error.svg
  20. 1 0
      static/images/components/modal/modal.svg
  21. 1 0
      static/images/components/modal/success.svg
  22. 0 1
      static/images/index/备用发电.svg
  23. 0 1
      static/images/index/安全检查.svg
  24. 0 0
      static/images/index/巡查.svg
  25. 0 0
      static/images/index/巡检计划制定.svg
  26. 0 1
      static/images/index/指标记录.svg
  27. 0 1
      static/images/index/水库管理.svg
  28. 0 1
      static/images/index/河湖长巡河.svg
  29. 0 0
      static/images/index/签到.svg
  30. 1 0
      static/images/index/隐患上报.svg
  31. 1 0
      static/images/index/隐患处理.svg
  32. 1 0
      static/images/index/隐患审核.svg
  33. 1 0
      static/images/index/隐患查询.svg
  34. BIN
      static/images/tabbar/home-a.png
  35. BIN
      static/images/tabbar/home.png
  36. BIN
      static/images/tabbar/map-a.png
  37. BIN
      static/images/tabbar/map.png
  38. BIN
      static/images/tabbar/message-a.png
  39. BIN
      static/images/tabbar/message.png
  40. BIN
      static/images/tabbar/user-a.png
  41. BIN
      static/images/tabbar/user.png
  42. 133 0
      yarn.lock

+ 4 - 0
.hbuilderx/launch.json

@@ -10,6 +10,10 @@
      	{
      		"launchtype" : "local"
      	},
+     	"mp-weixin" : 
+     	{
+     		"launchtype" : "local"
+     	},
      	"type" : "uniCloud"
      }
     ]

+ 3 - 0
components/Collapse/CustomCollapse.vue

@@ -23,6 +23,9 @@
 	}
 	export default defineComponent({
 		props,
+		options: {
+			styleIsolation: 'shared'
+		},
 		setup(props){
 			const collapseModel = ['item']
 			const collapseTitle = ref(props.title)

+ 99 - 0
components/Modal/CustomModal.vue

@@ -0,0 +1,99 @@
+<template>
+	<!-- 自定义提示组件 -->
+	<!-- 根据title,配置提示的文字 -->
+	<!-- 全局采用ref方式调用打开按钮-->
+	<view class="custom-modal">
+		<zwy-popup :ishide="isShow" width="660rpx" height="440rpx" radius="12rpx">
+			<!-- 自定义展示内容 -->
+			<view class="content">
+				<view class="icon">
+					<image style="width: 100%;height: 100%;" src="/static/images/components/modal/modal.svg" mode="scaleToFill"></image>
+				</view>
+				<view class="title">
+					{{modalInfo.title}}
+				</view>
+			</view>
+			<view class="footer">
+				<button style="border-radius: 1998rpx;line-height: 60rpx;" type="default" @tap="handleCancel">取消</button>
+				<button style="border-radius: 1998rpx;line-height: 60rpx;" type="primary" @tap="handleOk">确定</button>
+			</view>
+		</zwy-popup>
+	</view>
+</template>
+
+<script setup>
+	import {
+		reactive,
+		ref,
+		defineExpose
+	} from 'vue';
+	const isShow = ref(false)
+	const modalInfo = reactive({
+		title: '',
+		onOk: ()=>{},
+		onCancel: ()=>{}
+	})
+	/**
+	 * @description 打开弹窗
+	 * @param option 配置项,可以配置标题、确定\取消事件
+	 * @param option.title 标题
+	 * @param option.onOk 确定事件
+	 * @param option.onCancel 取消事件
+	 */
+	const showModal = (option) => {
+		modalInfo.title = option.title;
+		modalInfo.onOk = option.onOk;
+		modalInfo.onCancel = option.onCancel;
+		isShow.value = true
+	}
+	const hideToast = () => {
+		isShow.value = false
+	}
+	const handleCancel = () => {
+		modalInfo.onCancel()
+		isShow.value = false
+	}
+	const handleOk = () => {
+		modalInfo.onOk()
+		isShow.value = false
+	}
+	defineExpose({
+		showModal
+	})
+</script>
+
+<style lang="scss" scoped>
+	.custom-modal{
+		
+		.content{
+			position: relative;
+			width: 100%;
+			height: 100%;
+			display: flex;
+			justify-content: center;
+			flex-direction: column;
+			align-items: center;
+			
+			.icon{
+				margin-left: -10rpx;
+				width: 210rpx;
+				height: 144rpx;
+			}
+			
+			.title{
+				margin-top: 8rpx;
+				font-family: Source Han Sans;
+				font-size: 50rpx;
+				font-weight: 500;
+				font-feature-settings: "kern" on;
+				color: $uni-text-color;
+			}
+		}
+		
+		.footer{
+			display: flex;
+			justify-content: space-around;
+			align-items: center;
+		}
+	}
+</style>

+ 132 - 0
components/Modal/CustomToast.vue

@@ -0,0 +1,132 @@
+<template>
+	<!-- 自定义提示组件 -->
+	<!-- 根据type展示成功、失败状态提示 -->
+	<!-- 根据title/remark,配置提示的文字 -->
+	<!-- 全局采用ref方式调用打开按钮,默认展示1500ms后关闭,也可以直接调用关闭事件-->
+	<view class="custom-toast">
+		<zwy-popup :ishide="isShow" width="660rpx" height="364rpx" radius="12rpx">
+			<!-- 自定义展示内容 -->
+			<view class="content">
+				<view class="bg-box">
+					<image style="width: 100%;height: 100%;" src="/static/images/components/modal/bg.svg" mode="scaleToFill"></image>
+				</view>
+				<view class="icon">
+					<image style="width: 100%;height: 100%;" :src="`/static/images/components/modal/${toastInfo.type}.svg`" mode="scaleToFill"></image>
+				</view>
+				<view class="title">
+					{{toastInfo.title}}
+				</view>
+				<view class="remark">
+					{{toastInfo.remark}}
+				</view>
+			</view>
+		</zwy-popup>
+	</view>
+</template>
+
+<script setup>
+	import {
+		reactive,
+		ref,
+		defineExpose
+	} from 'vue';
+	const isShow = ref(false)
+	const timer = ref(null)
+	const toastInfo = reactive({
+		type: '',
+		title: '',
+		duration: 1500,
+		remark: ''
+	})
+	const baseInfo = {
+		success: {
+			title: '操作成功',
+			remark: '',
+			duration: 1500
+		},
+		error: {
+			title: '操作失败',
+			remark: '',
+			duration: 1500
+		}
+	}
+	/**
+	 * @description 打开弹窗
+	 * @param option 配置项,可以单独配置类型、标题、描述、时间
+	 * 如果没有类型,默认使用success,但其他参数还是可以覆盖
+	 * @param option.type 类型:success/error
+	 * @param option.title 标题
+	 * @param option.remark 描述
+	 * @param option.duration 持续时长
+	 */
+	const showToast = (option) => {
+		let tempType = option?.type
+		if (!tempType || !baseInfo[tempType]) {
+			tempType = 'success'
+		}
+		toastInfo.type = tempType;
+		toastInfo.title = option.title || baseInfo[tempType].title;
+		toastInfo.remark = option.remark || baseInfo[tempType].remark;
+		toastInfo.duration = option.duration || baseInfo[tempType].duration;
+		isShow.value = true
+		timer.value && clearTimeout(timer.value)
+		timer.value = setTimeout(() => {
+			hideToast()
+		}, toastInfo.duration)
+	}
+	const hideToast = () => {
+		isShow.value = false
+		timer.value && clearTimeout(timer.value)
+	}
+	defineExpose({
+		showToast,
+		hideToast
+	})
+</script>
+
+<style lang="scss" scoped>
+	.custom-toast{
+		
+		.content{
+			position: relative;
+			width: 100%;
+			height: 100%;
+			display: flex;
+			justify-content: center;
+			flex-direction: column;
+			align-items: center;
+			
+			.bg-box{
+				position: absolute;
+				width: 100%;
+				height: 100%;
+				left: 0;
+				top: 0;
+				z-index: -1;
+			}
+			
+			.icon{
+				margin-left: -10rpx;
+				width: 210rpx;
+				height: 144rpx;
+			}
+			
+			.title{
+				margin-top: 8rpx;
+				font-family: Source Han Sans;
+				font-size: 50rpx;
+				font-weight: 500;
+				font-feature-settings: "kern" on;
+				color: $uni-text-color;
+			}
+			
+			.remark{
+				margin-top: 16rpx;
+				font-family: Source Han Sans;
+				font-size: 36rpx;
+				font-feature-settings: "kern" on;
+				color: $uni-text-color;
+			}
+		}
+	}
+</style>

+ 325 - 0
components/OpenLayerMap/Draw.vue

@@ -0,0 +1,325 @@
+<template>
+	<view class="openlayer-map-draw">
+		<view :pos="position" :change:pos="olMap.createPolygon" style="display: none;"></view>
+		<view :domId="mapId" :change:domId="olMap.initMap" style="display: none;"></view>
+		<view :id="mapId" class="map"></view>
+		<view class="btns">
+			<button class="btn" type="default" @tap="olMap.handleStart">开始绘制</button>
+			<button class="btn" type="default" @tap="olMap.handleClear">清除绘制</button>
+			<button class="btn" type="default" @tap="olMap.handleSubmit">完成绘制</button>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		name: "openlayer-map-draw",
+		props: {
+			coordinates: {
+				type: Array,
+				required: false,
+				default: () => {
+					return []
+				}
+			}
+		},
+		data() {
+			return {
+				position: [],
+				mapId: 'ol-map' + ('000000' + Math.floor(Math.random() * 999999)).slice(-6),
+			};
+		},
+		methods: {
+			//给renderJS调用的方法
+			methodForRenderJs: async function(val) {
+				if (val.type === 'startInitOlMap') {
+					uni.showLoading({
+						title: "地图加载中..."
+					})
+				}
+				// 地图初始化完成,绘制传入坐标
+				if (val.type === 'changeSize') {
+					this.position = this.coordinates;
+					uni.hideLoading()
+				}
+				if (val.type === 'isStop') {
+					uni.$msg('已有范围,请先清除后重新绘制')
+				}
+				if (val.type === 'needStart') {
+					uni.$msg('请先绘制范围')
+				}
+				if (val.type === 'submit') {
+					uni.$msg('提交')
+					console.log(val.coords)
+					if(val.coords && val.coords.length){
+						this.$emit('onSubmit', val.coords)
+					}
+				}
+			}
+		}
+	}
+</script>
+
+<script lang="renderjs" module="olMap">
+	import Map from 'ol/Map.js';
+	import View from 'ol/View.js';
+	import {
+		defaults as defaultControls
+	} from 'ol/control.js';
+	import {
+		getWidth,
+		getTopLeft
+	} from 'ol/extent.js';
+	import TileLayer from 'ol/layer/Tile.js';
+	import {
+		get as getProjection
+	} from 'ol/proj.js';
+	import {
+		fromLonLat
+	} from "ol/proj";
+	import WMTS from 'ol/source/WMTS.js';
+	import WMTSTileGrid from 'ol/tilegrid/WMTS.js';
+	import Feature from 'ol/Feature';
+	import Point from 'ol/geom/Point';
+	import Polygon from 'ol/geom/Polygon';
+	import {
+		Icon,
+		Style
+	} from 'ol/style';
+	import VectorSource from 'ol/source/Vector';
+	import {
+		Vector as VectorLayer
+	} from 'ol/layer';
+	import Fill from 'ol/style/Fill';
+	import Text from 'ol/style/Text';
+	import Stroke from 'ol/style/Stroke';
+	import Circle from 'ol/style/Circle';
+	import { Draw } from "ol/interaction";
+
+	export default {
+		name: "openlayer-map",
+		data() {
+			return {
+				map: null,
+				points: [],
+				polygonLayer: null,
+				pointsLayer: null,
+				drawStatus: 'start',
+				drawSource: null,
+				draw: null
+			};
+		},
+		methods: {
+			WMTS_Layer(url) {
+				if (!url) return null
+				let projection = getProjection('EPSG:4326')
+				let extent = projection.getExtent()
+				let width = getWidth(extent)
+
+				let resolutions = [],
+					matrixIds = []
+				for (let z = 1; z < 19; z++) {
+					resolutions[z] = width / (256 * Math.pow(2, z))
+					matrixIds[z] = z
+				}
+				let tileGrid = new WMTSTileGrid({
+					origin: getTopLeft(extent),
+					resolutions,
+					matrixIds
+				})
+
+				// 匹配坐标系、图层类型
+				let type = url.match(new RegExp(/\/(.{3})_(c|w)\//))
+				return new TileLayer({
+					source: new WMTS({
+						crossOrigin: 'anonymous',
+						url: url,
+						layer: type[1],
+						matrixSet: type[2],
+						format: 'tiles',
+						style: 'default',
+						wrapX: true,
+						projection: projection,
+						tileGrid
+					})
+				})
+			},
+			initMap(domId) {
+				var webKey = '15f7b01aababbb39ab568f4ba12ea21c';
+				let wmtsUrl_1 = 'http://t{0-7}.tianditu.gov.cn/vec_c/wmts?tk=' + webKey;
+				let wmtsUrl_2 = 'http://t{0-7}.tianditu.gov.cn/cva_c/wmts?tk=' + webKey;
+				let center = [104.93616806129798, 33.38784018924233]
+				this.$ownerInstance.callMethod('methodForRenderJs', {
+					type: 'startInitOlMap'
+				});
+				setTimeout(() => {
+					this.map = new Map({
+						target: domId,
+						view: new View({
+							projection: 'EPSG:4326',
+							center: center,
+							zoom: 16,
+							maxZoom: 22,
+							minZoom: 1
+						}),
+						controls: defaultControls({
+							zoom: false,
+							rotate: false,
+							attribution: false
+						})
+					});
+					let layer = this.WMTS_Layer(wmtsUrl_1)
+					this.map.addLayer(layer)
+					let layer1 = this.WMTS_Layer(wmtsUrl_2)
+					this.map.addLayer(layer1)
+					this.map.updateSize()
+					// 先注册一下绘制面图层
+					this.drawSource = new VectorSource({});
+					this.map.addLayer(new VectorLayer({
+						source: this.drawSource
+					}))
+					this.$ownerInstance.callMethod('methodForRenderJs', {
+						type: 'changeSize'
+					});
+				}, 3000);
+			},
+			handleClear() {
+				this.drawStatus = 'clear'
+				this.map.removeLayer(this.polygonLayer)
+				this.map.removeLayer(this.pointsLayer)
+				this.map.removeInteraction(this.draw)
+				this.draw = null
+				this.polygonLayer = null
+				this.pointsLayer = null
+				this.drawSource.clear()
+			},
+			handleSubmit() {
+				if(!this.draw || this.drawStatus !== 'start'){
+					this.$ownerInstance.callMethod('methodForRenderJs', {
+						type: 'needStart'
+					});
+					return;
+				}
+				this.draw.finishDrawing()
+				let features = this.drawSource.getFeatures()
+				if(!features.length){
+					this.$ownerInstance.callMethod('methodForRenderJs', {
+						type: 'needStart'
+					});
+					return;
+				}
+				let coords = features[0].getGeometry().getCoordinates()
+				this.$ownerInstance.callMethod('methodForRenderJs', {
+					type: 'submit',
+					coords: coords
+				});
+				this.drawStatus = 'stop'
+			},
+			handleStart() {
+				if(this.drawStatus === 'stop'){
+					this.$ownerInstance.callMethod('methodForRenderJs', {
+						type: 'isStop'
+					});
+					return;
+				}
+				this.draw = new Draw({
+					source: this.drawSource,
+					type: 'Polygon',
+					style: new Style({
+						stroke: new Stroke({
+							color: 'red',
+							width: 2
+						}),
+						fill: new Fill({
+							color: 'pink'
+						})
+					})
+				})
+				this.map.addInteraction(this.draw);
+				this.draw.on("drawend", (evt) => {
+				  console.log("结束绘制");
+				  console.log(evt);
+				});
+				this.drawStatus = 'start'
+			},
+			createPolygon(coordinates) {
+				if (!coordinates.length || !this.map) {
+					return
+				}
+				this.drawStatus = 'stop'
+				this.points = JSON.parse(JSON.stringfy(coordinates))
+				// 绘制顶点
+				let pointStyle = new Style({
+					image: new Circle({
+						radius: 20,
+						fill: new Fill({
+							color: 'yellow'
+						})
+					})
+				})
+				let pointsVector = new VectorSource({});
+				coordinates.forEach(item => {
+					let pointFeature = new Feature({
+						geometry: new Point(item)
+					});
+					pointFeature.setStyle(pointStyle)
+					pointsVector.addFeature(pointFeature)
+				})
+				this.pointsLayer = new VectorLayer({
+					source: pointsVector
+				});
+				this.map.addLayer(this.pointsLayer);
+
+				// 绘制面
+				var iconFeature = new Feature({
+					geometry: new Polygon(coordinates)
+				});
+				var iconStyle = new Style({
+					fill: new Fill({
+						color: 'pink'
+					})
+				});
+				iconFeature.setStyle(iconStyle);
+				var vectorSource = new VectorSource({});
+				vectorSource.addFeature(iconFeature)
+				this.polygonLayer = new VectorLayer({
+					source: vectorSource
+				});
+				this.map.addLayer(this.polygonLayer);
+			}
+		},
+		beforeUnmount() {
+			this.map && this.map.dispose();
+			this.map = null;
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.openlayer-map-draw {
+		width: 100%;
+		height: 100%;
+		position: relative;
+
+		.map {
+			width: 100%;
+			height: 100%;
+		}
+
+		.btns {
+			position: absolute;
+			bottom: 0;
+			right: 0;
+			width: 100%;
+			display: flex;
+			justify-content: space-between;
+			align-items: center;
+
+			.btn {
+				height: 35px;
+				line-height: 35px;
+				flex: 0 0 30%;
+			}
+		}
+	}
+</style>

+ 91 - 36
components/Recorder/CustomRecorder.vue

@@ -1,12 +1,11 @@
 <template>
-	<page-meta :page-style="'overflow:'+(show?'hidden':'visible')"></page-meta>
 	<view class="custom-recorder">
 		<view class="record-file-list" v-if="list.length">
 			<view class="record-file-list-item" v-for="(item, index) in list" :key="index">
-				{{item.name+'.amr'}}
+				{{item.path}}
 			</view>
 		</view>
-		<uni-popup ref="popup" type="bottom" class="pop-up-box" @change="onPopupChange">
+		<uni-popup ref="popup" type="bottom" class="pop-up-box">
 			<view class="pop-up-content">
 				<view class="content-header">
 					音频录音
@@ -16,10 +15,12 @@
 						{{duration}}
 					</view>
 					<view class="icon">
-						
+
 					</view>
 					<view class="btn">
-						<button style="height: 68rpx;line-height: 68rpx;border-radius: 1998rpx;" type="primary" @longpress="handleStart" @touchcancel="handleStop" @touchend="handleStop">{{btnText[recordStatus]}}</button>
+						<button style="height: 68rpx;line-height: 68rpx;border-radius: 1998rpx;" type="primary"
+							@longpress="handleStart" @touchcancel="handleStop"
+							@touchend="handleStop">{{btnText[recordStatus]}}</button>
 					</view>
 				</view>
 			</view>
@@ -28,11 +29,21 @@
 </template>
 
 <script>
-import moment from 'moment';
+	import moment from 'moment';
+	// #ifdef APP-PLUS
+	console.log('走的app')
 	const recorder = plus.audio.getRecorder();
 	const player = plus.audio.createPlayer({
 		autoplay: false
 	});
+	// #endif
+	
+	// #ifdef MP-WEIXIN
+	console.log('走的微信')
+	const recorder = wx.getRecorderManager();
+	const player = wx.createInnerAudioContext();
+	// #endif
+
 
 	export default {
 		data() {
@@ -40,34 +51,68 @@ import moment from 'moment';
 				list: [],
 				duration: "00:00:00",
 				recordStatus: "stop",
-				btnText:{
+				btnText: {
 					stop: "按住说话",
 					start: "说完了"
 				},
 				voicePath: '',
-				realDuration: 100,
-				show:false
+				realDuration: 100
 			}
 		},
-		onLoad() {},
+		onLoad() {
+			// #ifdef MP-WEIXIN
+			let self = this;
+			recorder.onStop(function (res){
+				console.log('结束啦')
+				let { tempFilePath, duration } = res
+				self.voicePath = path
+				console.log(self.voicePath)
+				console.log('时长', duration)
+			})
+			// 监听播放进度
+			player.onTimeUpdate((res)=>{
+				console.log(res)
+			})
+			// 监听播放进度
+			recorder.onStart(function(res){
+				console.log('开始啦')
+				console.log(res)
+			})
+			// 监听播放进度
+			recorder.onError(function(res){
+				console.log('出错啦')
+				console.log(res)
+			})
+			// #endif
+		},
+		beforeDestroy() {
+			player.destroy(); // 释放音频资源
+		},
 		methods: {
 			startRecord() {
 				console.log('开始录音');
+				// #ifdef APP-PLUS
+				console.log('走的app')
 				recorder.record({
 						format: 'amr',
-						filename:"_doc/hlt_app/录音文件"
+						filename: "_doc/hlt_app/录音文件"
 					},
-					(success) => {
+					(path) => {
 						console.log('录制成功')
 						// 此处就要上传这个文件
 						// 上传成功后,生成一条记录
-						
-						this.voicePath = success
+						this.voicePath = path
 						console.log(this.voicePath)
 						plus.io.getAudioInfo({
-							filePath: success,
-							success: ({duration}) => {
+							filePath: path,
+							success: ({
+								duration
+							}) => {
 								console.log('时长', duration)
+								list.push({
+									path,
+									duration
+								})
 							}
 						})
 					},
@@ -75,22 +120,35 @@ import moment from 'moment';
 						uni.$msg(err)
 					}
 				)
+				// #endif
+				
+				// #ifdef MP-WEIXIN
+				console.log('走的微信')
+				recorder.start()
+				// #endif
 			},
+			// 结束录音
 			endRecord() {
 				console.log('录音结束');
 				recorder.stop();
 			},
+			// 播放
 			playVoice() {
 				console.log('播放录音');
 				if (this.voicePath) {
+					// #ifdef APP-PLUS
 					player.setStyles({
 						src: this.voicePath
 					});
+					// #endif
+					// #ifdef MP-WEIXIN
+					player.src = this.voicePath
+					// #endif
 					player.play()
 				}
 			},
 			// 打开底部弹窗,用于开始录音
-			handleOpenRecord(){
+			handleOpenRecord() {
 				this.$refs.popup.open()
 			},
 			// 按住说话事件
@@ -101,22 +159,21 @@ import moment from 'moment';
 				this.timer && clearInterval(this.timer)
 				// 计时器内部处理经过时长并显示在面板
 				let timeStart = 0
-				this.timer = setInterval(()=>{
+				this.timer = setInterval(() => {
 					timeStart += 1000
-					let sec = this.timeFormat(moment.duration(timeStart).asSeconds()%60)
-					let min = this.timeFormat(moment.duration(timeStart).asMinutes()%60)
+					let sec = this.timeFormat(moment.duration(timeStart).asSeconds() % 60)
+					let min = this.timeFormat(moment.duration(timeStart).asMinutes() % 60)
 					let hour = this.timeFormat(moment.duration(timeStart).asHours())
 					this.duration = `${hour}:${min}:${sec}`
 				}, 1000)
 			},
-			timeFormat(time){
-				if(0<=time && time<1){
+			timeFormat(time) {
+				if (0 <= time && time < 1) {
 					return '00'
 				}
-				if(time>=1 && time<10){
+				if (time >= 1 && time < 10) {
 					return '0' + Math.floor(time)
-				}
-				else{
+				} else {
 					return Math.floor(time)
 				}
 			},
@@ -131,9 +188,6 @@ import moment from 'moment';
 				this.percent = 0
 				this.duration = "00:00:00"
 				this.timer && clearInterval(this.timer)
-			},
-			onPopupChange(e) {
-				this.show = e.show
 			}
 		}
 	}
@@ -142,13 +196,13 @@ import moment from 'moment';
 <style lang="scss" scoped>
 	.custom-recorder {
 		width: 100%;
-		
-		.pop-up-box{
-			.pop-up-content{
+
+		.pop-up-box {
+			.pop-up-content {
 				border-top-left-radius: 20rpx;
 				border-top-right-radius: 20rpx;
-				
-				.content-header{
+
+				.content-header {
 					background-color: #fff;
 					border-top-left-radius: 20rpx;
 					border-top-right-radius: 20rpx;
@@ -162,15 +216,16 @@ import moment from 'moment';
 					font-feature-settings: "kern" on;
 					color: $uni-text-color;
 				}
-				.content-body{
+
+				.content-body {
 					background: #EFF0F5;
 					height: 400rpx;
 					display: flex;
 					flex-direction: column;
 					align-items: center;
 					justify-content: center;
-					
-					.btn{
+
+					.btn {
 						margin-top: 72rpx;
 					}
 				}

+ 270 - 0
components/Select/CustomMultiSelect.vue

@@ -0,0 +1,270 @@
+<template>
+	<view class="popup" v-show="show">
+		<view class="bg" @tap="cancelMultiple"></view>
+	    <view class="selectMultiple" :animation="animationData">
+	    	<view class="multipleBody">
+	    		<view class="title">
+	    			<view class="close" @tap="cancelMultiple">
+	    				取消
+	    			</view>
+					<view class="title-label">
+						请选择
+					</view>
+	    			<view class="confirm" @tap="confirmMultiple">
+	    				确定
+	    			</view>
+	    		</view>
+				<!-- 单选 -->
+				<view class="list" v-if="!isMultiSelect && list.length">
+					<picker-view :value="selectValue" @change="onSingleChange" class="picker-view" indicator-style="height: 80rpx;">
+						<picker-view-column>
+							<view class="picker-item" v-for="(item, index) in list" :key="index" style="font-size: 32rpx;">{{item.label}}</view>
+						</picker-view-column>
+					</picker-view>
+				</view>
+				<!-- 多选 -->
+	    		<view class="list" v-if="isMultiSelect && list.length">
+	    			<scroll-view class="diet-list" :scroll-y="true">
+	    				<view v-for="(item, index) in list" :class="['item', item.selected ? 'checked' : '']" @tap="onChange(index, item)">
+	    					<view class="empty-box" style="width: 32rpx;height: 32rpx;"></view>
+							<span style="font-size: 32rpx;">{{item.label}}</span>
+	    					<icon v-show="item.selected" type="success_no_circle" size="16" color="#2D8DFF"/>
+							<view v-show="!item.selected" class="empty-box" style="width: 32rpx;height: 32rpx;"></view>
+	    				</view>
+	    			</scroll-view>
+	    		</view>
+	    	</view>
+	    </view>
+	</view>
+</template>
+
+<script>
+	export default {
+		name:"custom-multi-select",
+		data() {
+			return {
+				selectValue: [0],
+				// 选中值
+				value: [],
+				// 选中列表
+				selected: [],
+				// 列表数据
+				list: [],
+				originList: [],
+				// 出场动画
+				animationData: {},
+			};
+		},
+		props: {
+			// 是否显示
+			show: {
+				type: Boolean,
+				default: false
+			},
+			//数据列表
+			columns: {
+				type: Array,
+				default: []
+			},
+			// 默认选中
+			defaultIndex: {
+				type: Array,
+				default: [],
+			},
+			isMultiSelect: {
+				type: Boolean,
+				default: true
+			},
+		},
+		watch: {
+			// 监听是否显示
+			show(val) {
+				if(val) {
+					this.openMultiple();
+				}
+			}
+		},
+		methods: {
+			onSingleChange(e){
+				console.log(this.selectValue)
+				this.value = [];
+				this.selected = [];
+				let item = this.list[e.detail.value[0]]
+				if(!item){
+					return
+				}
+				this.value.push(item.value.toString());
+				this.selected.push({
+					label: item.label,
+					value: item.value,
+				});
+			},
+			// 列点击事件
+			onChange(index, item) {
+				// 单选
+				if (!this.isMultiSelect) {
+					
+				}
+				// 是否已选中
+				if(this.value.indexOf(item.value.toString()) >= 0) {
+					this.list[index].selected = false;
+				} else {
+					this.list[index].selected = true;
+				}
+				
+				// 筛选已勾选数据
+				this.value = [];
+				this.selected = [];
+				this.list.forEach((col_item, col_index) => {
+					if(col_item.selected) {
+						this.value.push(col_item.value.toString());
+						this.selected.push({
+							label: col_item.label,
+							value: col_item.value,
+						});
+					}
+				});
+				this.$emit("change", {selected: this.selected, value: this.value});
+			},
+			// 弹出框开启触发事件
+			openMultiple() {
+				// 初始化列表数据,默认勾选数据
+				this.value = this.defaultIndex;
+				this.columns.forEach((item, index) => {
+					this.$set(item, "selected", false);
+					if(this.value.indexOf(item.value.toString()) >= 0) {
+						item.selected = true;
+					}
+				});
+				this.originList = Object.assign([], this.columns);
+				this.list = JSON.parse(JSON.stringify(this.originList))
+				// 弹出动画
+				this.openAnimation();
+			},
+			// 确认
+			confirmMultiple() {
+				this.$emit("confirm", {selected: this.selected, value: this.value});
+			},
+			// 关闭/取消
+			cancelMultiple() {
+				this.$emit("cancel");
+			},
+			// 展开动画
+			openAnimation() {
+				var animation = uni.createAnimation()
+				animation.translate(0, 300).step({ duration: 0 });
+				this.animationData = animation.export();
+				this.$nextTick(() => {
+					animation.translate(0, 0).step({ duration: 300, timingFunction: 'ease' });
+					this.animationData = animation.export()
+				})
+			},
+		}
+	}
+</script>
+
+<style scoped lang="scss">
+	.popup {
+		width: 100%;
+		height: 100vh;
+		position: fixed;
+		z-index: 99999;
+		left: 0;
+		bottom: 0;
+		
+		::-webkit-scrollbar{
+			display: none;
+		}
+		
+		.bg {
+			width: 100%;
+			height: 100%;
+			background-color: rgba(black, .5);
+		}
+	}
+	.selectMultiple {
+		width: 100%;
+		position: absolute;
+		left: 0;
+		bottom: 0;
+		background-color: white;
+		border-top-left-radius: 20rpx;
+		border-top-right-radius: 20rpx;
+		
+		.multipleBody {
+			width: 100%;
+			box-sizing: border-box;
+			
+			.title {
+				padding: 0 20rpx;
+				height: 80rpx;
+				font-size: 28rpx;
+				display: flex;
+				justify-content: space-between;
+				align-items: center; /* 添加这一行 */
+				box-sizing: border-box;
+				border-bottom: 2rpx solid rgba(#999, 0.5);
+				margin-bottom: 20rpx;
+				
+				.close {
+					color: $uni-text-color-grey;
+				}
+				
+				.title-label{
+					color: $uni-text-color;
+				}
+				
+				.confirm {
+					color: $uni-user-selected;
+				}
+			}
+			
+			.list {
+				width: 100%;
+				height: 600rpx;
+				position: relative;
+				
+				.picker-view{
+					height: 600rpx;
+					
+					.picker-item {
+						line-height: 80rpx;
+						text-align: center;
+					}
+				}
+				
+				.diet-list {
+					height: 600rpx;
+					
+					.item {
+						width: 100%;
+						height: 80rpx;
+						font-size: 32rpx;
+						display: flex;
+						align-items: center;
+						justify-content: space-between;
+						
+						span {
+							flex: 1;
+							
+							text-align: center;
+							overflow: hidden;
+							display: -webkit-box;
+							-webkit-box-orient:vertical;
+							-webkit-line-clamp:1;
+						}
+						.icon{
+							height: 80rpx;
+						}
+						&.checked {
+							color: #2D8DFF;
+						}
+						&:last-child {
+							border-bottom: none;
+						}
+					}
+				}
+			}
+		}
+	}
+</style>

+ 1 - 1
manifest.json

@@ -1,6 +1,6 @@
 {
     "name" : "hlt_app",
-    "appid" : "",
+    "appid" : "__UNI__29A91AE",
     "description" : "",
     "versionName" : "1.0.0",
     "versionCode" : "100",

+ 1 - 0
package.json

@@ -1,6 +1,7 @@
 {
   "dependencies": {
     "moment": "^2.30.1",
+    "ol": "^9.1.0",
     "pinyin-pro": "^3.19.7"
   }
 }

+ 32 - 10
pages.json

@@ -16,7 +16,8 @@
 			"path": "pages/index/index",
 			"style": {
 				"navigationBarTitleText": "首页",
-				"transparentTitle": "always"
+				// "transparentTitle": "always",
+				"navigationStyle": "custom"
 			}
 		},
 		{
@@ -131,7 +132,10 @@
 		{
 			"path": "pages/waterMarkCamera/WaterMarkCamera",
 			"style": {
-				"transparentTitle": "always"
+				"navigationStyle": "custom",
+				"app-plus": {
+					"titleNView": false
+				}
 			}
 		},
 		{
@@ -142,6 +146,24 @@
 				"enablePullDownRefresh" : false,
 				"navigationBarBackgroundColor": "#e9f3fd"
 			}
+		},
+		{
+			"path" : "pages/index/pages/InspectionPlan/index",
+			"style" : 
+			{
+				"navigationBarTitleText" : "巡检计划制定",
+				"enablePullDownRefresh" : false,
+				"navigationBarBackgroundColor": "#e9f3fd"
+			}
+		},
+		{
+			"path" : "pages/drawMap/index",
+			"style" : 
+			{
+				"navigationBarTitleText" : "绘制范围",
+				"enablePullDownRefresh" : false,
+				"navigationBarBackgroundColor": "#e9f3fd"
+			}
 		}
 	],
 	"globalStyle": {
@@ -160,26 +182,26 @@
 			{
 				"pagePath": "pages/index/index",
 				"text": "首页",
-				"iconPath": "static/images/tabbar/home.svg",
-				"selectedIconPath": "static/images/tabbar/home-a.svg"
+				"iconPath": "static/images/tabbar/home.png",
+				"selectedIconPath": "static/images/tabbar/home-a.png"
 			},
 			{
 				"pagePath": "pages/map/index",
 				"text": "地图",
-				"iconPath": "static/images/tabbar/map.svg",
-				"selectedIconPath": "static/images/tabbar/map-a.svg"
+				"iconPath": "static/images/tabbar/map.png",
+				"selectedIconPath": "static/images/tabbar/map-a.png"
 			},
 			{
 				"pagePath": "pages/message/index",
 				"text": "消息",
-				"iconPath": "static/images/tabbar/message.svg",
-				"selectedIconPath": "static/images/tabbar/message-a.svg"
+				"iconPath": "static/images/tabbar/message.png",
+				"selectedIconPath": "static/images/tabbar/message-a.png"
 			},
 			{
 				"pagePath": "pages/user/index",
 				"text": "我的",
-				"iconPath": "static/images/tabbar/user.svg",
-				"selectedIconPath": "static/images/tabbar/user-a.svg"
+				"iconPath": "static/images/tabbar/user.png",
+				"selectedIconPath": "static/images/tabbar/user-a.png"
 			}
 		]
 	},

+ 37 - 0
pages/drawMap/index.vue

@@ -0,0 +1,37 @@
+<template>
+	<view class="draw-map">
+		<draw @onSubmit="onSubmit"></draw>
+	</view>
+</template>
+
+<script>
+	import Draw from '@/components/OpenLayerMap/Draw.vue';
+	export default {
+		components:{
+			Draw
+		},
+		data(){
+			return {
+				eventChannel:null
+			}
+		},
+		onLoad(e) {
+			this.eventChannel = this.getOpenerEventChannel();
+		},
+		methods:{
+			onSubmit(e) {
+				this.eventChannel.emit('savePolygonCoords', {
+					coords: e
+				})
+				uni.navigateBack();
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	.draw-map{
+		height: calc(100vh - var(--window-top) - 40rpx);
+		background-color: $uni-user-page-bgc;
+	}
+</style>

+ 28 - 26
pages/index/components/inspectionFunc.vue

@@ -21,54 +21,57 @@
 
 <script setup>
 	const inspectionFuncList = [{
-			title: "考勤打卡",
-			icon: "考勤打卡",
+			title: "签到",
+			icon: "签到",
+			page: 'Deploy',
 			bgc: 0
 		},
 		{
-			title: "巡检任务",
-			icon: "巡检任务",
+			title: "巡检计划制定",
+			icon: "巡检计划制定",
+			page: 'InspectionPlan',
 			bgc: 0
 		},
 		{
-			title: "临时巡检",
-			icon: "临时巡检",
+			title: "巡检任务",
+			icon: "巡检任务",
+			page: 'Deploy',
 			bgc: 0
 		},
 		{
-			title: "备用发电",
-			icon: "备用发电",
+			title: "巡查",
+			icon: "巡查",
+			page: 'Deploy',
 			bgc: 0
 		},
 		{
-			title: "指标记录",
-			icon: "指标记录",
+			title: "隐患上报",
+			icon: "隐患上报",
+			page: 'Deploy',
 			bgc: 0
 		},
 		{
-			title: "工程检查",
-			icon: "工程检查",
-			bgc: 1
-		},
-		{
-			title: "安全检查",
-			icon: "安全检查",
+			title: "隐患审核",
+			icon: "隐患审核",
+			page: 'Deploy',
 			bgc: 1
 		},
 		{
-			title: "河湖长巡河",
-			icon: "河湖长巡河",
+			title: "隐患处理",
+			icon: "隐患处理",
+			page: 'Deploy',
 			bgc: 1
 		},
 		{
-			title: "水库管理",
-			icon: "水库管理",
+			title: "隐患查询",
+			icon: "隐患查询",
+			page: 'Deploy',
 			bgc: 1
 		}
 	]
 	const handleClick = (item) => {
-		uni.switchTab({
-			url: '/pages/map/index'
+		uni.navigateTo({
+			url:`/pages/index/pages/${item.page}/index`
 		})
 	}
 </script>
@@ -92,14 +95,13 @@
 			background: #FFFFFF;
 			display: flex;
 			flex-wrap: wrap;
-			justify-content: space-between;
 
 			.inspection-func-item {
 				display: flex;
 				flex-direction: column;
 				margin-bottom: 40rpx;
 				align-items: center;
-				flex: 0 0 33%;
+				flex: 0 0 33.3%;
 
 				&:nth-last-of-type(-n+3) {
 					margin-bottom: 0;
@@ -112,7 +114,7 @@
 
 				.title {
 					font-family: Source Han Sans;
-					font-size: 36rpx;
+					font-size: 32rpx;
 					font-weight: 500;
 					font-feature-settings: "kern" on;
 					color: $uni-text-color;

+ 62 - 42
pages/index/index.vue

@@ -1,20 +1,26 @@
 <template>
 	<view class="home-page-box">
-		<view class="navigation-box"></view>
-		<!-- 单位 -->
-		<view class="conpany-box">
-			<view class="conpany-title">
-				黑龙滩管理处
+		<view class="bg-box">
+			<image style="width: 100%; height: 100%;" src="/static/images/index/bg.png" mode="scaleToFill"></image>
+		</view>
+		<view class="status-bar-box"></view>
+		<view class="navigation-bar-box"></view>
+		<view class="home-page-box-content">
+			<!-- 单位 -->
+			<view class="conpany-box">
+				<view class="conpany-title">
+					黑龙滩管理处
+				</view>
+				<view class="split-line"></view>
 			</view>
-			<view class="split-line"></view>
+			<!-- 标题 -->
+			<header-title></header-title>
+			<!-- 水库水情功能区 -->
+			<reservoir-func></reservoir-func>
+			<!-- 巡查管护功能区 -->
+			<inspection-func></inspection-func>
+			<view class="empty-box"></view>
 		</view>
-		<!-- 标题 -->
-		<header-title></header-title>
-		<!-- 水库水情功能区 -->
-		<reservoir-func></reservoir-func>
-		<!-- 巡查管护功能区 -->
-		<inspection-func></inspection-func>
-		<view class="empty-box"></view>
 	</view>
 </template>
 
@@ -27,45 +33,59 @@
 	import headerTitle from './components/headerTitle.vue';
 	import reservoirFunc from './components/reservoirFunc.vue';
 	import inspectionFunc from './components/inspectionFunc.vue';
-	
-	onMounted(() => {
-	})
+
+	onMounted(() => {})
 </script>
 
 <style lang="scss" scoped>
 	.home-page-box {
-		min-height: calc(100vh - var(--window-bottom));
-		background: url('@/static/images/index/bg.png') no-repeat;
-		background-size: 100% 100%;
-		padding: 0 20rpx;
 		
-		.navigation-box{
+		// background: url('@/static/images/index/bg.png') no-repeat;
+		// background-size: 100% 100%;
+		padding: 0 20rpx;
+
+		.bg-box {
+			position: fixed;
+			left: 0;
+			top: 0;
+			width: 100%;
+			height: 100%;
+			z-index: -1;
+		}
+
+		.status-bar-box {
 			height: var(--status-bar-height);
-			min-height: 88rpx;
-			margin-bottom: 44rpx;
 		}
-		
-		.conpany-box{
-			
+		.navigation-bar-box{
+			height: 88rpx;
+		}
+
+		&-content {
+			height: calc(100vh - var(--window-bottom) - 88rpx - var(--status-bar-height));
+			overflow: auto;
 			
-			.conpany-title{
-				font-family: Source Han Sans;
-				font-size: 50rpx;
-				font-weight: bold;
-				font-feature-settings: "kern" on;
-				color: $uni-text-color;
-				line-height: 72rpx;
+			.conpany-box {
+
+				.conpany-title {
+					font-family: Source Han Sans;
+					font-size: 50rpx;
+					font-weight: bold;
+					font-feature-settings: "kern" on;
+					color: $uni-text-color;
+					line-height: 72rpx;
+				}
+
+				.split-line {
+					margin-top: 16rpx;
+					width: 140rpx;
+					height: 8rpx;
+					background: #2E7DF3;
+				}
 			}
-			
-			.split-line{
-				margin-top: 16rpx;
-				width: 140rpx;
-				height: 8rpx;
-				background: #2E7DF3;
+
+			.empty-box {
+				height: 40rpx;
 			}
 		}
-		.empty-box{
-			height: 40rpx;
-		}
 	}
 </style>

+ 11 - 4
pages/index/pages/Deploy/index.vue

@@ -34,7 +34,15 @@
 	</view>
 </template>
 
-<script setup>
+<script lang="ts">
+	export default {
+		options:{
+			styleIsolation: 'shared'
+		}
+	}
+</script>
+
+<script setup lang="ts">
 	import {
 		reactive
 	} from 'vue';
@@ -113,7 +121,7 @@
 
 			.custom-collapse {
 
-				::v-deep .title-box {
+				.title-box {
 					padding-bottom: 20rpx;
 					font-family: Source Han Sans;
 					font-size: 40rpx;
@@ -122,8 +130,7 @@
 					color: $uni-text-color;
 				}
 
-				::v-deep .plan-list {
-					margin-top: 20rpx;
+				.plan-list {
 
 					&-item {
 						padding: 0 30rpx;

+ 349 - 0
pages/index/pages/InspectionPlan/index.vue

@@ -0,0 +1,349 @@
+<template>
+	<view class="inspection-plan">
+		<view class="inspection-plan-create-form-box">
+			<uni-forms ref="valiFormRef" :rules="rules" label-width="350rpx" :model="valiFormData" label-position="left"
+				:border="true">
+
+				<view class="create-form-box">
+					<view class="form-box-title">
+						巡检信息
+					</view>
+					<uni-forms-item class="is-first-border" label="巡检组" required name="group">
+						<view class="custom-text" @tap="handleOpenSelect('group')">
+							<view class="input-text" v-if="valiFormData.group">{{valiFormData.group}}</view>
+							<view class="placeholder-text" v-else>请选择</view>
+							<uni-icons type="down" size="16"></uni-icons>
+						</view>
+					</uni-forms-item>
+					<uni-forms-item label="巡检负责人" required name="mainPerson">
+						<view class="custom-text" @tap="handleOpenSelect('mainPerson')">
+							<view class="input-text" v-if="valiFormData.mainPerson">{{valiFormData.mainPerson}}</view>
+							<view class="placeholder-text" v-else>请选择</view>
+							<uni-icons type="down" size="16"></uni-icons>
+						</view>
+					</uni-forms-item>
+					<uni-forms-item label="协同人员" required name="withPerson">
+						<view class="custom-text">
+							<view class="input-text" v-if="valiFormData.withPerson">{{valiFormData.withPerson}}</view>
+							<view class="placeholder-text" v-else>请选择</view>
+							<uni-icons type="down" size="16"></uni-icons>
+						</view>
+					</uni-forms-item>
+					<uni-forms-item label="巡检工作" required name="workType">
+						<view class="custom-text">
+							<view class="input-text" v-if="valiFormData.workType">{{valiFormData.workType}}</view>
+							<view class="placeholder-text" v-else>请选择</view>
+							<uni-icons type="down" size="16"></uni-icons>
+						</view>
+					</uni-forms-item>
+					<uni-forms-item label="是否汛期" name="isWater">
+						<radio-group @change="radioChange" style="display: flex;justify-content: flex-end;">
+							<label style="margin-right: 20rpx; display: flex; align-items: center;">
+								<radio value="1" :checked="true" />是
+							</label>
+							<label style="display: flex; align-items: center;">
+								<radio value="0" />否
+							</label>
+						</radio-group>
+					</uni-forms-item>
+					<uni-forms-item label="巡检类型" required name="type">
+						<view class="custom-text">
+							<view class="input-text" v-if="valiFormData.type">{{valiFormData.type}}</view>
+							<view class="placeholder-text" v-else>请选择</view>
+							<uni-icons type="down" size="16"></uni-icons>
+						</view>
+					</uni-forms-item>
+					<uni-forms-item label="巡检周期" required name="cycle">
+						<view class="custom-text">
+							<view class="input-text" v-if="valiFormData.cycle">{{valiFormData.cycle}}</view>
+							<view class="placeholder-text" v-else>请选择</view>
+							<uni-icons type="down" size="16"></uni-icons>
+						</view>
+					</uni-forms-item>
+					<uni-forms-item label="自定义天数" required name="customCycle">
+						<uni-easyinput type="number" class="custom-input" :inputBorder="false"
+							v-model="valiFormData.customCycle" placeholder="请输入水位" />
+					</uni-forms-item>
+					<uni-forms-item label="起止时间" required name="dateRange">
+						<uni-datetime-picker type="daterange" v-model="valiFormData.dateRange" :clear-icon="false">
+							<uni-easyinput suffixIcon="calendar" :clearable="false" class="custom-input"
+								:inputBorder="false" :value="valiFormData.dateRange.toString()" placeholder="请选择日期" />
+						</uni-datetime-picker>
+					</uni-forms-item>
+					<uni-forms-item label="是否派工" name="isWork">
+						<radio-group @change="radioChange1" style="display: flex;justify-content: flex-end;">
+							<label style="margin-right: 20rpx; display: flex; align-items: center;">
+								<radio value="1" :checked="true" />是
+							</label>
+							<label style="display: flex; align-items: center;">
+								<radio value="0" />否
+							</label>
+						</radio-group>
+					</uni-forms-item>
+					<uni-forms-item label="备注" name="remark">
+						<view class="custom-remark">
+							<view class="placeholder-text">
+								点击图标开始录音
+							</view>
+							<view class="record-btn" @tap="handleStartRecord">
+								<image style="width: 100%; height: 100%;"
+									src="/static/images/components/recorder/record.svg" mode="scaleToFill"></image>
+							</view>
+						</view>
+					</uni-forms-item>
+					<custom-recorder ref="recorderRef"></custom-recorder>
+				</view>
+
+				<view class="create-form-box">
+					<view class="form-box-title">
+						巡检范围
+					</view>
+					<uni-forms-item label="巡检范围" required name="mapRange">
+						<uni-easyinput type="number" class="custom-input" :inputBorder="false"
+							v-model="valiFormData.mapRange" placeholder="请输入水位" />
+					</uni-forms-item>
+					<view class="form-box-btn">
+						<button type="primary" @tap="handleDraw" style="border-radius: 1998rpx;">
+							前往绘制
+						</button>
+					</view>
+				</view>
+			</uni-forms>
+			<view class="empty" style="height: 110rpx;"></view>
+		</view>
+		<view class="bottom-btns">
+			<button type="primary" style="border-radius: 19998rpx; width: 100%;" @tap="handleSubmit">提交</button>
+		</view>
+		<custom-multi-select :show="ifOpenSelect" :columns="columns" :is-multi-select="isMulti" @cancel="onSelectClose" @confirm="onSelectSubmit"></custom-multi-select>
+	</view>
+</template>
+
+<script setup>
+	import {
+		reactive,
+		ref
+	} from 'vue';
+	import CustomRecorder from '@/components/Recorder/CustomRecorder.vue';
+	import CustomMultiSelect from '@/components/Select/CustomMultiSelect.vue';
+	
+	const ifOpenSelect = ref(false)
+	const columns = ref([
+		{
+			label:"选项0",
+			value:"0"
+		},
+		{
+			label:"选项1",
+			value:"1"
+		},
+		{
+			label:"选项2",
+			value:"2"
+		},
+		{
+			label:"选项3",
+			value:"3"
+		},
+		{
+			label:"选项4",
+			value:"4"
+		},
+		{
+			label:"选项5",
+			value:"5"
+		},
+		{
+			label:"选项6",
+			value:"6"
+		},
+	])
+	const isMulti = ref(true)
+	const handleOpenSelect = (type)=>{
+		// ifOpenSelect.value = true
+		if(type==='group'){
+			columns.value = []
+			for (let i = 0; i < 30; i++) {
+				columns.value.push({
+					label: `选项${i}`,
+					value: i
+				})
+			}
+			isMulti.value = true
+			ifOpenSelect.value = true
+		}
+		if(type==='mainPerson'){
+			columns.value = []
+			for (let i = 0; i < 20; i++) {
+				columns.value.push({
+					label: `选项${i}`,
+					value: i
+				})
+			}
+			isMulti.value = false
+			ifOpenSelect.value = true
+		}
+	}
+	const onSelectClose = ()=>{
+		ifOpenSelect.value = false
+	}
+	const onSelectSubmit = (e)=>{
+		console.log(e)
+		ifOpenSelect.value = false
+	}
+	
+	const handleDraw = () => {
+		uni.navigateTo({
+			url: '/pages/drawMap/index',
+			events:{
+				savePolygonCoords:(e)=>{
+					console.log(e.coords)
+				}
+			}
+		})
+	}
+	const rules = {}
+	const valiFormRef = ref(null)
+	const valiFormData = reactive({
+		group: "",
+		mainPerson: "",
+		withPerson: "",
+		workType: "",
+		isWater: "1",
+		type: "",
+		cycle: "",
+		customCycle: "",
+		dateRange: [],
+		isWork: "1",
+		remark: "",
+
+		mapRange: "",
+		points: []
+	})
+	const radioChange = (e) => {
+		valiFormData.isWater = e.detail.value
+	}
+	const radioChange1 = (e) => {
+		valiFormData.isWork = e.detail.value
+	}
+
+	//录音器管理
+	const recorderRef = ref(null)
+	const handleStartRecord = () => {
+		recorderRef.value && recorderRef.value.handleOpenRecord()
+	}
+
+	// 提交
+	const handleSubmit = () => {
+		valiFormRef.value.validate().then((res) => {
+			console.log(res)
+		}).catch(e => {
+			console.log('err', e)
+		})
+	}
+</script>
+
+<style lang="scss" scoped>
+	.inspection-plan {
+		min-height: calc(100vh - var(--window-top) - 40rpx);
+		background-color: $uni-user-page-bgc;
+		padding: 20rpx;
+
+		.inspection-plan-create-form-box {
+
+			.create-form-box {
+				border-radius: 12rpx;
+				background: #FFFFFF;
+				padding: 30rpx;
+				margin-bottom: 20rpx;
+
+				&:last-child {
+					margin-bottom: 0;
+				}
+
+				.form-box-title {
+					font-family: Source Han Sans;
+					font-size: 40rpx;
+					font-weight: 500;
+					font-feature-settings: "kern" on;
+					color: $uni-text-color;
+				}
+
+				.form-box-btn {
+					width: 50%;
+					margin: auto;
+				}
+
+				::v-deep .custom-input {
+
+					input {
+						text-align: right;
+					}
+
+					.uni-input-placeholder {
+						text-align: right;
+					}
+
+					.uni-date__x-input {
+						text-align: right;
+					}
+				}
+
+				::v-deep .uni-forms-item {
+					align-items: center;
+				}
+
+				::v-deep .custom-uni-form-item {
+					display: block;
+				}
+
+				// 录音控制
+				::v-deep .custom-remark {
+					width: 100%;
+					display: flex;
+					justify-content: flex-end;
+					align-items: center;
+
+					.placeholder-text {
+						margin-right: 20rpx;
+					}
+
+					.record-btn {
+						width: 28rpx;
+						height: 40rpx;
+					}
+				}
+
+				// 自定义不用展示的输入框
+				::v-deep .custom-text {
+					width: 100%;
+					display: flex;
+					justify-content: flex-end;
+					align-items: center;
+					font-size: 32rpx;
+
+					.input-text {
+						color: $uni-text-color;
+					}
+
+					.placeholder-text {
+						font-size: 24rpx;
+						color: $uni-text-color-grey;
+					}
+				}
+			}
+		}
+
+		.bottom-btns {
+			position: fixed;
+			left: 0;
+			bottom: 0;
+			width: calc(100% - 40rpx);
+			height: 110rpx;
+			display: flex;
+			justify-content: space-between;
+			align-items: center;
+			padding: 0 20rpx;
+			background: #FFFFFF;
+		}
+	}
+</style>

+ 4 - 0
pages/index/pages/MyFlow/components/DataList.vue

@@ -3,6 +3,7 @@
 		<view class="my-flow-data-list-item" v-for="(item,index) in list" :key="index">
 			<flow-card :cardInfo="item" @handleClickDetail="handleClick(item)"></flow-card>
 		</view>
+		<custom-toast ref="toastRef"></custom-toast>
 	</view>
 </template>
 
@@ -14,6 +15,8 @@
 		ref
 	} from 'vue';
 	import FlowCard from '@/components/Card/FlowCard.vue';
+	import CustomToast from '@/components/Modal/CustomToast.vue';
+	const toastRef = ref(null)
 
 	const list = ref([
 		{
@@ -48,6 +51,7 @@
 	// 跳转详情
 	const handleClick = (item) => {
 		console.log(item)
+		toastRef.value && toastRef.value.showToast({title:'操作了',remark:'点击的详情。。。'})
 		// uni.navigateTo({
 		// 	url:'/pages/index/pages/Ditch/info/index'
 		// })

+ 4 - 4
pages/waterMarkCamera/WaterMarkCamera.nvue

@@ -6,10 +6,10 @@
 			:style="{ width: windowWidth, height: windowHeight }"></live-pusher>
 
 		<cover-view class="remark">
-			<text class="mark-text name">{{ username }}</text>
-			<text class="mark-text time">{{ time }}</text>
-			<text class="mark-text address">{{ address }}</text>
-			<text class="mark-text lnglat">{{ lnglat }}</text>
+			<cover-view class="mark-text name">{{ username }}</cover-view>
+			<cover-view class="mark-text time">{{ time }}</cover-view>
+			<cover-view class="mark-text address">{{ address }}</cover-view>
+			<cover-view class="mark-text lnglat">{{ lnglat }}</cover-view>
 		</cover-view>
 
 		<view class="menu">

File diff suppressed because it is too large
+ 1 - 0
static/images/components/modal/bg.svg


File diff suppressed because it is too large
+ 1 - 0
static/images/components/modal/error.svg


File diff suppressed because it is too large
+ 1 - 0
static/images/components/modal/modal.svg


File diff suppressed because it is too large
+ 1 - 0
static/images/components/modal/success.svg


File diff suppressed because it is too large
+ 0 - 1
static/images/index/备用发电.svg


File diff suppressed because it is too large
+ 0 - 1
static/images/index/安全检查.svg


static/images/index/工程检查.svg → static/images/index/巡查.svg


static/images/index/临时巡检.svg → static/images/index/巡检计划制定.svg


File diff suppressed because it is too large
+ 0 - 1
static/images/index/指标记录.svg


File diff suppressed because it is too large
+ 0 - 1
static/images/index/水库管理.svg


File diff suppressed because it is too large
+ 0 - 1
static/images/index/河湖长巡河.svg


static/images/index/考勤打卡.svg → static/images/index/签到.svg


File diff suppressed because it is too large
+ 1 - 0
static/images/index/隐患上报.svg


File diff suppressed because it is too large
+ 1 - 0
static/images/index/隐患处理.svg


File diff suppressed because it is too large
+ 1 - 0
static/images/index/隐患审核.svg


File diff suppressed because it is too large
+ 1 - 0
static/images/index/隐患查询.svg


BIN
static/images/tabbar/home-a.png


BIN
static/images/tabbar/home.png


BIN
static/images/tabbar/map-a.png


BIN
static/images/tabbar/map.png


BIN
static/images/tabbar/message-a.png


BIN
static/images/tabbar/message.png


BIN
static/images/tabbar/user-a.png


BIN
static/images/tabbar/user.png


+ 133 - 0
yarn.lock

@@ -2,12 +2,145 @@
 # yarn lockfile v1
 
 
+"@petamoriken/float16@^3.4.7":
+  version "3.8.6"
+  resolved "https://registry.yarnpkg.com/@petamoriken/float16/-/float16-3.8.6.tgz#580701cb97a510882342333d31c7cbfd9e14b4f4"
+  integrity sha512-GNJhABTtcmt9al/nqdJPycwFD46ww2+q2zwZzTjY0dFFwUAFRw9zszvEr9osyJRd9krRGy6hUDopWUg9fX7VVw==
+
+color-name@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/color-name/-/color-name-2.0.0.tgz#03ff6b1b5aec9bb3cf1ed82400c2790dfcd01d2d"
+  integrity sha512-SbtvAMWvASO5TE2QP07jHBMXKafgdZz8Vrsrn96fiL+O92/FN/PLARzUW5sKt013fjAprK2d2iCn2hk2Xb5oow==
+
+color-parse@^2.0.0:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/color-parse/-/color-parse-2.0.2.tgz#37b46930424924060988edf25b24e6ffb4a1dc3f"
+  integrity sha512-eCtOz5w5ttWIUcaKLiktF+DxZO1R9KLNY/xhbV6CkhM7sR3GhVghmt6X6yOnzeaM24po+Z9/S1apbXMwA3Iepw==
+  dependencies:
+    color-name "^2.0.0"
+
+color-rgba@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/color-rgba/-/color-rgba-3.0.0.tgz#77090bdcdb2951c1735e20099ddd50401675375b"
+  integrity sha512-PPwZYkEY3M2THEHHV6Y95sGUie77S7X8v+h1r6LSAPF3/LL2xJ8duUXSrkic31Nzc4odPwHgUbiX/XuTYzQHQg==
+  dependencies:
+    color-parse "^2.0.0"
+    color-space "^2.0.0"
+
+color-space@^2.0.0, color-space@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/color-space/-/color-space-2.0.1.tgz#da39871175baf4a5785ba519397df04b8d67e0fa"
+  integrity sha512-nKqUYlo0vZATVOFHY810BSYjmCARrG7e5R3UE3CQlyjJTvv5kSSmPG1kzm/oDyyqjehM+lW1RnEt9It9GNa5JA==
+
+earcut@^2.2.3:
+  version "2.2.4"
+  resolved "https://registry.yarnpkg.com/earcut/-/earcut-2.2.4.tgz#6d02fd4d68160c114825d06890a92ecaae60343a"
+  integrity sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ==
+
+geotiff@^2.0.7:
+  version "2.1.3"
+  resolved "https://registry.yarnpkg.com/geotiff/-/geotiff-2.1.3.tgz#993f40f2aa6aa65fb1e0451d86dd22ca8e66910c"
+  integrity sha512-PT6uoF5a1+kbC3tHmZSUsLHBp2QJlHasxxxxPW47QIY1VBKpFB+FcDvX+MxER6UzgLQZ0xDzJ9s48B9JbOCTqA==
+  dependencies:
+    "@petamoriken/float16" "^3.4.7"
+    lerc "^3.0.0"
+    pako "^2.0.4"
+    parse-headers "^2.0.2"
+    quick-lru "^6.1.1"
+    web-worker "^1.2.0"
+    xml-utils "^1.0.2"
+    zstddec "^0.1.0"
+
+ieee754@^1.1.12:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
+  integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
+
+lerc@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/lerc/-/lerc-3.0.0.tgz#36f36fbd4ba46f0abf4833799fff2e7d6865f5cb"
+  integrity sha512-Rm4J/WaHhRa93nCN2mwWDZFoRVF18G1f47C+kvQWyHGEZxFpTUi73p7lMVSAndyxGt6lJ2/CFbOcf9ra5p8aww==
+
 moment@^2.30.1:
   version "2.30.1"
   resolved "https://registry.yarnpkg.com/moment/-/moment-2.30.1.tgz#f8c91c07b7a786e30c59926df530b4eac96974ae"
   integrity sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==
 
+ol@^9.1.0:
+  version "9.1.0"
+  resolved "https://registry.yarnpkg.com/ol/-/ol-9.1.0.tgz#738e9f17093f65dafe114b8a78c69f110f5d0220"
+  integrity sha512-nDrkJ2tzZNpo/wzN/PpHV5zdxbnXZaFktoMaD2cFLEc6gCwlgLY21Yd8wnt/4FjaVYwLBnbN9USXSwIBGcyksQ==
+  dependencies:
+    color-rgba "^3.0.0"
+    color-space "^2.0.1"
+    earcut "^2.2.3"
+    geotiff "^2.0.7"
+    pbf "3.2.1"
+    rbush "^3.0.1"
+
+pako@^2.0.4:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/pako/-/pako-2.1.0.tgz#266cc37f98c7d883545d11335c00fbd4062c9a86"
+  integrity sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==
+
+parse-headers@^2.0.2:
+  version "2.0.5"
+  resolved "https://registry.yarnpkg.com/parse-headers/-/parse-headers-2.0.5.tgz#069793f9356a54008571eb7f9761153e6c770da9"
+  integrity sha512-ft3iAoLOB/MlwbNXgzy43SWGP6sQki2jQvAyBg/zDFAgr9bfNWZIUj42Kw2eJIl8kEi4PbgE6U1Zau/HwI75HA==
+
+pbf@3.2.1:
+  version "3.2.1"
+  resolved "https://registry.yarnpkg.com/pbf/-/pbf-3.2.1.tgz#b4c1b9e72af966cd82c6531691115cc0409ffe2a"
+  integrity sha512-ClrV7pNOn7rtmoQVF4TS1vyU0WhYRnP92fzbfF75jAIwpnzdJXf8iTd4CMEqO4yUenH6NDqLiwjqlh6QgZzgLQ==
+  dependencies:
+    ieee754 "^1.1.12"
+    resolve-protobuf-schema "^2.1.0"
+
 pinyin-pro@^3.19.7:
   version "3.19.7"
   resolved "https://registry.yarnpkg.com/pinyin-pro/-/pinyin-pro-3.19.7.tgz#a0c0f994686f48935202687f197808039439b5cc"
   integrity sha512-SydYnjrvUpvW6qRpuZPfutYAz+lgoMJDPAbKUy8fnXt3qQIg+Wdpcd07A/1ljj0mTG7YDoYjXcF/jHTBCPShYQ==
+
+protocol-buffers-schema@^3.3.1:
+  version "3.6.0"
+  resolved "https://registry.yarnpkg.com/protocol-buffers-schema/-/protocol-buffers-schema-3.6.0.tgz#77bc75a48b2ff142c1ad5b5b90c94cd0fa2efd03"
+  integrity sha512-TdDRD+/QNdrCGCE7v8340QyuXd4kIWIgapsE2+n/SaGiSSbomYl4TjHlvIoCWRpE7wFt02EpB35VVA2ImcBVqw==
+
+quick-lru@^6.1.1:
+  version "6.1.2"
+  resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-6.1.2.tgz#e9a90524108629be35287d0b864e7ad6ceb3659e"
+  integrity sha512-AAFUA5O1d83pIHEhJwWCq/RQcRukCkn/NSm2QsTEMle5f2hP0ChI2+3Xb051PZCkLryI/Ir1MVKviT2FIloaTQ==
+
+quickselect@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/quickselect/-/quickselect-2.0.0.tgz#f19680a486a5eefb581303e023e98faaf25dd018"
+  integrity sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==
+
+rbush@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/rbush/-/rbush-3.0.1.tgz#5fafa8a79b3b9afdfe5008403a720cc1de882ecf"
+  integrity sha512-XRaVO0YecOpEuIvbhbpTrZgoiI6xBlz6hnlr6EHhd+0x9ase6EmeN+hdwwUaJvLcsFFQ8iWVF1GAK1yB0BWi0w==
+  dependencies:
+    quickselect "^2.0.0"
+
+resolve-protobuf-schema@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/resolve-protobuf-schema/-/resolve-protobuf-schema-2.1.0.tgz#9ca9a9e69cf192bbdaf1006ec1973948aa4a3758"
+  integrity sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ==
+  dependencies:
+    protocol-buffers-schema "^3.3.1"
+
+web-worker@^1.2.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/web-worker/-/web-worker-1.3.0.tgz#e5f2df5c7fe356755a5fb8f8410d4312627e6776"
+  integrity sha512-BSR9wyRsy/KOValMgd5kMyr3JzpdeoR9KVId8u5GVlTTAtNChlsE4yTxeY7zMdNSyOmoKBv8NH2qeRY9Tg+IaA==
+
+xml-utils@^1.0.2:
+  version "1.8.0"
+  resolved "https://registry.yarnpkg.com/xml-utils/-/xml-utils-1.8.0.tgz#dd9baa161012849b97703d8423d09d9d815a5910"
+  integrity sha512-1TY5yLw8DApowZAUsWCniNr8HH6Ebt6O7UQvmIwziGKwUNsQx6e+4NkfOvCfnqmYIcPjCeoI6dh1JenPJ9a1hQ==
+
+zstddec@^0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/zstddec/-/zstddec-0.1.0.tgz#7050f3f0e0c3978562d0c566b3e5a427d2bad7ec"
+  integrity sha512-w2NTI8+3l3eeltKAdK8QpiLo/flRAr2p8AGeakfMZOXBxOg9HIu4LVDxBi81sYgVhFhdJjv1OrB5ssI8uFPoLg==