deotalandAi/apps/FrontendDesigner/src/views/admin/AdminContent.vue

463 lines
12 KiB
Vue

<template>
<div class="admin-content">
<div class="dashboard-header">
<div class="header-left">
<h2 class="title">{{ $t('admin.content.title') }}</h2>
<p class="subtitle">Manage and review content items</p>
</div>
<div class="header-actions">
<el-button type="primary" :icon="Plus" @click="dialogVisible = true">
{{ $t('admin.content.add') }}
</el-button>
<el-button :icon="Refresh" @click="refresh">
{{ $t('admin.content.refresh') }}
</el-button>
</div>
</div>
<!-- 筛选和搜索 -->
<el-card class="filter-card" shadow="never">
<div class="filters">
<el-row :gutter="16">
<el-col :span="6">
<el-input
v-model="filters.keyword"
:placeholder="$t('admin.content.search')"
clearable
:prefix-icon="Search"
/>
</el-col>
<el-col :span="4">
<el-select
v-model="filters.status"
:placeholder="$t('admin.content.status')"
clearable
style="width: 100%"
>
<el-option
v-for="status in statusOptions"
:key="status.value"
:label="status.label"
:value="status.value"
/>
</el-select>
</el-col>
<el-col :span="4">
<el-select
v-model="filters.type"
:placeholder="$t('admin.content.type')"
clearable
style="width: 100%"
>
<el-option
v-for="type in typeOptions"
:key="type.value"
:label="type.label"
:value="type.value"
/>
</el-select>
</el-col>
<el-col :span="6">
<el-date-picker
v-model="filters.dateRange"
type="daterange"
range-separator="-"
:start-placeholder="$t('admin.common.startDate')"
:end-placeholder="$t('admin.common.endDate')"
style="width: 100%"
/>
</el-col>
<el-col :span="4">
<el-button type="primary" :icon="Search" @click="search">
{{ $t('admin.common.search') }}
</el-button>
<el-button @click="resetFilters">{{ $t('admin.common.reset') }}</el-button>
</el-col>
</el-row>
</div>
</el-card>
<!-- 内容列表 -->
<el-card class="table-card" shadow="never">
<!-- stripe -->
<el-table :data="tableData" style="width: 100%" >
<el-table-column prop="id" label="ID" width="80" />
<el-table-column prop="title" :label="$t('admin.content.title')" min-width="200" />
<el-table-column prop="author" :label="$t('admin.content.author')" width="120" />
<el-table-column prop="type" :label="$t('admin.content.type')" width="100">
<template #default="{ row }">
<el-tag :type="getTypeTagType(row.type)">
{{ $t(`admin.content.typeOptions.${row.type}`) }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="status" :label="$t('admin.content.status')" width="100">
<template #default="{ row }">
<el-tag :type="getStatusTagType(row.status)">
{{ $t(`admin.content.statusOptions.${row.status}`) }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="publishDate" :label="$t('admin.content.publishDate')" width="120" />
<el-table-column prop="views" :label="$t('admin.content.views')" width="80" />
<el-table-column :label="$t('admin.content.actions')" width="200" fixed="right">
<template #default="{ row }">
<el-button link type="primary" :icon="View" @click="handleView(row)">
{{ $t('admin.content.view') }}
</el-button>
<el-button link type="primary" :icon="Edit" @click="handleEdit(row)">
{{ $t('admin.content.edit') }}
</el-button>
<el-button link type="danger" :icon="Delete" @click="handleDelete(row)">
{{ $t('admin.content.delete') }}
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<div class="pagination-wrapper">
<el-pagination
v-model:current-page="pagination.currentPage"
v-model:page-size="pagination.pageSize"
:page-sizes="[10, 20, 50, 100]"
:total="pagination.total"
layout="total, sizes, prev, pager, next, jumper"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</div>
</el-card>
<!-- 添加/编辑对话框 -->
<el-dialog
v-model="dialogVisible"
:title="isEditing ? $t('admin.content.edit') : $t('admin.content.add')"
width="600px"
>
<el-form :model="form" :rules="rules" ref="formRef" label-width="100px">
<el-form-item :label="$t('admin.content.title')" prop="title">
<el-input v-model="form.title" />
</el-form-item>
<el-form-item :label="$t('admin.content.type')" prop="type">
<el-select v-model="form.type" style="width: 100%">
<el-option
v-for="type in typeOptions"
:key="type.value"
:label="type.label"
:value="type.value"
/>
</el-select>
</el-form-item>
<el-form-item :label="$t('admin.content.status')" prop="status">
<el-select v-model="form.status" style="width: 100%">
<el-option
v-for="status in statusOptions"
:key="status.value"
:label="status.label"
:value="status.value"
/>
</el-select>
</el-form-item>
<el-form-item :label="$t('admin.content.author')" prop="author">
<el-input v-model="form.author" />
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogVisible = false">{{ $t('admin.common.cancel') }}</el-button>
<el-button type="primary" @click="handleSubmit">{{ $t('admin.common.save') }}</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue'
import { Plus, Search, Edit, Delete, View, Refresh } from '@element-plus/icons-vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { useI18n } from 'vue-i18n'
const { t } = useI18n()
// 数据
const tableData = ref([
{
id: 1,
title: 'How to use Vue3 effectively',
author: 'John Doe',
type: 'article',
status: 'published',
publishDate: '2024-01-15',
views: 1250
},
{
id: 2,
title: 'Beautiful sunset photography',
author: 'Jane Smith',
type: 'image',
status: 'pending',
publishDate: '2024-01-14',
views: 890
},
{
id: 3,
title: 'JavaScript ES6 Features Tutorial',
author: 'Bob Johnson',
type: 'video',
status: 'draft',
publishDate: '2024-01-13',
views: 567
}
])
const filters = reactive({
keyword: '',
status: '',
type: '',
dateRange: []
})
const pagination = reactive({
currentPage: 1,
pageSize: 10,
total: 3
})
const form = reactive({
title: '',
type: '',
status: '',
author: ''
})
const dialogVisible = ref(false)
const isEditing = ref(false)
const formRef = ref()
const statusOptions = [
{ value: 'published', label: t('admin.content.statusOptions.published') },
{ value: 'pending', label: t('admin.content.statusOptions.pending') },
{ value: 'draft', label: t('admin.content.statusOptions.draft') },
{ value: 'rejected', label: t('admin.content.statusOptions.rejected') }
]
const typeOptions = [
{ value: 'article', label: t('admin.content.typeOptions.article') },
{ value: 'image', label: t('admin.content.typeOptions.image') },
{ value: 'video', label: t('admin.content.typeOptions.video') }
]
const rules = {
title: [{ required: true, message: 'Please enter title', trigger: 'blur' }],
type: [{ required: true, message: 'Please select type', trigger: 'change' }],
status: [{ required: true, message: 'Please select status', trigger: 'change' }],
author: [{ required: true, message: 'Please enter author', trigger: 'blur' }]
}
// 方法
const getStatusTagType = (status) => {
const types = {
published: 'success',
pending: 'warning',
draft: 'info',
rejected: 'danger'
}
return types[status] || 'info'
}
const getTypeTagType = (type) => {
const types = {
article: 'primary',
image: 'success',
video: 'warning'
}
return types[type] || 'info'
}
const search = () => {
// 模拟搜索
console.log('Search with filters:', filters)
}
const resetFilters = () => {
filters.keyword = ''
filters.status = ''
filters.type = ''
filters.dateRange = []
}
const refresh = () => {
// 模拟刷新
console.log('Refresh data')
ElMessage.success('Data refreshed successfully')
}
const handleAddContent = () => {
isEditing.value = false
Object.assign(form, {
title: '',
type: '',
status: '',
author: ''
})
dialogVisible.value = true
}
const handleView = (row) => {
ElMessage.info(`View content: ${row.title}`)
}
const handleEdit = (row) => {
isEditing.value = true
Object.assign(form, row)
dialogVisible.value = true
}
const handleDelete = (row) => {
ElMessageBox.confirm(
`Are you sure you want to delete "${row.title}"?`,
'Confirm Deletion',
{
confirmButtonText: 'Yes',
cancelButtonText: 'No',
type: 'warning'
}
).then(() => {
ElMessage.success('Content deleted successfully')
})
}
const handleSubmit = () => {
formRef.value.validate((valid) => {
if (valid) {
ElMessage.success('Content saved successfully')
dialogVisible.value = false
}
})
}
const handleSizeChange = (size) => {
pagination.pageSize = size
console.log('Page size changed to:', size)
}
const handleCurrentChange = (page) => {
pagination.currentPage = page
console.log('Current page changed to:', page)
}
onMounted(() => {
// 初始化数据
})
</script>
<style scoped>
.admin-content {
padding: 20px;
background-color: #f5f5f5;
min-height: calc(100vh - 60px);
}
.dashboard-header {
display: flex;
justify-content: space-between;
align-items: center;
background: white;
padding: 24px;
border-radius: 8px;
margin-bottom: 16px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.header-left {
flex: 1;
}
.header-left .title {
margin: 0;
font-size: 24px;
font-weight: 600;
color: #1f2937;
}
.header-left .subtitle {
margin: 8px 0 0 0;
font-size: 14px;
color: #6b7280;
}
.header-actions {
display: flex;
gap: 12px;
align-items: center;
}
.filter-card {
margin-bottom: 16px;
}
.filters {
padding: 0;
}
.table-card {
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.pagination-wrapper {
display: flex;
justify-content: center;
padding: 20px 0;
}
.dialog-footer {
display: flex;
justify-content: flex-end;
gap: 12px;
}
/* 响应式设计 */
@media (max-width: 768px) {
.admin-content {
padding: 16px;
}
.dashboard-header {
flex-direction: column;
align-items: flex-start;
gap: 16px;
padding: 20px;
}
.header-actions {
width: 100%;
justify-content: flex-end;
}
.filters .el-col {
margin-bottom: 12px;
}
}
@media (max-width: 480px) {
.admin-content {
padding: 12px;
}
.dashboard-header {
padding: 16px;
}
.header-actions {
flex-direction: column;
width: 100%;
}
.header-actions .el-button {
width: 100%;
}
}
</style>