|
|
@@ -0,0 +1,354 @@
|
|
|
+<template>
|
|
|
+ <view class="app-content">
|
|
|
+ <view class="list-wrap">
|
|
|
+ <block v-if="!$util.isEmpty(list.data)">
|
|
|
+ <block v-for="(item, index) in list.data" :key="item.id">
|
|
|
+ <view class="list" :class="{ dragging: draggedIndex === index }" :style="{
|
|
|
+ transform: transformStyle(index),
|
|
|
+ transition: isDragging ? 'none' : 'transform 0.3s ease',
|
|
|
+ zIndex: draggedIndex === index ? 999 : 1
|
|
|
+ }" @click="navigateToGoodsSort(item)">
|
|
|
+ <!-- <view class="list-img">
|
|
|
+ <image :src="item.img" mode="aspectFit"></image>
|
|
|
+ </view> -->
|
|
|
+ <view class="list-det">
|
|
|
+ <view class="app-size-28 app-color-0">满<text style="margin-left: 8upx;font-size: 32upx; font-weight: bold">{{ item.amount }}元</text>,送{{ item.num }}个红包</view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="confirm-btn">
|
|
|
+ <button class="admin-button-com middle blue"
|
|
|
+ style="position:absolute;top:50rpx;right: 170rpx" @click="navigateToSendHb(item)">修改</button>
|
|
|
+ <button class="admin-button-com middle blue"
|
|
|
+ style="position:absolute;top:50rpx;right: 10rpx">删除</button>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </block>
|
|
|
+ </block>
|
|
|
+ <block v-else>
|
|
|
+ <app-wrapper-empty title="暂无数据" :is-empty="$util.isEmpty(list.data)" />
|
|
|
+ </block>
|
|
|
+ </view>
|
|
|
+ <view class="app-footer">
|
|
|
+ <button class="admin-button-com middle blue" @click="addHbRuleFn">创建规则</button>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+</template>
|
|
|
+<script>
|
|
|
+import ModalModule from '@/components/plugin/modal';
|
|
|
+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 { hbRulesList, sendHbRule, deleteHbRule } from '@/api/hb';
|
|
|
+import { categoryListInfo } from '@/api/goods';
|
|
|
+import { sort } from '@/api/category';
|
|
|
+export default {
|
|
|
+ name: 'category',
|
|
|
+ components: {
|
|
|
+ ModalModule,
|
|
|
+ AppUploader,
|
|
|
+ OperateModule,
|
|
|
+ AppWrapperEmpty
|
|
|
+ },
|
|
|
+ mixins: [list],
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ draggedIndex: -1,
|
|
|
+ draggedItem: null,
|
|
|
+ dragOffsetY: 0,
|
|
|
+ isDragging: false,
|
|
|
+ itemHeight: 160, // 列表项高度,单位rpx
|
|
|
+ startY: 0
|
|
|
+ };
|
|
|
+ },
|
|
|
+ onPullDownRefresh() {
|
|
|
+ this.resetList();
|
|
|
+ this.getCategoryList().then(() => {
|
|
|
+ uni.stopPullDownRefresh();
|
|
|
+ });
|
|
|
+ },
|
|
|
+ onReachBottom() {
|
|
|
+ if (!this.list.finished) {
|
|
|
+ this.getCategoryList().then(() => {
|
|
|
+ uni.stopPullDownRefresh();
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ uni.stopPullDownRefresh();
|
|
|
+ }
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ async init() {
|
|
|
+ this.getHbRulesList();
|
|
|
+ },
|
|
|
+ getHbRulesList() {
|
|
|
+ hbRulesList().then(res => {
|
|
|
+ if(res.code == 1) {
|
|
|
+ let data = { code: res.code, msg: res.msg, data: { list: res.data.list } };
|
|
|
+ this.completes(data);
|
|
|
+ } else {
|
|
|
+ this.$msg(res.msg);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+ navigateToSendHb(item) {
|
|
|
+ uni.navigateTo({ url: '/admin/hb/sendHb?id=' + item.id})
|
|
|
+ },
|
|
|
+ // 跳转到商品排序页面
|
|
|
+ navigateToGoodsSort(item) {
|
|
|
+ uni.navigateTo({ url: '/admin/goods/goodsSort?id=' + item.id + "&name=" + item.categoryName })
|
|
|
+ },
|
|
|
+ addHbRuleFn() {
|
|
|
+ uni.navigateTo({ url: '/admin/hb/sendHb'})
|
|
|
+ },
|
|
|
+ getCategoryList() {
|
|
|
+ return categoryListInfo().then((res) => {
|
|
|
+ let data = { code: res.code, msg: res.msg, data: { list: res.data } };
|
|
|
+ this.completes(data);
|
|
|
+ });
|
|
|
+ },
|
|
|
+ // 拖拽相关方法
|
|
|
+ transformStyle(index) {
|
|
|
+ if (index === this.draggedIndex) {
|
|
|
+ return `translateY(${this.dragOffsetY}rpx)`;
|
|
|
+ }
|
|
|
+ return 'translateY(0rpx)';
|
|
|
+ },
|
|
|
+
|
|
|
+ dragStart(e) {
|
|
|
+ const index = parseInt(e.currentTarget.dataset.index);
|
|
|
+ this.draggedIndex = index;
|
|
|
+ this.draggedItem = this.list.data[index];
|
|
|
+ this.startY = e.touches[0].clientY;
|
|
|
+ this.isDragging = true;
|
|
|
+ },
|
|
|
+
|
|
|
+ dragMove(e) {
|
|
|
+ if (!this.isDragging || this.draggedIndex === -1) return;
|
|
|
+
|
|
|
+ const currentY = e.touches[0].clientY;
|
|
|
+ const deltaY = currentY - this.startY;
|
|
|
+
|
|
|
+ const systemInfo = uni.getSystemInfoSync();
|
|
|
+ const pixelRatio = 750 / systemInfo.windowWidth;
|
|
|
+ // 根据设备像素比例转换为rpx单位
|
|
|
+ const deltaYrpx = deltaY * pixelRatio;
|
|
|
+
|
|
|
+ this.dragOffsetY = deltaYrpx;
|
|
|
+
|
|
|
+ // 计算目标位置
|
|
|
+ const itemHeightrpx = this.itemHeight * pixelRatio;
|
|
|
+
|
|
|
+ // 使用更精确的计算方法确定移动的项目数
|
|
|
+ const moveDistance = Math.abs(deltaYrpx);
|
|
|
+ const moveDirection = deltaYrpx > 0 ? 1 : -1;
|
|
|
+ const moveItems = Math.floor(moveDistance / (itemHeightrpx * 0.5)) * moveDirection;
|
|
|
+
|
|
|
+ // 确保目标索引在有效范围内
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ dragEnd() {
|
|
|
+ if (!this.isDragging) return;
|
|
|
+
|
|
|
+ // 重置拖拽状态
|
|
|
+ this.draggedIndex = -1;
|
|
|
+ this.draggedItem = null;
|
|
|
+ this.dragOffsetY = 0;
|
|
|
+ this.isDragging = false;
|
|
|
+ this.startY = 0;
|
|
|
+
|
|
|
+ // 更新排序值并发送到后端
|
|
|
+ this.updateSortOrder();
|
|
|
+ },
|
|
|
+
|
|
|
+ updateSortOrder() {
|
|
|
+ // 更新每个项目的inTurn值,从大到小排序
|
|
|
+ const sortData = this.list.data.map((item, index) => ({
|
|
|
+ id: item.id,
|
|
|
+ inTurn: this.list.data.length - index // 反向索引,使第一个项目有最大值
|
|
|
+ // 如果是分页加载的,请用 data.total 替换掉 this.list.data.length
|
|
|
+ }));
|
|
|
+
|
|
|
+ // 调用API更新排序
|
|
|
+ sort({ items: sortData })
|
|
|
+ .then((res) => {
|
|
|
+ if (res.code === 1) {
|
|
|
+ this.$msg('已更新');
|
|
|
+ } else {
|
|
|
+ this.$msg('排序更新失败');
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .catch((err) => {
|
|
|
+ console.error('更新排序失败:', err);
|
|
|
+ this.$msg('排序更新失败');
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ // 上移
|
|
|
+ upFn(id) {
|
|
|
+ const index = this.list.data.findIndex((item) => item.id === id);
|
|
|
+ if (index > 0) {
|
|
|
+ const newData = [...this.list.data];
|
|
|
+ const temp = newData[index];
|
|
|
+ newData[index] = newData[index - 1];
|
|
|
+ newData[index - 1] = temp;
|
|
|
+ this.list.data = newData;
|
|
|
+ this.updateSortOrder();
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 下移
|
|
|
+ downFn(id) {
|
|
|
+ const index = this.list.data.findIndex((item) => item.id === id);
|
|
|
+ if (index < this.list.data.length - 1) {
|
|
|
+ const newData = [...this.list.data];
|
|
|
+ const temp = newData[index];
|
|
|
+ newData[index] = newData[index + 1];
|
|
|
+ newData[index + 1] = temp;
|
|
|
+ this.list.data = newData;
|
|
|
+ this.updateSortOrder();
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 置顶
|
|
|
+ topFn(id) {
|
|
|
+ const index = this.list.data.findIndex((item) => item.id === id);
|
|
|
+ if (index > 0) {
|
|
|
+ const newData = [...this.list.data];
|
|
|
+ const targetItem = newData[index];
|
|
|
+
|
|
|
+ // 将目标项移到第一位
|
|
|
+ newData.splice(index, 1);
|
|
|
+ newData.unshift(targetItem);
|
|
|
+
|
|
|
+ this.list.data = newData;
|
|
|
+ this.updateSortOrder();
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 置底
|
|
|
+ bottomFn(id) {
|
|
|
+ const index = this.list.data.findIndex((item) => item.id === id);
|
|
|
+ if (index < this.list.data.length - 1) {
|
|
|
+ const newData = [...this.list.data];
|
|
|
+ const targetItem = newData[index];
|
|
|
+
|
|
|
+ // 将目标项移到最后一位
|
|
|
+ newData.splice(index, 1);
|
|
|
+ newData.push(targetItem);
|
|
|
+
|
|
|
+ this.list.data = newData;
|
|
|
+ this.updateSortOrder();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+};
|
|
|
+</script>
|
|
|
+<style lang="scss" scoped>
|
|
|
+.app-content {
|
|
|
+ min-height: calc(100vh - 100rpx);
|
|
|
+ padding-bottom: 100rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.list-wrap {
|
|
|
+ position: relative;
|
|
|
+ background-color: #fff;
|
|
|
+
|
|
|
+ .list {
|
|
|
+ height: 160rpx;
|
|
|
+ @include disFlex(center, flex-start);
|
|
|
+ padding: 30rpx 0;
|
|
|
+ margin: 0 30rpx;
|
|
|
+ color: $fontColor3;
|
|
|
+ border-bottom: 1px solid $borderColor;
|
|
|
+ position: relative;
|
|
|
+
|
|
|
+ .list-img {
|
|
|
+ width: 130rpx;
|
|
|
+ height: 130rpx;
|
|
|
+
|
|
|
+ image {
|
|
|
+ width: 130rpx;
|
|
|
+ height: 130rpx;
|
|
|
+ border-radius: 20rpx;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .list-det {
|
|
|
+ margin-left: 20rpx;
|
|
|
+
|
|
|
+ &>div {
|
|
|
+ margin-top: 14rpx;
|
|
|
+
|
|
|
+ &:first-child {
|
|
|
+ margin-top: 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.move-btn {
|
|
|
+ position: absolute;
|
|
|
+ top: 65rpx;
|
|
|
+ color: blue;
|
|
|
+ border: 1px solid #cccccc;
|
|
|
+ padding: 5rpx 10rpx;
|
|
|
+ border-radius: 50%;
|
|
|
+}
|
|
|
+
|
|
|
+.move-btn-line {
|
|
|
+ position: absolute;
|
|
|
+ top: 65rpx;
|
|
|
+ color: blue;
|
|
|
+}
|
|
|
+
|
|
|
+// 拖拽相关样式
|
|
|
+.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: 12rpx;
|
|
|
+ transform: scale(1.05);
|
|
|
+}
|
|
|
+
|
|
|
+.drag-handle {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ width: 70rpx;
|
|
|
+ height: 70rpx;
|
|
|
+ border-radius: 12rpx;
|
|
|
+ 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 4rpx 16rpx rgba(0, 122, 255, 0.2);
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|