Browse Source

add new

master
panda 8 months ago
parent
commit
65a1cef200
  1. BIN
      src/assets/image.png
  2. 6
      src/assets/index.ts
  3. 92
      src/components/blogs/HomePage.vue
  4. 210
      src/components/blogs/ceshi.vue
  5. 13
      src/views/blog/blogcontent/BlogDetailView.vue
  6. 64
      src/views/blog/blogcontent/BlogListView.vue

BIN
src/assets/image.png

After

Width: 62  |  Height: 67  |  Size: 11 KiB

6
src/assets/index.ts

@ -3,7 +3,7 @@ import { createFromIconfontCN } from '@ant-design/icons-vue';
function createIconComponent(iconType: string) { function createIconComponent(iconType: string) {
const IconComponent = createFromIconfontCN({ const IconComponent = createFromIconfontCN({
scriptUrl: '//at.alicdn.com/t/c/font_4513281_qhbaqfo6egj.js', // 在 iconfont.cn 上生成
scriptUrl: '//at.alicdn.com/t/c/font_4513281_1cb6b9dny0i.js', // 在 iconfont.cn 上生成
}); });
return defineComponent({ return defineComponent({
@ -32,6 +32,10 @@ const iconComponents = {
YanJingLined: createIconComponent('icon-yanjing'), YanJingLined: createIconComponent('icon-yanjing'),
XieZiLined: createIconComponent('icon-xiezi'), XieZiLined: createIconComponent('icon-xiezi'),
CravatarLined: createIconComponent('icon-cravatar'), CravatarLined: createIconComponent('icon-cravatar'),
GongAnLined: createIconComponent('icon-gonganbeian'),
IcpLined: createIconComponent('icon-wsmp-icprecord'),
BanQuanLined: createIconComponent('icon-banquan'),
} }

92
src/components/blogs/HomePage.vue

@ -104,6 +104,54 @@
</div> </div>
</div> </div>
<div class="footer">
<div class="miit">
<a-space wrap>
<a-text>
<component :is=iconComponents.BanQuanLined />
<span>Copyright © 2024</span>
</a-text>
<a-button type="link" href="/home">
<component :is=iconComponents.TitleOutLined />
<span>SunFree</span>
</a-button>
<a-button type="link" href="https://beian.miit.gov.cn/">
<component :is=iconComponents.IcpLined />
<span>苏ICP备2024067473号-1</span>
</a-button>
<a-button type="link" href="https://beian.mps.gov.cn/#/query/webSearch">
<component :is=iconComponents.GongAnLined />
<span>苏公网安备32021402003003号</span>
</a-button>
</a-space>
</div>
<div class="badge">
<a-space wrap>
<a-button type="link" class="badge-button" href="https://cn.vuejs.org/">
<span class="tag-nav">front-end</span>
<span class="tag-main-first">Vue.js</span>
</a-button>
<a-button type="link" class="badge-button" href="https://fastapi.tiangolo.com/zh/">
<span class="tag-nav">back-end</span>
<span class="tag-main-second">FastAPI</span>
</a-button>
<a-button type="link" class="badge-button" href="https://www.antdv.com/docs/vue/introduce-cn/">
<span class="tag-nav">UI</span>
<span class="tag-main-third">Ant Design Vue</span>
</a-button>
<a-button type="link" class="badge-button" href="https://cloud.tencent.com/">
<span class="tag-nav">VPS</span>
<span class="tag-main-fourth">tencent cloud</span>
</a-button>
</a-space>
</div>
<div>
</div>
<div></div>
</div>
</Simplebar> </Simplebar>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
@ -121,7 +169,6 @@ import { useRouter, useRoute } from 'vue-router';
import iconComponents from "@/assets/index"; import iconComponents from "@/assets/index";
import type { classticInterface } from '@/api/admin'; import type { classticInterface } from '@/api/admin';
import type { comLinkInterface } from '@/api/admin/index'; import type { comLinkInterface } from '@/api/admin/index';
const router = useRouter() const router = useRouter()
const route = useRoute() const route = useRoute()
const author = ref("SunFree.") const author = ref("SunFree.")
@ -684,4 +731,47 @@ watch(
.statistic { .statistic {
text-align: center; text-align: center;
} }
.footer {
display: flex;
flex-direction: column;
align-items: center;
}
.footer a {
color: #6e5555;
}
.footer .badge {
margin: 48px 0;
}
.footer .miit {
margin: 48px 0 0 0;
}
.footer .badge .tag-nav {
background-color: #505050;
}
.footer .miit span{
padding: 0 6px;
}
.footer .badge span {
padding: 0 6px;
color: white;
}
.footer .badge .tag-main-first {
background-color: rgb(3, 3, 250);
}
.footer .badge .tag-main-second {
background-color: rgb(235, 15, 228);
}
.footer .badge .tag-main-third {
background-color: rgb(10, 207, 39);
}
.footer .badge .tag-main-fourth {
background-color: rgb(229, 131, 12);
}
</style> </style>

210
src/components/blogs/ceshi.vue

@ -1,189 +1,45 @@
<template> <template>
<div> <div>
<div
v-for="anchor in titles"
:style="{ padding: `10px 0 10px ${anchor.indent}px` }"
@click="handleAnchorClick(anchor)"
:key="anchor.lineIndex"
>
<a style="cursor: pointer">{{ anchor.title }}</a>
<div v-for="blog in bloglist" :key="blog.id">
<!-- 在这里展示你的博客内容 -->
<h2>{{ blog.blogtitle }}</h2>
<p>{{ blog.blogcontent }}</p>
</div> </div>
<v-md-preview :text="text" ref="preview" />
<a-pagination v-model:current="current" v-if="dataLoaded" :total="total" :page-size="pageSize" @change="onPageChange"
show-less-items />
</div> </div>
</template> </template>
<script setup lang="ts">
<script lang="ts" setup>
import { ref, onMounted } from 'vue'; import { ref, onMounted } from 'vue';
const text = `
# heading 1
contentcontentcontent
contentcontentcontent
contentcontentcontent
contentcontentcontentcontentcontentcontent
contentcontentcontent
contentcontentcontentcontentcontentcontent
contentcontentcontent
contentcontentcontentcontentcontentcontent
contentcontentcontent
contentcontentcontentcontentcontentcontent
contentcontentcontent
contentcontentcontentcontentcontentcontent
contentcontentcontent
contentcontentcontentcontentcontentcontent
contentcontentcontent
contentcontentcontentcontentcontentcontent
contentcontentcontent
contentcontentcontentcontentcontentcontent
contentcontentcontent
contentcontentcontentcontentcontentcontent
contentcontentcontent
contentcontentcontentcontentcontentcontent
contentcontentcontent
contentcontentcontentcontentcontentcontent
contentcontentcontent
contentcontentcontentcontentcontentcontent
contentcontentcontent
contentcontentcontentcontentcontentcontent
contentcontentcontent
contentcontentcontentcontentcontentcontent
contentcontentcontent
contentcontentcontentcontentcontentcontent
contentcontentcontent
contentcontentcontentcontentcontentcontent
contentcontentcontent
contentcontentcontentcontentcontentcontent
contentcontentcontent
contentcontentcontentcontentcontentcontent
contentcontentcontent
contentcontentcontent
contentcontentcontent
## heading 2
contentcontentcontent
contentcontentcontent
contentcontentcontent
contentcontentcontent
contentcontentcontentcontentcontentcontent
contentcontentcontent
contentcontentcontent
contentcontentcontentcontentcontentcontent
contentcontentcontent
contentcontentcontent
contentcontentcontentcontentcontentcontent
contentcontentcontent
contentcontentcontent
contentcontentcontentcontentcontentcontent
contentcontentcontent
contentcontentcontent
contentcontentcontentcontentcontentcontent
contentcontentcontent
contentcontentcontent
contentcontentcontentcontentcontentcontent
contentcontentcontent
contentcontentcontent
contentcontentcontentcontentcontentcontent
contentcontentcontent
contentcontentcontent
contentcontentcontentcontentcontentcontent
contentcontentcontent
contentcontentcontent
contentcontentcontentcontentcontentcontent
contentcontentcontent
contentcontentcontent
contentcontentcontentcontentcontentcontent
contentcontentcontent
contentcontentcontent
contentcontentcontentcontentcontentcontent
contentcontentcontent
contentcontentcontent
contentcontentcontent
### heading 3
contentcontentcontent
contentcontentcontent
contentcontentcontent
contentcontentcontent
contentcontentcontentcontentcontentcontent
contentcontentcontent
contentcontentcontent
contentcontentcontentcontentcontentcontent
contentcontentcontent
contentcontentcontent
contentcontentcontentcontentcontentcontent
contentcontentcontent
contentcontentcontent
contentcontentcontentcontentcontentcontent
contentcontentcontent
contentcontentcontent
contentcontentcontentcontentcontentcontent
contentcontentcontent
contentcontentcontent
contentcontentcontentcontentcontentcontent
contentcontentcontent
contentcontentcontent
contentcontentcontentcontentcontentcontent
contentcontentcontent
contentcontentcontent
contentcontentcontentcontentcontentcontent
contentcontentcontent
contentcontentcontent
contentcontentcontentcontentcontentcontent
contentcontentcontent
contentcontentcontent
contentcontentcontentcontentcontentcontent
contentcontentcontent
contentcontentcontent
contentcontentcontentcontentcontentcontent
contentcontentcontent
contentcontentcontent
contentcontentcontentcontentcontentcontent
contentcontentcontent
contentcontentcontent
contentcontentcontentcontentcontentcontent
contentcontentcontent
contentcontentcontent
contentcontentcontent
`;
const preview = ref<any>(null);
const titles = ref<{ title: string; lineIndex: string; indent: number }[]>([]);
onMounted(() => {
const anchors = document.querySelectorAll('h1, h2, h3, h4, h5, h6');
const titlesArray = Array.from(anchors).filter((title) => !!title.innerText.trim());
if (!titlesArray.length) {
titles.value = [];
return;
}
const hTags = Array.from(new Set(titlesArray.map((title) => title.tagName))).sort();
titles.value = titlesArray.map((el) => ({
title: el.innerText,
lineIndex: el.getAttribute('data-v-md-line') || '', //
indent: 20 * (parseInt(el.tagName.substring(1)) - 1) //
}));
import type { blogInterface } from '@/api/admin';
import { get } from '@/tools/request';
const current = ref(1);
const total = ref();
const pageSize = ref(5);
const bloglist = ref<blogInterface[]>([])
const dataLoaded = ref(false);
const fetchData = async (page: number, pageSize: number) => {
try {
const response = await get('/blogs/list', {
page,
page_size: pageSize,
}); });
bloglist.value = response.data.data.blogs;
total.value = response.data.data.total;
} catch (error) {
console.error('Failed to fetch data', error);
}
};
function handleAnchorClick(anchor: { title: string; lineIndex: string }) {
if (preview.value) {
const heading = preview.value.$el.querySelector(`[data-v-md-line="${anchor.lineIndex}"]`);
const onPageChange = (page: number) => {
current.value = page;
fetchData(page, pageSize.value);
};
if (heading) {
preview.value.scrollToTarget({
target: heading,
scrollContainer: window,
top: 60,
onMounted(() => {
fetchData(current.value, pageSize.value);
}); });
} else {
console.error(`Heading element not found for lineIndex: ${anchor.lineIndex}`);
}
} else {
console.error('Preview component not initialized.');
}
}
</script> </script>

13
src/views/blog/blogcontent/BlogDetailView.vue

@ -1,11 +1,14 @@
<template> <template>
<div id="blogDetail"> <div id="blogDetail">
<div v-for="anchor in titles" :style="{ padding: `4px 0 4px ${anchor.indent * 20}px` }"
<!-- <div v-for="anchor in titles" :style="{ padding: `4px 0 4px ${anchor.indent * 20}px` }"
@click="handleAnchorClick(anchor)" :key="anchor.lineIndex"> @click="handleAnchorClick(anchor)" :key="anchor.lineIndex">
<a style="cursor: pointer">{{ anchor.title }}</a> <a style="cursor: pointer">{{ anchor.title }}</a>
</div>
</div> -->
<a-card>
<v-md-preview v-if="text.blogcontent" :text="text.blogcontent" v-bind="previewProps" /> <v-md-preview v-if="text.blogcontent" :text="text.blogcontent" v-bind="previewProps" />
</a-card>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@ -18,6 +21,10 @@ const text = ref({
blogtitle: "", blogtitle: "",
blogcontent: "" blogcontent: ""
}); });
const titles = ref<{ title: string; lineIndex: string; indent: number }[]>([]); const titles = ref<{ title: string; lineIndex: string; indent: number }[]>([]);
// Props for v-md-preview component // Props for v-md-preview component
@ -88,6 +95,6 @@ onMounted(async () => {
<style scoped> <style scoped>
#blogDetail { #blogDetail {
width: 45%; width: 45%;
margin: 0 24px;
} }
</style> </style>

64
src/views/blog/blogcontent/BlogListView.vue

@ -48,6 +48,16 @@
</a-card> </a-card>
</a-badge-ribbon> </a-badge-ribbon>
</div> </div>
<div id="pagination">
<a-pagination v-model:current="current" v-if="dataLoaded" v-model:page-size="pageSizeRef"
:page-size-options="pageSizeOptions" :total="total" show-size-changer @change="onShowSizeChange">
<template #buildOptionText="props">
<span v-if="props.value !== '50'">{{ props.value }}/</span>
<span v-else>全部</span>
</template>
</a-pagination>
</div>
</div> </div>
</template> </template>
@ -62,39 +72,43 @@ const randomColor = () => {
const labelColor = ref(["processing", "success", "error", "warning", "magenta", "red", "volcano", "orange", "gold", "lime", "green", "cyan", "blue", "geekblue", "purple"]) const labelColor = ref(["processing", "success", "error", "warning", "magenta", "red", "volcano", "orange", "gold", "lime", "green", "cyan", "blue", "geekblue", "purple"])
return labelColor.value[Math.floor(Math.random() * labelColor.value.length)]; return labelColor.value[Math.floor(Math.random() * labelColor.value.length)];
} }
const dataLoaded = ref(false);
//
const pageSizeOptions = ref<string[]>(['10', '20', '30', '40', '50']);
const current = ref(1);
const total = ref();
const pageSizeRef = ref(10);
const bloglist = ref<blogInterface[]>([]) const bloglist = ref<blogInterface[]>([])
const blogList = async () => {
const onShowSizeChange = (page: number) => {
current.value = page;
blogList(page, pageSizeRef.value)
};
const blogList = async (page: number, pageSize: number) => {
try { try {
const response = await get("/blogs/list");
if (response) {
bloglist.value = response.data.data.map((items: any, index: any) => ({
key: (index + 1).toString(),
id: items.id,
blogtitle: items.blogtitle,
create_at: dayjs(items.create_at).format('YYYY-MM-DD HH:mm:ss'),
update_at: dayjs(items.update_at).format('YYYY-MM-DD HH:mm:ss'),
readnum: items.readnum,
readminite: (items.blogcontent.length/150).toFixed(2),
wordcount: items.blogcontent.length,
img: items.img,
blogcontent: items.blogcontent,
typename: items.typename,
labelnames: items.labelnames
}))
} else {
console.log("bloglist is not exits")
}
const response = await get('/blogs/list', {
page,
page_size: pageSize,
});
console.log(response)
bloglist.value = response.data.data.blogs;
total.value = response.data.data.total; //
pageSizeRef.value = pageSize; // response.data.data.page_size
dataLoaded.value = true
} catch (error) { } catch (error) {
console.log("bloglist is error")
console.error('Failed to fetch data', error);
} }
};
}
const readMore = (id: any) => { const readMore = (id: any) => {
router.push(`/blog/${id}`) router.push(`/blog/${id}`)
} }
onMounted(() => { onMounted(() => {
blogList();
blogList(current.value, pageSizeRef.value);
}); });
</script> </script>
@ -192,4 +206,8 @@ onMounted(() => {
margin-left: 24px; margin-left: 24px;
} }
#pagination{
display: flex;
justify-content: right;
}
</style> </style>
Loading…
Cancel
Save