Browse Source

1. 花束排序完成 2. 分类展示与排序完成

shizhongqi 1 năm trước cách đây
mục cha
commit
967036e097
2 tập tin đã thay đổi với 368 bổ sung283 xóa
  1. 35 161
      hdApp/src/admin/goods/categorySort.vue
  2. 333 122
      hdApp/src/admin/goods/goodsSort.vue

+ 35 - 161
hdApp/src/admin/goods/categorySort.vue

@@ -18,16 +18,15 @@
 							<view class="app-size-28 app-color-0" style="font-size:30upx;font-weight:bold;">{{ item.categoryName}}</view>						
 						</view>
 
-						<!-- <text style="position:absolute;top:65upx;right:410upx;color:#CCCCCC;">{{item.inTurn}}</text> -->
-
-						<text v-if="index > 0" style="right:335upx;" class="move-btn" @click.stop="topFn(item.id)">↑</text>
+						<!--<text v-if="index > 0" style="right:335upx;" class="move-btn" @click.stop="topFn(item.id)">↑</text>
 						<text v-if="index > 0" style="right:350upx;line-height: 10upx;" class="move-btn-line">-</text>
 
-						<text v-if="index < list.data.length - 1" style="right:255upx;" class="move-btn" @click.stop="bottomFn(item.id)">↓</text>
-						<text v-if="index < list.data.length - 1" style="right:272upx;line-height: 68upx;" class="move-btn-line">-</text>
+						<text v-if="index < list.data.length - 1" style="right:282upx;" class="move-btn" @click.stop="bottomFn(item.id)">↓</text>
+						<text v-if="index < list.data.length - 1" style="right:282upx;line-height: 68upx;" class="move-btn-line">-</text>
 
-						<text style="right:170upx;" class="move-btn" @click.stop="upFn(item.id)">↑</text>
-						<text style="right:95upx;" class="move-btn" @click.stop="downFn(item.id)">↓</text>
+						<text style="right:200upx;" class="move-btn" @click.stop="upFn(item.id)">↑</text>
+						<text style="right:125upx;" class="move-btn" @click.stop="downFn(item.id)">↓</text>
+						-->
 
 						<view
 						style="position:absolute;top:58upx;right:28upx;cursor:move;"
@@ -54,7 +53,7 @@ import AppUploader from '@/components/app-uploader'
 import OperateModule from '@/admin/home/components/module/operate'
 import AppWrapperEmpty from '@/components/app-wrapper-empty'
 import { list } from '@/mixins'
-import { categoryListInfo, categoryAddB, categoryUpdateB } from '@/api/goods'
+import { categoryListInfo } from '@/api/goods'
 import { sort } from '@/api/category'
 export default {
 	name: 'category',
@@ -67,8 +66,6 @@ export default {
 	mixins: [list],
 	data() {
 		return {
-			modifyModal: false,
-
 			draggedIndex: -1,
 			draggedItem: null,
 			dragOffsetY: 0,
@@ -77,25 +74,21 @@ export default {
 			startY: 0,
 		}
 	},
-	computed: {
-	},
 	onPullDownRefresh() {
 		this.resetList()
-		this._list().then(res => {
+		this._list().then(() => {
 			uni.stopPullDownRefresh()
 		})
 	},
 	onReachBottom() {
 		if (!this.list.finished) {
-			this._list().then(res => {
+			this._list().then(() => {
 				uni.stopPullDownRefresh()
 			})
 		} else {
 			uni.stopPullDownRefresh()
 		}
 	},
-	onLoad() {
-	},
 	methods: {
 		// 跳转到商品排序页面
 		navigateToGoodsSort(categoryId) {
@@ -103,64 +96,17 @@ export default {
 				url: '/admin/goods/goodsSort?id=' + categoryId
 			})
 		},
-		radioChange(e){
-			this.flower = e.detail.value
-		},
-		// edit(item){
-		// 	this.modifyModal = true
-		// 	this.modifyTitle = '编辑'
-		// 	this.modifyForm = { categoryId:item.id, categoryName: item.categoryName, inTurn: item.inTurn, status: item.status }
-		// 	this.flower = parseInt(item.flower)
-		// 	this.catDisabled = true
-		// },
-		
 		
 		async init() {
 			this._list()
 		},
+		
 		_list() {
 			return categoryListInfo().then(res => {
 				let data = { code: res.code, msg: res.msg, data: { list: res.data } }
 				this.completes(data)
 			})
 		},
-		// _categoryAddOrEditB() {
-		// 	if (!this.modifyForm.categoryName) {
-		// 		this.$msg('请输入分类名称')
-		// 		return false
-		// 	}
-		// 	let form = JSON.parse(JSON.stringify(this.modifyForm))
-		// 	let host = categoryAddB
-		// 	if(form.categoryId && form.categoryId > 0){
-		// 		host =  categoryUpdateB
-		// 	}
-		// 	if(Number(this.flower) == 2){
-		// 		this.$msg('请选择属性')
-		// 		return false
-		// 	}
-		// 	host({ ...form,flower:this.flower }).then(res => {
-		// 		this.$msg('操作成功!')
-		// 		this.modalCancel()
-		// 		setTimeout(() => {
-		// 			this.resetList()
-		// 			this._list()
-		// 		}, 1000)
-		// 	})
-		// },
-		// modifyModalClick(e) {
-		// 	if (e.index === 0) {
-		// 		this.modalCancel()
-		// 	} else {
-		// 		this._categoryAddOrEditB()
-		// 	}
-		// },
-		// modalCancel() {
-		// 	this.delModal = false
-		// 	this.modifyModal = false
-		// },
-		switchChangeFn(e) {
-			this.modifyForm.status = e.detail.value ? 1 : 0
-		},
 		
 		// 拖拽相关方法
 		transformStyle(index) {
@@ -176,25 +122,6 @@ export default {
 			this.draggedItem = this.list.data[index]
 			this.startY = e.touches[0].clientY
 			this.isDragging = true
-			
-			// 添加拖拽时的视觉反馈
-			// 设置当前拖拽项的样式
-			// uni.createSelectorQuery()
-			// 	.selectAll('.list')
-			// 	.boundingClientRect(rects => {
-			// 		if (rects && rects[this.draggedIndex]) {
-			// 			this.itemHeight = rects[0].height
-			// 			// 通过数据绑定方式设置样式,不直接操作DOM
-			// 			this.$set(this.list.data[this.draggedIndex], 'isDragging', true)
-			// 			// 震动反馈
-			// 			uni.vibrateShort({
-			// 				success: () => {
-			// 					console.log('震动反馈成功')
-			// 				}
-			// 			})
-			// 		}
-			// 	}).exec()
-			
 		},
 		
 		dragMove(e) {
@@ -203,13 +130,12 @@ export default {
 			const currentY = e.touches[0].clientY
 			const deltaY = currentY - this.startY
 			
-			// 根据设备像素比例转换为upx单位,确保在不同设备上表现一致
-			const pixelRatio = uni.getSystemInfoSync().pixelRatio || 2
+			// 根据设备像素比例转换为upx单位
 			const deltaYupx = deltaY * (750 / uni.getSystemInfoSync().windowWidth)
 			
 			this.dragOffsetY = deltaYupx
 			
-			// 更精确地计算目标位置
+			// 计算目标位置
 			const itemHeightUpx = this.itemHeight * (750 / uni.getSystemInfoSync().windowWidth)
 			
 			// 使用更精确的计算方法确定移动的项目数
@@ -220,7 +146,6 @@ export default {
 			// 确保目标索引在有效范围内
 			const targetIndex = Math.max(0, Math.min(this.list.data.length - 1, this.draggedIndex + moveItems))
 			
-			
 			if (targetIndex !== this.draggedIndex) {
 				// 交换元素位置
 				const newData = [...this.list.data]
@@ -233,14 +158,10 @@ export default {
 				this.draggedIndex = targetIndex
 				this.startY = currentY
 				this.dragOffsetY = 0
-				
-				// 提供触感反馈
-				// uni.vibrateShort()
 			}
 		},
 		
-		dragEnd(e) {
-			console.log('dragEnd')
+		dragEnd() {
 			if (!this.isDragging) return
 			
 			// 重置拖拽状态
@@ -250,25 +171,16 @@ export default {
 			this.isDragging = false
 			this.startY = 0
 			
-			// 在UniApp中不需要手动移除视觉反馈,因为状态已重置
-			// 移除视觉反馈
-			// const items = document.querySelectorAll('.list')
-			// items.forEach(item => {
-			// 	item.style.opacity = '1'
-			// 	item.style.boxShadow = 'none'
-			// })
 			// 更新排序值并发送到后端
 			this.updateSortOrder()
 		},
 		
 		updateSortOrder() {
-			// 更新每个项目的inTurn值,从大到小排序(值越大越靠前)
+			// 更新每个项目的inTurn值,从大到小排序
 			const sortData = this.list.data.map((item, index) => ({
 				id: item.id,
 				inTurn: this.list.data.length - index // 反向索引,使第一个项目有最大值
 			}))
-
-			console.log(sortData)
 			
 			// 调用API更新排序
 			sort({ items: sortData }).then(res => {
@@ -283,10 +195,8 @@ export default {
 			})
 		},
 		
-		// 原有的上移下移方法
+		// 上移
 		upFn(id) {
-			console.log('upFn: ' + id)
-			
 			const index = this.list.data.findIndex(item => item.id === id)
 			if (index > 0) {
 				const newData = [...this.list.data]
@@ -298,9 +208,8 @@ export default {
 			}
 		},
 		
+		// 下移
 		downFn(id) {
-			console.log('downFn: ' + id)
-			
 			const index = this.list.data.findIndex(item => item.id === id)
 			if (index < this.list.data.length - 1) {
 				const newData = [...this.list.data]
@@ -314,8 +223,6 @@ export default {
 
 		// 置顶
 		topFn(id) {
-			console.log('topFn: ' + id)
-			
 			const index = this.list.data.findIndex(item => item.id === id)
 			if (index > 0) {
 				const newData = [...this.list.data]
@@ -329,10 +236,9 @@ export default {
 				this.updateSortOrder()
 			}
 		},
+		
 		// 置底
 		bottomFn(id) {
-			console.log('bottomFn: ' + id)
-			
 			const index = this.list.data.findIndex(item => item.id === id)
 			if (index < this.list.data.length - 1) {
 				const newData = [...this.list.data]
@@ -365,9 +271,6 @@ export default {
 		color: $fontColor3;
 		border-bottom: 1px solid $borderColor;
 		position:relative;
-		.list-index {
-			width: 50upx;
-		}
 		.list-img {
 			width: 130upx;
 			height: 130upx;
@@ -385,51 +288,9 @@ export default {
 					margin-top: 0;
 				}
 			}
-			.list-operate {
-				width:480upx;
-				margin-top:10upx;
-				@include disFlex(center, space-between);
-				.operate-det {
-					width:490upx;
-					padding-left:120upx;
-					& > span {
-						border:1px solid #ccc;
-						border-radius:25upx;
-						padding:5upx 20upx 5upx 20upx;
-						font-size:25upx;
-						margin-left:35upx;
-						&:first-child {
-							margin-left: 0;
-						}
-					}
-				}
-			}
 		}
 	}
 }
-.app-footer {
-	justify-content: flex-end;
-	.admin-button-com {
-		width: 200upx;
-		margin-right: 30upx;
-	}
-}
-.modify-modal {
-	.prompt-text {
-		color: red;
-		position: relative;
-		right: 52upx;
-		bottom: 24upx;
-		// margin-bottom: 10upx;
-	}
-	.line-label {
-		width: 140upx;
-		flex-shrink: 0;
-	}
-	.switch-wrap {
-		margin-top: 30upx;
-	}
-}
 .move-btn {
 	position: absolute;
 	top:65upx;
@@ -455,11 +316,24 @@ export default {
 }
 
 .drag-handle {
+	display: flex;
+	align-items: center;
+	justify-content: center;
+	width: 80upx;
+	height: 75upx;
+	border-radius: 12upx;
+	background-color: rgba(0, 0, 0, 0.03);
 	transition: all 0.2s ease;
-}
-
-.drag-handle:active {
-	transform: scale(1.1);
-	opacity: 0.8;
+	-webkit-touch-callout: none; /* 禁用长按菜单 */
+	-webkit-user-select: none; /* 禁用文本选择 */
+	user-select: none;
+	touch-action: none; /* 禁用浏览器默认触摸行为 */
+	
+	/* 增加触摸反馈 */
+	&:active {
+		transform: scale(1.1);
+		background-color: rgba(0, 122, 255, 0.1);
+		box-shadow: 0 4upx 16upx rgba(0, 122, 255, 0.2);
+	}
 }
 </style>

+ 333 - 122
hdApp/src/admin/goods/goodsSort.vue

@@ -5,37 +5,44 @@
 				<block v-for="(item, index) in list.data" :key="item.id">
 					<view 
 						class="list"
-						:class="{ 'dragging': draggedIndex === index }"
+						:class="{ 
+							'dragging': draggedIndex === index,
+							'target-position': targetIndex === index && isDragging && targetIndex !== draggedIndex
+						}"
 						:style="{ 
 							transform: transformStyle(index), 
 							transition: isDragging ? 'none' : 'transform 0.3s ease', 
-							zIndex: draggedIndex === index ? 999 : 1 
+							zIndex: draggedIndex === index ? 999 : (targetIndex === index && isDragging ? 888 : 1)
 						}">
 						<view class="list-img">
 							<image :src="item.cover" mode="aspectFit" ></image>
 						</view>
-						<view class="list-det">
-							<view class="app-size-28 app-color-0" style="font-size:30upx;font-weight:bold;">{{ item.name || item.goodsName}}</view>						
+						<view class="list-det" style="position:absolute;top:10upx;left:125upx;">
+							<view class="app-size-28 app-color-0" style="font-size:28upx;font-weight:bold;">{{ item.name || item.goodsName}}</view>						
 						</view>
 
-						<text v-if="index > 0" style="right:335upx;" class="move-btn" @click.stop="topFn(item.id)">↑</text>
-						<text v-if="index > 0" style="right:350upx;line-height: 12upx;" class="move-btn-line">-</text>
+                        <view class="list-det" style="position:absolute;bottom:10upx;left:122upx;">
+							<view v-if="item.priceType == 1" class="app-size-28 app-color-0" style="font-size:24upx;">¥{{ item.price}}</view>						
+							<view v-else class="app-size-28 app-color-0" style="font-size:24upx;border:1px solid #ccc;border-radius:30upx;padding:3upx 15upx;">无价格</view>						
+						</view>
+
+						<text v-if="index > 0" style="right:375upx;" class="move-btn move-btn-top" :class="{ 'disabled': isOperating }" @click.stop="topFn(item.id)" title="置顶">⇈</text>
 
-						<text v-if="index < list.data.length - 1" style="right:255upx;" class="move-btn" @click.stop="bottomFn(item.id)">↓</text>
-						<text v-if="index < list.data.length - 1" style="right:272upx;line-height: 72upx;" class="move-btn-line">-</text>
+						<text v-if="index < list.data.length - 1" style="right:290upx;" class="move-btn move-btn-bottom" :class="{ 'disabled': isOperating }" @click.stop="bottomFn(item.id)" title="置底">⇊</text>
+				
 
-						<text style="right:170upx;" class="move-btn" @click.stop="upFn(item.id)">↑</text>
-						<text style="right:95upx;" class="move-btn" @click.stop="downFn(item.id)">↓</text>
+						<text style="right:205upx;" class="move-btn move-btn-up" :class="{ 'disabled': isOperating }" @click.stop="upFn(item.id)" title="上移一位">↑</text>
+						<text style="right:120upx;" class="move-btn move-btn-down" :class="{ 'disabled': isOperating }" @click.stop="downFn(item.id)" title="下移一位">↓</text>
 
 						<view
-						style="position:absolute;top:58upx;right:28upx;cursor:move;"
+						style="position:absolute;top:50upx;right:14upx;cursor:move;"
 						class="drag-handle"
 						:data-index="index" 
 						:data-id="item.id"
 						@touchstart="dragStart" 
 						@touchmove="dragMove" 
 						@touchend="dragEnd">
-							<text style="color:#333333;font-size:45upx;">≡</text>
+							<text style="color:#666666;font-size:48upx;padding:8upx 6upx;line-height:1;">≡</text>
 						</view>
 					</view>
 				</block>
@@ -58,19 +65,32 @@ export default {
 	mixins: [list],
 	data() {
 		return {
-			categoryId: '', // 分类ID
 			draggedIndex: -1,
 			draggedItem: null,
 			dragOffsetY: 0,
 			isDragging: false,
-			itemHeight: 160, // 列表项高度,单位upx
+			itemHeight: 160, // 列表项高度,单位upx(与CSS中的height保持一致)
 			startY: 0,
+			scrollTop: 0, // 页面滚动高度
+			originalOrder: [], // 原始顺序,用于拖拽失败时恢复
+			targetIndex: -1, // 目标交换位置的索引
+			isOperating: false, // 防止快速点击操作按钮
+            totalNum: 0, // 总数量
+		}
+	},
+	onPageScroll(e) {
+		// 拖拽期间禁止更新滚动高度
+		if (!this.isDragging) {
+			this.scrollTop = e.scrollTop
 		}
 	},
 	onPullDownRefresh() {
 		this.resetList()
 		this._list().then(res => {
 			uni.stopPullDownRefresh()
+		}).catch(err => {
+			console.error('下拉刷新失败:', err)
+			uni.stopPullDownRefresh()
 		})
 	},
 	onReachBottom() {
@@ -82,13 +102,6 @@ export default {
 			uni.stopPullDownRefresh()
 		}
 	},
-	onLoad(options) {
-		// 接收传递过来的分类ID参数
-		if (options && options.id) {
-			this.categoryId = options.id
-		}
-		//this.init()
-	},
 	methods: {
 		async init() {
 			// 确保list.data是数组
@@ -100,37 +113,15 @@ export default {
 		_list() {
 			// 传递分类ID参数和分页参数到API
 			const params = {
-				categoryId: this.categoryId,
+				cId: this.option.id,
 				page: this.list.page,
 				pageSize: this.list.pageSize
 			}
-			console.log('请求参数:', params)
-			console.log('当前list.data:', this.list.data)
-			console.log('list.data类型:', Array.isArray(this.list.data) ? 'Array' : typeof this.list.data)
 			
 			return getListB(params).then(res => {
-				console.log('API返回数据:', res)
-				
-				// 确保返回的数据结构符合预期
-				const responseData = {
-					code: res.code,
-					msg: res.msg,
-					data: {
-						list: res.data && res.data.list ? res.data.list : [],
-						finished: res.moreData,
-						totalPage: res.totalPage || 1
-					}
-				}
-				
-				console.log('处理后的数据:', responseData)
-				console.log('处理后的数据 -- :', res)
-
 				// 使用mixin提供的completes方法处理分页数据
 				this.completes(res)
-				
-				console.log('最终列表数据:', this.list.data)
-				console.log('列表长度:', this.list.data.length)
-				console.log('是否还有更多数据:', this.list.finished)
+                this.totalNum = Number(res.data.total)
 			}).catch(err => {
 				console.error('API请求失败:', err)
 				this.list.loading = false
@@ -146,54 +137,97 @@ export default {
 		},
 		
 		dragStart(e) {
+			// 防止重复触发
+			if (this.isDragging) return
+			
+			this.isDragging = true
+			
 			const index = parseInt(e.currentTarget.dataset.index)
+			if (isNaN(index) || index < 0 || index >= this.list.data.length) {
+				this.isDragging = false
+				return
+			}
+			
 			this.draggedIndex = index
 			this.draggedItem = this.list.data[index]
 			this.startY = e.touches[0].clientY
-			this.isDragging = true
+			this.targetIndex = index // 初始化目标位置为当前位置
+			
+			// 保存原始顺序,用于拖拽失败时恢复
+			this.originalOrder = [...this.list.data]
+			
+			// 添加拖拽模式样式,防止页面滚动
+			this.toggleDragMode(true)
+			
+			// 阻止默认行为,防止页面滚动(兼容微信端与H5)
+			if (e.preventDefault) {
+				e.preventDefault()
+			}
+			if (e.stopPropagation) {
+				e.stopPropagation()
+			}
+			return false
 		},
 		
 		dragMove(e) {
 			if (!this.isDragging || this.draggedIndex === -1) return
 			
+			// 验证触摸点是否存在
+			if (!e.touches || !e.touches[0]) return
+			
+			// 阻止默认行为,防止页面滚动(兼容微信端与H5)
+			if (e.preventDefault) {
+				e.preventDefault()
+			}
+			if (e.stopPropagation) {
+				e.stopPropagation()
+			}
+			
 			const currentY = e.touches[0].clientY
 			const deltaY = currentY - this.startY
 			
 			// 根据设备像素比例转换为upx单位,确保在不同设备上表现一致
-			const pixelRatio = uni.getSystemInfoSync().pixelRatio || 2
-			const deltaYupx = deltaY * (750 / uni.getSystemInfoSync().windowWidth)
+			const systemInfo = uni.getSystemInfoSync()
+			const pixelRatio = 750 / systemInfo.windowWidth
+			const deltaYupx = deltaY * pixelRatio
 			
-			this.dragOffsetY = deltaYupx
+			// 限制拖拽范围,防止超出列表边界
+			const maxOffset = (this.list.data.length - 1 - this.draggedIndex) * this.itemHeight
+			const minOffset = -this.draggedIndex * this.itemHeight
+			const limitedOffset = Math.max(minOffset, Math.min(maxOffset, deltaYupx))
 			
-			// 更精确地计算目标位置
-			const itemHeightUpx = this.itemHeight * (750 / uni.getSystemInfoSync().windowWidth)
+			this.dragOffsetY = limitedOffset
 			
-			// 使用更精确的计算方法确定移动的项目数
-			const moveDistance = Math.abs(deltaYupx)
-			const moveDirection = deltaYupx > 0 ? 1 : -1
-			const moveItems = Math.floor(moveDistance / (itemHeightUpx * 0.5)) * moveDirection
+			// 实时计算目标位置,让用户看到将要交换的元素
+			const moveItems = Math.round(limitedOffset / this.itemHeight)
+			this.targetIndex = Math.max(0, Math.min(this.list.data.length - 1, this.draggedIndex + moveItems))
+		},
+		
+		dragEnd() {
+			if (!this.isDragging) return
 			
-			// 确保目标索引在有效范围内
+			// 计算最终位置
+			const moveItems = Math.round(this.dragOffsetY / this.itemHeight)
 			const targetIndex = Math.max(0, Math.min(this.list.data.length - 1, this.draggedIndex + moveItems))
 			
+			// 如果位置有变化,则更新数组
 			if (targetIndex !== this.draggedIndex) {
-				// 交换元素位置
 				const newData = [...this.list.data]
 				const draggedItem = newData[this.draggedIndex]
+				
+				// 移除拖拽项
 				newData.splice(this.draggedIndex, 1)
+				// 插入到新位置
 				newData.splice(targetIndex, 0, draggedItem)
 				
-				// 更新数据和拖拽状态
 				this.list.data = newData
-				this.draggedIndex = targetIndex
-				this.startY = currentY
-				this.dragOffsetY = 0
+				
+				// 更新排序值并发送到后端
+				this.updateSortOrder()
 			}
-		},
-		
-		dragEnd(e) {
-			console.log('dragEnd')
-			if (!this.isDragging) return
+			
+			// 移除拖拽模式样式
+			this.toggleDragMode(false)
 			
 			// 重置拖拽状态
 			this.draggedIndex = -1
@@ -201,19 +235,17 @@ export default {
 			this.dragOffsetY = 0
 			this.isDragging = false
 			this.startY = 0
-			
-			// 更新排序值并发送到后端
-			this.updateSortOrder()
+			this.originalOrder = []
+			this.targetIndex = -1 // 重置目标位置
 		},
 		
 		updateSortOrder() {
 			// 更新每个项目的inTurn值,从大到小排序(值越大越靠前)
 			const sortData = this.list.data.map((item, index) => ({
 				id: item.id,
-				inTurn: this.list.data.length - index // 反向索引,使第一个项目有最大值
+				inTurn: this.totalNum - index // 反向索引,使第一个项目有最大值
 			}))
-
-			console.log(sortData)
+			// console.log('排序数据:', sortData)
 			
 			// 调用API更新排序
 			sort({ items: sortData }).then(res => {
@@ -221,17 +253,64 @@ export default {
 					this.$msg('排序更新成功')
 				} else {
 					this.$msg('排序更新失败')
+					// 恢复原始顺序
+					this.list.data = this.originalOrder
 				}
 			}).catch(err => {
 				console.error('更新排序失败:', err)
 				this.$msg('排序更新失败')
+				// 恢复原始顺序
+				this.list.data = this.originalOrder
 			})
 		},
 		
+		// 切换拖拽模式,防止页面滚动
+		toggleDragMode(isDragging) {
+			// #ifdef H5
+			// H5平台:直接操作body样式
+			if (isDragging) {
+				document.body.classList.add('dragging-mode')
+			} else {
+				document.body.classList.remove('dragging-mode')
+			}
+			// #endif
+			
+			// #ifndef H5
+			// 微信小程序、App:使用页面样式和滚动API
+			if (isDragging) {
+				uni.setPageStyle({
+					style: {
+						'overflow': 'hidden',
+						'position': 'fixed',
+						'width': '100%',
+						'top': `-${this.scrollTop}px`,
+						'left': '0',
+						'right': '0'
+					}
+				})
+			} else {
+				uni.setPageStyle({
+					style: {
+						'overflow': '',
+						'position': '',
+						'width': '',
+						'top': '',
+						'left': '',
+						'right': ''
+					}
+				})
+				uni.pageScrollTo({
+					scrollTop: this.scrollTop,
+					duration: 0
+				})
+			}
+			// #endif
+		},
+		
 		// 原有的上移下移方法
 		upFn(id) {
-			console.log('upFn: ' + id)
-			
+			if (this.isOperating) return
+			this.isOperating = true
 			const index = this.list.data.findIndex(item => item.id === id)
 			if (index > 0) {
 				const newData = [...this.list.data]
@@ -241,11 +320,16 @@ export default {
 				this.list.data = newData
 				this.updateSortOrder()
 			}
+			
+			// 防抖延迟
+			setTimeout(() => {
+				this.isOperating = false
+			}, 300)
 		},
 		
 		downFn(id) {
-			console.log('downFn: ' + id)
-			
+			if (this.isOperating) return
+			this.isOperating = true
 			const index = this.list.data.findIndex(item => item.id === id)
 			if (index < this.list.data.length - 1) {
 				const newData = [...this.list.data]
@@ -255,12 +339,17 @@ export default {
 				this.list.data = newData
 				this.updateSortOrder()
 			}
+			
+			// 防抖延迟
+			setTimeout(() => {
+				this.isOperating = false
+			}, 300)
 		},
 
 		// 置顶
 		topFn(id) {
-			console.log('topFn: ' + id)
-			
+			if (this.isOperating) return
+			this.isOperating = true
 			const index = this.list.data.findIndex(item => item.id === id)
 			if (index > 0) {
 				const newData = [...this.list.data]
@@ -273,11 +362,17 @@ export default {
 				this.list.data = newData
 				this.updateSortOrder()
 			}
+			
+			// 防抖延迟
+			setTimeout(() => {
+				this.isOperating = false
+			}, 300)
 		},
+		
 		// 置底
 		bottomFn(id) {
-			console.log('bottomFn: ' + id)
-			
+			if (this.isOperating) return
+			this.isOperating = true
 			const index = this.list.data.findIndex(item => item.id === id)
 			if (index < this.list.data.length - 1) {
 				const newData = [...this.list.data]
@@ -290,6 +385,11 @@ export default {
 				this.list.data = newData
 				this.updateSortOrder()
 			}
+			
+			// 防抖延迟
+			setTimeout(() => {
+				this.isOperating = false
+			}, 300)
 		}
 	}
 }
@@ -310,9 +410,6 @@ export default {
 		color: $fontColor3;
 		border-bottom: 1px solid $borderColor;
 		position:relative;
-		.list-index {
-			width: 50upx;
-		}
 		.list-img {
 			width: 130upx;
 			height: 130upx;
@@ -330,61 +427,175 @@ export default {
 					margin-top: 0;
 				}
 			}
-			.list-operate {
-				width:480upx;
-				margin-top:10upx;
-				@include disFlex(center, space-between);
-				.operate-det {
-					width:490upx;
-					padding-left:120upx;
-					& > span {
-						border:1px solid #ccc;
-						border-radius:25upx;
-						padding:5upx 20upx 5upx 20upx;
-						font-size:25upx;
-						margin-left:35upx;
-						&:first-child {
-							margin-left: 0;
-						}
-					}
-				}
-			}
 		}
 	}
 }
 .move-btn {
 	position: absolute;
-	top:65upx;
-	color:blue;
-	border:1px solid #CCCCCC;
-	padding: 6upx 12upx;
-	border-radius:50%;
-    z-index: 9999;
+	top: 60upx;
+	display: inline-flex;
+	align-items: center;
+	justify-content: center;
+	width: 60upx;
+	height: 60upx;
+	color: #fff;
+	background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+	border: 2px solid rgba(255, 255, 255, 0.3);
+	border-radius: 50%;
+	font-size: 28upx; /* 增大20% */
+	font-weight: bold;
+	box-shadow: 0 4upx 12upx rgba(102, 126, 234, 0.3);
+	transition: all 0.2s ease;
+	z-index: 9999;
+	cursor: pointer;
+	
+	/* 触摸反馈 */
+	&:active {
+		transform: scale(0.95);
+		box-shadow: 0 2upx 8upx rgba(102, 126, 234, 0.5);
+	}
+	
+	/* 悬停效果 */
+	&:hover {
+		transform: translateY(-2upx);
+		box-shadow: 0 6upx 20upx rgba(102, 126, 234, 0.4);
+	}
 }
-.move-btn-line {
-	position: absolute;
-	top:65upx;
-	color:blue;
-    font-size: 26upx;
-    z-index: 1;
+
+/* 置顶按钮 - 红色渐变 */
+.move-btn-top {
+	// background: linear-gradient(135deg, #ff6b6b 0%, #ee5a24 100%);
+	// box-shadow: 0 4upx 12upx rgba(255, 107, 107, 0.3);
+    background: linear-gradient(135deg, #feca57 0%, #ff9ff3 100%);
+	box-shadow: 0 4upx 12upx rgba(254, 202, 87, 0.3);
+	
+	&:hover {
+		box-shadow: 0 6upx 20upx rgba(255, 107, 107, 0.4);
+	}
+	
+	&:active {
+		box-shadow: 0 2upx 8upx rgba(255, 107, 107, 0.5);
+	}
+}
+
+/* 置底按钮 - 橙色渐变 */
+.move-btn-bottom {
+	background: linear-gradient(135deg, #feca57 0%, #ff9ff3 100%);
+	box-shadow: 0 4upx 12upx rgba(254, 202, 87, 0.3);
+	
+	&:hover {
+		box-shadow: 0 6upx 20upx rgba(254, 202, 87, 0.4);
+	}
+	
+	&:active {
+		box-shadow: 0 2upx 8upx rgba(254, 202, 87, 0.5);
+	}
+}
+
+/* 上移按钮 - 绿色渐变 */
+.move-btn-up {
+	background: linear-gradient(135deg, #48dbfb 0%, #0abde3 100%);
+	box-shadow: 0 4upx 12upx rgba(72, 219, 251, 0.3);
+	
+	&:hover {
+		box-shadow: 0 6upx 20upx rgba(72, 219, 251, 0.4);
+	}
+	
+	&:active {
+		box-shadow: 0 2upx 8upx rgba(72, 219, 251, 0.5);
+	}
+}
+
+/* 下移按钮 - 紫色渐变 */
+.move-btn-down {
+	// background: linear-gradient(135deg, #a55eea 0%, #8854d0 100%);
+	// box-shadow: 0 4upx 12upx rgba(165, 94, 234, 0.3);
+    background: linear-gradient(135deg, #48dbfb 0%, #0abde3 100%);
+	box-shadow: 0 4upx 12upx rgba(72, 219, 251, 0.3);
+	
+	&:hover {
+		box-shadow: 0 6upx 20upx rgba(165, 94, 234, 0.4);
+	}
+	
+	&:active {
+		box-shadow: 0 2upx 8upx rgba(165, 94, 234, 0.5);
+	}
 }
 
+/* 按钮禁用状态 */
+.move-btn.disabled {
+	opacity: 0.5;
+	transform: none !important;
+	box-shadow: 0 2upx 6upx rgba(0, 0, 0, 0.1) !important;
+	pointer-events: none;
+	cursor: not-allowed;
+	&:hover, &:active {
+		transform: none !important;
+		box-shadow: 0 2upx 6upx rgba(0, 0, 0, 0.1) !important;
+	}
+}
 // 拖拽相关样式
 .list.dragging {
 	border: 2px dashed #007AFF !important;
-	box-shadow: 0 4px 20px rgba(0, 122, 255, 0.3) !important;
-	background-color: rgba(0, 122, 255, 0.05) !important;
-	opacity: 0.85;
-	border-radius: 12upx;
-	transform: scale(1.05);
+	box-shadow: 0 8upx 40upx rgba(0, 122, 255, 0.25) !important;
+	background-color: rgba(0, 122, 255, 0.08) !important;
+	opacity: 0.9;
+	border-radius: 16upx;
+	transform: scale(1.02);
+	transition: none !important; /* 拖拽时禁用过渡动画 */
+}
+
+.list.target-position {
+	border: 3px solid #52C41A !important; /* 使用绿色边框区别于拖拽元素 */
+	box-shadow: 0 6upx 30upx rgba(82, 196, 26, 0.3) !important;
+	background-color: rgba(82, 196, 26, 0.1) !important;
+	opacity: 0.95;
+	border-radius: 16upx;
+	transform: scale(1.01);
+	transition: all 0.2s ease !important; /* 目标位置保持平滑过渡 */
+	
+	/* 添加一个内部指示器 */
+	&::before {
+		content: '';
+		position: absolute;
+		top: 50%;
+		left: 50%;
+		transform: translate(-50%, -50%);
+		width: 100upx;
+		height: 6upx;
+		background: linear-gradient(90deg, #52C41A, #73D13D);
+		border-radius: 3upx;
+		opacity: 0.8;
+		z-index: 99990;
+	}
 }
 
 .drag-handle {
+	display: flex;
+	align-items: center;
+	justify-content: center;
+	width: 80upx;
+	height: 75upx;
+	border-radius: 12upx;
+	background-color: rgba(0, 0, 0, 0.03);
 	transition: all 0.2s ease;
+	-webkit-touch-callout: none; /* 禁用长按菜单 */
+	-webkit-user-select: none; /* 禁用文本选择 */
+	user-select: none;
+	touch-action: none; /* 禁用浏览器默认触摸行为 */
+	
+	/* 增加触摸反馈 */
+	&:active {
+		transform: scale(1.1);
+		background-color: rgba(0, 122, 255, 0.1);
+		box-shadow: 0 4upx 16upx rgba(0, 122, 255, 0.2);
+	}
 }
 
-.drag-handle:active {
-	transform: scale(1.1);
-	opacity: 0.8;
+/* 防止拖拽时页面滚动 */
+.dragging-mode {
+	overflow: hidden !important;
+	touch-action: none !important;
+	-webkit-overflow-scrolling: auto !important;
 }
 </style>