| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342 |
- <template>
- <view class="wrap">
- <!-- 可移动区域:高度随数据多少自动撑开 -->
- <mescroll-body ref="mescrollRef" @init="mescrollInit" @down="downCallback" @up="upCallback" :down="downOption"
- :up="upOption">
- <view v-if="list.length>0">
- <movable-area class="movable-area" :style="{ height: areaHeight + 'px' }">
- <movable-view v-for="(item, index) in list" :key="item.id" class="movable-row"
- :style="{ height: rowHeight + 'px' }" direction="vertical" :y="item.y" :disabled="!canMove"
- @longpress="handleLongPress(index)" @change="onChange" @touchend="handleTouchEnd">
- <!-- 左侧勾选(可选) -->
- <view class="choose" @tap.stop="toggleCheck(item)">
- <image v-if="item.checked" src="@/static/image/hall/choose_icon.png" />
- <image v-else src="@/static/image/hall/choose_moren_icon.png" />
- </view>
- <!-- 主内容 -->
- <image class="pic" :src="item.cover || item.thumbnail" mode="aspectFill" />
- <view class="title textTwo">{{ item.title }}</view>
- <!-- 右侧拖拽把手 -->
- <view v-if="type == 'edit'" class="handle" @longpress.stop="handleLongPress(index)">
- <u-icon name="list" color="#999" size="24" />
- </view>
- </movable-view>
- </movable-area>
- </view>
- </mescroll-body>
- <!-- 底部操作栏 -->
- <view class="footer">
- <view>已选择 {{ checkedCount }} 个视频</view>
- <view class="addbtn" @tap="handleSubmit">
- {{ type === "add" ? "加入合集" : "移除合集" }}
- </view>
- </view>
- </view>
- </template>
- <script>
- import {
- videoAdd,
- removeVideo,
- updateVideo,
- videoCollectionMyList,
- videoCollectionList,
- getVideoList,
- collectionList,
- updateSort,
- getMyVideoList
- } from "@/api/expert.js"
- const ROW = 120; // 每行高度 rpx → px 转换后
- export default {
- data() {
- return {
- type: "add",
- isOperate: true, // 是否进入编辑模式
- list: [], // 数据
- rowHeight: 0, // 每行 px 高度
- areaHeight: 0, // 区域 px 高度
- canMove: false, // 是否正在拖拽
- dragIndex: -1, // 当前拖拽项下标
- mescroll: null,
- downOption: { //下拉刷新
- use: true,
- auto: false // 不自动加载 (mixin已处理第一个tab触发downCallback)
- },
- upOption: {
- onScroll: false,
- use: true, // 是否启用上拉加载; 默认true
- page: {
- pae: 0, // 当前页码,默认0,回调之前会加1,即callback(page)会从1开始
- size: 10 // 每页数据的数量,默认10
- },
- noMoreSize: 5, // 配置列表的总数量要大于等于5条才显示'-- END --'的提示
- textNoMore: "已经到底了",
- empty: {
- icon: 'https://cos.his.cdwjyyh.com/fs/20240423/cf4a86b913a04341bb44e34bb4d37aa2.png',
- tip: '暂无数据'
- }
- },
- };
- },
- computed: {
- checkedCount() {
- return this.list.filter((i) => i.checked).length;
- },
- },
- onLoad(opt) {
- this.type = opt.type || "add";
- // this.getList()
- const sys = uni.getSystemInfoSync();
- this.rowHeight = (ROW * sys.windowWidth) / 750;
- // 模拟 8 条数据
- // const raw = Array.from({
- // length: 8
- // }, (_, i) => ({
- // id: i,
- // title: "西藏旅游" + i,
- // checked: false,
- // }));
- // this.initData(raw);
- },
- methods: {
- mescrollInit(mescroll) {
- this.mescroll = mescroll;
- },
- downCallback(mescroll) {
- mescroll.resetUpScroll()
- },
- async upCallback(page) {
- let that = this;
- let res = ''
- if (this.type == 'edit') {
- let params = {
- status: 1,
- collectionId: uni.getStorageSync('collectionData').collectionId || '',
- pageNum: page.num,
- pageSize: page.size
- }
- res = await collectionList(params)
- } else {
- let params = {
- status: 1,
- collectionId: uni.getStorageSync('collectionData').collectionId || '',
- talentId: uni.getStorageSync('expertInfo').talentId,
- pageNum: page.num,
- pageSize: page.size
- }
- res = await getMyVideoList(params)
- // res = await getVideoList(params)
- }
- if (res.code == 200) {
- let data = res.data.list.map((item, index) => ({
- ...item,
- checked: false,
- sort: index + 1,
- y: index * this.rowHeight,
- }));
- if (page.num == 1) that.list = []
- that.list = that.list.concat(data);
- that.mescroll.endBySize(data.length, res.data.total);
- this.areaHeight = data.length * this.rowHeight;
- }
- },
- async getList() {
- let res = ''
- if (this.type == 'edit') {
- let params = {
- status: 1,
- collectionId: uni.getStorageSync('collectionData').collectionId || ''
- }
- res = await collectionList(params)
- } else {
- let params = {
- status: 1,
- collectionId: uni.getStorageSync('collectionData').collectionId || '',
- talentId: uni.getStorageSync('expertInfo').talentId,
- }
- res = await getMyVideoList(params)
- // res = await getVideoList(params)
- }
- if (res.code == 200) {
- this.list = res.data.list.map((item, index) => ({
- ...item,
- checked: false,
- sort: index + 1,
- y: index * this.rowHeight,
- }));
- this.areaHeight = this.list.length * this.rowHeight;
- }
- },
- // 初始化坐标
- initData(src) {
- const sys = uni.getSystemInfoSync();
- // rpx → px
- this.rowHeight = (ROW * sys.windowWidth) / 750;
- },
- // 长按把手启动拖拽
- handleLongPress(index) {
- this.canMove = true;
- this.dragIndex = index;
- },
- // 拖拽过程中 movable-view 会不断触发 change
- onChange(e) {
- if (!this.canMove || e.detail.source !== "touch") return;
- const curY = e.detail.y;
- let targetIdx = Math.round(curY / this.rowHeight);
- targetIdx = Math.max(0, Math.min(targetIdx, this.list.length - 1));
- if (targetIdx !== this.dragIndex) {
- this.swapData(this.dragIndex, targetIdx);
- this.dragIndex = targetIdx;
- }
- },
- // 交换数据并重置 y
- async swapData(from, to) {
- const arr = [...this.list];
- const tmp = arr.splice(from, 1)[0];
- arr.splice(to, 0, tmp);
- let updateData = arr.map((item, idx) => ({
- ...item,
- sort: idx + 1,
- y: idx * this.rowHeight
- }));
- let params = updateData.map(({
- id,
- sort
- }) => ({
- id,
- sort
- }));
- const res = await updateSort(params)
- // this.list =
- if (res.code == 200) {
- this.getList()
- }
- },
- // 松手
- handleTouchEnd() {
- this.canMove = false;
- this.dragIndex = -1;
- },
- toggleCheck(item) {
- item.checked = !item.checked;
- },
- async handleSubmit() {
- if (this.type === "add") {
- let params = []
- this.list.forEach((item, idx) => {
- if (item.checked) {
- params.push({
- collectionId: 7,
- videoId: item.id * 1
- })
- }
- });
- const res = await videoAdd(params)
- // const res = await updateVideo(params)
- if (res.code == 200) {
- uni.showToast({
- title: '加入成功!',
- })
- setTimeout(() => {
- uni.navigateBack()
- }, 1000)
- }
- }
- if (this.type === "edit") {
- uni.showModal({
- title: "移除合集",
- content: "合集内的视频移除后,视频会继续保留在个人页",
- confirmText: "移除",
- confirmColor: "#FF5030",
- success: async (result) => {
- let params = this.list.filter(item => item.checked).map(item => item.id);
- const res = await removeVideo(params)
- if (res.code == 200) {
- uni.showToast({
- title: '移除成功!',
- })
- setTimeout(() => {
- uni.navigateBack()
- }, 1000)
- }
- }
- });
- }
- },
- },
- };
- </script>
- <style lang="scss" scoped>
- .wrap {
- padding-bottom: 140rpx; // 给底部栏留空
- }
- .movable-area {
- width: 100%;
- }
- .movable-row {
- width: 100%;
- display: flex;
- align-items: center;
- padding: 28rpx;
- box-sizing: border-box;
- background: #fff;
- border-bottom: 1rpx solid #eee;
- }
- .choose {
- margin-right: 20rpx;
- image {
- width: 36rpx;
- height: 36rpx;
- }
- }
- .pic {
- width: 100rpx;
- height: 100rpx;
- border-radius: 10rpx;
- flex-shrink: 0;
- }
- .title {
- flex: 1;
- padding: 0 20rpx;
- font-size: 30rpx;
- color: #333;
- }
- .handle {
- padding: 20rpx;
- }
- .footer {
- position: fixed;
- left: 0;
- bottom: 0;
- width: 100%;
- display: flex;
- align-items: center;
- justify-content: space-between;
- padding: 24rpx 40rpx;
- box-sizing: border-box;
- background: #fff;
- border-top: 1rpx solid #eee;
- font-size: 28rpx;
- color: #999;
- .addbtn {
- padding: 20rpx 40rpx;
- background: #FF5030;
- color: #fff;
- border-radius: 50rpx;
- }
- }
- </style>
|