更新最新代码
This commit is contained in:
@@ -0,0 +1,127 @@
|
||||
const { itemsOf, startList, applyList, failList, finishList, withListPagination } = require('../../utils/list-pagination');
|
||||
const { withDataCache } = require('../../utils/page-cache');
|
||||
const { getLayout } = require('../../utils/layout');
|
||||
// pages/lovewords/lovewords.js - 一起听过的歌
|
||||
const { api } = require('../../utils/request');
|
||||
Page(withDataCache(withListPagination({
|
||||
onResize: function() { this.setData(getLayout()); },
|
||||
data: { loading: true, loadError: false,
|
||||
list: [],
|
||||
showModal: false,
|
||||
isEdit: false,
|
||||
editId: '',
|
||||
form: { song_name: '', artist: '', note: '' }
|
||||
},
|
||||
|
||||
onLoad: function() {
|
||||
this.setData(getLayout());
|
||||
this.loadData();
|
||||
},
|
||||
onShow: function() { this.loadData(); },
|
||||
|
||||
onPullDownRefresh: async function() {
|
||||
await this.loadData();
|
||||
wx.stopPullDownRefresh();
|
||||
},
|
||||
|
||||
onShareAppMessage: function() {
|
||||
return { title: '让所有的爱有迹可循', path: '/pages/lovewords/lovewords', imageUrl: '/images/share.png' };
|
||||
},
|
||||
onShareTimeline: function() {
|
||||
return { title: '让所有的爱有迹可循', imageUrl: '/images/share.png' };
|
||||
},
|
||||
|
||||
loadData: async function(page) {
|
||||
const ticket = startList(this, page);
|
||||
if (!ticket) return;
|
||||
try {
|
||||
const list = await api.songsList({page:ticket.page,page_size:20});
|
||||
const items = itemsOf(list).map(function(item) {
|
||||
if (item.created_at) {
|
||||
var d = new Date(item.created_at);
|
||||
item.date_month = String(d.getMonth() + 1).padStart(2, '0');
|
||||
item.date_day = String(d.getDate()).padStart(2, '0');
|
||||
}
|
||||
return item;
|
||||
});
|
||||
applyList(this, ticket, list, items, 'list');
|
||||
} catch (e) {
|
||||
failList(this,ticket);
|
||||
console.error(e);
|
||||
wx.showToast({ title: '加载失败', icon: 'none' });
|
||||
}
|
||||
finally { finishList(this,ticket); }
|
||||
},
|
||||
|
||||
noop: function() {},
|
||||
onSongMenu: function(e) {
|
||||
wx.showActionSheet({ itemList:['编辑歌曲', '删除歌曲'], success:(res) => {
|
||||
if (res.tapIndex === 0) this.editSong(e);
|
||||
else if (res.tapIndex === 1) this.deleteSong(e);
|
||||
}});
|
||||
},
|
||||
deleteSong: function(e) {
|
||||
var id = e.currentTarget.dataset.id;
|
||||
wx.showModal({
|
||||
title: '确认删除',
|
||||
content: '确定要删除这首歌吗?',
|
||||
success: async (res) => {
|
||||
if (res.confirm) {
|
||||
try {
|
||||
await api.songsDelete({ id: id });
|
||||
wx.showToast({ title: '已删除', icon: 'success' });
|
||||
this.loadData();
|
||||
} catch (err) { wx.showToast({ title: err.error || '删除失败', icon: 'none' }); }
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 编辑歌曲:打开弹窗并带入原数据
|
||||
editSong: function(e) {
|
||||
var ds = e.currentTarget.dataset;
|
||||
this.setData({
|
||||
showModal: true,
|
||||
isEdit: true,
|
||||
editId: ds.id,
|
||||
form: { song_name: ds.name || '', artist: ds.artist || '', note: ds.note || '' }
|
||||
});
|
||||
},
|
||||
|
||||
// ===== 添加/编辑弹窗 =====
|
||||
showModal: function() {
|
||||
this.setData({ showModal: true, isEdit: false, editId: '', form: { song_name: '', artist: '', note: '' } });
|
||||
},
|
||||
hideModal: function() { this.setData({ showModal: false, isEdit: false, editId: '' }); },
|
||||
onSongNameInput: function(e) { this.setData({ 'form.song_name': e.detail.value }); },
|
||||
onArtistInput: function(e) { this.setData({ 'form.artist': e.detail.value }); },
|
||||
onNoteInput: function(e) { this.setData({ 'form.note': e.detail.value }); },
|
||||
|
||||
submit: async function() {
|
||||
var form = this.data.form;
|
||||
if (!form.song_name || !form.artist) {
|
||||
wx.showToast({ title: '请填写歌曲名和歌手名', icon: 'none' }); return;
|
||||
}
|
||||
try {
|
||||
if (this.data.isEdit && this.data.editId) {
|
||||
await api.songsUpdate({ id: this.data.editId, song_name: form.song_name, artist: form.artist, note: form.note || '' });
|
||||
wx.showToast({ title: '已修改 ✏️', icon: 'success' });
|
||||
} else {
|
||||
await api.songsAdd(form);
|
||||
wx.showToast({ title: '收藏成功 🎵', icon: 'success' });
|
||||
}
|
||||
this.hideModal();
|
||||
this.loadData();
|
||||
} catch (e) {
|
||||
wx.showToast({ title: e.error || '保存失败', icon: 'none' });
|
||||
}
|
||||
},
|
||||
|
||||
goToPublish: function() {
|
||||
this.showModal();
|
||||
},
|
||||
|
||||
goBack: function() { wx.navigateBack(); },
|
||||
goHome: function() { wx.switchTab({ url: '/pages/index/index' }); },
|
||||
goProfile: function() { wx.switchTab({ url: '/pages/profile/profile' }); }
|
||||
}, 'loadData'), {"loadData": ["songsList"]}));
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"navigationStyle": "custom",
|
||||
"enablePullDownRefresh": true,
|
||||
"usingComponents": {
|
||||
"app-nav": "/components/app-nav/app-nav",
|
||||
"page-state": "/components/page-state/page-state"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
<view class="app-shell app-shell--secondary" style="{{layoutStyle}}">
|
||||
<launch-transition />
|
||||
<!-- pages/lovewords/lovewords.wxml - 一起听过的歌 -->
|
||||
<app-nav title="一起听的歌" back="{{true}}" />
|
||||
|
||||
|
||||
|
||||
<scroll-view class="page-bg" scroll-y bindscrolltolower="loadMore" lower-threshold="120" show-scrollbar="{{false}}" bounces="{{true}}">
|
||||
<view class="c-body"><view class="c-heading j-row"><view><text class="j-eyebrow">OUR SOUNDTRACK</text><text class="j-page-title">一起听过的旋律</text></view><button class="j-button j-button-small" bindtap="goToPublish">+ 添加</button></view>
|
||||
<page-state wx:if="{{loading}}" kind="loading" title="正在加载" /><page-state wx:elif="{{loadError}}" kind="error" title="加载失败" description="请检查网络后重新加载" action="重试" bind:action="loadData" />
|
||||
<view class="song-list" wx:if="{{!loading && !loadError && list.length}}">
|
||||
<view class="song-item" wx:for="{{list}}" wx:key="id">
|
||||
<view class="song-number">{{index < 9 ? '0' + (index + 1) : index + 1}}</view>
|
||||
<view class="song-content">
|
||||
<text class="song-name">{{item.song_name}}</text><text class="song-artist">{{item.artist}}</text>
|
||||
<text class="song-note" wx:if="{{item.note}}">{{item.note}}</text>
|
||||
<view class="song-footer"><text>{{item.nickname || item.author || '我们'}}</text><text wx:if="{{item.date_month}}">{{item.date_month}}/{{item.date_day}}</text></view>
|
||||
</view>
|
||||
<view class="song-menu" bindtap="onSongMenu" data-id="{{item.id}}" data-name="{{item.song_name}}" data-artist="{{item.artist}}" data-note="{{item.note}}" aria-label="歌曲操作"><image src="/images/more.svg" mode="aspectFit" /></view>
|
||||
</view>
|
||||
</view>
|
||||
<page-state wx:if="{{!loading && !loadError && !list.length}}" title="收藏我们的第一首歌" description="让某一段旋律,成为两个人的记忆" action="添加歌曲" bind:action="goToPublish" />
|
||||
</view>
|
||||
<view class="j-pagination" wx:if="{{!loading && !loadError && total > 0}}"><text wx:if="{{loadingMore}}">正在加载…</text><text wx:elif="{{moreError}}" bindtap="loadMore">加载失败,点击重试</text><text wx:elif="{{hasMore}}" bindtap="loadMore">加载更多</text><text wx:else>已加载全部</text></view>
|
||||
</scroll-view>
|
||||
|
||||
<!-- 添加弹窗 -->
|
||||
<view class="modal-overlay" wx:if="{{showModal}}" bindtap="hideModal">
|
||||
<view class="modal" catchtap="noop">
|
||||
<button class="modal-close" bindtap="hideModal"><image src="/images/close.svg" mode="aspectFit" /></button>
|
||||
<text class="title">{{isEdit ? '编辑歌曲' : '收藏歌曲'}}</text>
|
||||
<text class="modal-subtitle">记录我们一起听过的歌</text>
|
||||
<view class="input-group">
|
||||
<label>歌曲名</label>
|
||||
<input placeholder-class="handwritten-placeholder" class="input" placeholder="输入歌曲名" value="{{form.song_name}}" bindinput="onSongNameInput" />
|
||||
</view>
|
||||
<view class="input-group">
|
||||
<label>歌手</label>
|
||||
<input placeholder-class="handwritten-placeholder" class="input" placeholder="输入歌手名" value="{{form.artist}}" bindinput="onArtistInput" />
|
||||
</view>
|
||||
<view class="input-group">
|
||||
<label>备注(选填)</label>
|
||||
<input placeholder-class="handwritten-placeholder" class="input" placeholder="一句话,限60字" maxlength="60" value="{{form.note}}" bindinput="onNoteInput" />
|
||||
</view>
|
||||
<button class="btn btn-primary" bindtap="submit" hover-class="none">{{isEdit ? '保存修改' : '保存'}}</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</view>
|
||||
@@ -0,0 +1,17 @@
|
||||
@import '../../styles/common.wxss';
|
||||
@import '../../styles/design.wxss';
|
||||
@import '../../styles/journal.wxss';
|
||||
@import '../../styles/companion.wxss';
|
||||
.song-list { background:#FFFDF8; border:1rpx solid #E9DDD0; border-radius:12rpx 32rpx 12rpx 12rpx; padding:0 26rpx; }
|
||||
.song-item { display:flex; align-items:flex-start; gap:18rpx; padding:30rpx 0; border-bottom:1rpx solid #E9DDD0; }.song-item:last-child { border-bottom:0; }
|
||||
.song-number { flex-shrink:0; width:32rpx; padding-top:5rpx; font-size:22rpx; color:#A39386; font-variant-numeric:tabular-nums; }
|
||||
.song-content { min-width:0; flex:1; }.song-name { display:block; font-size:29rpx; line-height:1.5; font-weight:600; color:#352E2A; overflow-wrap:break-word; }
|
||||
.song-artist { display:block; font-size:24rpx; color:#85776D; margin-top:4rpx; line-height:1.5; }
|
||||
.song-note { display:block; margin-top:14rpx; font-size:24rpx; line-height:1.6; color:#65594F; }
|
||||
.song-footer { display:flex; gap:16rpx; flex-wrap:wrap; margin-top:16rpx; font-size:21rpx; color:#A39386; }
|
||||
.song-menu { width:64rpx; height:64rpx; margin-right:-12rpx; display:flex; align-items:center; justify-content:center; flex-shrink:0; }.song-menu image { width:36rpx; height:36rpx; }
|
||||
.modal-overlay { z-index:1200; }.modal-close { background:transparent; }.modal .title { display:block; text-align:left; font-size:32rpx; color:#352E2A; }.modal-subtitle { text-align:left; }
|
||||
|
||||
@import '../../styles/button-theme.wxss';
|
||||
|
||||
@import '../../styles/typography.wxss';
|
||||
Reference in New Issue
Block a user