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. 104
      src/components/blogs/HomePage.vue
  4. 210
      src/components/blogs/ceshi.vue
  5. 41
      src/views/blog/blogcontent/BlogDetailView.vue
  6. 68
      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) {
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({
@ -32,6 +32,10 @@ const iconComponents = {
YanJingLined: createIconComponent('icon-yanjing'),
XieZiLined: createIconComponent('icon-xiezi'),
CravatarLined: createIconComponent('icon-cravatar'),
GongAnLined: createIconComponent('icon-gonganbeian'),
IcpLined: createIconComponent('icon-wsmp-icprecord'),
BanQuanLined: createIconComponent('icon-banquan'),
}

104
src/components/blogs/HomePage.vue

@ -104,6 +104,54 @@
</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>
</template>
<script lang="ts" setup>
@ -121,7 +169,6 @@ import { useRouter, useRoute } from 'vue-router';
import iconComponents from "@/assets/index";
import type { classticInterface } from '@/api/admin';
import type { comLinkInterface } from '@/api/admin/index';
const router = useRouter()
const route = useRoute()
const author = ref("SunFree.")
@ -203,13 +250,13 @@ const items = ref<MenuProps['items']>([
},
]);
const jumpMenu = ({ key }:{key:string}) => {
// `item` `key` `url`
const selectedItem = items.value.find((i:any) => i.key === key);
if (selectedItem && selectedItem.url) {
const jumpMenu = ({ key }: { key: string }) => {
// `item` `key` `url`
const selectedItem = items.value.find((i: any) => i.key === key);
if (selectedItem && selectedItem.url) {
router.push(selectedItem.url);
}
};
}
};
const updateCarouselVisibility = (routeName: any) => {
handleScrollEnabled.value = false;
if (scrollbar.value) {
@ -684,4 +731,47 @@ watch(
.statistic {
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>

210
src/components/blogs/ceshi.vue

@ -1,189 +1,45 @@
<template>
<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>
<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>
</template>
<script setup lang="ts">
<script lang="ts" setup>
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;
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);
}
};
const hTags = Array.from(new Set(titlesArray.map((title) => title.tagName))).sort();
const onPageChange = (page: number) => {
current.value = page;
fetchData(page, pageSize.value);
};
titles.value = titlesArray.map((el) => ({
title: el.innerText,
lineIndex: el.getAttribute('data-v-md-line') || '', //
indent: 20 * (parseInt(el.tagName.substring(1)) - 1) //
}));
onMounted(() => {
fetchData(current.value, pageSize.value);
});
function handleAnchorClick(anchor: { title: string; lineIndex: string }) {
if (preview.value) {
const heading = preview.value.$el.querySelector(`[data-v-md-line="${anchor.lineIndex}"]`);
if (heading) {
preview.value.scrollToTarget({
target: heading,
scrollContainer: window,
top: 60,
});
} else {
console.error(`Heading element not found for lineIndex: ${anchor.lineIndex}`);
}
} else {
console.error('Preview component not initialized.');
}
}
</script>

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

@ -1,14 +1,17 @@
<template>
<div id="blogDetail">
<div v-for="anchor in titles" :style="{ padding: `4px 0 4px ${anchor.indent * 20}px` }"
@click="handleAnchorClick(anchor)" :key="anchor.lineIndex">
<a style="cursor: pointer">{{ anchor.title }}</a>
</div>
<div id="blogDetail">
<!-- <div v-for="anchor in titles" :style="{ padding: `4px 0 4px ${anchor.indent * 20}px` }"
@click="handleAnchorClick(anchor)" :key="anchor.lineIndex">
<a style="cursor: pointer">{{ anchor.title }}</a>
</div> -->
<a-card>
<v-md-preview v-if="text.blogcontent" :text="text.blogcontent" v-bind="previewProps" />
</div>
</template>
<script setup lang="ts">
</a-card>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, nextTick } from 'vue';
import { useRoute } from 'vue-router';
import { get } from '@/tools/request';
@ -18,6 +21,10 @@ const text = ref({
blogtitle: "",
blogcontent: ""
});
const titles = ref<{ title: string; lineIndex: string; indent: number }[]>([]);
// Props for v-md-preview component
@ -41,7 +48,7 @@ const blogOneList = async () => {
const processHeadings = async () => {
await nextTick();
const anchors = document.querySelectorAll('#blogDetail h1, #blogDetail h2, #blogDetail h3, #blogDetail h4, #blogDetail h5, #blogDetail h6');
const titlesArray = Array.from(anchors).filter((title:any) => !!title.innerText.trim());
const titlesArray = Array.from(anchors).filter((title: any) => !!title.innerText.trim());
if (!titlesArray.length) {
titles.value = [];
@ -84,10 +91,10 @@ onMounted(async () => {
});
</script>
<style scoped>
#blogDetail {
width: 45%;
}
</style>
<style scoped>
#blogDetail {
width: 45%;
margin: 0 24px;
}
</style>

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

@ -48,6 +48,16 @@
</a-card>
</a-badge-ribbon>
</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>
</template>
@ -56,45 +66,49 @@ import { onMounted, ref } from 'vue';
import iconComponents from '@/assets';
import dayjs from 'dayjs';
import type { blogInterface } from '@/api/admin';
import {get} from "@/tools/request"
import { get } from "@/tools/request"
import router from '@/router';
const randomColor = () => {
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)];
}
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 = async () => {
const onShowSizeChange = (page: number) => {
current.value = page;
blogList(page, pageSizeRef.value)
};
const blogList = async (page: number, pageSize: number) => {
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) {
console.log("bloglist is error")
console.error('Failed to fetch data', error);
}
};
}
const readMore=(id:any)=>{
const readMore = (id: any) => {
router.push(`/blog/${id}`)
}
onMounted(() => {
blogList();
blogList(current.value, pageSizeRef.value);
});
</script>
@ -192,4 +206,8 @@ onMounted(() => {
margin-left: 24px;
}
#pagination{
display: flex;
justify-content: right;
}
</style>
Loading…
Cancel
Save