This commit is contained in:
username 2024-06-12 16:21:20 +08:00
parent 186c910543
commit f255121dff
24 changed files with 8724 additions and 4362 deletions

8291
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -12,7 +12,9 @@
"core-js": "^3.8.3",
"dayjs": "^1.11.10",
"element-ui": "^2.15.14",
"masonry-layout": "^4.2.2",
"vue": "^2.6.14",
"vue-lazyload": "^3.0.0",
"vue-router": "^3.5.1",
"vuex": "^3.6.2"
},

View File

@ -1,21 +1,31 @@
<template>
<div id="app">
<main>
<router-view />
<trigger></trigger>
</main>
<footer>
<basePage></basePage>
</footer>
</div>
</template>
<script>
import trigger from '@/components/trigger.vue'
import basePage from './components/base.vue'
export default {
components: {
trigger
trigger,
basePage
}
}
</script>
<style lang="less">
*{
box-sizing: border-box;
}
/* 针对 WebKit 浏览器 */
::-webkit-scrollbar {
width: 5px; /* 滚动条宽度 */

5
src/api/dailySentence.js Normal file
View File

@ -0,0 +1,5 @@
import axios from 'axios'
export const fetchUser = () => {
return axios.get('https://api.oioweb.cn/api/SimpWords')
}

9
src/api/jiwang.js Normal file
View File

@ -0,0 +1,9 @@
import request from '../utils/request'
export function getlist (id) {
return request({
url: `/list/${id}`,
method: 'get',
params: { id }
})
}

View File

@ -1,135 +1,157 @@
.box-shadow-mixin() {
box-shadow: 5px 10px 10px rgba(0, 0, 0, 0.1),
-5px -10px 20px rgba(0, 0, 0, 0.2);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1), 0 -4px 8px rgba(0, 0, 0, 0.1);
}
.box {
background: url("../images/sub.jpg") no-repeat center center fixed;
-webkit-background-size: cover;
-moz-background-size: cover;
-o-background-size: cover;
background-size: cover;
height: 100vh;
margin-top: 0;
position: relative;
margin-bottom: 50px;
}
.head {
width: 1200px;
// height: 2200px;
max-width: 1200px;
margin: 20px auto;
display: flex;
justify-content: space-between;
}
.head-left {
width: 800px;
// height: 2200px;
float: left;
.head-left {
width: 70%;
display: flex;
flex-wrap: wrap;
gap: 20px;
.content-left {
width: 752px;
background-color: #fff;
.box-shadow-mixin();
margin-bottom: 10px;
padding: 20px;
float: left;
flex: 1 1 calc(50% - 20px);
box-sizing: border-box;
position: relative;
transition: transform 0.3s ease, box-shadow 0.3s ease;
&:hover {
transform: translateY(-5px);
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2);
}
.con-title-left {
a:hover {
color: #006cff;
}
}
display: flex;
flex-direction: column;
align-items: center;
img {
width: 200px;
// height: 200px;
margin-top: 10px;
float: left;
width: 100%;
height: auto;
border-radius: 8px;
margin-bottom: 15px;
}
h3 {
font-size: 1.5em;
margin-bottom: 10px;
text-align: center;
a {
color: #333;
text-decoration: none;
&:hover {
color: #007bff;
}
}
}
.time {
color: gray;
font-size: 12px;
position: absolute;
right: 20px;
bottom: 20px;
font-size: 0.9em;
margin-top: auto;
align-self: flex-end;
}
}
}
.head-right {
float: right;
width: 390px;
// height: 2200px;
.develop {
width: 390px;
height: 215px;
margin-bottom: 20px;
position: relative;
overflow: hidden;
transition: transform 0.5s ease;
border: 1px solid #eee;
img {
width: 390px;
height: 215px;
transition: transform 0.5s ease;
}
.title {
width: 390px;
height: 40px;
background-color: rgba(0, 0, 0, 0.5);
position: absolute;
bottom: 0;
z-index: 999;
p {
color: white;
line-height: 40px;
margin-left: 20px;
}
}
}
.develop:hover img {
transform: scale(1.2);
/* 鼠标经过时图片放大到原始大小的 1.2 倍 */
}
.content-right {
width: 390px;
height: 337px;
background-color: #fff;
.con-title-right {
.box-shadow-mixin();
h3 {
padding: 40px 0 0 40px;
}
p {
width: 50px;
margin: 10px 0 0 40px;
border: 1px solid black;
transition: all 0.5s;
}
.flex {
margin: 10px;
.el-tag {
margin: 5px;
cursor: pointer;
font-size: 16px;
}
}
}
}
.content-right:hover p {
width: 80px;
border: 1px solid red;
}
}
}
.head-right {
width: 28%;
.content-right {
width: 100%;
background-color: #fff;
border-radius: 12px;
.box-shadow-mixin();
padding: 20px;
box-sizing: border-box;
margin-bottom: 20px;
.con-title-right {
h3 {
font-size: 1.5em;
margin-bottom: 20px;
}
.flex {
display: flex;
flex-wrap: wrap;
gap: 10px;
.el-tag {
cursor: pointer;
font-size: 1em;
}
}
}
}
.popular-articles {
background-color: #fff;
border-radius: 12px;
.box-shadow-mixin();
padding: 20px;
margin-bottom: 20px;
h3 {
font-size: 1.5em;
margin-bottom: 20px;
}
ul {
list-style: none;
padding: 0;
li {
margin-bottom: 10px;
a {
color: #333;
text-decoration: none;
&:hover {
color: #007bff;
}
}
}
}
}
.advertisement {
background-color: #fff;
border-radius: 12px;
.box-shadow-mixin();
padding: 20px;
h3 {
font-size: 1.5em;
margin-bottom: 20px;
}
img {
width: 100%;
height: auto;
border-radius: 8px;
}
}
}

20
src/components/base.vue Normal file
View File

@ -0,0 +1,20 @@
<template>
<div class="base"></div>
</template>
<script>
export default {
name: 'basePage',
data () {
return {}
}
}
</script>
<style lang="less" scoped>
.base {
width: 100%;
height: 100px;
background-color: palegreen;
}
</style>

View File

@ -1,411 +1,261 @@
<template>
<div class="wrap">
<!-- 播放器主体区域 -->
<div class="play_wrap" id="player">
<div class="search_bar">
<img src="../assets/images/player_title.png" alt="" />
<!-- 搜索歌曲 -->
<input type="text" autocomplete="off" v-model="query" placeholder="歌手名或歌曲名" @keyup.enter="searchMusic" />
<div
class="footer-player"
:class="{ locked: isLocked }"
@mouseenter="showPlayer = true"
@mouseleave="showPlayer = isLocked ? true : false"
>
<!-- 三角形按钮 -->
<div class="triangle"></div>
<!-- 播放器控制部分 -->
<div class="footer-player-container">
<div class="controls">
<button @click="prevSong" class="control-btn">&#9664;</button>
<button @click="togglePlayPause" class="control-btn">
<i v-if="isPlaying" class="fas fa-pause"></i>
<i v-else class="fas fa-play"></i>
</button>
<button @click="nextSong" class="control-btn">&#9654;</button>
</div>
<div class="center_con">
<!-- 搜索歌曲列表 -->
<div class='song_wrapper'>
<ul class="song_list">
<li v-for="(item, index) in musicList" :key="index">
<a href="javascript:;" @click="playMusic(item.id)"></a>
<b>{{ item.name }}</b>
<span v-if="item.mvid!=0" @click="playMV(item.mvid);play()"><i></i></span>
<!-- 歌曲信息 -->
<div class="song-info">
<img :src="currentSong.cover" class="cover" alt="Cover" />
<div class="details">
<h2>{{ currentSong.title }}</h2>
<p>{{ currentSong.artist }}</p>
</div>
</div>
<!-- 播放列表 -->
<div class="playlist">
<ul>
<li
v-for="(song, index) in playlist"
:key="index"
@click="playSong(index)"
>
<span>{{ song.title }}</span>
<span>{{ song.artist }}</span>
</li>
</ul>
<img src="../assets/images/line.png" class="switch_btn" alt="">
</div>
<!-- 歌曲信息容器 -->
<div class="player_con" :class="{playing:isPlaying}">
<img src="../assets/images/player_bar.png" class="play_bar" />
<!-- 黑胶碟片 -->
<img src="../assets/images/disc.png" class="disc autoRotate" />
<img :src="musicCover" class="cover autoRotate" />
</div>
</div>
<div class="audio_con">
<audio ref='audio' @play="play" @pause="pause" :src="musicUrl" controls autoplay loop class="myaudio"></audio>
</div>
<div class="video_con" v-show="isShow" style="display: none;">
<video :src="mvUrl" controls="controls"></video>
<div class="mask" @click="hide"></div>
</div>
<!-- 锁定按钮 -->
<button @click="toggleLock" class="lock-btn">
<i :class="isLocked ? 'fas fa-lock' : 'fas fa-lock-open'"></i>
</button>
</div>
</div>
</template>
<script>
import axios from 'axios'
export default {
name: 'musIc',
name: 'musicPage',
data () {
return {
//
query: '',
//
musicList: [],
//
musicUrl: '',
//
musicCover: require('@/assets/images/musicLogo.png'),
//
hotComments: [],
//
searchQuery: '',
playlist: [
{
title: 'Song 1',
artist: 'Artist 1',
cover: require('@/assets/images/789.jpg')
},
{
title: 'Song 2',
artist: 'Artist 2',
cover: require('@/assets/images/789.jpg')
},
{
title: 'Song 3',
artist: 'Artist 3',
cover: require('@/assets/images/789.jpg')
}
],
currentSongIndex: 0,
isPlaying: false,
//
isShow: false,
// mv
mvUrl: ''
showPlayer: false,
isLocked: false
}
},
computed: {
currentSong () {
return this.playlist[this.currentSongIndex]
}
},
methods: {
//
async searchMusic () {
const that = this
axios.get('https://autumnfish.cn/search' + this.query).then(
function (response) {
// console.log(response);
that.musicList = response.data.result.songs
console.log(response.data.result.songs)
}
)
searchMusic () {
//
},
//
playMusic (musicId) {
const that = this
that.musicUrl = 'http://music.163.com/song/media/outer/url?id=' + musicId + '.mp3'
//
axios.get('https://song.ddmt.top/cloudmusic/?type=detail&id=' + musicId).then(
function (response) {
console.log(response)
// console.log(response.data.songs[0].al.picUrl);
that.musicCover = response.data.songs[0].al.picUrl
})
//
axios.get('https://autumnfish.cn/comment/hot?type=0&id=' + musicId).then(
function (response) {
// console.log(response);
// console.log(response.data.hotComments);
that.hotComments = response.data.hotComments
}
)
playSong (index) {
this.currentSongIndex = index
this.isPlaying = true //
},
//
play () {
this.isPlaying = true
togglePlayPause () {
this.isPlaying = !this.isPlaying
},
//
pause () {
this.isPlaying = false
prevSong () {
this.currentSongIndex =
(this.currentSongIndex - 1 + this.playlist.length) %
this.playlist.length
this.isPlaying = true //
},
// mv
playMV (mvid) {
const that = this
axios.get('https://autumnfish.cn/mv/url?id=' + mvid).then(
function (response) {
// console.log(response);
console.log(response.data.data.url)
that.isShow = true
that.mvUrl = response.data.data.url
}
)
nextSong () {
this.currentSongIndex =
(this.currentSongIndex + 1) % this.playlist.length
this.isPlaying = true //
},
//
hide () {
this.isShow = false
toggleLock () {
this.isLocked = !this.isLocked
}
}
}
</script>
<style lang="less" scoped>
<style scoped>
@import url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css");
.wrap {
width: 600px;
height: 544px;
margin: 60px auto;
clear: both;
body {
margin: 0;
font-family: "Arial", sans-serif;
background: #f0f0f0;
color: #333;
position: relative;
}
.play_wrap {
width: 600px;
height: 544px;
.triangle {
position: absolute;
right: 0;
bottom: 70px;
width: 0;
height: 0;
border: 0 solid transparent;
border-right: 10px solid transparent;
border-left: 10px solid transparent;
border-bottom: 12px solid #333;
}
.search_bar {
height: 60px;
background-color: #1eacda;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
.footer-player {
position: fixed;
bottom: -60px; /* 初始隐藏位置 */
left: 0;
width: 100%;
z-index: 9999999999999999;
background: #333;
color: #fff;
display: flex;
justify-content: center;
align-items: center;
box-shadow: 0 -4px 10px rgba(0, 0, 0, 0.1);
transition: bottom 0.3s ease-in-out;
}
.footer-player:hover {
bottom: 0; /* 鼠标经过时显示整个播放器 */
}
.footer-player:hover .triangle{
position: absolute;
bottom: 70px;
right: 0;
}
.footer-player.locked {
bottom: 0; /* 锁定状态下始终显示 */
}
.footer-player-container {
width: 80%;
max-width: 1200px;
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 0;
}
.controls {
display: flex;
align-items: center;
justify-content: space-between;
position: relative;
z-index: 11;
}
.search_bar img {
margin-left: 23px;
.control-btn {
background: none;
border: none;
color: #fff;
font-size: 24px;
margin: 0 10px;
cursor: pointer;
transition: transform 0.3s;
}
.search_bar input {
margin-right: 23px;
width: 296px;
height: 34px;
border-radius: 17px;
border: 0px;
background: url("../assets/images/zoom.png") 265px center no-repeat
rgba(255, 255, 255, 0.45);
text-indent: 15px;
outline: none;
.control-btn:hover {
transform: scale(1.2);
}
.center_con {
height: 435px;
background-color: rgba(255, 255, 255, 0.5);
.song-info {
display: flex;
position: relative;
align-items: center;
}
.song_wrapper {
width: 200px;
height: 435px;
box-sizing: border-box;
.cover {
width: 50px;
height: 50px;
border-radius: 10px;
margin-right: 20px;
}
.details h2 {
margin: 0;
font-size: 18px;
}
.details p {
margin: 5px 0 0;
color: #ccc;
}
.playlist {
background: #444;
border-radius: 10px;
padding: 10px;
list-style: none;
position: absolute;
left: 0px;
top: 0px;
z-index: 1;
}
.song_stretch {
width: 600px;
}
.song_list {
width: 100%;
box-shadow: 0 -4px 10px rgba(0, 0, 0, 0.2);
overflow-y: auto;
overflow-x: hidden;
height: 100%;
}
.song_list::-webkit-scrollbar {
max-height: 50px;
display: none;
}
.song_list li {
font-size: 12px;
color: #333;
height: 40px;
display: flex;
flex-wrap: wrap;
align-items: center;
width: 580px;
padding-left: 10px;
}
.song_list li:nth-child(odd) {
background-color: rgba(240, 240, 240, 0.3);
}
.song_list li a {
.footer-player:hover .playlist,
.footer-player.locked .playlist {
display: block;
width: 17px;
height: 17px;
background-image: url("../assets/images/play.png");
background-size: 100%;
margin-right: 5px;
box-sizing: border-box;
}
.song_list li b {
font-weight: normal;
width: 122px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.song_stretch .song_list li b {
width: 200px;
}
.song_stretch .song_list li em {
width: 150px;
}
.song_list li span {
width: 23px;
height: 17px;
margin-right: 50px;
}
.song_list li span i {
display: block;
width: 100%;
height: 100%;
cursor: pointer;
background: url("../assets/images/table.png") left -48px no-repeat;
}
.song_list li em,
.song_list li i {
font-style: normal;
width: 100px;
}
.player_con {
width: 400px;
height: 435px;
position: absolute;
left: 200px;
top: 0px;
}
.player_con2 {
width: 400px;
height: 435px;
position: absolute;
left: 200px;
top: 0px;
}
.player_con2 video {
position: absolute;
left: 20px;
top: 30px;
width: 355px;
height: 265px;
}
.disc {
position: absolute;
left: 73px;
top: 60px;
z-index: 9;
}
.cover {
position: absolute;
left: 125px;
top: 112px;
width: 150px;
height: 150px;
border-radius: 75px;
z-index: 8;
}
.audio_con {
height: 50px;
background-color: #f1f3f4;
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
}
.myaudio {
width: 600px;
height: 40px;
margin-top: 5px;
outline: none;
background-color: #f1f3f4;
}
/* 旋转的动画 */
@keyframes Rotate {
from {
transform: rotateZ(0);
}
to {
transform: rotateZ(360deg);
}
}
/* 旋转的类名 */
.autoRotate {
animation-name: Rotate;
animation-iteration-count: infinite;
animation-play-state: paused;
animation-timing-function: linear;
animation-duration: 5s;
}
/* 是否正在播放 */
.player_con.playing .disc,
.player_con.playing .cover {
animation-play-state: running;
}
.play_bar {
position: absolute;
left: 200px;
top: -10px;
z-index: 10;
transform: rotate(-25deg);
transform-origin: 12px 12px;
transition: 1s;
}
/* 播放杆 转回去 */
.player_con.playing .play_bar {
transform: rotate(0);
}
/* 搜索历史列表 */
.search_history {
position: absolute;
width: 296px;
overflow: hidden;
background-color: rgba(255, 255, 255, 0.3);
.playlist ul {
list-style: none;
right: 23px;
top: 50px;
box-sizing: border-box;
padding: 10px 20px;
border-radius: 17px;
}
.search_history li {
line-height: 24px;
font-size: 12px;
cursor: pointer;
}
.switch_btn {
position: absolute;
right: 0;
top: 0;
cursor: pointer;
}
.right_line {
position: absolute;
left: 0;
top: 0;
}
.video_con video {
position: fixed;
width: 600px;
height: 546px;
left: 50%;
top: 50%;
margin-top: -273px;
transform: translateX(-50%);
z-index: 990;
}
.video_con .mask {
position: fixed;
width: 100%;
height: 100%;
left: 0;
top: 0;
z-index: 980;
background-color: rgba(0, 0, 0, 0.8);
}
.video_con .shutoff {
position: fixed;
width: 40px;
height: 40px;
background: url("../assets/images/shutoff.png") no-repeat;
left: 50%;
margin-left: 400px;
margin-top: -273px;
top: 50%;
z-index: 995;
padding: 0;
margin: 0;
}
.playlist li {
padding: 10px;
display: flex;
justify-content: space-between;
cursor: pointer;
/* transition: background 0.3s; */
}
.playlist li:hover {
background: #555;
}
.lock-btn {
background: none;
border: none;
color: #fff;
font-size: 24px;
cursor: pointer;
transition: transform 0.3s;
margin-left: 20px;
}
.lock-btn:hover {
transform: scale(1.2);
}
</style>

View File

@ -2,50 +2,52 @@
<div class="nav" :class="{ fixed: isFixed }">
<div class="navList">
<p>
<router-link to="/home">墨思留痕</router-link>
<router-link to="/">墨思留痕</router-link>
</p>
<ul class="nackground">
<li>
<router-link to="/home" exact-active-class="active">首页</router-link>
<router-link to="/" exact-active-class="active">首页</router-link>
</li>
<li>
<router-link to="/labelpage" exact-active-class="active"
>标签</router-link
>
<router-link to="/labelpage" exact-active-class="active">标签</router-link>
</li>
<li>
<router-link to="/subject" exact-active-class="active"
>专题</router-link
>
<router-link to="/listPage" exact-active-class="active">专题</router-link>
</li>
<li>
<router-link to="/messageboard" exact-active-class="active"
>留言板</router-link
>
<router-link to="/messageboard" exact-active-class="active">留言板</router-link>
</li>
<li>
<router-link to="/interlinkage" exact-active-class="active"
>友情链接</router-link
>
<router-link to="/photoGallery" exact-active-class="active">照片集</router-link>
</li>
<li>
<router-link to="/about" exact-active-class="active"
>个人中心</router-link
>
<router-link to="/interlinkage" exact-active-class="active">友情链接</router-link>
</li>
<li>
<router-link to="/about" exact-active-class="active">个人中心</router-link>
</li>
</ul>
<div class="search">
<div class="search" @click.stop>
<el-input
v-model="input"
placeholder="请输入内容"
clearable
style="width: 230px; margin-right: 10px"
@keyup.enter="performSearch"
></el-input>
<el-button icon="el-icon-search" circle></el-button>
<el-button icon="el-icon-search" circle @click="performSearch"></el-button>
<el-avatar style="margin-left: 10px; position: absolute; top: 10px">
<router-link to="/about">user</router-link>
</el-avatar>
<div class="out" @click="handleOut">退出</div>
<div v-if="resultsVisible" class="search-results" @click.stop>
<ul v-if="searchResults.length">
<li v-for="result in searchResults" :key="result.id">
<router-link :to="result.link">{{ result.title }}</router-link>
</li>
</ul>
<p v-else >暂无内容</p>
</div>
</div>
</div>
</div>
@ -56,33 +58,59 @@ export default {
data () {
return {
input: '',
Search: 'Search',
isFixed: false //
searchResults: [],
isFixed: false, //
resultsVisible: false // /
}
},
mounted () {
window.addEventListener('scroll', this.handleScroll)
document.addEventListener('click', this.hideResults)
},
beforeDestroy () {
window.removeEventListener('scroll', this.handleScroll)
document.removeEventListener('click', this.hideResults)
},
methods: {
handleScroll () {
const scrollTop = window.scrollY || document.documentElement.scrollTop
this.isFixed = scrollTop > 60
},
//
performSearch () {
if (!this.input.trim()) {
this.$message({
message: '请输入内容',
type: 'warning'
})
return
}
// API
const allItems = [
{ id: 1, title: '首页内容', link: '/home' },
{ id: 2, title: '标签内容', link: '/labelpage' },
{ id: 3, title: '专题内容', link: '/listPage' },
{ id: 4, title: '留言板内容', link: '/messageboard' },
{ id: 5, title: '友情链接内容', link: '/interlinkage' },
{ id: 6, title: '个人中心内容', link: '/about' }
]
this.searchResults = allItems.filter(item =>
item.title.includes(this.input)
)
this.resultsVisible = true
},
// 退
handleOut () {
// localStoragetoken
localStorage.removeItem('user-token')
// Vuex
this.$store.commit('logout')
//
this.$router.push({ path: '/' })
this.$router.push({ path: '/login' })
this.$message({
message: '退出成功',
type: 'success'
})
},
//
hideResults () {
this.resultsVisible = false
}
}
}
@ -174,7 +202,7 @@ export default {
.out {
position: absolute;
right: -50px;
right: -70px;
top: 15px;
color: #006cff;
width: 50px;
@ -189,5 +217,41 @@ export default {
color: #fff;
background-color: #006cff;
}
.search-results {
position: absolute;
top: 100%;
left: 0;
width: 100%;
background: #fff;
border: 1px solid #ddd;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
z-index: 1000;
ul {
list-style: none;
margin: 0;
padding: 0;
li {
padding: 8px 16px;
a {
text-decoration: none;
color: #333;
}
a:hover {
background-color: #f5f5f5;
}
}
}
p {
font-size: 14px;
margin-bottom: 15px;
color: #333;
}
}
}
</style>

116
src/components/shareBtn.vue Normal file
View File

@ -0,0 +1,116 @@
<template>
<div class="share-btn">
<button @click="toggleShareOptions">分享</button>
<div v-if="showOptions" class="share-options">
<button @click="sharePage">分享页面</button>
<button @click="copyLink">复制链接</button>
</div>
</div>
</template>
<script>
export default {
name: 'shareBtn',
data () {
return {
showOptions: false
}
},
methods: {
toggleShareOptions () {
this.showOptions = !this.showOptions
},
async sharePage () {
if (navigator.share) {
try {
await navigator.share({
title: document.title,
url: window.location.href
})
this.$message({
message: '分享成功',
type: 'success'
})
} catch (error) {
this.$message({
message: '分享失败',
type: 'error'
})
}
} else {
this.copyLink()
}
},
copyLink () {
const url = window.location.href
try {
navigator.clipboard.writeText(url).then(() => {
this.$message({
message: '链接已复制',
type: 'success'
})
})
} catch (err) {
this.$message({
message: '复制失败',
type: 'error'
})
}
}
}
}
</script>
<style lang="less" scoped>
.share-btn {
position: fixed;
bottom: 10px;
right: 10px;
z-index: 999;
button {
background-color: #42b983;
color: #fff;
border: none;
padding: 10px 20px;
border-radius: 5px;
cursor: pointer;
margin-bottom: 5px;
}
.share-options {
display: flex;
flex-direction: column;
position: absolute;
bottom: 45px;
right: 0;
background-color: #fff;
border: 1px solid #ddd;
border-radius: 5px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
button {
background-color: #42b983;
color: #fff;
border: none;
padding: 10px;
border-radius: 0;
cursor: pointer;
&:first-child {
border-top-left-radius: 5px;
border-top-right-radius: 5px;
}
&:last-child {
border-bottom-left-radius: 5px;
border-bottom-right-radius: 5px;
}
&:hover {
background-color: #357a38;
}
}
}
}
</style>

View File

@ -1,30 +1,18 @@
import Vue from 'vue'
import VueRouter from 'vue-router'
import Login from '@/views/login'
import Home from '../views/Home.vue'
// import CSSContent from '@/views/CSS3/index.vue'
// import cyuyan from '@/views/Cyuyan/index.vue'
// import diangong from '@/views/diangong/index.vue'
// import HTMLContent from '@/views/HTML5/index.vue'
// import javaContent from '@/views/java/index.vue'
// import jqueryContent from '@/views/jQuery/index.vue'
// import LinuxContent from '@/views/linuxxitong/index.vue'
// import MySQLContent from '@/views/MySQLjishu/index.vue'
// import NodeContent from '@/views/Node/index.vue'
// import PHPContent from '@/views/PHPsheji/index.vue'
// import pythonContent from '@/views/python/index.vue'
// import vsContent from '@/views/vscodejis/index.vue'
// import VueContent from '@/views/Vue/index.vue'
// import jiwang from '@/views/jiwang/jiwang.vue'
// import jsContent from '@/views/JavaScript/index.vue'
import NoteDetail from '@/views/particulars/list'
// import store from '@/store' // Vuex store
import NoteDetail from '@/views/particulars/paiListPage'
Vue.use(VueRouter)
const routes = [
{
path: '/home',
path: '/',
name: 'Home',
component: Home
component: Home,
meta: { requiresAuth: true }
},
{
path: '/about',
@ -37,9 +25,9 @@ const routes = [
component: (resolve) => require(['@/views/labelPage'], resolve)
},
{
path: '/subject',
name: 'subject',
component: (resolve) => require(['@/views/subject'], resolve)
path: '/listPage',
name: 'listPage',
component: (resolve) => require(['@/views/subject/listPage'], resolve)
},
{
path: '/messageboard',
@ -47,96 +35,31 @@ const routes = [
component: (resolve) => require(['@/views/messageBoard'], resolve)
},
{
path: '/',
path: '/photoGallery',
name: 'photoGallery',
component: (resolve) => require(['@/views/photoGallery'], resolve)
},
{
path: '/login',
name: 'Login',
component: (resolve) => require(['@/views/login'], resolve)
component: Login
},
{
path: '/TopicDetails',
name: 'TopicDetails',
component: (resolve) => require(['@/views/particulars/TopicDetails'], resolve)
component: (resolve) => require(['@/views/subject/TopicDetails'], resolve)
},
{
path: '/interlinkage',
name: 'interlinkage',
component: (resolve) => require(['@/views/interlinkage'], resolve)
},
// {
// path: '/jiwang',
// name: 'jiwang',
// component: jiwang
// },
// {
// path: '/jsContent',
// name: 'jsContent',
// component: jsContent
// },
// {
// path: '/CSSContent',
// name: 'CSSContent',
// component: CSSContent
// },
// {
// path: '/cyuyan',
// name: 'cyuyan',
// component: cyuyan
// },
// {
// path: '/diangong',
// name: 'diangong',
// component: diangong
// },
// {
// path: '/HTMLContent',
// name: 'HTMLContent',
// component: HTMLContent
// },
// {
// path: '/javaContent',
// name: 'javaContent',
// component: javaContent
// },
// {
// path: '/jqueryContent',
// name: 'jqueryContent',
// component: jqueryContent
// },
// {
// path: '/LinuxContent',
// name: 'LinuxContent',
// component: LinuxContent
// },
// {
// path: '/MySQLContent',
// name: 'MySQLContent',
// component: MySQLContent
// },
// {
// path: '/NodeContent',
// name: 'NodeContent',
// component: NodeContent
// },
// {
// path: '/PHPContent',
// name: 'PHPContent',
// component: PHPContent
// },
// {
// path: '/vsContent',
// name: 'vsContent',
// component: vsContent
// },
// {
// path: '/VueContent',
// name: 'VueContent',
// component: VueContent
// },
// {
// path: '/pythonContent',
// name: 'pythonContent',
// component: pythonContent
// },
{ path: '/list/:id', component: NoteDetail }
{ path: '/paiListPage/:id', component: NoteDetail },
{
path: '/detailPage',
name: 'detailPage',
component: (resolve) => require(['@/views/particulars/detailPage'], resolve)
}
]
const router = new VueRouter({
@ -151,4 +74,16 @@ const router = new VueRouter({
routes
})
// router.beforeEach((to, from, next) => {
// const isAuthenticated = store.getters.isAuthenticated
// if (to.matched.some(record => record.meta.requiresAuth) && !isAuthenticated) {
// next('/login')
// } else if (to.path === '/login' && isAuthenticated) {
// next('/')
// } else {
// next()
// }
// })
export default router

View File

@ -1,3 +1,4 @@
// src/store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
@ -5,34 +6,22 @@ Vue.use(Vuex)
export default new Vuex.Store({
state: {
user: null, // 初始用户状态为null
token: null, // 初始token状态为null
isLoggedIn: false // 初始登录状态为false
},
getters: {
isAuthenticated: false
},
mutations: {
setLoggedIn (state, isLoggedIn) {
state.isLoggedIn = isLoggedIn
},
setToken (state, token) {
state.token = token
},
setUser (state, user) {
state.user = user
},
logout (state) {
// 清除用户信息
state.token = null
state.user = null
// ... 清除其他与用户相关的状态
setAuthenticated (state, status) {
state.isAuthenticated = status
}
},
actions: {
async setUser ({ commit }, user) {
commit('setLoggedIn', user)
login ({ commit }) {
commit('setAuthenticated', true)
},
logout ({ commit }) {
commit('setAuthenticated', false)
}
},
modules: {
getters: {
isAuthenticated: state => state.isAuthenticated
}
})

View File

@ -2,130 +2,447 @@
<div class="AboutUs">
<navigationBar />
<div class="box">
<el-tabs type="border-card">
<el-tab-pane label="个人信息">
<div class="AboutUs-left">
<h3>个人信息</h3>
<hr />
<div class="AboutUs-img">
<img src="../assets/images/sub.jpg" alt="" />
<img src="../assets/images/sub.jpg" alt="用户头像" />
</div>
<div class="user-info">
<div
v-for="(item, index) in users"
:key="index"
class="user-item"
>
<p class="user-name">{{ item.name }}</p>
<p class="user-date">{{ item.date }}</p>
</div>
</div>
<p v-for="(item, index) in users" :key="index">
{{ item.name }}
<span>{{ item.date }}</span>
</p>
</div>
<div class="AboutUs-right">
<p @click="isShow = true">切换背景</p>
</div>
<h3>其他操作</h3>
<hr />
<p @click="toggleBackground">切换背景</p>
<p>帮助与反馈</p>
</div>
<trigger :visible.sync="isShow"></trigger>
</el-tab-pane>
<el-tab-pane label="待办事项">
<div class="wtbDone">
<input type="text" v-model="newTodo" placeholder="请输入待办事项" />
<button class="handleAdd" @click="handleAdd">添加</button>
<ul>
<li
v-for="(todo, index) in todos"
:key="index"
:class="{ selected: index === selectedTodoIndex }"
@click="selectTodo(index)"
>
{{ todo }}
</li>
</ul>
<div class="wtbDone-footer">
<button @click="handleDelete">删除</button>
</div>
</div>
</el-tab-pane>
<el-tab-pane label="基本设置">
<div class="basic-settings">
<!-- 左边内容 -->
<div class="left-section">
<!-- 昵称 -->
<div class="form-item">
<label for="nickname">昵称</label>
<input
type="text"
id="nickname"
v-model="nickname"
placeholder="请输入昵称"
/>
</div>
<!-- 介绍 -->
<div class="form-item">
<label for="intro">介绍</label>
<input id="intro" v-model="intro" placeholder="请输入介绍" />
</div>
<!-- 性别 -->
<div class="form-item">
<label>性别</label>
<input type="radio" v-model="gender" value="male" />
<input
type="radio"
v-model="gender"
value="female"
style="margin-left: 10px"
/>
</div>
<!-- 生日 -->
<div class="form-item">
<label for="birthday">生日</label>
<input type="date" id="birthday" v-model="birthday" />
</div>
<!-- 地区选择 -->
<div class="form-item">
<label for="region">地区</label>
<select id="region" v-model="region">
<option value="region1">地区1</option>
<option value="region2">地区2</option>
<option value="region3">地区3</option>
</select>
<select id="region" v-model="city" style="margin-left: 10px">
<option value="city1">地区1</option>
<option value="city2">地区2</option>
<option value="city3">地区3</option>
</select>
</div>
<!-- 保存按钮 -->
<div class="form-item">
<button class="save-btn" @click="saveUserInfo">保存</button>
</div>
</div>
<!-- 右边内容 -->
<div class="right-section">
<div class="avatar-section">
<!-- 头像显示 -->
<img :src="avatar" alt="用户头像" class="avatar" />
<!-- 更换头像按钮 -->
<span class="change-avatar-btn" @click="changeAvatar"
>更换头像</span
>
</div>
</div>
</div>
</el-tab-pane>
</el-tabs>
</div>
<musIc />
</div>
</template>
<script>
import navigationBar from '@/components/navigationBar.vue'
import trigger from '@/components/trigger.vue'
export default {
data () {
return {
isShow: false,
nickname: '',
intro: '',
gender: '',
birthday: '',
region: '',
city: '',
avatar: require('@/assets/images/789.jpg'), //
users: [
{
name: '用户名称',
date: '创建日期'
},
{
name: '用户名称',
date: '创建日期'
name: '当前用户名',
date: '2024-01-01'
}
],
dialogVisible: false
newTodo: '',
todos: [], //
selectedTodoIndex: null //
}
},
components: {
navigationBar,
trigger
},
methods: {
toggleBackground () {
this.isShow = true
},
saveUserInfo () {
//
this.$message.success('保存成功')
},
changeAvatar () {
//
this.$message.success('更换成功')
},
//
handleAdd () {
if (this.newTodo.trim() !== '') {
this.todos.push(this.newTodo.trim())
this.newTodo = ''
this.$message.success('添加成功')
} else {
this.$message.error('请输入待办事项')
}
},
//
selectTodo (index) {
this.selectedTodoIndex = index
},
//
handleDelete () {
if (this.selectedTodoIndex !== null) {
this.todos.splice(this.selectedTodoIndex, 1)
this.selectedTodoIndex = null
this.$message.success('删除成功')
} else {
this.$message.error('请选择要删除的待办事项')
}
}
}
}
</script>
<style lang="less" scoped>
.wtbDone {
width: 400px;
height: 500px;
border: 1px solid black;
margin: auto;
padding: 10px;
border-radius: 8px;
background-color: #fff;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
.AboutUs {
.box {
width: 1220px;
// height: 500px;
margin: 100px auto;
input {
width: 300px;
height: 40px;
padding: 5px;
margin-top: 20px;
outline: none;
border-radius: 4px;
border: 1px solid #ccc;
&:focus {
border: 1px solid #007bff;
}
}
}
.AboutUs-left {
width: 500px;
height: 500px;
float: left;
background-color: #fff;
margin-right: 20px;
border-radius: 10px;
box-shadow: 0 0 10px #ccc;
box-sizing: border-box;
ul {
list-style: none;
padding: 0;
width: 350px;
height: 310px;
margin: 20px auto;
overflow-y: scroll;
border: 1px solid #ddd;
border-radius: 4px;
h3 {
li {
width: 100%;
height: 40px;
line-height: 40px;
font-size: 20px;
color: #333;
margin: 0 0 5px 20px;
text-align: center;
background-color: #f5f5f5;
border-bottom: 1px solid #ddd;
cursor: pointer;
transition: background-color 0.3s;
&:hover {
background-color: #e6e6e6;
}
.AboutUs-img {
width: 100%;
height: 180px;
margin-top: 10px;
&.selected {
background-color: #d3e5ff;
}
}
}
.wtbDone-footer {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 20px;
padding: 10px;
}
button {
width: 70px;
height: 40px;
background-color: #007bff;
color: #fff;
border: none;
border-radius: 4px;
margin-left: 5px;
cursor: pointer;
transition: background-color 0.3s;
&:hover {
background-color: #0056b3;
}
}
.box {
background-color: #f5f5f5;
border-radius: 8px;
padding: 20px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
margin: 80px auto;
max-width: 800px;
}
.AboutUs-left {
text-align: left;
}
.AboutUs-right {
text-align: left;
}
hr {
border: none;
border-top: 1px solid #ddd;
margin: 20px 0;
}
.AboutUs-img {
text-align: center;
}
.AboutUs-img img {
width: 120px;
height: 120px;
border-radius: 50%;
margin-bottom: 20px;
border: 4px solid #fff;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
.user-info {
margin-bottom: 20px;
}
.user-name {
color: #333;
font-size: 18px;
margin-bottom: 5px;
}
.user-date {
color: #666;
font-size: 14px;
}
.AboutUs-right p {
color: #007bff;
font-size: 18px;
margin-bottom: 10px;
cursor: pointer;
}
.AboutUs-right p:hover {
text-decoration: underline;
}
.el-tabs {
text-align: left;
}
.basic-settings {
display: flex;
justify-content: space-between;
align-items: flex-start;
}
.left-section {
width: 50%;
padding-right: 20px;
}
.right-section {
width: 40%;
padding-left: 20px;
}
.form-item {
margin-bottom: 20px;
#nickname {
width: 250px;
padding: 5px;
outline: none;
height: 30px;
}
#intro {
width: 250px;
padding: 5px;
outline: none;
height: 100px;
}
}
.form-item label {
display: inline-block;
font-weight: bold;
}
#region {
outline: none;
width: 120px;
height: 30px;
padding: 5px;
}
.input-field {
width: calc(100% - 80px);
padding: 8px;
border: 1px solid #ccc;
border-radius: 4px;
}
.save-btn {
padding: 8px 20px;
background-color: #007bff;
color: #fff;
border: none;
border-radius: 4px;
cursor: pointer;
transition: background-color 0.3s;
margin-left: 120px;
&:hover {
background-color: #0056b3;
}
}
.avatar-section {
width: 150px;
height: 150px;
border-radius: 50%;
background-color: palegreen;
position: relative;
overflow: hidden;
img {
width: 100px;
height: 100px;
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
border-radius: 50%;
margin-top: 8%;
margin-left: 38%;
object-fit: cover;
}
}
.change-avatar-btn {
width: 100%;
position: absolute;
bottom: 0;
left: 0;
padding: 5px;
text-align: center;
background-color: rgba(0, 0, 0, 0.5);
color: #fff;
border: none;
cursor: pointer;
}
}
transition: background-color 0.3s;
p {
height: 40px;
line-height: 40px;
font-size: 18px;
color: #333;
margin: 10px 0 0 20px;
border-bottom: 1px solid #ccc;
span {
font-size: 16px;
margin-right: 20px;
float: right;
}
}
}
.AboutUs-right {
width: 700px;
height: 500px;
background-color: #fff;
float: left;
border-radius: 10px;
box-shadow: 0 0 10px #ccc;
box-sizing: border-box;
p{
height: 40px;
line-height: 40px;
font-size: 18px;
color: #333;
margin: 10px 0 0 20px;
border-bottom: 1px solid #ccc;
cursor: pointer;
&:hover{
color: #409EFF;
}
}
&:hover {
background-color: #218838;
}
}
</style>

View File

@ -4,35 +4,20 @@
<div class="box"></div>
<div class="head">
<div class="head-left">
<div class="content-left" v-for="(item, index) in contList" :key="index">
<div class="con-title-left">
<img :src="item.img" />
<h3>
<router-link to="/">{{ item.title }}</router-link>
</h3>
<img :src="item.img" />
<p class="time">{{ item.date }}</p>
</div>
</div>
</div>
<div class="head-right">
<div class="develop">
<img src="../assets/images/789.jpg" alt="" />
<div class="title">
<p>123</p>
</div>
</div>
<div class="develop">
<img src="../assets/images/789.jpg" alt="" />
<div class="title">
<p>123</p>
</div>
</div>
<div class="content-right">
<div class="con-title-right">
<h3>标签云</h3>
<p></p>
<div class="flex gap-2 mt-4">
<el-tag
v-for="item in items"
@ -46,6 +31,18 @@
</div>
</div>
</div>
<div class="popular-articles">
<h3>热门文章</h3>
<ul>
<li v-for="(article, index) in popularArticles" :key="index">
<router-link to="/">{{ article.title }}</router-link>
</li>
</ul>
</div>
<div class="advertisement">
<h3>广告</h3>
<img src="../assets/images/table.png" alt="广告" />
</div>
</div>
</div>
<el-backtop :right="100" :bottom="100" />
@ -54,103 +51,71 @@
</template>
<script>
// import { getHome } from '@/api/home'
export default {
name: 'HoMe',
data () {
return {
slideList: [
{ img: require('@/assets/images/789.jpg') },
{ img: require('@/assets/images/899.jpg') },
{ img: require('@/assets/images/789.jpg') }
],
currentIndex: 0, //
timer: null, //
contList: [
{
img: require('@/assets/images/789.jpg'),
title: '',
title: '文章标题1',
date: '2024-04-24'
},
{
img: require('@/assets/images/789.jpg'),
title: '',
title: '文章标题2',
date: '2024-04-24'
},
{
img: require('@/assets/images/789.jpg'),
title: '',
title: '文章标题3',
date: '2024-04-24'
},
{
img: require('@/assets/images/789.jpg'),
title: '',
title: '文章标题3',
date: '2024-04-24'
},
{
img: require('@/assets/images/789.jpg'),
title: '',
title: '文章标题3',
date: '2024-04-24'
},
{
img: require('@/assets/images/789.jpg'),
title: '',
title: '文章标题3',
date: '2024-04-24'
}
],
items: [
{ type: 'success', label: '后端技术' },
{ type: 'success', label: '前端技术' },
{ type: 'info', label: '架构1' },
{ type: 'info', label: '架构' },
{ type: 'warning', label: '项目管理' },
{ type: 'danger', label: '开发规范' },
{ type: 'success', label: '组织' },
{ type: 'success', label: 'JAVA' },
{ type: 'info', label: 'Redis' },
{ type: 'warning', label: 'c++基础' },
{ type: 'danger', label: 'Aop' },
{ type: 'warning', label: 'C++基础' },
{ type: 'danger', label: 'AOP' },
{ type: 'success', label: 'HTML5' },
{ type: 'success', label: 'Rabbitmq' },
{ type: 'info', label: 'ElmenuUI-plus' },
{ type: 'success', label: 'RabbitMQ' },
{ type: 'info', label: 'ElementUI-plus' },
{ type: 'warning', label: '云资源' },
{ type: 'danger', label: 'VUE' },
{ type: 'danger', label: '业务' },
{ type: 'danger', label: '123' }
],
popularArticles: [
{ title: '热门文章1' },
{ title: '热门文章2' },
{ title: '热门文章3' }
]
}
},
// mounted () {
// this.getData()
// },
methods: {
// getData () {
// getHome().then(res => {
// console.log(res)
// this.contList = res.data.result
// console.log(this.contList)
// })
// },
play () {
this.timer = setInterval(() => {
this.currentIndex++
if (this.currentIndex >= this.slideList.length) {
this.currentIndex = 0
}
}, 3000)
},
stop () {
clearInterval(this.timer)
},
go () {
this.play()
},
change (index) {
this.currentIndex = index
},
mounted () {
//
this.go()
}
}
}
</script>

View File

@ -6,11 +6,14 @@
</div>
<div class="container">
<div class="content" v-for="(item, index) in contentList" :key="index" @click="goLink(item.url)">
<div class="content-inner">
<img :src="item.img" :alt="item.name">
<span>{{ item.name }}</span>
</div>
</div>
</div>
<musIc />
</div>
</template>
<script>
@ -19,6 +22,46 @@ export default {
data () {
return {
contentList: [
{
img: require('@/assets/images/kecheng/C.jpg'),
name: '百度一下,你就知道',
url: 'http://www.baidu.com'
},
{
img: require('@/assets/images/kecheng/C.jpg'),
name: '4399小游戏',
url: 'http://www.4399.com'
},
{
img: require('@/assets/images/kecheng/C.jpg'),
name: '百度一下,你就知道',
url: 'http://www.baidu.com'
},
{
img: require('@/assets/images/kecheng/C.jpg'),
name: '4399小游戏',
url: 'http://www.4399.com'
},
{
img: require('@/assets/images/kecheng/C.jpg'),
name: '百度一下,你就知道',
url: 'http://www.baidu.com'
},
{
img: require('@/assets/images/kecheng/C.jpg'),
name: '4399小游戏',
url: 'http://www.4399.com'
},
{
img: require('@/assets/images/kecheng/C.jpg'),
name: '百度一下,你就知道',
url: 'http://www.baidu.com'
},
{
img: require('@/assets/images/kecheng/C.jpg'),
name: '4399小游戏',
url: 'http://www.4399.com'
},
{
img: require('@/assets/images/kecheng/C.jpg'),
name: '百度一下,你就知道',
@ -43,50 +86,57 @@ export default {
<style lang="less" scoped>
.interlinkage {
width: 1200px;
height: 800px;
margin: 70px auto;
border: 1px solid #ccc;
background-color: palegoldenrod;
background-color: #f5f5f5;
padding: 20px;
border-radius: 10px;
}
.title {
width: 1200px;
height: 60px;
.title {
margin-bottom: 20px;
}
h2 {
line-height: 60px;
margin-left: 20px;
}
}
.title h2 {
font-size: 24px;
color: #333;
}
.container {
.container {
display: grid;
grid-template-columns: repeat(5, 1fr);
grid-gap: 10px;
grid-gap: 20px;
}
.content {
width: 230px;
height: 50px;
.content {
background-color: #fff;
&:hover{
margin-top: -10px;
box-shadow: 0 0 10px #ccc;
color: aquamarine;
}
img{
width: 50px;
height: 50px;
float: left;
}
span{
line-height: 50px;
margin-left: 10px;
border-radius: 5px;
padding: 10px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
cursor: pointer;
font-family: 'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif;
}
}
}
transition: all 0.3s ease;
}
.content:hover {
transform: translateY(-5px);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
.content .content-inner {
display: flex;
align-items: center;
}
.content img {
width: 40px;
height: 40px;
border-radius: 50%;
}
.content span {
margin-left: 10px;
font-size: 16px;
color: #333;
vertical-align: middle;
}
</style>

View File

@ -11,7 +11,7 @@
<div class="box-bd">
<ul class="clearfix">
<li v-for="(item, index) in items" :key="index" >
<router-link :to="`/list/${index + 1}`"> <!-- 这里的index + 1对应着表的序号 -->
<router-link :to="`/paiListPage/${index + 1}`"> <!-- 这里的index + 1对应着表的序号 -->
<img :src="item.url" :alt="item.title" />
<h4>{{ item.title }}</h4>
</router-link>
@ -26,6 +26,7 @@
</div>
<!-- 其他代码 -->
<musIc />
</div>
</template>

View File

@ -56,7 +56,9 @@
</template>
<script>
import { login } from '@/api/login' //
import dayjs from 'dayjs'
export default {
name: 'LoginIndex',
data () {
@ -89,13 +91,26 @@ export default {
setInterval(() => {
this.postDate = dayjs().format('HH : mm : ss')
}, 1000)
},
mounted () {
},
methods: {
login () {
//
login(this.form).then(response => {
//
console.log(response) //
this.$router.push('/')
this.$message({
message: '登陆成功',
type: 'success'
})
}).catch(error => {
//
console.error('登录失败:', error)
this.$message({
message: '登录失败,请检查账号或密码',
type: 'error'
})
})
},
remenber (data) {
this.checked = data

View File

@ -1,8 +1,10 @@
<template>
<div>
<header>
<navigationBar />
</header>
<div class="msg-all-contain">
<div class="msg-board-title">留言板</div>
<div class="msg-board-title">待办事项</div>
<div class="msg-board">
<div class="msg-board-contain">
<div class="msg-head">
@ -18,7 +20,7 @@
rows="5"
>
</textarea>
<button @click="submit"></button>
<button @click="submit"></button>
</div>
<div class="msg-content">
<comments-child
@ -157,7 +159,7 @@ export default {
}
.msg-all-contain {
width: 1200px;
margin: auto;
margin:80px auto ;
height: 100%;
overflow-y: auto;
}

View File

@ -1,64 +0,0 @@
<template>
<div class="topic-details">
<div class="title" v-if="data">
<h2>{{ data.title }}</h2>
</div>
<div class="con" v-if="data">
<p v-html="data.content"></p>
</div>
<div v-else-if="loading">加载中...</div>
<div v-else-if="error">{{ error }}</div>
</div>
</template>
<script>
import { getSubject } from '@/api/subject'
export default {
name: 'topicDetails',
data () {
return {
data: null,
loading: true,
error: null
}
},
created () {
this.getList()
},
// watch: {
// '$route.query.id': 'fetchData'
// },
methods: {
getList () {
const id = this.$route.query.id
getSubject(id).then(res => {
this.loading = true
this.error = null
this.data = res.data
})
}
}
}
</script>
<style lang="less" scoped>
.topic-details {
width: 1200px;
height: 800px;
margin: auto;
h2 {
text-align: center;
margin: 30px;
}
p {
text-align: justify;
margin: 30px;
line-height: 2;
text-indent: 2em;
}
}
</style>

View File

@ -0,0 +1,32 @@
<template>
<div>
<h1>详情页</h1>
</div>
</template>
<script>
import { getSubject } from '@/api/subject'
export default {
name: 'detailPage',
data () {
return {
list: ''
}
},
created () {
this.getDeail()
},
methods: {
getDeail () {
getSubject().then(res => {
this.list = res.data
console.log(this.list)
})
}
}
}
</script>
<style>
</style>

View File

@ -4,11 +4,14 @@
<div class="kecheng">
<div class="empty" v-if="!detailContent.length">暂无内容</div>
<div class="con" v-for="(item, index) in detailContent" :key="index">
<div class="title">{{ item.title }}</div>
<div class="title" @click="pushDetailPage">{{ item.title }}</div>
<div class="content" v-html="item.content"></div>
</div>
</div>
</main>
<div class="fortter">
</div>
</div>
</template>
@ -33,11 +36,21 @@ export default {
.then((response) => {
//
this.detailContent = response.data
this.total = response.data.length
// console.log(response)
})
.catch((error) => {
console.error('Error fetching content:', error)
})
},
pushDetailPage () {
//
this.$router.push({
name: 'detailPage',
params: {
id: this.$route.params.id
}
})
}
}
}

294
src/views/photoGallery.vue Normal file
View File

@ -0,0 +1,294 @@
<template>
<div class="photo-gallery">
<header>
<navigationBar />
</header>
<div class="upload-button">
<button @click="openModal">添加照片</button>
</div>
<div v-if="showModal" class="modal" @click.self="closeModal">
<div class="modal-content">
<span class="close" @click="closeModal">&times;</span>
<form @submit.prevent="addPhoto">
<div class="form-group">
<label for="photo-upload">上传照片</label>
<input type="file" id="photo-upload" @change="onFileChange" required />
</div>
<div class="form-group">
<label for="photo-description">照片描述</label>
<input type="text" id="photo-description" v-model="newPhoto.alt" placeholder="照片描述" required />
</div>
<button type="submit">上传照片</button>
</form>
</div>
</div>
<div class="gallery">
<div
class="gallery-item"
v-for="(item, index) in photos"
:key="index"
:class="item.sizeClass"
ref="photoItems"
>
<img :data-src="item.src" :alt="item.alt" class="lazy" />
</div>
</div>
<musIc />
</div>
</template>
<script>
export default {
name: 'photoGallery',
data () {
return {
photos: [
{ src: require('@/assets/images/789.jpg'), alt: 'Photo 1', sizeClass: 'medium' },
{ src: require('@/assets/images/789.jpg'), alt: 'Photo 2', sizeClass: 'large' },
{ src: require('@/assets/images/789.jpg'), alt: 'Photo 3', sizeClass: 'small' },
{ src: require('@/assets/images/789.jpg'), alt: 'Photo 4', sizeClass: 'medium' },
{ src: require('@/assets/images/789.jpg'), alt: 'Photo 5', sizeClass: 'large' },
{ src: require('@/assets/images/789.jpg'), alt: 'Photo 6', sizeClass: 'small' },
{ src: require('@/assets/images/789.jpg'), alt: 'Photo 7', sizeClass: 'medium' },
{ src: require('@/assets/images/789.jpg'), alt: 'Photo 8', sizeClass: 'large' },
{ src: require('@/assets/images/789.jpg'), alt: 'Photo 9', sizeClass: 'small' },
{ src: require('@/assets/images/789.jpg'), alt: 'Photo 10', sizeClass: 'medium' },
{ src: require('@/assets/images/789.jpg'), alt: 'Photo 11', sizeClass: 'large' },
{ src: require('@/assets/images/789.jpg'), alt: 'Photo 12', sizeClass: 'small' },
{ src: require('@/assets/images/789.jpg'), alt: 'Photo 13', sizeClass: 'medium' },
{ src: require('@/assets/images/789.jpg'), alt: 'Photo 14', sizeClass: 'large' },
{ src: require('@/assets/images/789.jpg'), alt: 'Photo 15', sizeClass: 'small' },
{ src: require('@/assets/images/789.jpg'), alt: 'Photo 16', sizeClass: 'medium' },
{ src: require('@/assets/images/789.jpg'), alt: 'Photo 17', sizeClass: 'large' },
{ src: require('@/assets/images/789.jpg'), alt: 'Photo 18', sizeClass: 'small' },
{ src: require('@/assets/images/789.jpg'), alt: 'Photo 19', sizeClass: 'medium' },
{ src: require('@/assets/images/789.jpg'), alt: 'Photo 20', sizeClass: 'large' },
{ src: require('@/assets/images/789.jpg'), alt: 'Photo 21', sizeClass: 'small' },
{ src: require('@/assets/images/789.jpg'), alt: 'Photo 22', sizeClass: 'medium' },
{ src: require('@/assets/images/789.jpg'), alt: 'Photo 23', sizeClass: 'large' },
{ src: require('@/assets/images/789.jpg'), alt: 'Photo 24', sizeClass: 'small' },
{ src: require('@/assets/images/789.jpg'), alt: 'Photo 25', sizeClass: 'medium' },
{ src: require('@/assets/images/789.jpg'), alt: 'Photo 26', sizeClass: 'large' },
{ src: require('@/assets/images/789.jpg'), alt: 'Photo 27', sizeClass: 'small' }
],
newPhoto: {
src: '',
alt: ''
},
newPhotoFile: null,
showModal: false
}
},
methods: {
loadImages () {
const images = this.$refs.photoItems
const options = {
root: null,
rootMargin: '0px',
threshold: 0.1
}
const observer = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target.querySelector('img')
img.src = img.getAttribute('data-src')
observer.unobserve(entry.target)
}
})
}, options)
images.forEach(image => {
observer.observe(image)
})
},
onFileChange (e) {
const file = e.target.files[0]
if (file) {
this.newPhotoFile = URL.createObjectURL(file)
}
},
addPhoto () {
if (this.newPhotoFile && this.newPhoto.alt) {
const sizeClasses = ['small', 'medium', 'large']
const sizeClass = sizeClasses[Math.floor(Math.random() * sizeClasses.length)]
this.photos.push({
src: this.newPhotoFile,
alt: this.newPhoto.alt,
sizeClass: sizeClass
})
this.newPhotoFile = null
this.newPhoto.alt = ''
this.showModal = false
document.body.classList.remove('no-scroll')
this.$nextTick(() => {
this.loadImages()
})
}
},
openModal () {
this.showModal = true
document.body.classList.add('no-scroll')
},
closeModal () {
this.showModal = false
document.body.classList.remove('no-scroll')
}
},
mounted () {
this.loadImages()
}
}
</script>
<style lang="less" scoped>
.photo-gallery {
max-width: 1200px;
margin: 30px auto;
padding: 20px;
}
header {
margin-bottom: 20px;
}
.upload-button {
position: fixed;
bottom: 20px;
right: 20px;
}
.upload-button button {
background: #007bff;
color: white;
border: none;
padding: 10px 20px;
font-size: 16px;
border-radius: 50px;
cursor: pointer;
transition: background 0.3s;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
.upload-button button:hover {
background: #0056b3;
}
.modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: center;
}
.modal-content {
background: #fff;
padding: 20px;
border-radius: 12px;
position: relative;
width: 400px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
animation: fadeIn 0.3s;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: scale(0.9);
}
to {
opacity: 1;
transform: scale(1);
}
}
.close {
position: absolute;
top: 10px;
right: 10px;
font-size: 20px;
cursor: pointer;
}
.form-group {
margin-bottom: 15px;
}
.form-group label {
display: block;
margin-bottom: 5px;
font-weight: bold;
}
.form-group input[type="file"] {
display: block;
width: 100%;
}
.form-group input[type="text"] {
display: block;
width: calc(100% - 20px);
padding: 8px 10px;
font-size: 14px;
border: 1px solid #ddd;
border-radius: 4px;
}
button {
background: #007bff;
color: white;
border: none;
padding: 10px 20px;
font-size: 16px;
border-radius: 4px;
cursor: pointer;
transition: background 0.3s;
}
button:hover {
background: #0056b3;
}
.gallery {
column-count: 4;
column-gap: 16px;
}
.gallery-item {
break-inside: avoid;
background: #fff;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
margin-bottom: 16px;
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.gallery-item:hover {
transform: translateY(-5px);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
}
.gallery-item img {
width: 100%;
height: auto;
display: block;
}
.gallery-item.small img {
height: 150px;
}
.gallery-item.medium img {
height: 200px;
}
.gallery-item.large img {
height: 250px;
}
</style>

View File

@ -0,0 +1,92 @@
<template>
<div class="topic-details">
<div class="container" v-if="data">
<div class="title">
<h2>{{ data.title }}</h2>
</div>
<div class="con">
<p v-html="data.content"></p>
</div>
</div>
<div v-else-if="loading" class="loading">加载中...</div>
<div v-else-if="error" class="error">{{ error }}</div>
<shareBtn></shareBtn>
</div>
</template>
<script>
import shareBtn from '@/components/shareBtn.vue'
import { getSubject } from '@/api/subject'
export default {
name: 'topicDetails',
components: {
shareBtn
},
data () {
return {
data: null,
loading: true,
error: null
}
},
created () {
this.getList()
},
methods: {
getList () {
const id = this.$route.query.id
getSubject(id)
.then(res => {
this.loading = false
this.error = null
this.data = res.data
})
}
}
}
</script>
<style lang="less" scoped>
.topic-details {
width: 100%;
max-width: 1200px;
margin: auto;
padding: 20px;
box-sizing: border-box;
background-color: #f9f9f9;
border: 1px solid #ddd;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.container {
padding: 20px;
}
.title {
text-align: center;
margin-bottom: 20px;
}
.title h2 {
font-size: 24px;
color: #333;
}
.con p {
text-align: justify;
line-height: 1.6;
color: #666;
}
.loading, .error {
text-align: center;
padding: 20px;
background-color: #fff;
border: 1px solid #ddd;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
margin-bottom: 20px;
}
</style>

View File

@ -10,8 +10,7 @@
</svg>
<div class="ana">
<p>
Youth by sharpening and brilliant <br />life because of struggle and
sublimation
{{ user }}
</p>
</div>
</div>
@ -43,16 +42,25 @@
<script>
import { getSubject } from '@/api/subject'
import { fetchUser } from '@/api/dailySentence'
export default {
name: 'subJect',
data () {
return {
articleS: [],
total: 0
total: 0,
user: ''
}
},
created () {
this.getList()
//
this.user = localStorage.getItem('userContent') || ''
// 8
setInterval(() => {
this.fetchUser()
}, 1000 * 60 * 60 * 24) // 24
},
methods: {
getList () {
@ -60,9 +68,19 @@ export default {
this.articleS = res.data
this.total = res.data.length
})
},
fetchUser () {
fetchUser()
.then(response => {
this.user = response.data.result.content
//
localStorage.setItem('userContent', this.user)
})
.catch(error => {
console.log(error)
})
}
}
}
</script>
@ -72,7 +90,7 @@ export default {
height: 600px;
margin-bottom: 20px;
position: relative;
background-image: url(../assets/images/sub2.jpg);
background-image: url(../../assets/images/sub2.jpg);
background-size: cover;
background-position: center;
background-repeat: no-repeat;
@ -84,16 +102,16 @@ export default {
.ana {
width: 500px;
height: 100px;
height: auto;
position: absolute;
top: 10%;
top: 15%;
left: 62%;
background: rgba(255, 255, 255, 0.2);
background: rgba(255, 255, 255, 0.3);
box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.37);
backdrop-filter: blur(0px);
-webkit-backdrop-filter: blur(0px);
border-radius: 10px;
border: 1px solid rgba(255, 255, 255, 0.18);
backdrop-filter: blur(0px);
-webkit-backdrop-filter: blur(0px);
p {
text-align: center;