flaunt-web/src/views/Works.vue

140 lines
4.6 KiB
Vue

<template>
<div class="works-page">
<div class="container">
<h2>我的作品</h2>
<div class="toolbar">
<el-input v-model="keyword" placeholder="搜索作品标题..." prefix-icon="Search" clearable style="width:260px" />
<el-radio-group v-model="filterType" size="small">
<el-radio-button value="">全部</el-radio-button>
<el-radio-button value="chat">聊天</el-radio-button>
<el-radio-button value="balance">余额</el-radio-button>
</el-radio-group>
</div>
<div class="work-list" v-loading="loading">
<div v-for="work in worksList" :key="work.id" class="work-card">
<div class="card-thumb" :class="work.type">
<span>{{ work.type === 'chat' ? '💬' : '💰' }}</span>
</div>
<div class="card-info">
<h4>{{ work.title }}</h4>
<p class="meta">{{ work.type === 'chat' ? '聊天记录' : '余额截图' }} · {{ formatDate(work.updated_at) }}</p>
</div>
<div class="card-actions">
<el-button size="small" @click="renameWork(work)">改名</el-button>
<el-button size="small" type="primary" plain @click="editWork(work)">编辑</el-button>
<el-button size="small" type="danger" plain @click="deleteWork(work)">删除</el-button>
</div>
</div>
<el-empty v-if="!loading && !worksList.length" description="暂无作品" />
</div>
<div class="pagination-wrap" v-if="total > 0">
<el-pagination
background
layout="total, prev, pager, next"
:total="total"
:page-size="10"
:current-page="currentPage"
@current-change="onPageChange"
/>
</div>
</div>
</div>
</template>
<script setup>
import { ref, onMounted, watch } from 'vue'
import { useRouter } from 'vue-router'
import { ElMessage, ElMessageBox } from 'element-plus'
import api from '@/api'
const router = useRouter()
const loading = ref(false)
const keyword = ref('')
const filterType = ref('')
const worksList = ref([])
const currentPage = ref(1)
const total = ref(0)
onMounted(loadWorks)
watch([keyword, filterType], () => { currentPage.value = 1; loadWorks() })
async function loadWorks() {
loading.value = true
try {
const res = await api.works.list({
keyword: keyword.value,
type: filterType.value || undefined,
page: currentPage.value,
per_page: 10,
})
worksList.value = res.items
total.value = res.total
} finally { loading.value = false }
}
function onPageChange(page) {
currentPage.value = page
loadWorks()
}
function editWork(work) {
if (work.type === 'chat') router.push(`/chat?workId=${work.id}`)
else router.push(`/balance?workId=${work.id}`)
}
async function deleteWork(work) {
try { await ElMessageBox.confirm(`确定删除「${work.title}」?`, '确认', { confirmButtonText: '删除', cancelButtonText: '取消', type: 'warning' }) }
catch { return }
await api.works.delete(work.id)
ElMessage.success('已删除')
loadWorks()
}
async function renameWork(work) {
try {
const { value: newTitle } = await ElMessageBox.prompt('请输入新名称', '修改名称', {
confirmButtonText: '确定',
cancelButtonText: '取消',
inputValue: work.title,
inputPlaceholder: '输入新作品名称',
})
if (!newTitle || newTitle === work.title) return
await api.works.update(work.id, { title: newTitle })
ElMessage.success('已修改')
loadWorks()
} catch {}
}
function formatDate(iso) { return iso?.slice(0, 16).replace('T', ' ') || '' }
</script>
<style lang="scss" scoped>
.works-page { min-height: calc(100vh - 120px); padding: 30px 20px; }
.container { max-width: 900px; margin: 0 auto; h2 { margin-bottom: 20px; } }
.toolbar { display: flex; align-items: center; gap: 16px; margin-bottom: 20px; }
.work-list { display: flex; flex-direction: column; gap: 10px; }
.work-card {
display: flex; align-items: center; gap: 16px;
padding: 16px 20px; background: #fff; border-radius: 10px;
box-shadow: 0 1px 6px rgba(0,0,0,.04); transition: box-shadow .2s;
&:hover { box-shadow: 0 3px 12px rgba(0,0,0,.08); }
.card-thumb {
width: 48px; height: 48px; border-radius: 10px;
display: flex; align-items: center; justify-content: center; font-size: 22px;
&.chat { background: #e8f5e9; }
&.balance { background: #fff8e1; }
}
.card-info { flex: 1; h4 { font-size: 15px; margin-bottom: 2px; } .meta { font-size: 12px; color: #999; } }
.card-actions { display: flex; gap: 6px; }
}
.pagination-wrap {
display: flex; justify-content: center;
padding: 20px 0 10px;
}
</style>