Browse Source

add news

master
panda 9 months ago
parent
commit
d6014b12d3
  1. 23
      src/assets/index.ts
  2. 208
      src/components/admin/MainWrapper.vue
  3. 2
      src/components/blogs/HomePage.vue
  4. 18
      src/router/admin.ts
  5. 15
      src/router/home.ts
  6. 23
      src/router/index.ts
  7. 18
      src/store/index.ts
  8. 364
      src/views/admin/DashBoardView.vue

23
src/assets/index.ts

@ -0,0 +1,23 @@
import { defineComponent, h } from 'vue';
import { createFromIconfontCN } from '@ant-design/icons-vue';
function createIconComponent(iconType:string){
const IconComponent = createFromIconfontCN({
scriptUrl: '//at.alicdn.com/t/c/font_4513281_240ozh2p7bxh.js', // 在 iconfont.cn 上生成
});
return defineComponent({
setup() {
return () => h(IconComponent , { type: iconType });
},
});
}
const TitleOutLined = createIconComponent( 'icon-xiongmaochizhuye');
const BlogOutLined=createIconComponent( 'icon-blog');
const SystemOutLined=createIconComponent( 'icon-system');
const PhotoOutLined=createIconComponent( 'icon-photo');
const FileOutLined=createIconComponent( 'icon-file');
const DiaryOutLined=createIconComponent( 'icon-diary');
const CommentOutLined=createIconComponent( 'icon-comment');
const TypeOutLined=createIconComponent( 'icon-type');
export {TitleOutLined,BlogOutLined,SystemOutLined,PhotoOutLined,FileOutLined,DiaryOutLined,CommentOutLined,TypeOutLined}

208
src/components/admin/MainWrapper.vue

@ -0,0 +1,208 @@
<template>
<a-flex>
<div class="menu" :style="{ width: state.menuWidth }">
<div class="menu_header">
<TitleOutLined :class="collapsed ? 'small' : 'large'" />
<span v-if="!collapsed">{{ state.name }}</span>
</div>
<a-menu class="menu_navigate" v-model:openKeys="state.openKeys" v-model:selectedKeys="state.selectedKeys"
mode="inline" theme="light" :inline-collapsed="state.collapsed" :items="items" style="border-inline-end: none;"
@click="menuItemclick">
</a-menu>
</div>
<div class="main" style="flex: 1;">
<div class="main_header">
<a-space>
<a-button @click="toggleCollapsed">
<MenuUnfoldOutlined v-if="state.collapsed" />
<MenuFoldOutlined v-else />
</a-button>
<a-button type="text" @click="jumpdashboard">首页</a-button>
</a-space>
<div class="user">
<span>{{ username }}</span>
<div>
<a-button type="primary" @click="showModal" danger>
<LogoutOutlined />
</a-button>
<a-modal v-model:open="open" title="提示" @ok="handleOk" @cancel="handleCancel" ok-text="确认" cancel-text="取消">
<p>确定要注销吗</p>
</a-modal>
</div>
</div>
</div>
<RouterView />
</div>
</a-flex>
</template>
<script setup lang='ts'>
import { computed, ref, onMounted, h, reactive } from 'vue';
import { TitleOutLined } from "@/assets/index"
import { RouterView, useRouter } from 'vue-router'
import { MenuFoldOutlined, MenuUnfoldOutlined, LogoutOutlined, DashboardOutlined } from '@ant-design/icons-vue';
import { get } from "@/tools/request"
import { message } from 'ant-design-vue';
import { useAuthStore } from '@/store/index'
import { BlogOutLined, SystemOutLined, PhotoOutLined, FileOutLined, DiaryOutLined, CommentOutLined, TypeOutLined } from "@/assets"
const state = reactive({
collapsed: false,
openKeys: [1],
selectedKeys: ['1'],
name: '博客后台系统',
menuWidth: '10%'
});
const items = reactive([
{
key: '1',
icon: () => h(DashboardOutlined),
label: '仪表盘',
title: '仪表盘',
url: '/admin/dashboard'
},
{
key: '2',
icon: () => h(BlogOutLined),
label: '博客管理',
title: '博客管理',
url: '/admin/blogmanage'
},
{
key: '3',
icon: () => h(DiaryOutLined),
label: '日记管理',
title: '日记管理',
url: '/admin/diarymanage'
},
{
key: '4',
icon: () => h(TypeOutLined),
label: '分类管理',
title: '分类管理',
url: '/admin/typemanage'
},
{
key: '5',
icon: () => h(CommentOutLined),
label: '评论管理',
title: '评论管理',
url: '/admin/commentmanage'
},
{
key: '6',
icon: () => h(PhotoOutLined),
label: '相册管理',
title: '相册管理',
url: '/admin/imagemanage'
},
{
key: '7',
icon: () => h(FileOutLined),
label: '文件管理',
title: '文件管理',
url: '/admin/filemanage'
},
{
key: '8',
icon: () => h(SystemOutLined),
label: '系统设置',
title: '系统设置',
url: '/admin/systemmanage'
},
]);
const router = useRouter()
const menuItemclick = function ({ item }: { item: any }) {
router.push(item.url)
}
const collapsed = computed(() => state.collapsed);
const authStore = useAuthStore()
const username = ref("")
const toggleCollapsed = () => {
state.collapsed = !state.collapsed;
state.menuWidth = state.collapsed ? 'auto' : '10%'
};
const jumpdashboard = function () {
state.selectedKeys = ['1']
router.push('/admin/dashboard')
}
onMounted(async () => {
const userinfo = await get(
'/users/me',
undefined,
undefined,
{
'Accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded'
}
)
username.value = userinfo.data.username
});
const open = ref<boolean>(false);
const showModal = () => {
open.value = true;
};
const handleOk = (e: MouseEvent) => {
console.log(e);
authStore.removeToken()
message.loading("注销成功")
setTimeout(() => {
router.push('/login')
}, 2000);
open.value = false;
};
const handleCancel = (e: MouseEvent) => {
message.warn('取消注销');
}
</script>
<style scoped>
.menu {
border-right: 1px solid rgba(5, 5, 5, 0.06);
}
.main_header {
display: flex;
margin: 24px;
justify-content: space-between;
}
.menu_header {
display: flex;
justify-content: center;
align-items: center;
height: 98px;
font-size: 20px;
}
.small {
font-size: 30px;
margin: 0 5px 0 5px;
}
.large {
font-size: 50px;
margin: 0 10px 0 10px;
}
.navigate_button {
justify-content: space-between;
align-items: center;
border-block-end: 1px solid rgba(5, 5, 5, 0.06);
}
.user {
display: flex;
align-items: center;
}
.user>* {
padding: 0 5px;
}
</style>

2
src/components/blogs/HomePage.vue

@ -1,5 +1,5 @@
<template> <template>
<div>ceshi</div>
</template> </template>
<script setup lang='ts'> <script setup lang='ts'>

18
src/router/admin.ts

@ -0,0 +1,18 @@
import type { RouteRecordRaw } from 'vue-router'
const adminRoute:Array<RouteRecordRaw>=[
{
path:"/admin",
redirect:"/admin/dashboard",
name:'admin',
component:()=> import("@/components/admin/MainWrapper.vue"),
children:[
{
path:"dashboard",
name:"dashboard",
component:()=>import("@/views/admin/DashBoardView.vue")
}
]
}
]
export default adminRoute

15
src/router/home.ts

@ -0,0 +1,15 @@
import type { RouteRecordRaw } from 'vue-router'
const homeRoute:Array<RouteRecordRaw>=[
{
path: "/",
name: "home",
component: () => import("@/components/blogs/HomePage.vue"),
},
{
path: "/login",
name: "login",
component: () => import("@/components/admin/SignIn.vue"),
}
]
export default homeRoute

23
src/router/index.ts

@ -1,19 +1,16 @@
import { createRouter, createWebHistory } from 'vue-router'
import { createRouter, createWebHistory,type RouteRecordRaw } from 'vue-router';
import homeRoute from "./home"
import adminRoute from './admin';
const route:Array<RouteRecordRaw>=[
...homeRoute,
...adminRoute
]
const router = createRouter({ const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL), history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: "/",
name: "page",
component: () => import("@/components/blogs/HomePage.vue"),
},
{
path: "/login",
name: "login",
component: () => import("@/components/admin/SignIn.vue"),
},
]
routes: route
}) })
export default router export default router

18
src/store/index.ts

@ -0,0 +1,18 @@
import { defineStore } from 'pinia';
export const useAuthStore = defineStore({
id: 'auth',
state: () => ({
token: '',
username:''
}),
actions: {
setToken(token:string) {
this.token = token;
},
removeToken(){
localStorage.removeItem('token');
}
},
});

364
src/views/admin/DashBoardView.vue

@ -0,0 +1,364 @@
<template>
<div class="content">
<div class="card">
<a-row :gutter="16" style="justify-content: space-between;">
<a-col :span="4">
<a-card>
<a-statistic title="博客数量" :value="count.blogCount" suffix="篇" :value-style="{ color: '#3f8600' }"
style="margin-right: 50px">
<template #prefix>
<BlogOutLined />
</template>
</a-statistic>
</a-card>
</a-col>
<a-col :span="4">
<a-card>
<a-statistic title="照片数量" :value="count.photoCount" suffix="张" :value-style="{ color: '#3f8600' }"
style="margin-right: 50px">
<template #prefix>
<PhotoOutLined />
</template>
</a-statistic>
</a-card>
</a-col>
<a-col :span="4">
<a-card>
<a-statistic title="文件总数" :value="count.fileCount" suffix="个" :value-style="{ color: '#3f8600' }"
style="margin-right: 50px">
<template #prefix>
<FileOutLined />
</template>
</a-statistic>
</a-card>
</a-col>
<a-col :span="4">
<a-card>
<a-statistic title="日记发表" :value="count.diaryCount" suffix="篇" :value-style="{ color: '#3f8600' }"
style="margin-right: 50px">
<template #prefix>
<DiaryOutLined />
</template>
</a-statistic>
</a-card>
</a-col>
<a-col :span="4">
<a-card>
<a-statistic title="评论数量" :value="count.commentCount" suffix="条" :value-style="{ color: '#3f8600' }"
style="margin-right: 50px">
<template #prefix>
<CommentOutLined />
</template>
</a-statistic>
</a-card>
</a-col>
</a-row>
</div>
<div class="echarts-1">
<div ref="blog"></div>
<div ref="diary"></div>
<div ref="photo"></div>
</div>
<div class="echarts-2">
<div ref="own"></div>
</div>
<div class="comment">
<a-table bordered :data-source="dataSource" :columns="columns" :pagination="false">
<template #bodyCell="{ column, text, record }">
<template v-if="column.dataIndex === 'name'">
<div class="editable-cell">
<div class="editable-cell-text-wrapper">
{{ text || ' ' }}
</div>
</div>
</template>
<template v-else-if="column.dataIndex === 'operation'">
<a-popconfirm v-if="dataSource.length" title="确认删除么?" @confirm="onDelete(record.key)">
<a>删除</a>
</a-popconfirm>
</template>
</template>
</a-table>
</div>
</div>
</template>
<script setup lang='ts'>
import { BlogOutLined, PhotoOutLined, FileOutLined, DiaryOutLined, CommentOutLined } from "@/assets";
import { reactive, ref, onMounted } from 'vue';
import type { Ref } from 'vue';
import { createEcharts } from '@/hooks/intex'
const count = reactive({
blogCount: '12',
photoCount: '13',
fileCount: '14',
diaryCount: '15',
commentCount: '16'
})
const blog = ref(null);
const diary = ref(null);
const photo = ref(null);
const own = ref(null);
onMounted(() => {
const blogData = {
title: {
text: '周博客统计',
left: 'center'
},
tooltip: {
trigger: 'item'
},
legend: {
orient: 'vertical',
left: 'left'
},
series: [
{
name: '数量',
type: 'pie',
radius: '50%',
data: [
{ value: 1048, name: '星期一' },
{ value: 735, name: '星期二' },
{ value: 580, name: '星期三' },
{ value: 484, name: '星期四' },
{ value: 300, name: '星期五' },
{ value: 300, name: '星期六' },
{ value: 300, name: '星期日' }
],
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
};
const diaryData = {
title: {
text: '周日记统计',
left: 'center'
},
xAxis: {
type: 'category',
data: ['星期一', '星期二', '星期三', '星期四', '星期五', '星期六', '星期日']
},
yAxis: {
type: 'value'
},
series: [
{
data: [820, 932, 901, 934, 1290, 1330, 1320],
type: 'line',
smooth: true
}
]
};
const photoData = {
title: {
text: '周照片统计',
left: 'center'
},
xAxis: {
type: 'category',
data: ['星期一', '星期二', '星期三', '星期四', '星期五', '星期六', '星期日']
},
yAxis: {
type: 'value'
},
series: [
{
data: [120, 200, 150, 80, 70, 110, 130],
type: 'bar'
}
]
};
const ownData = {
title: {
text: '完全统计',
left: 'center',
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
},
legend: {
data: ['月日记量', '月博客量', '月照片量', '月评论量', '月文件量'],
top: '10%',
},
toolbox: {
show: true,
orient: 'vertical',
left: 'right',
bottom: '10%',
feature: {
mark: { show: true },
magicType: { show: true, type: ['line', 'bar', 'stack'] },
restore: { show: true },
saveAsImage: { show: true }
}
},
xAxis: [
{
type: 'category',
axisTick: { show: false },
data: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
}
],
yAxis: [
{
type: 'value'
}
],
series: [
{
name: '月日记量',
type: 'bar',
barGap: 0,
emphasis: {
focus: 'series'
},
data: [320, 332, 301, 334, 390, 320, 332, 301, 334, 390, 320, 332]
},
{
name: '月博客量',
type: 'bar',
emphasis: {
focus: 'series'
},
data: [220, 182, 191, 234, 290, 220, 182, 191, 234, 290, 220, 182]
},
{
name: '月照片量',
type: 'bar',
emphasis: {
focus: 'series'
},
data: [150, 232, 201, 154, 190, 220, 182, 191, 234, 290, 220, 182]
},
{
name: '月评论量',
type: 'bar',
emphasis: {
focus: 'series'
},
data: [98, 77, 101, 99, 40, 201, 154, 190, 220, 182, 191, 201, 154]
},
{
name: '月文件量',
type: 'bar',
emphasis: {
focus: 'series'
},
data: [98, 77, 101, 99, 40, 40, 201, 154, 190, 220, 182, 154, 190]
}
],
grid: [
{
bottom: '10%'
}
]
};
createEcharts(blog, blogData)
createEcharts(diary, diaryData)
createEcharts(photo, photoData)
createEcharts(own, ownData)
});
interface DataItem {
key: string;
name: string;
blog: string;
content: string;
time: String
}
const columns = [
{
title: '评论人',
dataIndex: 'name',
width: '10%',
},
{
title: '评论博客',
dataIndex: 'blog',
width: '15%',
},
{
title: '评论内容',
dataIndex: 'content',
},
{
title: '评论时间',
dataIndex: 'time',
width: '10%',
},
{
title: '操作',
dataIndex: 'operation',
},
];
const dataSource: Ref<DataItem[]> = ref<DataItem[]>([
{
key: '0',
name: 'wupeng',
blog: "linux系统安装",
content: '教程比较详细',
time: '2014'
},
{
key: '1',
name: 'wulei',
blog: "linux命令",
content: '写的很好,值得借鉴!',
time: '2014'
},
]);
const onDelete = (key: string) => {
dataSource.value = dataSource.value.filter(item => item.key !== key);
};
</script>
<style scoped>
.content{
margin: 24px;
}
.card,
.comment,
.echarts-1,
.echarts-2 {
background-color: #ececec;
padding: 24px;
}
.echarts-1 {
display: flex;
justify-content: space-between;
}
.echarts-1 div{
width: calc(85vw/3);
height: calc((85vw/3)/(5/3));
}
.echarts-2 div{
width: calc(85vw);
height: calc((85vw/3)/2);
}
</style>
Loading…
Cancel
Save