|
|
@@ -0,0 +1,465 @@
|
|
|
+<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
|
|
|
+ }">
|
|
|
+ <view class="list-img" @click="navigateToGoodsSort(item.id)">
|
|
|
+ <image :src="item.img" mode="aspectFit" ></image>
|
|
|
+ </view>
|
|
|
+ <view class="list-det" @click="navigateToGoodsSort(item.id)">
|
|
|
+ <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: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 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>
|
|
|
+
|
|
|
+ <view
|
|
|
+ style="position:absolute;top:58upx;right:28upx;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>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </block>
|
|
|
+ </block>
|
|
|
+ <block v-else>
|
|
|
+ <app-wrapper-empty title="暂无数据" :is-empty="$util.isEmpty(list.data)" />
|
|
|
+ </block>
|
|
|
+ </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 { categoryListInfo, categoryAddB, categoryUpdateB } from '@/api/goods'
|
|
|
+import { sort } from '@/api/category'
|
|
|
+export default {
|
|
|
+ name: 'category',
|
|
|
+ components: {
|
|
|
+ ModalModule,
|
|
|
+ AppUploader,
|
|
|
+ OperateModule,
|
|
|
+ AppWrapperEmpty
|
|
|
+ },
|
|
|
+ mixins: [list],
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ modifyModal: false,
|
|
|
+
|
|
|
+ draggedIndex: -1,
|
|
|
+ draggedItem: null,
|
|
|
+ dragOffsetY: 0,
|
|
|
+ isDragging: false,
|
|
|
+ itemHeight: 160, // 列表项高度,单位upx
|
|
|
+ startY: 0,
|
|
|
+ }
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ },
|
|
|
+ onPullDownRefresh() {
|
|
|
+ this.resetList()
|
|
|
+ this._list().then(res => {
|
|
|
+ uni.stopPullDownRefresh()
|
|
|
+ })
|
|
|
+ },
|
|
|
+ onReachBottom() {
|
|
|
+ if (!this.list.finished) {
|
|
|
+ this._list().then(res => {
|
|
|
+ uni.stopPullDownRefresh()
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ uni.stopPullDownRefresh()
|
|
|
+ }
|
|
|
+ },
|
|
|
+ onLoad() {
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ // 跳转到商品排序页面
|
|
|
+ navigateToGoodsSort(categoryId) {
|
|
|
+ uni.navigateTo({
|
|
|
+ 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) {
|
|
|
+ if (index === this.draggedIndex) {
|
|
|
+ return `translateY(${this.dragOffsetY}upx)`
|
|
|
+ }
|
|
|
+ return 'translateY(0upx)'
|
|
|
+ },
|
|
|
+
|
|
|
+ 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
|
|
|
+
|
|
|
+ // 添加拖拽时的视觉反馈
|
|
|
+ // 设置当前拖拽项的样式
|
|
|
+ // 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) {
|
|
|
+ if (!this.isDragging || this.draggedIndex === -1) return
|
|
|
+
|
|
|
+ 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)
|
|
|
+
|
|
|
+ this.dragOffsetY = deltaYupx
|
|
|
+
|
|
|
+ // 更精确地计算目标位置
|
|
|
+ const itemHeightUpx = this.itemHeight * (750 / uni.getSystemInfoSync().windowWidth)
|
|
|
+
|
|
|
+ // 使用更精确的计算方法确定移动的项目数
|
|
|
+ const moveDistance = Math.abs(deltaYupx)
|
|
|
+ const moveDirection = deltaYupx > 0 ? 1 : -1
|
|
|
+ const moveItems = Math.floor(moveDistance / (itemHeightUpx * 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
|
|
|
+
|
|
|
+ // 提供触感反馈
|
|
|
+ // uni.vibrateShort()
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ dragEnd(e) {
|
|
|
+ console.log('dragEnd')
|
|
|
+ if (!this.isDragging) return
|
|
|
+
|
|
|
+ // 重置拖拽状态
|
|
|
+ this.draggedIndex = -1
|
|
|
+ this.draggedItem = null
|
|
|
+ this.dragOffsetY = 0
|
|
|
+ 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值,从大到小排序(值越大越靠前)
|
|
|
+ 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 => {
|
|
|
+ if (res.code === 1) {
|
|
|
+ this.$msg('排序更新成功')
|
|
|
+ } else {
|
|
|
+ this.$msg('排序更新失败')
|
|
|
+ }
|
|
|
+ }).catch(err => {
|
|
|
+ console.error('更新排序失败:', err)
|
|
|
+ this.$msg('排序更新失败')
|
|
|
+ })
|
|
|
+ },
|
|
|
+
|
|
|
+ // 原有的上移下移方法
|
|
|
+ upFn(id) {
|
|
|
+ console.log('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) {
|
|
|
+ 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]
|
|
|
+ const temp = newData[index]
|
|
|
+ newData[index] = newData[index + 1]
|
|
|
+ newData[index + 1] = temp
|
|
|
+ this.list.data = newData
|
|
|
+ this.updateSortOrder()
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 置顶
|
|
|
+ topFn(id) {
|
|
|
+ console.log('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) {
|
|
|
+ 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]
|
|
|
+ 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 - 100upx);
|
|
|
+ padding-bottom: 100upx;
|
|
|
+}
|
|
|
+.list-wrap {
|
|
|
+ position: relative;
|
|
|
+ background-color: #fff;
|
|
|
+ .list {
|
|
|
+ height: 160upx;
|
|
|
+ @include disFlex(center, flex-start);
|
|
|
+ padding: 30upx 0;
|
|
|
+ margin: 0 30upx;
|
|
|
+ color: $fontColor3;
|
|
|
+ border-bottom: 1px solid $borderColor;
|
|
|
+ position:relative;
|
|
|
+ .list-index {
|
|
|
+ width: 50upx;
|
|
|
+ }
|
|
|
+ .list-img {
|
|
|
+ width: 130upx;
|
|
|
+ height: 130upx;
|
|
|
+ image {
|
|
|
+ width:130upx;
|
|
|
+ height:130upx;
|
|
|
+ border-radius: 20upx;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .list-det {
|
|
|
+ margin-left: 20upx;
|
|
|
+ & > div {
|
|
|
+ margin-top: 14upx;
|
|
|
+ &:first-child {
|
|
|
+ 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;
|
|
|
+ color:blue;
|
|
|
+ border:1px solid #CCCCCC;
|
|
|
+ padding:5upx 10upx;
|
|
|
+ border-radius:50%;
|
|
|
+}
|
|
|
+.move-btn-line {
|
|
|
+ position: absolute;
|
|
|
+ top:65upx;
|
|
|
+ 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: 12upx;
|
|
|
+ transform: scale(1.05);
|
|
|
+}
|
|
|
+
|
|
|
+.drag-handle {
|
|
|
+ transition: all 0.2s ease;
|
|
|
+}
|
|
|
+
|
|
|
+.drag-handle:active {
|
|
|
+ transform: scale(1.1);
|
|
|
+ opacity: 0.8;
|
|
|
+}
|
|
|
+</style>
|