heyang 9 meses atrás
pai
commit
e22bf10bc4
22 arquivos alterados com 2955 adições e 32 exclusões
  1. 14 0
      pages.json
  2. 95 0
      pages/views/sceneInspect/memorandum.vue
  3. 190 18
      pages/views/sceneInspect/sceneInspect.vue
  4. 566 0
      pages_manage/views/laboratory/safetyCardScan.vue
  5. BIN
      pages_safetyCheck/images/icon_sys_aqxxp@1x.png
  6. BIN
      pages_safetyCheck/images/icon_sys_jcjl@1x.png
  7. BIN
      pages_safetyCheck/images/icon_sys_jckz@1x.png
  8. BIN
      pages_safetyCheck/images/icon_xcjc_ld@1x.png
  9. BIN
      pages_safetyCheck/images/icon_xcjc_sx@1x.png
  10. 76 14
      pages_safetyCheck/views/itemsManage/hiddenDangerItems.vue
  11. 47 0
      uni_modules/uni-swipe-action/changelog.md
  12. 302 0
      uni_modules/uni-swipe-action/components/uni-swipe-action-item/bindingx.js
  13. 12 0
      uni_modules/uni-swipe-action/components/uni-swipe-action-item/isPC.js
  14. 195 0
      uni_modules/uni-swipe-action/components/uni-swipe-action-item/mpalipay.js
  15. 260 0
      uni_modules/uni-swipe-action/components/uni-swipe-action-item/mpother.js
  16. 84 0
      uni_modules/uni-swipe-action/components/uni-swipe-action-item/mpwxs.js
  17. 270 0
      uni_modules/uni-swipe-action/components/uni-swipe-action-item/render.js
  18. 348 0
      uni_modules/uni-swipe-action/components/uni-swipe-action-item/uni-swipe-action-item.vue
  19. 341 0
      uni_modules/uni-swipe-action/components/uni-swipe-action-item/wx.wxs
  20. 60 0
      uni_modules/uni-swipe-action/components/uni-swipe-action/uni-swipe-action.vue
  21. 84 0
      uni_modules/uni-swipe-action/package.json
  22. 11 0
      uni_modules/uni-swipe-action/readme.md

+ 14 - 0
pages.json

@@ -1,6 +1,12 @@
 {
 	"pages": [
 		{
+			"path": "pages/views/sceneInspect/memorandum", 
+			"style": {
+				"navigationBarTitleText": "现场检查"
+			}
+		},
+		{
 			"path": "pages/views/sceneInspect/sceneInspect", 
 			"style": {
 				"navigationBarTitleText": "现场检查"
@@ -14,6 +20,7 @@
 				"navigationStyle": "custom" //关闭原生导航
 			}
 		},
+		
 		{
 			"path": "pages/views/home/home", //首页
 			"style": {
@@ -670,6 +677,13 @@
 				// 		"navigationBarTitleText": "我的实验室"
 				// 	}
 				// },
+				/* 安全检查扫一扫进入实验室详情 */
+				{
+					"path": "views/laboratory/safetyCardScan", 
+					"style": {
+						"navigationBarTitleText": "实验室"
+					}
+				},
 				/* 实验室详情 */
 				{
 					"path": "views/laboratory/infoPage", //详情

+ 95 - 0
pages/views/sceneInspect/memorandum.vue

@@ -0,0 +1,95 @@
+<!-- 备忘录 -->
+<template>
+	<view class="memorandum">
+		<view class="memorandum-box">
+			<textarea class="memorandum-box-t" type="text" v-model="form.hazardDescribe" maxlength="200" @input="sumfontnum"
+				placeholder="请输入内容" placeholder-style="font-size:28rpx;color:#999;"></textarea>
+			<view class="memorandum-box-b"><text>{{fontNum}}</text>/200</view>
+		</view>
+		<view class="sub-btn">保存</view>
+	</view>
+
+</template>
+
+<script>
+	import {
+		config
+	} from '@/api/request/config.js'
+	import {
+		systemDeptDropList,
+	} from '@/pages/api/index.js'
+	export default {
+		name: "memorandum",
+		components: {
+
+		},
+		data() {
+			return {
+				baseUrl: config.base_url,
+				pageType: 0,
+				fontNum: 0,
+				form: {
+					hazardDescribe: '',
+				}
+			}
+		},
+		onLoad(option) {
+
+
+		},
+		onShow() {
+
+		},
+		mounted() {
+
+		},
+		methods: {
+			// 限制文本框字数
+			sumfontnum(e) {
+				console.log(e)
+				this.fontNum = e.detail.value.length
+			}
+
+		}
+	}
+</script>
+
+<style lang="stylus" scoped>
+	.memorandum {
+		height: 100%;
+		.memorandum-box {
+			width: 750rpx;
+			height: 300rpx;
+			background: #FFFFFF;
+			
+			.memorandum-box-t{
+				width: 750rpx;
+				height: 240rpx;
+				padding: 20rpx 30rpx;
+				box-sizing: border-box;
+			}
+			.memorandum-box-b{
+				font-size: 28rpx;
+				color: #999999;
+				line-height: 39rpx;
+				text-align: right;
+				padding: 0 30rpx;
+				box-sizing: border-box;
+				
+			}
+		}
+		.sub-btn{
+			width: 686rpx;
+			height: 100rpx;
+			background: #0183FA;
+			border-radius: 50rpx 50rpx 50rpx 50rpx;
+			font-size: 30rpx;
+			color: #FFFFFF;
+			line-height: 100rpx;
+			text-align: center;
+			margin-left: 34rpx;
+			position: fixed;
+			bottom: 24rpx;
+		}
+	}
+</style>

+ 190 - 18
pages/views/sceneInspect/sceneInspect.vue

@@ -1,10 +1,35 @@
 <!-- 现场检查 -->
 <template>
-	<view class="planDetail">
+	<view class="sceneInspect">
 		<scroll-view scroll-y @scrolltolower="scrollGet" class="info-max-box">
-			<view class="college">请选择学院单位
-			
+			<view class="college">
+				<picker @change="collegeChange" :value="collegeIndex" :range="collegeArray" :range-key="'deptName'">
+					<view class="college-l">{{queryParams.deptName?queryParams.deptName:'请选择学院单位'}}</view>
+				</picker>
+				<img class="college-r" @click="resetQuery" src="@/pages_safetyCheck/images/icon_aqjc_ss.png">
 			</view>
+			<view class="memorandum">
+				<view>备忘录</view>
+				<view>08-26 08:36
+					<img src="@/pages_safetyCheck/images/icon_wd_gd@1x.png">
+				</view>
+			</view>
+			<view class="memorandum">
+				<view>备忘录</view>
+				<view style="color: #0183FA;">2</view>
+			</view>
+			<uni-swipe-action>
+				<uni-swipe-action-item :right-options="options" @click="onClick" @change="swipeChange"
+					v-for="(item,index) in dataList">
+					<view class="list-li">
+						<img class="list-li-l" src="@/pages_safetyCheck/images/icon_xcjc_ld@1x.png">
+						<view class="list-li-r">
+							<view>{{item.name}}</view>
+							<view>{{item.time}}</view>
+						</view>
+					</view>
+				</uni-swipe-action-item>
+			</uni-swipe-action>
 		</scroll-view>
 	</view>
 
@@ -14,9 +39,11 @@
 	import {
 		config
 	} from '@/api/request/config.js'
-	import {} from '@/pages/api/index.js'
+	import {
+		systemDeptDropList,
+	} from '@/pages/api/index.js'
 	export default {
-		name: "planDetail",
+		name: "sceneInspect",
 		components: {
 
 		},
@@ -24,6 +51,35 @@
 			return {
 				baseUrl: config.base_url,
 				pageType: 0,
+				collegeArray: [],
+				collegeIndex: 0,
+				// 查询参数
+				queryParams: {
+					page: 1,
+					pageSize: 10,
+					deptId: '',
+					deptName: '',
+				},
+				dataList: [{
+						name: '楼栋名称房间号',
+						time: '2024-08-26 09:33',
+					},
+					{
+						name: '楼栋名称房间号',
+						time: '2024-08-26 09:33',
+					},
+				],
+				options: [{
+					text: '编辑',
+					style: {
+						backgroundColor: '#0183fa'
+					}
+				}, {
+					text: '删除',
+					style: {
+						backgroundColor: '#FD5C5C'
+					}
+				}]
 			}
 		},
 		onLoad(option) {
@@ -34,38 +90,154 @@
 
 		},
 		mounted() {
-
+			this.systemDeptDropList();
 		},
 		methods: {
 			//滚动事件
 			scrollGet() {},
+			collegeChange(e) {
+				let self = this;
+				self.collegeArray.forEach(function(item, index) {
+					if (index == e.detail.value) {
+						console.log(item)
+						self.$set(self.queryParams, 'deptId', item.deptId)
+						self.$set(self.queryParams, 'deptName', item.deptName)
+					}
+				})
+			},
+			resetQuery() {
+				this.$set(this.queryParams, 'deptId', '')
+				this.$set(this.queryParams, 'deptName', '')
+			},
+			onClick(e) {
+				uni.showToast({
+					title: `点击了${e.position === 'left' ? '左侧' : '右侧'} ${e.content.text}按钮`,
+					icon: 'none'
+				});
+				//点击选项按钮时触发事件	
+				//e = {content,index} ,content(点击内容)、index(下标)、position (位置信息)
+			},
+			swipeChange(e) {
+				//组件打开或关闭时触发	
+				// left:左侧 ,right:右侧,none:关闭
+			},
+			//获取院系
+			async systemDeptDropList() {
+				const {
+					data
+				} = await systemDeptDropList({
+					deptName: '',
+					level: 2,
+					deptType: 1
+				});
+				if (data.code == 200) {
+					this.collegeArray = data.data
+				}
+			},
 
 		}
 	}
 </script>
 
 <style lang="stylus" scoped>
-	.planDetail {
+	.sceneInspect {
 		height: 100%;
 		display flex;
 		box-sizing: border-box;
 
-		#fontColor-A {
-			color: #0040C1;
-		}
+		.college {
+			width: 750rpx;
+			height: 80rpx;
+			background: #FFFFFF;
+			padding: 0 30rpx;
+			box-sizing: border-box;
+			display: flex;
+			justify-content: flex-start;
+			align-items: center;
+			margin-bottom: 20rpx;
 
-		#fontColor-B {
-			color: #009519;
+			.college-l {
+				font-size: 30rpx;
+				color: #333333;
+				line-height: 80rpx;
+				text-align: left;
+			}
+
+			.college-r {
+				width: 30rpx;
+				height: 30rpx;
+				margin-left: 20rpx;
+			}
 		}
 
-		#bgColor-A {
-			color: #0183FA;
-			background: rgba(1, 131, 250, 0.2);
+		.memorandum {
+			width: 750rpx;
+			height: 80rpx;
+			background: #FFFFFF;
+			border-bottom: 1rpx solid #E0E0E0;
+			padding: 0 30rpx;
+			box-sizing: border-box;
+			display: flex;
+			justify-content: space-between;
+			align-items: center;
+
+			>view:nth-of-type(1) {
+				font-size: 28rpx;
+				color: #333333;
+				line-height: 39rpx;
+				text-align: left;
+			}
+
+			>view:nth-of-type(2) {
+				font-size: 28rpx;
+				color: #666666;
+				line-height: 39rpx;
+				text-align: left;
+				display: flex;
+				justify-content: flex-start;
+				align-items: center;
+
+				>img {
+					width: 24rpx;
+					height: 24rpx;
+					margin-left: 12rpx;
+				}
+			}
 		}
 
-		#bgColor-B {
-			color: #16B531;
-			background: rgba(22, 181, 49, 0.2);
+		.list-li {
+			width: 750rpx;
+			height: 100rpx;
+			background: #FFFFFF;
+			border-bottom: 1rpx solid #E0E0E0;
+			display: flex;
+			justify-content: flex-start;
+			align-items: center;
+			padding: 0 30rpx;
+			box-sizing: border-box;
+
+			.list-li-l {
+				width: 60rpx;
+				height: 60rpx;
+				margin-right: 24rpx;
+			}
+
+			.list-li-r {
+				>view:nth-of-type(1) {
+					font-size: 28rpx;
+					color: #333333;
+					line-height: 39rpx;
+					text-align: left;
+				}
+
+				>view:nth-of-type(2) {
+					font-size: 24rpx;
+					color: #666666;
+					line-height: 34rpx;
+					text-align: left;
+					margin-top: 6rpx;
+				}
+			}
 		}
 	}
 </style>

+ 566 - 0
pages_manage/views/laboratory/safetyCardScan.vue

@@ -0,0 +1,566 @@
+<!-- 安全检查扫一扫 实验室详情 -->
+<template>
+	<view class="safetyCardScan">
+		<scroll-view scroll-y @scrolltolower="scrollGet" class="info-max-box">
+			<view class="header">
+				<view class="tabTitle">
+					<view class="tabTitle_li" @tap="tabClick(index)" :key="index" v-for="(item,index) in tabText">
+						<view class="tabTitle_text">
+							<img :src="item.img">
+							<view
+								:id="curTab==index && curTab==0?'fontColor-A':(curTab==index && curTab==1?'fontColor-B':'')">
+								{{item.name}}
+							</view>
+						</view>
+						<view :class="{on:curTab==index}" class="tabTitle_across">
+							<img src="@/pages_safetyCheck/images/img_xyzc_bg@1x.png">
+						</view>
+						<view class="line"></view>
+					</view>
+				</view>
+			</view>
+			<view class="safetyCard" v-if="pageType==1">
+				<view class="lab-info">
+					<view class="lab-info-t">
+						<view>一级</view>
+						<view>化学类</view>
+						<view>实验室名称名称名称(房间号)</view>
+					</view>
+					<view class="lab-info-b">
+						<img src="@/pages_safetyCheck/images/icon_sys_xz@1x.png">
+						楼栋楼层
+					</view>
+				</view>
+				<view class="liability-unit">
+					<view>学院单位</view>
+					<view>学院单位名称</view>
+				</view>
+				<view class="small-title">
+					<view>实验室负责人</view>
+					<img src="@/pages_safetyCheck/images/icon_06_1.png">
+				</view>
+				<view class="sub-head">
+					<view>{{newData.adminName}}</view>
+					<view @click="callPhone(newData.adminPhone)">
+						<img src="@/pages_manage/images/icon_aqxxp_dh.png">
+						<view>{{newData.adminPhone}}</view>
+					</view>
+				</view>
+				<view class="small-title">安全员</view>
+				<view class="sub-head" v-for="(item,index) in newData.safeUserList" :key="index">
+					<view>{{item.safeUserName}}</view>
+					<view @click="callPhone(item.safeUserPhone)">
+						<img src="@/pages_manage/images/icon_aqxxp_dh.png">
+						<view>{{item.safeUserPhone}}</view>
+					</view>
+				</view>
+				<view class="classify" v-for="(item,index) in newData.labInfoBrandModels" :key="index">
+					<view v-if="item.privateList.length>0 && item.brandType==1" class="small-title">{{item.brandName}}
+					</view>
+					<view v-if="item.privateList.length>0 && item.brandType==1 && !item.isSpecial" class="small-items"
+						v-for="(item2,index2) in item.privateList" :key="index2">
+						<view>● </view>
+						<view>{{item2.infoName}}</view>
+					</view>
+					<view v-if="item.privateList.length>0 && item.brandType==1 && item.isSpecial" class="small-items"
+						v-for="(item2,index2) in item.privateList" :key="index2">
+						<view></view>
+						<view>{{item2.infoName}}</view>
+					</view>
+					<view v-if="item.privateList.length>0 && item.brandType==2" class="logotype">{{item.brandName}}
+					</view>
+					<view v-if="item.privateList.length>0 && item.brandType==2" class="logotype-img">
+						<img v-for="(item3,index3) in item.privateList" :key="index3" :src="baseUrl+item3.infoContent">
+					</view>
+				</view>
+			</view>
+			<!-- 物联控制 -->
+			<iotControl ref="iotControl" v-if="pageType == 2" :subjectData="subjectData"></iotControl>
+			<!-- 进出记录 -->
+			<accessRecord v-if="pageType == 4" :subjectData="subjectData"></accessRecord>
+			<!-- 语音广播弹窗 -->
+			<voiceBroadcast v-if="broadcastPage" :subjectData="subjectData"></voiceBroadcast>
+			<!-- 空调弹窗 -->
+			<airConditioning v-if="conditioningPage" :airConditioningData="airConditioningData"></airConditioning>
+		</scroll-view>
+	</view>
+
+</template>
+
+<script>
+	import {
+		iotControl
+	} from '@/pages_manage/views/laboratory/iotControl.vue'
+	import {
+		accessRecord
+	} from '@/pages_manage/views/laboratory/accessRecord.vue'
+	import {
+		voiceBroadcast
+	} from '@/pages_manage/views/laboratory/voiceBroadcast.vue'
+	import {
+		airConditioning
+	} from '@/pages_manage/views/laboratory/airConditioning.vue'
+	import {
+		config
+	} from '@/api/request/config.js'
+	import {
+
+	} from '@/pages/api/index.js'
+	export default {
+		name: "safetyCardScan",
+		components: {
+			iotControl,
+			accessRecord,
+			voiceBroadcast,
+			airConditioning,
+		},
+		data() {
+			return {
+				baseUrl: config.base_url,
+				pageType: 1,
+				tabText: [{
+						name: '安全信息牌',
+						img: require('@/pages_safetyCheck/images/icon_sys_aqxxp@1x.png'),
+					},
+					{
+						name: '监测控制',
+						img: require('@/pages_safetyCheck/images/icon_sys_jckz@1x.png'),
+					},
+					{
+						name: '进出记录',
+						img: require('@/pages_safetyCheck/images/icon_sys_jcjl@1x.png'),
+					},
+				],
+				curTab: 0,
+				newData: {
+					adminName: '李飘飘',
+					adminPhone: '13655668899',
+					safeUserList: [{
+							safeUserName: '周游',
+							safeUserPhone: '13655668899',
+						},
+						{
+							safeUserName: '周游',
+							safeUserPhone: '13655668899',
+						},
+					],
+				},
+				//语音广播弹窗
+				broadcastPage: false,
+				//空调弹窗
+				conditioningPage: false,
+				// 查询参数
+				queryParams: {
+					page: 1,
+					pageSize: 20,
+				},
+				subjectData: null,
+				// 空调弹窗
+				airConditioningData: null,
+				saoCodeType: false,
+
+			}
+		},
+		// 父页面
+		onReachBottom() {
+			uni.$emit('onReachBottom') // 设置监听事件
+		},
+		onPullDownRefresh() {
+			uni.$emit('onPullDownRefresh') // 设置监听事件
+		},
+		onLoad(option) {
+			//this.$set(this, 'newData', JSON.parse(decodeURIComponent(option.infoData)));
+			//this.$set(this, 'subjectData', JSON.parse(decodeURIComponent(option.infoData)));
+			if (option.saoCode) {
+				this.$set(this, 'saoCodeType', true);
+				this.$set(this, 'currentIndex', 1);
+				this.$set(this, 'pageType', 3);
+			} else {
+				this.$set(this, 'saoCodeType', false);
+				this.$set(this, 'currentIndex', 0);
+				this.$set(this, 'pageType', 2);
+			}
+
+		},
+		onShow() {
+
+		},
+		mounted() {
+
+		},
+		methods: {
+			//滚动事件
+			scrollGet() {},
+			//顶部tab点击
+			tabClick(index) {
+				this.curTab = index;
+				if (index == 0) {
+					//安全信息牌
+					this.$set(this, 'pageType', 1);
+				} else if (index == 1) {
+					//监测控制
+					this.$set(this, 'pageType', 2);
+				} else if (index == 2) {
+					//进出记录
+					this.$set(this, 'pageType', 4);
+				}
+			},
+			goVideoPage() {
+				console.log('视频')
+				let obj = {
+					type: 4,
+					subId: this.newData.subId
+				}
+				uni.navigateTo({
+					url: '/pages_manage/views/laboratory/videoPlayer?item=' + encodeURIComponent(JSON.stringify(
+						obj))
+				});
+			},
+			getIotControlData() {
+				this.$refs['iotControl'].iotAppHardwareFindByType();
+			},
+			buttonClick(type, row) {
+				let self = this;
+				if (type == 'subDetail') {
+					//实验室详情
+				} else if (type == 'broadcastOpen') {
+					//语音弹窗开启
+					this.$set(this, 'broadcastPage', true);
+				} else if (type == 'broadcastClose') {
+					//语音弹窗关闭
+					this.$set(this, 'broadcastPage', false);
+				} else if (type == 'conditioningOpen') {
+					//空调弹窗开启
+					this.$set(this, 'airConditioningData', row);
+					this.$set(this, 'conditioningPage', true);
+				} else if (type == 'conditioningClose') {
+					//空调弹窗关闭
+					this.$set(this, 'conditioningPage', false);
+				} else if (type == 'back') {
+					this.$set(this, 'pageType', 2);
+				}
+			},
+
+		}
+	}
+</script>
+
+<style lang="stylus" scoped>
+	.safetyCardScan {
+		height: 100%;
+
+		#fontColor-A {
+			color: #00DEDE;
+		}
+
+		#fontColor-B {
+			color: #FF8C00;
+		}
+
+		.header {
+			width: 100%;
+			position: fixed;
+			top: 0rpx;
+			z-index: 100;
+			background: #fff;
+
+			.tabTitle {
+				width: 750rpx;
+				height: 188rpx;
+				display flex;
+				justify-content: flex-start;
+				align-items: center;
+				border-bottom: 4rpx solid #F5F5F5;
+
+				.tabTitle_li {
+					height: 188rpx;
+					flex: 1;
+					position: relative;
+					text-align center;
+
+					.tabTitle_text {
+						display: flex;
+						justify-content: center;
+						flex-direction: column;
+						align-items: center;
+
+						>img {
+							width: 80rpx;
+							height: 80rpx;
+							margin-top: 20rpx;
+						}
+
+						>view:nth-of-type(1) {
+							font-size: 30rpx;
+							color: #333333;
+							line-height: 42rpx;
+							text-align: left;
+							margin-top: 10rpx;
+						}
+
+						>view:nth-of-type(2) {
+							font-size: 24rpx;
+							color: #666666;
+							line-height: 34rpx;
+							text-align: left;
+						}
+
+
+						position: relative;
+
+						&.on {}
+					}
+
+					.line {
+						width: 2rpx;
+						height: 40rpx;
+						background: #D8D8D8;
+						position: absolute;
+						top: 40%;
+					}
+
+					.tabTitle_across {
+						/* width: 50rpx;
+						height: 4rpx;
+						background: #0183FA;
+						border-radius: 2rpx; */
+						margin-left: 38%;
+						margin-top: 12rpx;
+						display none;
+
+						>img {
+							width: 40rpx;
+							height: 26rpx;
+						}
+
+						&.on {
+							display block;
+						}
+					}
+
+				}
+			}
+		}
+
+		/* 安全信息牌 */
+		.safetyCard {
+			margin-top: 190rpx;
+
+			.lab-info {
+				background: #FFFFFF;
+
+				.lab-info-t {
+					width: 750rpx;
+					height: 80rpx;
+					border: 2rpx dashed #E0E0E0;
+					display: flex;
+					justify-content: flex-start;
+					align-items: center;
+					padding: 0 30rpx;
+					box-sizing: border-box;
+
+					>view:nth-of-type(1) {
+						width: 100rpx;
+						height: 60rpx;
+						background: #FF0000;
+						border-radius: 50rpx 50rpx 50rpx 50rpx;
+						font-size: 30rpx;
+						color: #FFFFFF;
+						line-height: 60rpx;
+						text-align: center;
+					}
+
+					>view:nth-of-type(2) {
+						width: 130rpx;
+						height: 60rpx;
+						border-radius: 50rpx 50rpx 50rpx 50rpx;
+						border: 2rpx solid #FF8C00;
+						font-size: 30rpx;
+						color: #FF8C00;
+						line-height: 60rpx;
+						text-align: center;
+						margin: 0 30rpx 0 10rpx;
+					}
+
+					>view:nth-of-type(3) {
+						font-size: 30rpx;
+						color: #333333;
+						line-height: 42rpx;
+						text-align: left;
+						overflow: hidden;
+						text-overflow: ellipsis;
+						white-space: nowrap;
+					}
+				}
+
+				.lab-info-b {
+					height: 80rpx;
+					padding: 0 30rpx;
+					box-sizing: border-box;
+					display: flex;
+					justify-content: flex-start;
+					align-items: center;
+
+					>img {
+						width: 34rpx;
+						height: 34rpx;
+						margin-right: 12rpx;
+					}
+
+					font-size: 30rpx;
+					color: #333333;
+					line-height: 42rpx;
+					text-align: left;
+				}
+			}
+
+			.liability-unit {
+				width: 750rpx;
+				height: 80rpx;
+				background: #FFFFFF;
+				border-bottom: 1rpx solid #E0E0E0;
+				padding: 0 30rpx;
+				box-sizing: border-box;
+				display: flex;
+				justify-content: space-between;
+				margin-top: 14rpx;
+
+				>view:nth-of-type(1) {
+					font-size: 30rpx;
+					color: #333333;
+					line-height: 80rpx;
+					text-align: left;
+				}
+
+				>view:nth-of-type(2) {
+					font-size: 30rpx;
+					color: #666666;
+					line-height: 80rpx;
+					text-align: left;
+				}
+			}
+
+			.small-title {
+				width: 750rpx;
+				height: 80rpx;
+				background: #FFFFFF;
+				border-bottom: 1rpx solid #E0E0E0;
+				padding: 0 30rpx;
+				box-sizing: border-box;
+				display: flex;
+				justify-content: space-between;
+				align-items: center;
+
+				>view {
+					font-size: 30rpx;
+					color: #333333;
+					line-height: 80rpx;
+					text-align: left;
+				}
+
+				>img {
+					width: 24rpx;
+					height: 12rpx;
+				}
+			}
+
+			.sub-head {
+				width: 750rpx;
+				height: 80rpx;
+				background: #fff;
+				padding: 0 30rpx;
+				box-sizing: border-box;
+				display: flex;
+				justify-content: space-between;
+				align-items: center;
+				border-bottom: 1rpx solid #E0E0E0;
+
+				>view:nth-of-type(1) {
+					font-family: PingFang SC;
+					font-weight: 500;
+					font-size: 30rpx;
+					color: #666666;
+					line-height: 30rpx;
+				}
+
+				>view:nth-of-type(2) {
+					display: flex;
+					justify-content: flex-end;
+					align-items: center;
+
+					>img {
+						width: 34rpx;
+						height: 34rpx;
+						margin-right: 14rpx;
+					}
+
+					>view {
+						font-family: PingFang SC;
+						font-weight: 500;
+						font-size: 30rpx;
+						color: #0183FA;
+						line-height: 30rpx;
+					}
+				}
+			}
+
+			.sub-head:last-child {
+				border-bottom: none;
+			}
+
+			.classify {
+				.small-items {
+					padding-left: 20rpx;
+					box-sizing: border-box;
+					background: #fff;
+					display: flex;
+					justify-content: flex-start;
+					padding: 20rpx;
+					box-sizing: border-box;
+
+					>view:nth-of-type(1) {
+						color: #999999;
+						margin-right: 12rpx;
+					}
+
+					>view:nth-of-type(2) {
+						display: block;
+						font-family: PingFang SC;
+						font-weight: 500;
+						font-size: 28rpx;
+						line-height: 34rpx;
+						color: #999999;
+					}
+
+				}
+
+				.logotype {
+					width: 750rpx;
+					height: 100rpx;
+					font-family: PingFang SC;
+					font-weight: 500;
+					font-size: 32rpx;
+					color: #333333;
+					line-height: 100rpx;
+					padding-left: 20rpx;
+					box-sizing: border-box;
+					background: #0183FA;
+				}
+
+				.logotype-img {
+					padding: 26rpx 0 34rpx 0;
+					box-sizing: border-box;
+					background: #fff;
+
+					>img {
+						display: inline-block;
+						width: 86rpx;
+						height: 114rpx;
+						margin-left: 30rpx;
+						margin-bottom: 20rpx;
+					}
+				}
+			}
+		}
+	}
+</style>

BIN
pages_safetyCheck/images/icon_sys_aqxxp@1x.png


BIN
pages_safetyCheck/images/icon_sys_jcjl@1x.png


BIN
pages_safetyCheck/images/icon_sys_jckz@1x.png


BIN
pages_safetyCheck/images/icon_xcjc_ld@1x.png


BIN
pages_safetyCheck/images/icon_xcjc_sx@1x.png


+ 76 - 14
pages_safetyCheck/views/itemsManage/hiddenDangerItems.vue

@@ -10,12 +10,17 @@
 			</view>
 			<view class="line"></view>
 			<view class="search">
-				<view class="search-l" @click="dialogOpen()">检查指标
-					<img src="@/pages_safetyCheck/images/icon_06.png">
-				</view>
+				<uni-data-picker :ellipsis="false" :localdata="checkOptionList[0]" :map="{text:'name',value:'id'}"
+					popup-title="请选择所属目录" @change="(e)=>onchange(e)" @nodeclick="onnodeclick()"
+					ref="uniDataPicker" :addType="false" :addIndex="index">
+					<view class="search-l">
+						{{newData.hazardCheckName?newData.hazardCheckName:'检查指标'}}
+						<img src="@/pages_safetyCheck/images/icon_06.png">
+					</view>
+				</uni-data-picker>
 				<view class="search-r" @click="inspectionItemsClick()">
 					<img src="@/pages_safetyCheck/images/icon_aqjc_ss.png">
-					模糊搜索检查项
+					{{newData.hazardCheckCode?newData.hazardCheckCode:''}}{{newData.hazardCheckName?newData.hazardCheckName:'模糊搜索检查项'}}
 				</view>
 			</view>
 		</view>
@@ -30,7 +35,8 @@
 						<view v-if="item.hazardCheckId">{{item.hazardCheckCode}}{{item.hazardCheckName}}</view>
 						<view v-if="!item.hazardCheckId">{{item.hazardDescribe}}</view>
 					</view>
-					<view v-if="item.hazardCheckId" class="list-li-b" @click="hiddenDangerClick(item)">此检查项在当前实验室累计出现<text>{{item.hazardCheckNum}}</text>次隐患
+					<view v-if="item.hazardCheckId" class="list-li-b" @click="hiddenDangerClick(item)">
+						此检查项在当前实验室累计出现<text>{{item.hazardCheckNum}}</text>次隐患
 					</view>
 				</view>
 			</view>
@@ -46,6 +52,7 @@
 	} from '@/api/request/config.js'
 	import {
 		securityAppCheckPhotoList,
+		securityCheckOptionList,
 	} from '@/pages_safetyCheck/api/index.js'
 	export default {
 		name: "hiddenDangerItems",
@@ -69,23 +76,24 @@
 				queryParams: {
 					page: 1,
 					pageSize: 10,
-					subId:'',
-					rectifyStatus:0,
-					hazardCheckId:'',
-					searchValue:'',
+					subId: '',
+					rectifyStatus: 0,
+					hazardCheckId: '',
+					searchValue: '',
 				},
 				total: 0,
 				dataList: [],
 				getDataType: false,
-
+				//检查项
+				checkOptionList: [],
 
 			}
 		},
 		onLoad(option) {
 			this.$set(this, 'newData', JSON.parse(decodeURIComponent(option.infoData)));
 			this.pageType = this.newData.pageType;
-			this.queryParams.subId=this.newData.subId?this.newData.subId:''
-			this.queryParams.hazardCheckId=this.newData.hazardCheckId?this.newData.hazardCheckId:''
+			this.queryParams.subId = this.newData.subId ? this.newData.subId : ''
+			this.queryParams.hazardCheckId = this.newData.hazardCheckId ? this.newData.hazardCheckId : ''
 			uni.setNavigationBarTitle({
 				title: '实验室名称(房间号)'
 			})
@@ -104,6 +112,7 @@
 
 		},
 		mounted() {
+			this.getCheckOptionList()
 			this.getList()
 		},
 		methods: {
@@ -122,7 +131,7 @@
 			//顶部tab点击
 			tabClickTow(index) {
 				this.curTabTow = index;
-				this.queryParams.rectifyStatus=index;
+				this.queryParams.rectifyStatus = index;
 				this.getList()
 			},
 			dialogOpen() {
@@ -133,7 +142,7 @@
 			},
 			//搜索项跳转
 			inspectionItemsClick() {
-				this.newData.pageType=2;//1随手拍检查项
+				this.newData.pageType = 2; //1随手拍检查项
 				uni.redirectTo({
 					url: '/pages_safetyCheck/views/itemsManage/hiddenDangerItemsSearch?form=' + encodeURIComponent(
 						JSON.stringify(this.newData))
@@ -177,6 +186,58 @@
 					}
 				}
 			},
+			/**************************检查项***************************/
+			//获取检查项
+			async getCheckOptionList() {
+				const {
+					data
+				} = await securityCheckOptionList();
+				if (data.code == 200) {
+					let list = this.getTreeData(data.data);
+					console.log(list)
+					this.checkOptionList.push(JSON.parse(JSON.stringify(list)));
+
+				}
+			},
+			getTreeData(data) {
+				for (var i = 0; i < data.length > 0; i++) {
+					if (data[i].children == null || data[i].children.length <= 0) {
+						// children若为空数组,则将children设为undefined
+						data[i].children = undefined;
+					} else {
+						if (this.form.checkCategory == 1 && data[i].level == 3) {
+							if (data[i].children[0]) {
+								let mainPoint = []
+								for (let b = 0; b < data[i].children.length; b++) {
+									mainPoint.push(data[i].children[b].name)
+									data[i].mainPoint = mainPoint.join(',')
+								}
+							} else {
+								data[i].mainPoint = '';
+							}
+							data[i].children = [];
+						}
+						// children若不为空数组,则继续 递归调用 本方法
+						this.getTreeData(data[i].children);
+					}
+				}
+				return data;
+			},
+			//选中固有检查项(新)
+			onchange(e) {
+				let self = this;
+				//hazardCheckCode:'', //检查项目code序号
+				//hazardCheckName:'', //检查项目名称
+				//hazardCheckPro:'', //最后一级的id
+				console.log(e.detail.value)
+				this.$set(this.queryParams,'hazardCheckId',e.detail.value[e.detail.value.length - 1].value)
+				this.$set(this.newData,'hazardCheckName',e.detail.value[e.detail.value.length - 1].text)
+				this.getList()
+				
+			},
+			onnodeclick(node) {
+
+			},
 
 		}
 	}
@@ -317,6 +378,7 @@
 			margin-top: 200rpx;
 			padding-bottom: 20rpx;
 			box-sizing: border-box;
+
 			.total {
 				width: 180rpx;
 				height: 50rpx;

+ 47 - 0
uni_modules/uni-swipe-action/changelog.md

@@ -0,0 +1,47 @@
+## 1.3.10(2024-01-17)
+- 修复 点击按钮时,按钮会被点击穿透导致自动收缩的 bug(兼容阿里/百度/抖音小程序)
+## 1.3.9(2024-01-17)
+- 修复 点击按钮时,按钮会被点击穿透导致自动收缩的 bug
+## 1.3.8(2023-04-13)
+- 修复`uni-swipe-action`和`uni-swipe-action-item`不同时使用导致 closeOther 方法报错的 bug
+## 1.3.7(2022-06-06)
+- 修复 vue3 下使用组件不能正常运行的Bug
+## 1.3.6(2022-05-31)
+- 修复 h5端点击click触发两次的Bug
+## 1.3.5(2022-05-23)
+- 修复 isPC 找不到的Bug
+## 1.3.4(2022-05-19)
+-  修复 在 nvue 下 disabled 失效的bug
+## 1.3.3(2022-03-31)
+- 修复 按钮字体大小不能设置的bug
+## 1.3.2(2022-03-16)
+- 修复 h5和app端下报el错误的bug
+## 1.3.1(2022-03-07)
+- 修复 HBuilderX 1.4.X 版本中,h5和app端下报错的bug
+## 1.3.0(2021-11-19)
+- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
+- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-swipe-action](https://uniapp.dcloud.io/component/uniui/uni-swipe-action)
+## 1.2.4(2021-08-20)
+- 优化 close-all 方法
+## 1.2.3(2021-08-20)
+- 新增 close-all 方法,关闭所有已打开的组件
+## 1.2.2(2021-08-17)
+- 新增 resize() 方法,在非微信小程序、h5、app-vue端出现不能滑动的问题的时候,重置组件
+- 修复 app 端偶尔出现类似 Page[x][-x,xx;-x,xx,x,x-x] 的问题 
+- 优化 微信小程序、h5、app-vue 滑动逻辑,避免出现动态新增组件后不能滑动的问题
+## 1.2.1(2021-07-30)
+- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
+- 修复 跨页面修改组件数据 ,导致不能滑动的问题
+## 1.1.10(2021-06-17)
+- 修复 按钮点击执行两次的bug
+## 1.1.9(2021-05-12)
+- 新增 项目示例地址
+## 1.1.8(2021-03-26)
+- 修复 微信小程序 nv_navigator is not defined 报错的bug
+## 1.1.7(2021-02-05)
+- 调整为uni_modules目录规范
+- 新增 左侧滑动
+- 新增 插槽使用方式
+- 新增 threshold 属性,可以控制滑动缺省值
+- 优化 长列表滚动性能
+- 修复 滚动页面时触发组件滑动的Bug

+ 302 - 0
uni_modules/uni-swipe-action/components/uni-swipe-action-item/bindingx.js

@@ -0,0 +1,302 @@
+let bindIngXMixins = {}
+
+// #ifdef APP-NVUE
+const BindingX = uni.requireNativePlugin('bindingx');
+const dom = uni.requireNativePlugin('dom');
+const animation = uni.requireNativePlugin('animation');
+
+bindIngXMixins = {
+	data() {
+		return {}
+	},
+
+	watch: {
+		show(newVal) {
+			if (this.autoClose) return
+			if (this.stop) return
+			this.stop = true
+			if (newVal) {
+				this.open(newVal)
+			} else {
+				this.close()
+			}
+		},
+		leftOptions() {
+			this.getSelectorQuery()
+			this.init()
+		},
+		rightOptions(newVal) {
+			this.init()
+		}
+	},
+	created() {
+		this.swipeaction = this.getSwipeAction()
+		if (this.swipeaction && Array.isArray(this.swipeaction.children)) {
+			this.swipeaction.children.push(this)
+		}
+	},
+	mounted() {
+		this.box = this.getEl(this.$refs['selector-box--hock'])
+		this.selector = this.getEl(this.$refs['selector-content--hock']);
+		this.leftButton = this.getEl(this.$refs['selector-left-button--hock']);
+		this.rightButton = this.getEl(this.$refs['selector-right-button--hock']);
+		this.init()
+	},
+	// beforeDestroy() {
+	// 	this.swipeaction.children.forEach((item, index) => {
+	// 		if (item === this) {
+	// 			this.swipeaction.children.splice(index, 1)
+	// 		}
+	// 	})
+	// },
+	methods: {
+		init() {
+			this.$nextTick(() => {
+				this.x = 0
+				this.button = {
+					show: false
+				}
+				setTimeout(() => {
+					this.getSelectorQuery()
+				}, 200)
+			})
+		},
+		onClick(index, item, position) {
+			this.$emit('click', {
+				content: item,
+				index,
+				position
+			})
+		},
+		touchstart(e) {
+			// fix by mehaotian 禁止滑动
+			if (this.disabled) return
+			// 每次只触发一次,避免多次监听造成闪烁
+			if (this.stop) return
+			this.stop = true
+			if (this.autoClose && this.swipeaction) {
+				this.swipeaction.closeOther(this)
+			}
+
+			const leftWidth = this.button.left.width
+			const rightWidth = this.button.right.width
+			let expression = this.range(this.x, -rightWidth, leftWidth)
+			let leftExpression = this.range(this.x - leftWidth, -leftWidth, 0)
+			let rightExpression = this.range(this.x + rightWidth, 0, rightWidth)
+
+			this.eventpan = BindingX.bind({
+				anchor: this.box,
+				eventType: 'pan',
+				props: [{
+					element: this.selector,
+					property: 'transform.translateX',
+					expression
+				}, {
+					element: this.leftButton,
+					property: 'transform.translateX',
+					expression: leftExpression
+				}, {
+					element: this.rightButton,
+					property: 'transform.translateX',
+					expression: rightExpression
+				}, ]
+			}, (e) => {
+				// nope
+				if (e.state === 'end') {
+					this.x = e.deltaX + this.x;
+					this.isclick = true
+					this.bindTiming(e.deltaX)
+				}
+			});
+		},
+		touchend(e) {
+			if (this.isopen !== 'none' && !this.isclick) {
+				this.open('none')
+			}
+		},
+		bindTiming(x) {
+			const left = this.x
+			const leftWidth = this.button.left.width
+			const rightWidth = this.button.right.width
+			const threshold = this.threshold
+			if (!this.isopen || this.isopen === 'none') {
+				if (left > threshold) {
+					this.open('left')
+				} else if (left < -threshold) {
+					this.open('right')
+				} else {
+					this.open('none')
+				}
+			} else {
+				if ((x > -leftWidth && x < 0) || x > rightWidth) {
+					if ((x > -threshold && x < 0) || (x - rightWidth > threshold)) {
+						this.open('left')
+					} else {
+						this.open('none')
+					}
+				} else {
+					if ((x < threshold && x > 0) || (x + leftWidth < -threshold)) {
+						this.open('right')
+					} else {
+						this.open('none')
+					}
+				}
+			}
+		},
+
+		/**
+		 * 移动范围
+		 * @param {Object} num
+		 * @param {Object} mix
+		 * @param {Object} max
+		 */
+		range(num, mix, max) {
+			return `min(max(x+${num}, ${mix}), ${max})`
+		},
+
+		/**
+		 * 开启swipe
+		 */
+		open(type) {
+			this.animation(type)
+		},
+
+		/**
+		 * 关闭swipe
+		 */
+		close() {
+			this.animation('none')
+		},
+
+		/**
+		 * 开启关闭动画
+		 * @param {Object} type
+		 */
+		animation(type) {
+			const time = 300
+			const leftWidth = this.button.left.width
+			const rightWidth = this.button.right.width
+			if (this.eventpan && this.eventpan.token) {
+				BindingX.unbind({
+					token: this.eventpan.token,
+					eventType: 'pan'
+				})
+			}
+
+			switch (type) {
+				case 'left':
+					Promise.all([
+						this.move(this.selector, leftWidth),
+						this.move(this.leftButton, 0),
+						this.move(this.rightButton, rightWidth * 2)
+					]).then(() => {
+						this.setEmit(leftWidth, type)
+					})
+					break
+				case 'right':
+					Promise.all([
+						this.move(this.selector, -rightWidth),
+						this.move(this.leftButton, -leftWidth * 2),
+						this.move(this.rightButton, 0)
+					]).then(() => {
+						this.setEmit(-rightWidth, type)
+					})
+					break
+				default:
+					Promise.all([
+						this.move(this.selector, 0),
+						this.move(this.leftButton, -leftWidth),
+						this.move(this.rightButton, rightWidth)
+					]).then(() => {
+						this.setEmit(0, type)
+					})
+
+			}
+		},
+		setEmit(x, type) {
+			const leftWidth = this.button.left.width
+			const rightWidth = this.button.right.width
+			this.isopen = this.isopen || 'none'
+			this.stop = false
+			this.isclick = false
+			// 只有状态不一致才会返回结果
+			if (this.isopen !== type && this.x !== x) {
+				if (type === 'left' && leftWidth > 0) {
+					this.$emit('change', 'left')
+				}
+				if (type === 'right' && rightWidth > 0) {
+					this.$emit('change', 'right')
+				}
+				if (type === 'none') {
+					this.$emit('change', 'none')
+				}
+			}
+			this.x = x
+			this.isopen = type
+		},
+		move(ref, value) {
+			return new Promise((resolve, reject) => {
+				animation.transition(ref, {
+					styles: {
+						transform: `translateX(${value})`,
+					},
+					duration: 150, //ms
+					timingFunction: 'linear',
+					needLayout: false,
+					delay: 0 //ms
+				}, function(res) {
+					resolve(res)
+				})
+			})
+
+		},
+
+		/**
+		 * 获取ref
+		 * @param {Object} el
+		 */
+		getEl(el) {
+			return el.ref
+		},
+		/**
+		 * 获取节点信息
+		 */
+		getSelectorQuery() {
+			Promise.all([
+				this.getDom('left'),
+				this.getDom('right'),
+			]).then((data) => {
+				let show = 'none'
+				if (this.autoClose) {
+					show = 'none'
+				} else {
+					show = this.show
+				}
+
+				if (show === 'none') {
+					// this.close()
+				} else {
+					this.open(show)
+				}
+
+			})
+
+		},
+		getDom(str) {
+			return new Promise((resolve, reject) => {
+				dom.getComponentRect(this.$refs[`selector-${str}-button--hock`], (data) => {
+					if (data) {
+						this.button[str] = data.size
+						resolve(data)
+					} else {
+						reject()
+					}
+				})
+			})
+		}
+	}
+}
+
+// #endif
+
+export default bindIngXMixins

+ 12 - 0
uni_modules/uni-swipe-action/components/uni-swipe-action-item/isPC.js

@@ -0,0 +1,12 @@
+export function isPC() {
+	var userAgentInfo = navigator.userAgent;
+	var Agents = ["Android", "iPhone", "SymbianOS", "Windows Phone", "iPad", "iPod"];
+	var flag = true;
+	for (let v = 0; v < Agents.length - 1; v++) {
+		if (userAgentInfo.indexOf(Agents[v]) > 0) {
+			flag = false;
+			break;
+		}
+	}
+	return flag;
+}

+ 195 - 0
uni_modules/uni-swipe-action/components/uni-swipe-action-item/mpalipay.js

@@ -0,0 +1,195 @@
+export default {
+	data() {
+		return {
+			x: 0,
+			transition: false,
+			width: 0,
+			viewWidth: 0,
+			swipeShow: 0
+		}
+	},
+	watch: {
+		show(newVal) {
+			if (this.autoClose) return
+			if (newVal && newVal !== 'none') {
+				this.transition = true
+				this.open(newVal)
+			} else {
+				this.close()
+			}
+		}
+	},
+	created() {
+		this.swipeaction = this.getSwipeAction()
+		if (this.swipeaction && Array.isArray(this.swipeaction.children)) {
+			this.swipeaction.children.push(this)
+		}
+	},
+	mounted() {
+		this.isopen = false
+		setTimeout(() => {
+			this.getQuerySelect()
+		}, 50)
+	},
+	methods: {
+		appTouchStart(e) {
+			const {
+				clientX
+			} = e.changedTouches[0]
+			this.clientX = clientX
+			this.timestamp = new Date().getTime()
+		},
+		appTouchEnd(e, index, item, position) {
+			const {
+				clientX
+			} = e.changedTouches[0]
+			// fixed by xxxx 模拟点击事件,解决 ios 13 点击区域错位的问题
+			let diff = Math.abs(this.clientX - clientX)
+			let time = (new Date().getTime()) - this.timestamp
+			if (diff < 40 && time < 300) {
+				this.$emit('click', {
+					content: item,
+					index,
+					position
+				})
+			}
+		},
+		/**
+		 * 移动触发
+		 * @param {Object} e
+		 */
+		onChange(e) {
+			this.moveX = e.detail.x
+			this.isclose = false
+		},
+		touchstart(e) {
+			this.transition = false
+			this.isclose = true
+			if (this.autoClose && this.swipeaction) {
+				this.swipeaction.closeOther(this)
+			}
+		},
+		touchmove(e) {},
+		touchend(e) {
+			// 0的位置什么都不执行
+			if (this.isclose && this.isopen === 'none') return
+			if (this.isclose && this.isopen !== 'none') {
+				this.transition = true
+				this.close()
+			} else {
+				this.move(this.moveX + this.leftWidth)
+			}
+		},
+
+		/**
+		 * 移动
+		 * @param {Object} moveX
+		 */
+		move(moveX) {
+			// 打开关闭的处理逻辑不太一样
+			this.transition = true
+			// 未打开状态
+			if (!this.isopen || this.isopen === 'none') {
+				if (moveX > this.threshold) {
+					this.open('left')
+				} else if (moveX < -this.threshold) {
+					this.open('right')
+				} else {
+					this.close()
+				}
+			} else {
+				if (moveX < 0 && moveX < this.rightWidth) {
+					const rightX = this.rightWidth + moveX
+					if (rightX < this.threshold) {
+						this.open('right')
+					} else {
+						this.close()
+					}
+				} else if (moveX > 0 && moveX < this.leftWidth) {
+					const leftX = this.leftWidth - moveX
+					if (leftX < this.threshold) {
+						this.open('left')
+					} else {
+						this.close()
+					}
+				}
+
+			}
+
+		},
+
+		/**
+		 * 打开
+		 */
+		open(type) {
+			this.x = this.moveX
+			this.animation(type)
+		},
+
+		/**
+		 * 关闭
+		 */
+		close() {
+			this.x = this.moveX
+			// TODO 解决 x 值不更新的问题,所以会多触发一次 nextTick ,待优化
+			this.$nextTick(() => {
+				this.x = -this.leftWidth
+				if (this.isopen !== 'none') {
+					this.$emit('change', 'none')
+				}
+				this.isopen = 'none'
+			})
+		},
+
+		/**
+		 * 执行结束动画
+		 * @param {Object} type
+		 */
+		animation(type) {
+			this.$nextTick(() => {
+				if (type === 'left') {
+					this.x = 0
+				} else {
+					this.x = -this.rightWidth - this.leftWidth
+				}
+
+				if (this.isopen !== type) {
+					this.$emit('change', type)
+				}
+				this.isopen = type
+			})
+
+		},
+		getSlide(x) {},
+		getQuerySelect() {
+			const query = uni.createSelectorQuery().in(this);
+			query.selectAll('.movable-view--hock').boundingClientRect(data => {
+				this.leftWidth = data[1].width
+				this.rightWidth = data[2].width
+				this.width = data[0].width
+				this.viewWidth = this.width + this.rightWidth + this.leftWidth
+				if (this.leftWidth === 0) {
+					// TODO 疑似bug ,初始化的时候如果x 是0,会导致移动位置错误,所以让元素超出一点
+					this.x = -0.1
+				} else {
+					this.x = -this.leftWidth
+				}
+				this.moveX = this.x
+				this.$nextTick(() => {
+					this.swipeShow = 1
+				})
+
+				if (!this.buttonWidth) {
+					this.disabledView = true
+				}
+
+				if (this.autoClose) return
+				if (this.show !== 'none') {
+					this.transition = true
+					this.open(this.shows)
+				}
+			}).exec();
+
+		}
+	}
+}

+ 260 - 0
uni_modules/uni-swipe-action/components/uni-swipe-action-item/mpother.js

@@ -0,0 +1,260 @@
+let otherMixins = {}
+
+// #ifndef APP-PLUS|| MP-WEIXIN  ||  H5
+const MIN_DISTANCE = 10;
+otherMixins = {
+	data() {
+		// TODO 随机生生元素ID,解决百度小程序获取同一个元素位置信息的bug
+		const elClass = `Uni_${Math.ceil(Math.random() * 10e5).toString(36)}`
+		return {
+			uniShow: false,
+			left: 0,
+			buttonShow: 'none',
+			ani: false,
+			moveLeft: '',
+			elClass
+		}
+	},
+	watch: {
+		show(newVal) {
+			if (this.autoClose) return
+			this.openState(newVal)
+		},
+		left() {
+			this.moveLeft = `translateX(${this.left}px)`
+		},
+		buttonShow(newVal) {
+			if (this.autoClose) return
+			this.openState(newVal)
+		},
+		leftOptions() {
+			this.init()
+		},
+		rightOptions() {
+			this.init()
+		}
+	},
+	mounted() {
+		this.swipeaction = this.getSwipeAction()
+		if (this.swipeaction && Array.isArray(this.swipeaction.children)) {
+			this.swipeaction.children.push(this)
+		}
+		this.init()
+	},
+	methods: {
+		init() {
+			clearTimeout(this.timer)
+			this.timer = setTimeout(() => {
+				this.getSelectorQuery()
+			}, 100)
+			// 移动距离
+			this.left = 0
+			this.x = 0
+		},
+
+		closeSwipe(e) {
+			if (this.autoClose && this.swipeaction) {
+				this.swipeaction.closeOther(this)
+			}
+		},
+		appTouchStart(e) {
+			const {
+				clientX
+			} = e.changedTouches[0]
+			this.clientX = clientX
+			this.timestamp = new Date().getTime()
+		},
+		appTouchEnd(e, index, item, position) {
+			const {
+				clientX
+			} = e.changedTouches[0]
+			// fixed by xxxx 模拟点击事件,解决 ios 13 点击区域错位的问题
+			let diff = Math.abs(this.clientX - clientX)
+			let time = (new Date().getTime()) - this.timestamp
+			if (diff < 40 && time < 300) {
+				this.$emit('click', {
+					content: item,
+					index,
+					position
+				})
+			}
+		},
+		touchstart(e) {
+			if (this.disabled) return
+			this.ani = false
+			this.x = this.left || 0
+			this.stopTouchStart(e)
+			this.autoClose && this.closeSwipe()
+		},
+		touchmove(e) {
+			if (this.disabled) return
+			// 是否可以滑动页面
+			this.stopTouchMove(e);
+			if (this.direction !== 'horizontal') {
+				return;
+			}
+			this.move(this.x + this.deltaX)
+			return false
+		},
+		touchend() {
+			if (this.disabled) return
+			this.moveDirection(this.left)
+		},
+		/**
+		 * 设置移动距离
+		 * @param {Object} value
+		 */
+		move(value) {
+			value = value || 0
+			const leftWidth = this.leftWidth
+			const rightWidth = this.rightWidth
+			// 获取可滑动范围
+			this.left = this.range(value, -rightWidth, leftWidth);
+		},
+
+		/**
+		 * 获取范围
+		 * @param {Object} num
+		 * @param {Object} min
+		 * @param {Object} max
+		 */
+		range(num, min, max) {
+			return Math.min(Math.max(num, min), max);
+		},
+		/**
+		 * 移动方向判断
+		 * @param {Object} left
+		 * @param {Object} value
+		 */
+		moveDirection(left) {
+			const threshold = this.threshold
+			const isopen = this.isopen || 'none'
+			const leftWidth = this.leftWidth
+			const rightWidth = this.rightWidth
+			if (this.deltaX === 0) {
+				this.openState('none')
+				return
+			}
+			if ((isopen === 'none' && rightWidth > 0 && -left > threshold) || (isopen !== 'none' && rightWidth >
+					0 && rightWidth +
+					left < threshold)) {
+				// right
+				this.openState('right')
+			} else if ((isopen === 'none' && leftWidth > 0 && left > threshold) || (isopen !== 'none' && leftWidth >
+					0 &&
+					leftWidth - left < threshold)) {
+				// left
+				this.openState('left')
+			} else {
+				// default
+				this.openState('none')
+			}
+		},
+
+		/**
+		 * 开启状态
+		 * @param {Boolean} type
+		 */
+		openState(type) {
+			const leftWidth = this.leftWidth
+			const rightWidth = this.rightWidth
+			let left = ''
+			this.isopen = this.isopen ? this.isopen : 'none'
+			switch (type) {
+				case "left":
+					left = leftWidth
+					break
+				case "right":
+					left = -rightWidth
+					break
+				default:
+					left = 0
+			}
+
+
+			if (this.isopen !== type) {
+				this.throttle = true
+				this.$emit('change', type)
+			}
+
+			this.isopen = type
+			// 添加动画类
+			this.ani = true
+			this.$nextTick(() => {
+				this.move(left)
+			})
+			// 设置最终移动位置,理论上只要进入到这个函数,肯定是要打开的
+		},
+		close() {
+			this.openState('none')
+		},
+		getDirection(x, y) {
+			if (x > y && x > MIN_DISTANCE) {
+				return 'horizontal';
+			}
+			if (y > x && y > MIN_DISTANCE) {
+				return 'vertical';
+			}
+			return '';
+		},
+
+		/**
+		 * 重置滑动状态
+		 * @param {Object} event
+		 */
+		resetTouchStatus() {
+			this.direction = '';
+			this.deltaX = 0;
+			this.deltaY = 0;
+			this.offsetX = 0;
+			this.offsetY = 0;
+		},
+
+		/**
+		 * 设置滑动开始位置
+		 * @param {Object} event
+		 */
+		stopTouchStart(event) {
+			this.resetTouchStatus();
+			const touch = event.touches[0];
+			this.startX = touch.clientX;
+			this.startY = touch.clientY;
+		},
+
+		/**
+		 * 滑动中,是否禁止打开
+		 * @param {Object} event
+		 */
+		stopTouchMove(event) {
+			const touch = event.touches[0];
+			this.deltaX = touch.clientX - this.startX;
+			this.deltaY = touch.clientY - this.startY;
+			this.offsetX = Math.abs(this.deltaX);
+			this.offsetY = Math.abs(this.deltaY);
+			this.direction = this.direction || this.getDirection(this.offsetX, this.offsetY);
+		},
+
+		getSelectorQuery() {
+			const views = uni.createSelectorQuery().in(this)
+			views
+				.selectAll('.' + this.elClass)
+				.boundingClientRect(data => {
+					if (data.length === 0) return
+					let show = 'none'
+					if (this.autoClose) {
+						show = 'none'
+					} else {
+						show = this.show
+					}
+					this.leftWidth = data[0].width || 0
+					this.rightWidth = data[1].width || 0
+					this.buttonShow = show
+				})
+				.exec()
+		}
+	}
+}
+
+// #endif
+
+export default otherMixins

+ 84 - 0
uni_modules/uni-swipe-action/components/uni-swipe-action-item/mpwxs.js

@@ -0,0 +1,84 @@
+let mpMixins = {}
+let is_pc = null
+// #ifdef H5
+import {
+	isPC
+} from "./isPC"
+is_pc = isPC()
+// #endif
+// #ifdef APP-VUE|| MP-WEIXIN || H5
+
+mpMixins = {
+	data() {
+		return {
+			is_show: 'none'
+		}
+	},
+	watch: {
+		show(newVal) {
+			this.is_show = this.show
+		}
+	},
+	created() {
+		this.swipeaction = this.getSwipeAction()
+		if (this.swipeaction && Array.isArray(this.swipeaction.children)) {
+			this.swipeaction.children.push(this)
+		}
+	},
+	mounted() {
+		this.is_show = this.show
+	},
+	methods: {
+		// wxs 中调用
+		closeSwipe(e) {
+			if (this.autoClose && this.swipeaction) {
+				this.swipeaction.closeOther(this)
+			}
+		},
+
+		change(e) {
+			this.$emit('change', e.open)
+			if (this.is_show !== e.open) {
+				this.is_show = e.open
+			}
+		},
+
+		appTouchStart(e) {
+			if (is_pc) return
+			const {
+				clientX
+			} = e.changedTouches[0]
+			this.clientX = clientX
+			this.timestamp = new Date().getTime()
+		},
+		appTouchEnd(e, index, item, position) {
+			if (is_pc) return
+			const {
+				clientX
+			} = e.changedTouches[0]
+			// fixed by xxxx 模拟点击事件,解决 ios 13 点击区域错位的问题
+			let diff = Math.abs(this.clientX - clientX)
+			let time = (new Date().getTime()) - this.timestamp
+			if (diff < 40 && time < 300) {
+				this.$emit('click', {
+					content: item,
+					index,
+					position
+				})
+			}
+		},
+		onClickForPC(index, item, position) {
+			if (!is_pc) return
+			// #ifdef H5
+			this.$emit('click', {
+				content: item,
+				index,
+				position
+			})
+			// #endif
+		}
+	}
+}
+
+// #endif
+export default mpMixins

+ 270 - 0
uni_modules/uni-swipe-action/components/uni-swipe-action-item/render.js

@@ -0,0 +1,270 @@
+const MIN_DISTANCE = 10;
+export default {
+	showWatch(newVal, oldVal, ownerInstance, instance, self) {
+		var state = self.state
+		var $el = ownerInstance.$el || ownerInstance.$vm && ownerInstance.$vm.$el
+		if (!$el) return
+		this.getDom(instance, ownerInstance, self)
+		if (newVal && newVal !== 'none') {
+			this.openState(newVal, instance, ownerInstance, self)
+			return
+		}
+
+		if (state.left) {
+			this.openState('none', instance, ownerInstance, self)
+		}
+		this.resetTouchStatus(instance, self)
+	},
+
+	/**
+	 * 开始触摸操作
+	 * @param {Object} e
+	 * @param {Object} ins
+	 */
+	touchstart(e, ownerInstance, self) {
+		let instance = e.instance;
+		let disabled = instance.getDataset().disabled
+		let state = self.state;
+		this.getDom(instance, ownerInstance, self)
+		// fix by mehaotian, TODO 兼容 app-vue 获取dataset为字符串 , h5 获取 为 undefined 的问题,待框架修复
+		disabled = this.getDisabledType(disabled)
+		if (disabled) return
+		// 开始触摸时移除动画类
+		instance.requestAnimationFrame(function() {
+			instance.removeClass('ani');
+			ownerInstance.callMethod('closeSwipe');
+		})
+
+		// 记录上次的位置
+		state.x = state.left || 0
+		// 计算滑动开始位置
+		this.stopTouchStart(e, ownerInstance, self)
+	},
+
+	/**
+	 * 开始滑动操作
+	 * @param {Object} e
+	 * @param {Object} ownerInstance
+	 */
+	touchmove(e, ownerInstance, self) {
+		let instance = e.instance;
+		// 删除之后已经那不到实例了
+		if (!instance) return;
+		let disabled = instance.getDataset().disabled
+		let state = self.state
+		// fix by mehaotian, TODO 兼容 app-vue 获取dataset为字符串 , h5 获取 为 undefined 的问题,待框架修复
+		disabled = this.getDisabledType(disabled)
+		if (disabled) return
+		// 是否可以滑动页面
+		this.stopTouchMove(e, self);
+		if (state.direction !== 'horizontal') {
+			return;
+		}
+		if (e.preventDefault) {
+			// 阻止页面滚动
+			e.preventDefault()
+		}
+		let x = state.x + state.deltaX
+		this.move(x, instance, ownerInstance, self)
+	},
+
+	/**
+	 * 结束触摸操作
+	 * @param {Object} e
+	 * @param {Object} ownerInstance
+	 */
+	touchend(e, ownerInstance, self) {
+		let instance = e.instance;
+		let disabled = instance.getDataset().disabled
+		let state = self.state
+		// fix by mehaotian, TODO 兼容 app-vue 获取dataset为字符串 , h5 获取 为 undefined 的问题,待框架修复
+		disabled = this.getDisabledType(disabled)
+
+		if (disabled) return
+		// 滑动过程中触摸结束,通过阙值判断是开启还是关闭
+		// fixed by mehaotian 定时器解决点击按钮,touchend 触发比 click 事件时机早的问题 ,主要是 ios13
+		this.moveDirection(state.left, instance, ownerInstance, self)
+
+	},
+
+	/**
+	 * 设置移动距离
+	 * @param {Object} value
+	 * @param {Object} instance
+	 * @param {Object} ownerInstance
+	 */
+	move(value, instance, ownerInstance, self) {
+		value = value || 0
+		let state = self.state
+		let leftWidth = state.leftWidth
+		let rightWidth = state.rightWidth
+		// 获取可滑动范围
+		state.left = this.range(value, -rightWidth, leftWidth);
+		instance.requestAnimationFrame(function() {
+			instance.setStyle({
+				transform: 'translateX(' + state.left + 'px)',
+				'-webkit-transform': 'translateX(' + state.left + 'px)'
+			})
+		})
+
+	},
+
+	/**
+	 * 获取元素信息
+	 * @param {Object} instance
+	 * @param {Object} ownerInstance
+	 */
+	getDom(instance, ownerInstance, self) {
+		var state = self.state
+		var $el = ownerInstance.$el || ownerInstance.$vm && ownerInstance.$vm.$el
+		var leftDom = $el.querySelector('.button-group--left')
+		var rightDom = $el.querySelector('.button-group--right')
+
+		state.leftWidth = leftDom.offsetWidth || 0
+		state.rightWidth = rightDom.offsetWidth || 0
+		state.threshold = instance.getDataset().threshold
+	},
+
+	getDisabledType(value) {
+		return (typeof(value) === 'string' ? JSON.parse(value) : value) || false;
+	},
+
+	/**
+	 * 获取范围
+	 * @param {Object} num
+	 * @param {Object} min
+	 * @param {Object} max
+	 */
+	range(num, min, max) {
+		return Math.min(Math.max(num, min), max);
+	},
+
+
+	/**
+	 * 移动方向判断
+	 * @param {Object} left
+	 * @param {Object} value
+	 * @param {Object} ownerInstance
+	 * @param {Object} ins
+	 */
+	moveDirection(left, ins, ownerInstance, self) {
+		var state = self.state
+		var threshold = state.threshold
+		var position = state.position
+		var isopen = state.isopen || 'none'
+		var leftWidth = state.leftWidth
+		var rightWidth = state.rightWidth
+		if (state.deltaX === 0) {
+			this.openState('none', ins, ownerInstance, self)
+			return
+		}
+		if ((isopen === 'none' && rightWidth > 0 && -left > threshold) || (isopen !== 'none' && rightWidth > 0 &&
+				rightWidth +
+				left < threshold)) {
+			// right
+			this.openState('right', ins, ownerInstance, self)
+		} else if ((isopen === 'none' && leftWidth > 0 && left > threshold) || (isopen !== 'none' && leftWidth > 0 &&
+				leftWidth - left < threshold)) {
+			// left
+			this.openState('left', ins, ownerInstance, self)
+		} else {
+			// default
+			this.openState('none', ins, ownerInstance, self)
+		}
+	},
+
+
+	/**
+	 * 开启状态
+	 * @param {Boolean} type
+	 * @param {Object} ins
+	 * @param {Object} ownerInstance
+	 */
+	openState(type, ins, ownerInstance, self) {
+		let state = self.state
+		let leftWidth = state.leftWidth
+		let rightWidth = state.rightWidth
+		let left = ''
+		state.isopen = state.isopen ? state.isopen : 'none'
+		switch (type) {
+			case "left":
+				left = leftWidth
+				break
+			case "right":
+				left = -rightWidth
+				break
+			default:
+				left = 0
+		}
+
+		// && !state.throttle
+
+		if (state.isopen !== type) {
+			state.throttle = true
+			ownerInstance.callMethod('change', {
+				open: type
+			})
+
+		}
+
+		state.isopen = type
+		// 添加动画类
+		ins.requestAnimationFrame(() => {
+			ins.addClass('ani');
+			this.move(left, ins, ownerInstance, self)
+		})
+	},
+
+
+	getDirection(x, y) {
+		if (x > y && x > MIN_DISTANCE) {
+			return 'horizontal';
+		}
+		if (y > x && y > MIN_DISTANCE) {
+			return 'vertical';
+		}
+		return '';
+	},
+
+	/**
+	 * 重置滑动状态
+	 * @param {Object} event
+	 */
+	resetTouchStatus(instance, self) {
+		let state = self.state;
+		state.direction = '';
+		state.deltaX = 0;
+		state.deltaY = 0;
+		state.offsetX = 0;
+		state.offsetY = 0;
+	},
+
+	/**
+	 * 设置滑动开始位置
+	 * @param {Object} event
+	 */
+	stopTouchStart(event, ownerInstance, self) {
+		let instance = event.instance;
+		let state = self.state
+		this.resetTouchStatus(instance, self);
+		var touch = event.touches[0];
+		state.startX = touch.clientX;
+		state.startY = touch.clientY;
+	},
+
+	/**
+	 * 滑动中,是否禁止打开
+	 * @param {Object} event
+	 */
+	stopTouchMove(event, self) {
+		let instance = event.instance;
+		let state = self.state;
+		let touch = event.touches[0];
+
+		state.deltaX = touch.clientX - state.startX;
+		state.deltaY = touch.clientY - state.startY;
+		state.offsetY = Math.abs(state.deltaY);
+		state.offsetX = Math.abs(state.deltaX);
+		state.direction = state.direction || this.getDirection(state.offsetX, state.offsetY);
+	}
+}

+ 348 - 0
uni_modules/uni-swipe-action/components/uni-swipe-action-item/uni-swipe-action-item.vue

@@ -0,0 +1,348 @@
+<template>
+	<!-- 在微信小程序 app vue端 h5 使用wxs 实现-->
+	<!-- #ifdef APP-VUE || MP-WEIXIN || H5 -->
+	<view class="uni-swipe">
+		<!--  #ifdef MP-WEIXIN || VUE3 -->
+		<view class="uni-swipe_box" :change:prop="wxsswipe.showWatch" :prop="is_show" :data-threshold="threshold"
+			:data-disabled="disabled" @touchstart="wxsswipe.touchstart" @touchmove="wxsswipe.touchmove"
+			@touchend="wxsswipe.touchend">
+		<!-- #endif -->
+			<!--  #ifndef MP-WEIXIN || VUE3 -->
+			<view class="uni-swipe_box" :change:prop="renderswipe.showWatch" :prop="is_show" :data-threshold="threshold"
+				:data-disabled="disabled+''" @touchstart="renderswipe.touchstart" @touchmove="renderswipe.touchmove"
+				@touchend="renderswipe.touchend">
+			<!-- #endif -->
+				<!-- 在微信小程序 app vue端 h5 使用wxs 实现-->
+				<view class="uni-swipe_button-group button-group--left">
+					<slot name="left">
+						<view v-for="(item,index) in leftOptions" :key="index" :style="{
+					  backgroundColor: item.style && item.style.backgroundColor ? item.style.backgroundColor : '#C7C6CD'
+					}" class="uni-swipe_button button-hock" @touchstart.stop="appTouchStart"
+							@touchend.stop="appTouchEnd($event,index,item,'left')" @click.stop="onClickForPC(index,item,'left')">
+							<text class="uni-swipe_button-text"
+								:style="{color: item.style && item.style.color ? item.style.color : '#FFFFFF',fontSize: item.style && item.style.fontSize ? item.style.fontSize : '16px'}">{{ item.text }}</text>
+						</view>
+					</slot>
+				</view>
+				<view class="uni-swipe_text--center">
+					<slot></slot>
+				</view>
+				<view class="uni-swipe_button-group button-group--right">
+					<slot name="right">
+						<view v-for="(item,index) in rightOptions" :key="index" :style="{
+					  backgroundColor: item.style && item.style.backgroundColor ? item.style.backgroundColor : '#C7C6CD'
+					}" class="uni-swipe_button button-hock" @touchstart.stop="appTouchStart"
+							@touchend.stop="appTouchEnd($event,index,item,'right')" @click.stop="onClickForPC(index,item,'right')"><text
+								class="uni-swipe_button-text"
+								:style="{color: item.style && item.style.color ? item.style.color : '#FFFFFF',fontSize: item.style && item.style.fontSize ? item.style.fontSize : '16px'}">{{ item.text }}</text>
+						</view>
+					</slot>
+				</view>
+			</view>
+		</view>
+		<!-- #endif -->
+		<!-- app nvue端 使用 bindingx -->
+		<!-- #ifdef APP-NVUE -->
+		<view ref="selector-box--hock" class="uni-swipe" @horizontalpan="touchstart" @touchend="touchend">
+			<view ref='selector-left-button--hock' class="uni-swipe_button-group button-group--left">
+				<slot name="left">
+					<view v-for="(item,index) in leftOptions" :key="index" :style="{
+				  backgroundColor: item.style && item.style.backgroundColor ? item.style.backgroundColor : '#C7C6CD'
+				}" class="uni-swipe_button button-hock" @click.stop="onClick(index,item,'left')">
+						<text class="uni-swipe_button-text"
+							:style="{color: item.style && item.style.color ? item.style.color : '#FFFFFF', fontSize: item.style && item.style.fontSize ? item.style.fontSize : '16px'}">
+							{{ item.text }}
+						</text>
+					</view>
+				</slot>
+			</view>
+			<view ref='selector-right-button--hock' class="uni-swipe_button-group button-group--right">
+				<slot name="right">
+					<view v-for="(item,index) in rightOptions" :key="index" :style="{
+				  backgroundColor: item.style && item.style.backgroundColor ? item.style.backgroundColor : '#C7C6CD'
+				}" class="uni-swipe_button button-hock" @click.stop="onClick(index,item,'right')"><text
+							class="uni-swipe_button-text"
+							:style="{color: item.style && item.style.color ? item.style.color : '#FFFFFF',fontSize: item.style && item.style.fontSize ? item.style.fontSize : '16px'}">{{ item.text }}</text>
+					</view>
+				</slot>
+			</view>
+			<view ref='selector-content--hock' class="uni-swipe_box">
+				<slot></slot>
+			</view>
+		</view>
+		<!-- #endif -->
+		<!-- 其他平台使用 js ,长列表性能可能会有影响-->
+		<!-- #ifdef MP-ALIPAY || MP-BAIDU || MP-TOUTIAO || MP-QQ -->
+		<view class="uni-swipe">
+			<view class="uni-swipe_box" @touchstart="touchstart" @touchmove="touchmove" @touchend="touchend"
+				:style="{transform:moveLeft}" :class="{ani:ani}">
+				<view class="uni-swipe_button-group button-group--left" :class="[elClass]">
+					<slot name="left">
+						<view v-for="(item,index) in leftOptions" :key="index" :style="{
+					  backgroundColor: item.style && item.style.backgroundColor ? item.style.backgroundColor : '#C7C6CD',
+					  fontSize: item.style && item.style.fontSize ? item.style.fontSize : '16px'
+					}" class="uni-swipe_button button-hock" @touchstart.stop="appTouchStart"
+							@touchend.stop="appTouchEnd($event,index,item,'left')"><text class="uni-swipe_button-text"
+								:style="{color: item.style && item.style.color ? item.style.color : '#FFFFFF',}">{{ item.text }}</text>
+						</view>
+					</slot>
+				</view>
+				<slot></slot>
+				<view class="uni-swipe_button-group button-group--right" :class="[elClass]">
+					<slot name="right">
+						<view v-for="(item,index) in rightOptions" :key="index" :style="{
+					  backgroundColor: item.style && item.style.backgroundColor ? item.style.backgroundColor : '#C7C6CD',
+					  fontSize: item.style && item.style.fontSize ? item.style.fontSize : '16px'
+					}" @touchstart.stop="appTouchStart" @touchend.stop="appTouchEnd($event,index,item,'right')"
+							class="uni-swipe_button button-hock"><text class="uni-swipe_button-text"
+								:style="{color: item.style && item.style.color ? item.style.color : '#FFFFFF',}">{{ item.text }}</text>
+						</view>
+					</slot>
+				</view>
+			</view>
+		</view>
+		<!-- #endif -->
+
+</template>
+<script src="./wx.wxs" module="wxsswipe" lang="wxs"></script>
+
+<script module="renderswipe" lang="renderjs">
+	import render from './render.js'
+	export default {
+		mounted(e, ins, owner) {
+			this.state = {}
+		},
+		methods: {
+			showWatch(newVal, oldVal, ownerInstance, instance) {
+				render.showWatch(newVal, oldVal, ownerInstance, instance, this)
+			},
+			touchstart(e, ownerInstance) {
+				render.touchstart(e, ownerInstance, this)
+			},
+			touchmove(e, ownerInstance) {
+				render.touchmove(e, ownerInstance, this)
+			},
+			touchend(e, ownerInstance) {
+				render.touchend(e, ownerInstance, this)
+			}
+		}
+	}
+</script>
+<script>
+	import mpwxs from './mpwxs'
+	import bindingx from './bindingx.js'
+	import mpother from './mpother'
+
+	/**
+	 * SwipeActionItem 滑动操作子组件
+	 * @description 通过滑动触发选项的容器
+	 * @tutorial https://ext.dcloud.net.cn/plugin?id=181
+	 * @property {Boolean} show = [left|right|none] 	开启关闭组件,auto-close = false 时生效
+	 * @property {Boolean} disabled = [true|false] 		是否禁止滑动
+	 * @property {Boolean} autoClose = [true|false] 	滑动打开当前组件,是否关闭其他组件
+	 * @property {Number}  threshold 					滑动缺省值
+	 * @property {Array} leftOptions 					左侧选项内容及样式
+	 * @property {Array} rgihtOptions 					右侧选项内容及样式
+	 * @event {Function} click 							点击选项按钮时触发事件,e = {content,index} ,content(点击内容)、index(下标)
+	 * @event {Function} change 						组件打开或关闭时触发,left\right\none
+	 */
+
+	export default {
+		mixins: [mpwxs, bindingx, mpother],
+		emits: ['click', 'change'],
+		props: {
+			// 控制开关
+			show: {
+				type: String,
+				default: 'none'
+			},
+
+			// 禁用
+			disabled: {
+				type: Boolean,
+				default: false
+			},
+
+			// 是否自动关闭
+			autoClose: {
+				type: Boolean,
+				default: true
+			},
+
+			// 滑动缺省距离
+			threshold: {
+				type: Number,
+				default: 20
+			},
+
+			// 左侧按钮内容
+			leftOptions: {
+				type: Array,
+				default () {
+					return []
+				}
+			},
+
+			// 右侧按钮内容
+			rightOptions: {
+				type: Array,
+				default () {
+					return []
+				}
+			}
+
+		},
+		// #ifndef VUE3
+		// TODO vue2
+		destroyed() {
+			if (this.__isUnmounted) return
+			this.uninstall()
+		},
+		// #endif
+		// #ifdef VUE3
+		// TODO vue3
+		unmounted() {
+			this.__isUnmounted = true
+			this.uninstall()
+		},
+		// #endif
+
+		methods: {
+			uninstall() {
+				if (this.swipeaction) {
+					this.swipeaction.children.forEach((item, index) => {
+						if (item === this) {
+							this.swipeaction.children.splice(index, 1)
+						}
+					})
+				}
+			},
+			/**
+			 * 获取父元素实例
+			 */
+			getSwipeAction(name = 'uniSwipeAction') {
+				let parent = this.$parent;
+				let parentName = parent.$options.name;
+				while (parentName !== name) {
+					parent = parent.$parent;
+					if (!parent) return false;
+					parentName = parent.$options.name;
+				}
+				return parent;
+			}
+		}
+	}
+</script>
+<style lang="scss">
+	.uni-swipe {
+		position: relative;
+		/* #ifndef APP-NVUE */
+		overflow: hidden;
+		/* #endif */
+	}
+
+	.uni-swipe_box {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		flex-shrink: 0;
+		// touch-action: none;
+		/* #endif */
+		position: relative;
+	}
+
+	.uni-swipe_content {
+		// border: 1px red solid;
+	}
+
+	.uni-swipe_text--center {
+		width: 100%;
+		/* #ifndef APP-NVUE */
+		cursor: grab;
+		/* #endif */
+	}
+
+	.uni-swipe_button-group {
+		/* #ifndef APP-NVUE */
+		box-sizing: border-box;
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		position: absolute;
+		top: 0;
+		bottom: 0;
+		/* #ifdef H5 */
+		cursor: pointer;
+		/* #endif */
+	}
+
+	.button-group--left {
+		left: 0;
+		transform: translateX(-100%)
+	}
+
+	.button-group--right {
+		right: 0;
+		transform: translateX(100%)
+	}
+
+	.uni-swipe_button {
+		/* #ifdef APP-NVUE */
+		flex: 1;
+		/* #endif */
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		justify-content: center;
+		align-items: center;
+		padding: 0 20px;
+	}
+
+	.uni-swipe_button-text {
+		/* #ifndef APP-NVUE */
+		flex-shrink: 0;
+		/* #endif */
+		font-size: 14px;
+	}
+
+	.ani {
+		transition-property: transform;
+		transition-duration: 0.3s;
+		transition-timing-function: cubic-bezier(0.165, 0.84, 0.44, 1);
+	}
+
+	/* #ifdef MP-ALIPAY */
+	.movable-area {
+		/* width: 100%; */
+		height: 45px;
+	}
+
+	.movable-view {
+		display: flex;
+		/* justify-content: center; */
+		position: relative;
+		flex: 1;
+		height: 45px;
+		z-index: 2;
+	}
+
+	.movable-view-button {
+		display: flex;
+		flex-shrink: 0;
+		flex-direction: row;
+		height: 100%;
+		background: #C0C0C0;
+	}
+
+	/* .transition {
+		transition: all 0.3s;
+	} */
+
+	.movable-view-box {
+		flex-shrink: 0;
+		height: 100%;
+		background-color: #fff;
+	}
+
+	/* #endif */
+</style>

+ 341 - 0
uni_modules/uni-swipe-action/components/uni-swipe-action-item/wx.wxs

@@ -0,0 +1,341 @@
+var MIN_DISTANCE = 10;
+
+/**
+ * 判断当前是否为H5、app-vue
+ */
+var IS_HTML5 = false
+if (typeof window === 'object') IS_HTML5 = true
+
+/**
+ * 监听页面内值的变化,主要用于动态开关swipe-action
+ * @param {Object} newValue
+ * @param {Object} oldValue
+ * @param {Object} ownerInstance
+ * @param {Object} instance
+ */
+function showWatch(newVal, oldVal, ownerInstance, instance) {
+	var state = instance.getState()
+	getDom(instance, ownerInstance)
+	if (newVal && newVal !== 'none') {
+		openState(newVal, instance, ownerInstance)
+		return
+	}
+
+	if (state.left) {
+		openState('none', instance, ownerInstance)
+	}
+	resetTouchStatus(instance)
+}
+
+/**
+ * 开始触摸操作
+ * @param {Object} e
+ * @param {Object} ins
+ */
+function touchstart(e, ownerInstance) {
+	var instance = e.instance;
+	var disabled = instance.getDataset().disabled
+	var state = instance.getState();
+	getDom(instance, ownerInstance)
+	// fix by mehaotian, TODO 兼容 app-vue 获取dataset为字符串 , h5 获取 为 undefined 的问题,待框架修复
+	disabled = (typeof(disabled) === 'string' ? JSON.parse(disabled) : disabled) || false;
+	if (disabled) return
+	// 开始触摸时移除动画类
+	instance.requestAnimationFrame(function() {
+		instance.removeClass('ani');
+		ownerInstance.callMethod('closeSwipe');
+	})
+
+	// 记录上次的位置
+	state.x = state.left || 0
+	// 计算滑动开始位置
+	stopTouchStart(e, ownerInstance)
+}
+
+/**
+ * 开始滑动操作
+ * @param {Object} e
+ * @param {Object} ownerInstance
+ */
+function touchmove(e, ownerInstance) {
+	var instance = e.instance;
+	var disabled = instance.getDataset().disabled
+	var state = instance.getState()
+	// fix by mehaotian, TODO 兼容 app-vue 获取dataset为字符串 , h5 获取 为 undefined 的问题,待框架修复
+	disabled = (typeof(disabled) === 'string' ? JSON.parse(disabled) : disabled) || false;
+	if (disabled) return
+	// 是否可以滑动页面
+	stopTouchMove(e);
+	if (state.direction !== 'horizontal') {
+		return;
+	}
+
+	if (e.preventDefault) {
+		// 阻止页面滚动
+		e.preventDefault()
+	}
+
+	move(state.x + state.deltaX, instance, ownerInstance)
+}
+
+/**
+ * 结束触摸操作
+ * @param {Object} e
+ * @param {Object} ownerInstance
+ */
+function touchend(e, ownerInstance) {
+	var instance = e.instance;
+	var disabled = instance.getDataset().disabled
+	var state = instance.getState()
+	// fix by mehaotian, TODO 兼容 app-vue 获取dataset为字符串 , h5 获取 为 undefined 的问题,待框架修复
+	disabled = (typeof(disabled) === 'string' ? JSON.parse(disabled) : disabled) || false;
+
+	if (disabled) return
+	// 滑动过程中触摸结束,通过阙值判断是开启还是关闭
+	// fixed by mehaotian 定时器解决点击按钮,touchend 触发比 click 事件时机早的问题 ,主要是 ios13
+	moveDirection(state.left, instance, ownerInstance)
+
+}
+
+/**
+ * 设置移动距离
+ * @param {Object} value
+ * @param {Object} instance
+ * @param {Object} ownerInstance
+ */
+function move(value, instance, ownerInstance) {
+	value = value || 0
+	var state = instance.getState()
+	var leftWidth = state.leftWidth
+	var rightWidth = state.rightWidth
+	// 获取可滑动范围
+	state.left = range(value, -rightWidth, leftWidth);
+	instance.requestAnimationFrame(function() {
+		instance.setStyle({
+			transform: 'translateX(' + state.left + 'px)',
+			'-webkit-transform': 'translateX(' + state.left + 'px)'
+		})
+	})
+
+}
+
+/**
+ * 获取元素信息
+ * @param {Object} instance
+ * @param {Object} ownerInstance
+ */
+function getDom(instance, ownerInstance) {
+	var state = instance.getState()
+	var leftDom = ownerInstance.selectComponent('.button-group--left')
+	var rightDom = ownerInstance.selectComponent('.button-group--right')
+	var leftStyles = {
+		width: 0
+	}
+	var rightStyles = {
+		width: 0
+	}
+	leftStyles = leftDom.getBoundingClientRect()
+	rightStyles = rightDom.getBoundingClientRect()
+
+	state.leftWidth = leftStyles.width || 0
+	state.rightWidth = rightStyles.width || 0
+	state.threshold = instance.getDataset().threshold
+}
+
+/**
+ * 获取范围
+ * @param {Object} num
+ * @param {Object} min
+ * @param {Object} max
+ */
+function range(num, min, max) {
+	return Math.min(Math.max(num, min), max);
+}
+
+
+/**
+ * 移动方向判断
+ * @param {Object} left
+ * @param {Object} value
+ * @param {Object} ownerInstance
+ * @param {Object} ins
+ */
+function moveDirection(left, ins, ownerInstance) {
+	var state = ins.getState()
+	var threshold = state.threshold
+	var position = state.position
+	var isopen = state.isopen || 'none'
+	var leftWidth = state.leftWidth
+	var rightWidth = state.rightWidth
+	if (state.deltaX === 0) {
+		openState('none', ins, ownerInstance)
+		return
+	}
+	if ((isopen === 'none' && rightWidth > 0 && -left > threshold) || (isopen !== 'none' && rightWidth > 0 &&
+			rightWidth +
+			left < threshold)) {
+		// right
+		openState('right', ins, ownerInstance)
+	} else if ((isopen === 'none' && leftWidth > 0 && left > threshold) || (isopen !== 'none' && leftWidth > 0 &&
+			leftWidth - left < threshold)) {
+		// left
+		openState('left', ins, ownerInstance)
+	} else {
+		// default
+		openState('none', ins, ownerInstance)
+	}
+}
+
+
+/**
+ * 开启状态
+ * @param {Boolean} type
+ * @param {Object} ins
+ * @param {Object} ownerInstance
+ */
+function openState(type, ins, ownerInstance) {
+	var state = ins.getState()
+	var leftWidth = state.leftWidth
+	var rightWidth = state.rightWidth
+	var left = ''
+	state.isopen = state.isopen ? state.isopen : 'none'
+	switch (type) {
+		case "left":
+			left = leftWidth
+			break
+		case "right":
+			left = -rightWidth
+			break
+		default:
+			left = 0
+	}
+
+	// && !state.throttle
+
+	if (state.isopen !== type) {
+		state.throttle = true
+		ownerInstance.callMethod('change', {
+			open: type
+		})
+
+	}
+
+	state.isopen = type
+	// 添加动画类
+	ins.requestAnimationFrame(function() {
+		ins.addClass('ani');
+		move(left, ins, ownerInstance)
+	})
+	// 设置最终移动位置,理论上只要进入到这个函数,肯定是要打开的
+}
+
+
+function getDirection(x, y) {
+	if (x > y && x > MIN_DISTANCE) {
+		return 'horizontal';
+	}
+	if (y > x && y > MIN_DISTANCE) {
+		return 'vertical';
+	}
+	return '';
+}
+
+/**
+ * 重置滑动状态
+ * @param {Object} event
+ */
+function resetTouchStatus(instance) {
+	var state = instance.getState();
+	state.direction = '';
+	state.deltaX = 0;
+	state.deltaY = 0;
+	state.offsetX = 0;
+	state.offsetY = 0;
+}
+
+/**
+ * 设置滑动开始位置
+ * @param {Object} event
+ */
+function stopTouchStart(event) {
+	var instance = event.instance;
+	var state = instance.getState();
+	resetTouchStatus(instance);
+	var touch = event.touches[0];
+	if (IS_HTML5 && isPC()) {
+		touch = event;
+	}
+	state.startX = touch.clientX;
+	state.startY = touch.clientY;
+}
+
+/**
+ * 滑动中,是否禁止打开
+ * @param {Object} event
+ */
+function stopTouchMove(event) {
+	var instance = event.instance;
+	var state = instance.getState();
+	var touch = event.touches[0];
+	if (IS_HTML5 && isPC()) {
+		touch = event;
+	}
+	state.deltaX = touch.clientX - state.startX;
+	state.deltaY = touch.clientY - state.startY;
+	state.offsetY = Math.abs(state.deltaY);
+	state.offsetX = Math.abs(state.deltaX);
+	state.direction = state.direction || getDirection(state.offsetX, state.offsetY);
+}
+
+function isPC() {
+	var userAgentInfo = navigator.userAgent;
+	var Agents = ["Android", "iPhone", "SymbianOS", "Windows Phone", "iPad", "iPod"];
+	var flag = true;
+	for (var v = 0; v < Agents.length - 1; v++) {
+		if (userAgentInfo.indexOf(Agents[v]) > 0) {
+			flag = false;
+			break;
+		}
+	}
+	return flag;
+}
+
+var movable = false
+
+function mousedown(e, ins) {
+	if (!IS_HTML5) return
+	if (!isPC()) return
+	touchstart(e, ins)
+	movable = true
+}
+
+function mousemove(e, ins) {
+	if (!IS_HTML5) return
+	if (!isPC()) return
+	if (!movable) return
+	touchmove(e, ins)
+}
+
+function mouseup(e, ins) {
+	if (!IS_HTML5) return
+	if (!isPC()) return
+	touchend(e, ins)
+	movable = false
+}
+
+function mouseleave(e, ins) {
+	if (!IS_HTML5) return
+	if (!isPC()) return
+	movable = false
+}
+
+module.exports = {
+	showWatch: showWatch,
+	touchstart: touchstart,
+	touchmove: touchmove,
+	touchend: touchend,
+	mousedown: mousedown,
+	mousemove: mousemove,
+	mouseup: mouseup,
+	mouseleave: mouseleave
+}

+ 60 - 0
uni_modules/uni-swipe-action/components/uni-swipe-action/uni-swipe-action.vue

@@ -0,0 +1,60 @@
+<template>
+	<view>
+		<slot></slot>
+	</view>
+</template>
+
+<script>
+	/**
+	 * SwipeAction 滑动操作
+	 * @description 通过滑动触发选项的容器
+	 * @tutorial https://ext.dcloud.net.cn/plugin?id=181
+	 */
+	export default {
+		name:"uniSwipeAction",
+		data() {
+			return {};
+		},
+		created() {
+			this.children = [];
+		},
+		methods: {
+			// 公开给用户使用,重制组件样式
+			resize(){
+				// wxs 会自己计算组件大小,所以无需执行下面代码
+				// #ifndef APP-VUE || H5 || MP-WEIXIN
+				this.children.forEach(vm=>{
+					vm.init()
+				})
+				// #endif
+			},
+			// 公开给用户使用,关闭全部 已经打开的组件
+			closeAll(){
+				this.children.forEach(vm=>{
+					// #ifdef APP-VUE || H5 || MP-WEIXIN
+					vm.is_show = 'none'
+					// #endif
+
+					// #ifndef APP-VUE || H5 || MP-WEIXIN
+					vm.close()
+					// #endif
+				})
+			},
+			closeOther(vm) {
+				if (this.openItem && this.openItem !== vm) {
+					// #ifdef APP-VUE || H5 || MP-WEIXIN
+					this.openItem.is_show = 'none'
+					// #endif
+
+					// #ifndef APP-VUE || H5 || MP-WEIXIN
+					this.openItem.close()
+					// #endif
+				}
+				// 记录上一个打开的 swipe-action-item ,用于 auto-close
+				this.openItem = vm
+			}
+		}
+	};
+</script>
+
+<style></style>

+ 84 - 0
uni_modules/uni-swipe-action/package.json

@@ -0,0 +1,84 @@
+{
+	"id": "uni-swipe-action",
+	"displayName": "uni-swipe-action 滑动操作",
+	"version": "1.3.10",
+	"description": "SwipeAction 滑动操作操作组件",
+	"keywords": [
+        "",
+        "uni-ui",
+        "uniui",
+        "滑动删除",
+        "侧滑删除"
+    ],
+	"repository": "https://github.com/dcloudio/uni-ui",
+	"engines": {
+		"HBuilderX": ""
+	},
+	"directories": {
+		"example": "../../temps/example_temps"
+	},
+    "dcloudext": {
+        "sale": {
+			"regular": {
+				"price": "0.00"
+			},
+			"sourcecode": {
+				"price": "0.00"
+			}
+		},
+		"contact": {
+			"qq": ""
+		},
+		"declaration": {
+			"ads": "无",
+			"data": "无",
+			"permissions": "无"
+		},
+        "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
+        "type": "component-vue"
+	},
+	"uni_modules": {
+		"dependencies": ["uni-scss"],
+		"encrypt": [],
+		"platforms": {
+			"cloud": {
+				"tcb": "y",
+				"aliyun": "y"
+			},
+			"client": {
+				"App": {
+					"app-vue": "y",
+					"app-nvue": "y"
+				},
+				"H5-mobile": {
+					"Safari": "y",
+					"Android Browser": "y",
+					"微信浏览器(Android)": "y",
+					"QQ浏览器(Android)": "y"
+				},
+				"H5-pc": {
+					"Chrome": "y",
+					"IE": "y",
+					"Edge": "y",
+					"Firefox": "y",
+					"Safari": "y"
+				},
+				"小程序": {
+					"微信": "y",
+					"阿里": "y",
+					"百度": "y",
+					"字节跳动": "y",
+					"QQ": "y"
+				},
+				"快应用": {
+					"华为": "y",
+					"联盟": "u"
+				},
+				"Vue": {
+					"vue2": "y",
+					"vue3": "y"
+				}
+			}
+		}
+	}
+}

+ 11 - 0
uni_modules/uni-swipe-action/readme.md

@@ -0,0 +1,11 @@
+
+
+## SwipeAction 滑动操作
+> **组件名:uni-swipe-action**
+> 代码块: `uSwipeAction`、`uSwipeActionItem`
+
+
+通过滑动触发选项的容器
+
+### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-swipe-action)
+#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839