feat: 完善人生轨迹详情页功能及微信小程序登录优化
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<view class="script-library">
|
||||
<view class="script-library" @click="closeScriptMenu">
|
||||
<view class="page-head">
|
||||
<view class="back-title" @click="backToScript">
|
||||
<text class="back-arrow">‹</text>
|
||||
@@ -71,7 +71,27 @@
|
||||
</view>
|
||||
<view class="right-state">
|
||||
<text class="state-pill" :class="'state-' + getStatus(script)">{{ getStatusLabel(script) }}</text>
|
||||
<text class="ellipsis" @click.stop="openScriptMenu(script)">•••</text>
|
||||
<view class="menu-wrap">
|
||||
<text class="ellipsis" :class="{ active: activeMenuId === String(script.id) }" @click.stop="toggleScriptMenu(script)">•••</text>
|
||||
<view v-if="activeMenuId === String(script.id)" class="card-menu" @click.stop>
|
||||
<view class="menu-action" @click="toggleFavorite(script)">
|
||||
<text class="menu-dot"></text>
|
||||
<text>{{ isFavorite(script) ? '取消收藏' : '收藏剧本' }}</text>
|
||||
</view>
|
||||
<view class="menu-action" @click="continueScript(script)">
|
||||
<text class="menu-dot"></text>
|
||||
<text>继续生成</text>
|
||||
</view>
|
||||
<view class="menu-action" @click="openScriptDetailFromMenu(script)">
|
||||
<text class="menu-dot"></text>
|
||||
<text>查看详情</text>
|
||||
</view>
|
||||
<view class="menu-action danger" @click="requestDeleteScript(script)">
|
||||
<text class="menu-dot"></text>
|
||||
<text>删除剧本</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -112,6 +132,17 @@
|
||||
<text class="empty-text">去爽文生成页写下一句灵感,生成你的第一段平行人生。</text>
|
||||
<view class="empty-action" @click="createScript">新建剧本</view>
|
||||
</view>
|
||||
|
||||
<view v-if="deleteTarget" class="confirm-mask" @click.stop="cancelDeleteScript">
|
||||
<view class="confirm-panel" @click.stop>
|
||||
<text class="confirm-title">删除剧本</text>
|
||||
<text class="confirm-copy">确定删除《{{ deleteTarget.title || '未命名剧本' }}》吗?删除后将无法在历史剧本中查看。</text>
|
||||
<view class="confirm-actions">
|
||||
<view class="confirm-btn secondary" @click="cancelDeleteScript">取消</view>
|
||||
<view class="confirm-btn danger" :class="{ disabled: deletingScript }" @click="confirmDeleteScript">{{ deletingScript ? '删除中' : '确认删除' }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
@@ -126,6 +157,9 @@ const keyword = ref('')
|
||||
const sortMode = ref('updated')
|
||||
const viewMode = ref('list')
|
||||
const localFavorites = ref(uni.getStorageSync('script_favorites') || {})
|
||||
const activeMenuId = ref('')
|
||||
const deleteTarget = ref(null)
|
||||
const deletingScript = ref(false)
|
||||
|
||||
const typeTabs = [
|
||||
{ label: '长篇', value: 'long' },
|
||||
@@ -350,23 +384,73 @@ const toggleViewMode = () => {
|
||||
viewMode.value = viewMode.value === 'list' ? 'grid' : 'list'
|
||||
}
|
||||
|
||||
const openScriptMenu = (script) => {
|
||||
const closeScriptMenu = () => {
|
||||
activeMenuId.value = ''
|
||||
}
|
||||
|
||||
const toggleScriptMenu = (script) => {
|
||||
const id = String(script?.id || '')
|
||||
activeMenuId.value = activeMenuId.value === id ? '' : id
|
||||
}
|
||||
|
||||
const toggleFavorite = (script) => {
|
||||
const favorite = isFavorite(script)
|
||||
uni.showActionSheet({
|
||||
itemList: [favorite ? '取消收藏' : '收藏剧本', '继续生成', '查看详情'],
|
||||
success: ({ tapIndex }) => {
|
||||
if (tapIndex === 0) {
|
||||
const next = { ...localFavorites.value }
|
||||
if (favorite) delete next[String(script.id)]
|
||||
else next[String(script.id)] = true
|
||||
localFavorites.value = next
|
||||
uni.setStorageSync('script_favorites', next)
|
||||
uni.showToast({ title: favorite ? '已取消收藏' : '已收藏', icon: 'success' })
|
||||
}
|
||||
if (tapIndex === 1) viewScript(script)
|
||||
if (tapIndex === 2) openScriptDetail(script)
|
||||
}
|
||||
})
|
||||
const next = { ...localFavorites.value }
|
||||
if (favorite) delete next[String(script.id)]
|
||||
else next[String(script.id)] = true
|
||||
localFavorites.value = next
|
||||
uni.setStorageSync('script_favorites', next)
|
||||
closeScriptMenu()
|
||||
uni.showToast({ title: favorite ? '已取消收藏' : '已收藏', icon: 'success' })
|
||||
}
|
||||
|
||||
const continueScript = (script) => {
|
||||
closeScriptMenu()
|
||||
viewScript(script)
|
||||
}
|
||||
|
||||
const openScriptDetailFromMenu = (script) => {
|
||||
closeScriptMenu()
|
||||
openScriptDetail(script)
|
||||
}
|
||||
|
||||
const requestDeleteScript = (script) => {
|
||||
closeScriptMenu()
|
||||
if (!script?.id || String(script.id).startsWith('demo-')) {
|
||||
uni.showToast({ title: '示例剧本不可删除', icon: 'none' })
|
||||
return
|
||||
}
|
||||
deleteTarget.value = script
|
||||
}
|
||||
|
||||
const cancelDeleteScript = () => {
|
||||
if (deletingScript.value) return
|
||||
deleteTarget.value = null
|
||||
}
|
||||
|
||||
const confirmDeleteScript = async () => {
|
||||
if (!deleteTarget.value?.id || deletingScript.value) return
|
||||
deletingScript.value = true
|
||||
const id = String(deleteTarget.value.id)
|
||||
const res = await store.deleteScript(id)
|
||||
deletingScript.value = false
|
||||
|
||||
if (!res.success) {
|
||||
uni.showToast({ title: res.error || '删除失败', icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
const next = { ...localFavorites.value }
|
||||
delete next[id]
|
||||
localFavorites.value = next
|
||||
uni.setStorageSync('script_favorites', next)
|
||||
const conversationId = deleteTarget.value.conversationId || deleteTarget.value.plotJson?.conversationId
|
||||
if (conversationId) uni.removeStorageSync(`script_conversation_history_${conversationId}`)
|
||||
uni.removeStorageSync(`script_chat_history_${id}`)
|
||||
const pending = uni.getStorageSync('pending_open_script_chat')
|
||||
if (pending?.id === id) uni.removeStorageSync('pending_open_script_chat')
|
||||
deleteTarget.value = null
|
||||
uni.showToast({ title: '已删除剧本', icon: 'success' })
|
||||
}
|
||||
|
||||
</script>
|
||||
@@ -670,6 +754,7 @@ const openScriptMenu = (script) => {
|
||||
}
|
||||
|
||||
.right-state {
|
||||
position: relative;
|
||||
flex-shrink: 0;
|
||||
gap: 14rpx;
|
||||
}
|
||||
@@ -699,11 +784,89 @@ const openScriptMenu = (script) => {
|
||||
}
|
||||
|
||||
.ellipsis {
|
||||
min-width: 48rpx;
|
||||
height: 44rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 18rpx;
|
||||
color: rgba(224, 214, 243, 0.66);
|
||||
font-size: 24rpx;
|
||||
letter-spacing: 3rpx;
|
||||
}
|
||||
|
||||
.ellipsis.active {
|
||||
color: #fff;
|
||||
background: rgba(149, 55, 255, 0.22);
|
||||
box-shadow: 0 0 20rpx rgba(168, 67, 255, 0.28);
|
||||
}
|
||||
|
||||
.menu-wrap {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.card-menu {
|
||||
position: absolute;
|
||||
top: 52rpx;
|
||||
right: 0;
|
||||
z-index: 30;
|
||||
width: 202rpx;
|
||||
padding: 10rpx;
|
||||
border-radius: 22rpx;
|
||||
border: 1rpx solid rgba(192, 132, 252, 0.32);
|
||||
background:
|
||||
radial-gradient(circle at 90% 0%, rgba(168, 85, 247, 0.22), transparent 36%),
|
||||
rgba(12, 8, 34, 0.96);
|
||||
box-shadow:
|
||||
inset 0 1rpx 0 rgba(255, 255, 255, 0.08),
|
||||
0 18rpx 42rpx rgba(0, 0, 0, 0.34);
|
||||
backdrop-filter: blur(22rpx);
|
||||
-webkit-backdrop-filter: blur(22rpx);
|
||||
}
|
||||
|
||||
.card-menu::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
right: 22rpx;
|
||||
top: -10rpx;
|
||||
width: 18rpx;
|
||||
height: 18rpx;
|
||||
border-left: 1rpx solid rgba(192, 132, 252, 0.3);
|
||||
border-top: 1rpx solid rgba(192, 132, 252, 0.3);
|
||||
background: rgba(12, 8, 34, 0.96);
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
.menu-action {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
height: 58rpx;
|
||||
padding: 0 14rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12rpx;
|
||||
border-radius: 16rpx;
|
||||
color: rgba(240, 232, 255, 0.9);
|
||||
font-size: 23rpx;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.menu-action:active {
|
||||
background: rgba(149, 55, 255, 0.18);
|
||||
}
|
||||
|
||||
.menu-action.danger {
|
||||
color: #ff8fa3;
|
||||
}
|
||||
|
||||
.menu-dot {
|
||||
width: 8rpx;
|
||||
height: 8rpx;
|
||||
border-radius: 50%;
|
||||
background: currentColor;
|
||||
opacity: 0.72;
|
||||
}
|
||||
|
||||
.tag-row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
@@ -826,4 +989,79 @@ const openScriptMenu = (script) => {
|
||||
font-weight: 800;
|
||||
background: linear-gradient(135deg, #b346ff, #7330ff);
|
||||
}
|
||||
|
||||
.confirm-mask {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 80;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0 48rpx;
|
||||
background: rgba(3, 2, 13, 0.62);
|
||||
backdrop-filter: blur(12rpx);
|
||||
-webkit-backdrop-filter: blur(12rpx);
|
||||
}
|
||||
|
||||
.confirm-panel {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
padding: 34rpx 30rpx 28rpx;
|
||||
border-radius: 28rpx;
|
||||
border: 1rpx solid rgba(192, 132, 252, 0.34);
|
||||
background:
|
||||
radial-gradient(circle at 92% 0%, rgba(168, 85, 247, 0.2), transparent 36%),
|
||||
linear-gradient(145deg, rgba(22, 13, 58, 0.98), rgba(8, 7, 26, 0.98));
|
||||
box-shadow: 0 24rpx 72rpx rgba(0, 0, 0, 0.42);
|
||||
}
|
||||
|
||||
.confirm-title {
|
||||
display: block;
|
||||
color: #fff;
|
||||
font-size: 32rpx;
|
||||
font-weight: 900;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.confirm-copy {
|
||||
display: block;
|
||||
margin-top: 18rpx;
|
||||
color: rgba(229, 219, 247, 0.76);
|
||||
font-size: 24rpx;
|
||||
line-height: 1.55;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.confirm-actions {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 18rpx;
|
||||
margin-top: 30rpx;
|
||||
}
|
||||
|
||||
.confirm-btn {
|
||||
height: 70rpx;
|
||||
border-radius: 24rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 25rpx;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.confirm-btn.secondary {
|
||||
color: #e8ccff;
|
||||
border: 1rpx solid rgba(192, 132, 252, 0.3);
|
||||
background: rgba(88, 28, 135, 0.2);
|
||||
}
|
||||
|
||||
.confirm-btn.danger {
|
||||
color: #fff;
|
||||
background: linear-gradient(145deg, #e05276, #8d2444);
|
||||
box-shadow: 0 12rpx 30rpx rgba(224, 82, 118, 0.24);
|
||||
}
|
||||
|
||||
.confirm-btn.disabled {
|
||||
opacity: 0.55;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user