140 lines
4.6 KiB
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>
|