6.14
This commit is contained in:
parent
f255121dff
commit
952447ec70
@ -5,7 +5,7 @@
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||
<title><%= htmlWebpackPlugin.options.title %></title>
|
||||
<title>墨思留痕</title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
|
24
src/App.vue
24
src/App.vue
@ -13,8 +13,13 @@
|
||||
<script>
|
||||
import trigger from '@/components/trigger.vue'
|
||||
import basePage from './components/base.vue'
|
||||
export default {
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
|
||||
}
|
||||
},
|
||||
components: {
|
||||
trigger,
|
||||
basePage
|
||||
@ -23,22 +28,5 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
*{
|
||||
box-sizing: border-box;
|
||||
}
|
||||
/* 针对 WebKit 浏览器 */
|
||||
::-webkit-scrollbar {
|
||||
width: 5px; /* 滚动条宽度 */
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: #2ee600; /* 滑块颜色 */
|
||||
border-radius: 10px; /* 滑块圆角 */
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background: #f1f1f1ef; /* 轨道颜色 */
|
||||
border-radius: 10px; /* 轨道圆角 */
|
||||
}
|
||||
|
||||
</style>
|
||||
|
9
src/api/interlinkage.js
Normal file
9
src/api/interlinkage.js
Normal file
@ -0,0 +1,9 @@
|
||||
import request from '../utils/request'
|
||||
|
||||
export function interList (data) {
|
||||
return request({
|
||||
url: '/interList',
|
||||
method: 'get',
|
||||
data
|
||||
})
|
||||
}
|
@ -7,3 +7,11 @@ export function login (data) {
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function autoLogin (token) {
|
||||
return request({
|
||||
url: '/auto-login',
|
||||
method: 'post',
|
||||
data: { token }
|
||||
})
|
||||
}
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 18 KiB |
@ -2,6 +2,27 @@
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
list-style: none;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* 针对 WebKit 浏览器 */
|
||||
::-webkit-scrollbar {
|
||||
width: 5px;
|
||||
/* 滚动条宽度 */
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: #2ee600;
|
||||
/* 滑块颜色 */
|
||||
border-radius: 10px;
|
||||
/* 滑块圆角 */
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background: #f1f1f1ef;
|
||||
/* 轨道颜色 */
|
||||
border-radius: 10px;
|
||||
/* 轨道圆角 */
|
||||
}
|
||||
|
||||
body {
|
||||
|
@ -80,6 +80,13 @@ export default {
|
||||
return this.playlist[this.currentSongIndex]
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
// 检查 localStorage 中的锁定状态
|
||||
const savedLockState = localStorage.getItem('isLocked')
|
||||
if (savedLockState !== null) {
|
||||
this.isLocked = JSON.parse(savedLockState)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
searchMusic () {
|
||||
// 实现音乐搜索功能
|
||||
@ -93,8 +100,7 @@ export default {
|
||||
},
|
||||
prevSong () {
|
||||
this.currentSongIndex =
|
||||
(this.currentSongIndex - 1 + this.playlist.length) %
|
||||
this.playlist.length
|
||||
(this.currentSongIndex - 1 + this.playlist.length) % this.playlist.length
|
||||
this.isPlaying = true // 切换歌曲时自动播放
|
||||
},
|
||||
nextSong () {
|
||||
@ -104,6 +110,8 @@ export default {
|
||||
},
|
||||
toggleLock () {
|
||||
this.isLocked = !this.isLocked
|
||||
// 将锁定状态保存到 localStorage
|
||||
localStorage.setItem('isLocked', JSON.stringify(this.isLocked))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -102,9 +102,10 @@ export default {
|
||||
},
|
||||
// 退出
|
||||
handleOut () {
|
||||
this.$router.push({ path: '/login' })
|
||||
localStorage.removeItem('token')
|
||||
this.$router.push('/login')
|
||||
this.$message({
|
||||
message: '退出成功',
|
||||
message: '您已退出',
|
||||
type: 'success'
|
||||
})
|
||||
},
|
||||
|
0
src/components/quillEditor.vue
Normal file
0
src/components/quillEditor.vue
Normal file
@ -12,6 +12,8 @@ Vue.use(ElementUI)
|
||||
Vue.component('navigationBar', navigationBar)
|
||||
Vue.component('musIc', music)
|
||||
|
||||
document.title = '墨思留痕'
|
||||
|
||||
Vue.config.productionTip = false
|
||||
|
||||
new Vue({
|
||||
|
@ -1,4 +1,6 @@
|
||||
import axios from 'axios'
|
||||
import { Message } from 'element-ui'
|
||||
import router from '../router'
|
||||
|
||||
// 创建一个 axios 实例
|
||||
const service = axios.create({
|
||||
@ -9,27 +11,29 @@ const service = axios.create({
|
||||
// 请求拦截器
|
||||
service.interceptors.request.use(
|
||||
config => {
|
||||
// 从 localStorage 中获取 token
|
||||
const token = localStorage.getItem('user-token')
|
||||
const token = localStorage.getItem('token')
|
||||
if (token) {
|
||||
// 将 token 添加到请求头中
|
||||
config.headers.Authorization = `Bearer ${token}`
|
||||
}
|
||||
return config
|
||||
},
|
||||
error => {
|
||||
// 对请求错误做些什么
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
// 响应拦截器
|
||||
service.interceptors.response.use(
|
||||
response => {
|
||||
// 对响应数据做点什么
|
||||
return response
|
||||
},
|
||||
error => {
|
||||
if (error.response && error.response.status === 401) {
|
||||
Message.error('认证已过期,请重新登录')
|
||||
localStorage.removeItem('token')
|
||||
router.push('/login')
|
||||
} else {
|
||||
Message.error(error.message)
|
||||
}
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
@ -3,7 +3,6 @@
|
||||
<navigationBar />
|
||||
<div class="box">
|
||||
<el-tabs type="border-card">
|
||||
|
||||
<el-tab-pane label="个人信息">
|
||||
<div class="AboutUs-left">
|
||||
<div class="AboutUs-img">
|
||||
@ -117,8 +116,27 @@
|
||||
</div>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
|
||||
</el-tabs>
|
||||
|
||||
<!-- 头像上传 -->
|
||||
<el-dialog title="更换头像" :visible.sync="dialogVisible" width="30%">
|
||||
<el-upload
|
||||
class="avatar-uploader"
|
||||
action="https://jsonplaceholder.typicode.com/posts/"
|
||||
:show-file-list="false"
|
||||
:on-success="handleAvatarSuccess"
|
||||
:before-upload="beforeAvatarUpload"
|
||||
>
|
||||
<img v-if="imageUrl" :src="imageUrl" class="avatar" />
|
||||
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
|
||||
</el-upload>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="dialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="handleAddAvatar"
|
||||
>确 定</el-button
|
||||
>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</div>
|
||||
|
||||
<musIc />
|
||||
@ -139,6 +157,8 @@ export default {
|
||||
birthday: '',
|
||||
region: '',
|
||||
city: '',
|
||||
dialogVisible: false,
|
||||
imageUrl: '',
|
||||
avatar: require('@/assets/images/789.jpg'), // 默认头像地址
|
||||
users: [
|
||||
{
|
||||
@ -163,10 +183,6 @@ export default {
|
||||
// 保存用户信息的逻辑
|
||||
this.$message.success('保存成功')
|
||||
},
|
||||
changeAvatar () {
|
||||
// 更换头像的逻辑
|
||||
this.$message.success('更换成功')
|
||||
},
|
||||
// 添加按钮
|
||||
handleAdd () {
|
||||
if (this.newTodo.trim() !== '') {
|
||||
@ -190,6 +206,32 @@ export default {
|
||||
} else {
|
||||
this.$message.error('请选择要删除的待办事项')
|
||||
}
|
||||
},
|
||||
changeAvatar () {
|
||||
// 更换头像的逻辑
|
||||
this.dialogVisible = true
|
||||
},
|
||||
handleAvatarSuccess (res, file) {
|
||||
this.imageUrl = URL.createObjectURL(file.raw)
|
||||
},
|
||||
beforeAvatarUpload (file) {
|
||||
const isJPG = file.type === 'image/jpeg'
|
||||
const isLt2M = file.size / 1024 / 1024 < 2
|
||||
|
||||
if (!isJPG) {
|
||||
this.$message.error('上传头像图片只能是 JPG 格式!')
|
||||
}
|
||||
if (!isLt2M) {
|
||||
this.$message.error('上传头像图片大小不能超过 2MB!')
|
||||
}
|
||||
return isJPG && isLt2M
|
||||
},
|
||||
handleAddAvatar () {
|
||||
this.$message({
|
||||
message: '上传成功',
|
||||
type: 'success'
|
||||
})
|
||||
this.dialogVisible = false
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -197,7 +239,7 @@ export default {
|
||||
|
||||
<style lang="less" scoped>
|
||||
.wtbDone {
|
||||
width: 400px;
|
||||
width: 700px;
|
||||
height: 500px;
|
||||
border: 1px solid black;
|
||||
margin: auto;
|
||||
@ -207,7 +249,7 @@ export default {
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
||||
|
||||
input {
|
||||
width: 300px;
|
||||
width: 550px;
|
||||
height: 40px;
|
||||
padding: 5px;
|
||||
margin-top: 20px;
|
||||
@ -224,7 +266,7 @@ export default {
|
||||
ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
width: 350px;
|
||||
width: 600px;
|
||||
height: 310px;
|
||||
margin: 20px auto;
|
||||
overflow-y: scroll;
|
||||
@ -260,7 +302,7 @@ export default {
|
||||
}
|
||||
|
||||
button {
|
||||
width: 70px;
|
||||
width: 120px;
|
||||
height: 40px;
|
||||
background-color: #007bff;
|
||||
color: #fff;
|
||||
@ -445,4 +487,28 @@ hr {
|
||||
background-color: #218838;
|
||||
}
|
||||
}
|
||||
|
||||
.avatar-uploader .el-upload {
|
||||
border: 1px dashed #d9d9d9;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.avatar-uploader .el-upload:hover {
|
||||
border-color: #409eff;
|
||||
}
|
||||
.avatar-uploader-icon {
|
||||
font-size: 28px;
|
||||
color: #8c939d;
|
||||
width: 178px;
|
||||
height: 178px;
|
||||
line-height: 178px;
|
||||
text-align: center;
|
||||
}
|
||||
.avatar {
|
||||
width: 178px;
|
||||
height: 178px;
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
|
@ -17,65 +17,23 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { interList } from '@/api/interlinkage'
|
||||
export default {
|
||||
name: 'interLinkage',
|
||||
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: '百度一下,你就知道',
|
||||
url: 'http://www.baidu.com'
|
||||
},
|
||||
{
|
||||
img: require('@/assets/images/kecheng/C.jpg'),
|
||||
name: '4399小游戏',
|
||||
url: 'http://www.4399.com'
|
||||
}
|
||||
]
|
||||
contentList: []
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.getList()
|
||||
},
|
||||
methods: {
|
||||
getList () {
|
||||
interList().then(res => {
|
||||
this.contentList = res.data
|
||||
})
|
||||
},
|
||||
goLink (url) {
|
||||
window.open(url)
|
||||
}
|
||||
|
@ -11,7 +11,8 @@
|
||||
<div class="box-bd">
|
||||
<ul class="clearfix">
|
||||
<li v-for="(item, index) in items" :key="index">
|
||||
<router-link :to="`/paiListPage/${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>
|
||||
@ -25,7 +26,19 @@
|
||||
<button @click="openDialog">添加笔记</button>
|
||||
</div>
|
||||
|
||||
<!-- 其他代码 -->
|
||||
<!-- 添加笔记弹窗 -->
|
||||
<el-dialog title="提示" :visible.sync="dialogVisible" width="30%">
|
||||
<el-form ref="form" :model="form" label-width="80px" :rules="rules">
|
||||
<el-form-item label="笔记标题" prop="addContent">
|
||||
<el-input v-model="form.addContent"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="dialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="handleAdd">确 定</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
<musIc />
|
||||
</div>
|
||||
</template>
|
||||
@ -35,14 +48,11 @@ import { getTags } from '@/api/tags'
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
items: [
|
||||
|
||||
],
|
||||
drawer: false,
|
||||
direction: 'ltr',
|
||||
items: [],
|
||||
dialogVisible: false,
|
||||
form: {},
|
||||
addContent: '',
|
||||
form: {
|
||||
addContent: ''
|
||||
},
|
||||
rules: {
|
||||
addContent: [
|
||||
{ required: true, message: '请输入标题', trigger: 'blur' }
|
||||
@ -55,7 +65,7 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
fetchTags () {
|
||||
getTags().then(res => {
|
||||
getTags().then((res) => {
|
||||
this.items = res.data
|
||||
})
|
||||
},
|
||||
@ -63,17 +73,12 @@ export default {
|
||||
this.dialogVisible = true
|
||||
},
|
||||
handleAdd () {
|
||||
this.$refs.form.validate((valid) => {
|
||||
if (valid) {
|
||||
this.dialogVisible = false
|
||||
this.$message({
|
||||
message: '添加成功',
|
||||
type: 'success'
|
||||
})
|
||||
this.dialogVisible = false
|
||||
} else {
|
||||
this.$message.error('请检查输入项')
|
||||
}
|
||||
})
|
||||
this.form.addContent = ''
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -35,7 +35,7 @@
|
||||
</div>
|
||||
<div class="tool">
|
||||
<div>
|
||||
<el-checkbox v-model="checked" @change="remenber" v-if="!create"
|
||||
<el-checkbox v-model="checked" @change="remember" v-if="!create"
|
||||
>记住密码</el-checkbox
|
||||
>
|
||||
</div>
|
||||
@ -56,7 +56,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { login } from '@/api/login' // 导入登录请求的方法
|
||||
import { login, autoLogin } from '@/api/login'
|
||||
import dayjs from 'dayjs'
|
||||
|
||||
export default {
|
||||
@ -91,33 +91,110 @@ export default {
|
||||
setInterval(() => {
|
||||
this.postDate = dayjs().format('HH : mm : ss')
|
||||
}, 1000)
|
||||
|
||||
this.loadRememberedCredentials()
|
||||
|
||||
// 尝试自动登录
|
||||
const token = localStorage.getItem('token')
|
||||
if (token) {
|
||||
this.autoLogin(token)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
login () {
|
||||
// 调用后端登录接口
|
||||
login(this.form).then(response => {
|
||||
// 登录成功的处理逻辑
|
||||
console.log(response) // 假设登录成功后返回的数据中包含用户信息
|
||||
loadRememberedCredentials () {
|
||||
const rememberedUsername = localStorage.getItem('rememberedUsername')
|
||||
const rememberedPassword = localStorage.getItem('rememberedPassword')
|
||||
const rememberMeChecked = localStorage.getItem('rememberMeChecked')
|
||||
|
||||
if (rememberedUsername && rememberedPassword && rememberMeChecked) {
|
||||
this.form.username = rememberedUsername
|
||||
this.form.password = rememberedPassword
|
||||
this.checked = JSON.parse(rememberMeChecked)
|
||||
}
|
||||
},
|
||||
autoLogin (token) {
|
||||
autoLogin(token).then(response => {
|
||||
console.log(response)
|
||||
if (this.$route.path !== '/') {
|
||||
this.$router.push('/')
|
||||
}
|
||||
this.$message({
|
||||
message: '自动登录成功',
|
||||
type: 'success'
|
||||
})
|
||||
}).catch(error => {
|
||||
console.error('自动登录失败:', error)
|
||||
localStorage.removeItem('token')
|
||||
this.$message({
|
||||
message: '自动登录失败,请重新登录',
|
||||
type: 'error'
|
||||
})
|
||||
})
|
||||
},
|
||||
login () {
|
||||
if (this.form.username === '' || this.form.password === '') {
|
||||
this.$message({
|
||||
message: '账号或密码不能为空',
|
||||
type: 'error'
|
||||
})
|
||||
return
|
||||
}
|
||||
// 登录验证
|
||||
if (!this.create) {
|
||||
login({ ...this.form }).then(response => {
|
||||
console.log(response)
|
||||
localStorage.setItem('token', response.data.token)
|
||||
if (this.checked) {
|
||||
localStorage.setItem('rememberedUsername', this.form.username)
|
||||
localStorage.setItem('rememberedPassword', this.form.password)
|
||||
localStorage.setItem('rememberMeChecked', true)
|
||||
} else {
|
||||
localStorage.removeItem('rememberedUsername')
|
||||
localStorage.removeItem('rememberedPassword')
|
||||
localStorage.removeItem('rememberMeChecked')
|
||||
}
|
||||
if (this.$route.path !== '/') {
|
||||
this.$router.push('/')
|
||||
}
|
||||
this.$message({
|
||||
message: '登陆成功',
|
||||
type: 'success'
|
||||
})
|
||||
}).catch(error => {
|
||||
// 登录失败的处理逻辑
|
||||
console.error('登录失败:', error)
|
||||
if (error.response && error.response.status === 401) {
|
||||
this.$message({
|
||||
message: '登录失败,请检查账号或密码',
|
||||
message: '账号或密码错误',
|
||||
type: 'error'
|
||||
})
|
||||
})
|
||||
},
|
||||
remenber (data) {
|
||||
this.checked = data
|
||||
if (this.checked) {
|
||||
localStorage.setItem('news', JSON.stringify(this.form))
|
||||
} else {
|
||||
localStorage.removeItem('news')
|
||||
this.$message({
|
||||
message: '服务器错误,请稍后再试',
|
||||
type: 'error'
|
||||
})
|
||||
}
|
||||
})
|
||||
} else {
|
||||
this.$message({
|
||||
message: '暂未开放注册,请联系管理员',
|
||||
type: 'warning'
|
||||
})
|
||||
}
|
||||
},
|
||||
remember () {
|
||||
if (this.checked) {
|
||||
this.$message({
|
||||
message: '将会记住您的登录信息',
|
||||
type: 'info'
|
||||
})
|
||||
} else {
|
||||
localStorage.removeItem('rememberedUsername')
|
||||
localStorage.removeItem('rememberedPassword')
|
||||
localStorage.removeItem('rememberMeChecked')
|
||||
this.$message({
|
||||
message: '已取消记住密码',
|
||||
type: 'info'
|
||||
})
|
||||
}
|
||||
},
|
||||
forgetpas () {
|
||||
@ -128,25 +205,22 @@ export default {
|
||||
},
|
||||
register () {
|
||||
if (this.create) {
|
||||
window.location.reload()
|
||||
} else if (
|
||||
this.form.username ||
|
||||
this.form.password ||
|
||||
this.form.repassword
|
||||
) {
|
||||
// 从登录切换到注册清空表单内容
|
||||
// 从注册页面返回登录页面时保留内容
|
||||
this.create = false
|
||||
this.loadRememberedCredentials()
|
||||
} else {
|
||||
// 从登录页面进入注册页面时清空内容
|
||||
this.create = true
|
||||
this.form.username = ''
|
||||
this.form.password = ''
|
||||
this.form.repassword = ''
|
||||
}
|
||||
this.create = !this.create
|
||||
// 清除字段的验证错误
|
||||
this.$refs.form.clearValidate('username')
|
||||
this.$refs.form.clearValidate('password')
|
||||
this.$refs.form.clearValidate('repassword')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@ -180,7 +254,7 @@ export default {
|
||||
/* 左侧阴影 */ 5px -5px 10px rgba(0, 0, 0, 0.1),
|
||||
/* 下部阴影 */ -5px -5px 10px rgba(0, 0, 0, 0.1); /* 上部阴影 */
|
||||
width: 400px;
|
||||
height: 300px;
|
||||
height: 350px;
|
||||
padding: 30px;
|
||||
border-radius: 10px;
|
||||
transform: translate(-50%);
|
||||
|
@ -23,16 +23,26 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="gallery">
|
||||
<div class="pointer" :style="pointerStyle"></div>
|
||||
<div
|
||||
class="gallery-item"
|
||||
v-for="(item, index) in photos"
|
||||
:key="index"
|
||||
:class="item.sizeClass"
|
||||
@mouseover="onMouseOver($event, item.sizeClass)"
|
||||
@mouseleave="onMouseLeave"
|
||||
@click="openImageViewer(item.src)"
|
||||
ref="photoItems"
|
||||
>
|
||||
<img :data-src="item.src" :alt="item.alt" class="lazy" />
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="showImageViewer" class="image-viewer" @click.self="closeImageViewer">
|
||||
<div class="image-viewer-content">
|
||||
<span class="close" @click="closeImageViewer">×</span>
|
||||
<img :src="currentImage" />
|
||||
</div>
|
||||
</div>
|
||||
<musIc />
|
||||
</div>
|
||||
</template>
|
||||
@ -42,6 +52,7 @@ 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' },
|
||||
@ -72,42 +83,56 @@ export default {
|
||||
{ src: require('@/assets/images/789.jpg'), alt: 'Photo 27', sizeClass: 'small' }
|
||||
],
|
||||
newPhoto: {
|
||||
src: '',
|
||||
alt: ''
|
||||
src: '', // 新照片的URL
|
||||
alt: '' // 新照片的描述
|
||||
},
|
||||
newPhotoFile: null,
|
||||
showModal: false
|
||||
newPhotoFile: null, // 新照片的文件对象
|
||||
showModal: false, // 控制上传照片模态框的显示
|
||||
showImageViewer: false, // 控制图片查看器的显示
|
||||
currentImage: '', // 当前显示的大图的URL
|
||||
pointerStyle: {
|
||||
display: 'none', // 控制边框指示器的显示
|
||||
top: '0px',
|
||||
left: '0px',
|
||||
width: '0px',
|
||||
height: '0px',
|
||||
borderColor: '' // 边框指示器的颜色
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 加载图片方法
|
||||
loadImages () {
|
||||
const images = this.$refs.photoItems
|
||||
const images = this.$refs.photoItems // 获取所有照片项的引用
|
||||
const options = {
|
||||
root: null,
|
||||
rootMargin: '0px',
|
||||
threshold: 0.1
|
||||
threshold: 0.1 // 触发观察器的阈值
|
||||
}
|
||||
|
||||
// 创建IntersectionObserver对象
|
||||
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)
|
||||
img.src = img.getAttribute('data-src') // 加载图片
|
||||
observer.unobserve(entry.target) // 停止观察已加载的图片
|
||||
}
|
||||
})
|
||||
}, options)
|
||||
|
||||
images.forEach(image => {
|
||||
observer.observe(image)
|
||||
observer.observe(image) // 观察每个图片项
|
||||
})
|
||||
},
|
||||
// 处理文件变化
|
||||
onFileChange (e) {
|
||||
const file = e.target.files[0]
|
||||
if (file) {
|
||||
this.newPhotoFile = URL.createObjectURL(file)
|
||||
this.newPhotoFile = URL.createObjectURL(file) // 创建文件的临时URL
|
||||
}
|
||||
},
|
||||
// 添加新照片
|
||||
addPhoto () {
|
||||
if (this.newPhotoFile && this.newPhoto.alt) {
|
||||
const sizeClasses = ['small', 'medium', 'large']
|
||||
@ -117,24 +142,61 @@ export default {
|
||||
alt: this.newPhoto.alt,
|
||||
sizeClass: sizeClass
|
||||
})
|
||||
this.newPhotoFile = null
|
||||
this.newPhoto.alt = ''
|
||||
this.showModal = false
|
||||
document.body.classList.remove('no-scroll')
|
||||
this.newPhotoFile = null // 清空文件对象
|
||||
this.newPhoto.alt = '' // 清空描述
|
||||
this.showModal = false // 关闭模态框
|
||||
document.body.classList.remove('no-scroll') // 恢复页面滚动
|
||||
this.$nextTick(() => {
|
||||
this.loadImages()
|
||||
this.loadImages() // 重新加载图片
|
||||
})
|
||||
}
|
||||
},
|
||||
// 打开模态框
|
||||
openModal () {
|
||||
this.showModal = true
|
||||
document.body.classList.add('no-scroll')
|
||||
document.body.classList.add('no-scroll') // 禁用页面滚动
|
||||
},
|
||||
// 关闭模态框
|
||||
closeModal () {
|
||||
this.showModal = false
|
||||
document.body.classList.remove('no-scroll')
|
||||
document.body.classList.remove('no-scroll') // 恢复页面滚动
|
||||
},
|
||||
// 打开图片查看器
|
||||
openImageViewer (src) {
|
||||
this.currentImage = src
|
||||
this.showImageViewer = true
|
||||
document.body.classList.add('no-scroll') // 禁用页面滚动
|
||||
},
|
||||
// 关闭图片查看器
|
||||
closeImageViewer () {
|
||||
this.showImageViewer = false
|
||||
document.body.classList.remove('no-scroll') // 恢复页面滚动
|
||||
},
|
||||
// 鼠标悬停时显示边框指示器
|
||||
onMouseOver (event, sizeClass) {
|
||||
const galleryItem = event.currentTarget
|
||||
const rect = galleryItem.getBoundingClientRect()
|
||||
const scrollTop = window.pageYOffset || document.documentElement.scrollTop
|
||||
const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft
|
||||
|
||||
// 生成随机颜色
|
||||
const randomColor = '#' + Math.floor(Math.random() * 16777215).toString(16)
|
||||
|
||||
this.pointerStyle = {
|
||||
display: 'block',
|
||||
top: `${rect.top + scrollTop - 85}px`,
|
||||
left: `${rect.left + scrollLeft - 205}px`,
|
||||
width: `${rect.width + 30}px`,
|
||||
height: `${rect.height + 30}px`,
|
||||
borderColor: randomColor // 设置随机颜色
|
||||
}
|
||||
},
|
||||
// 鼠标离开时隐藏边框指示器
|
||||
onMouseLeave () {
|
||||
this.pointerStyle.display = 'none'
|
||||
}
|
||||
},
|
||||
// 组件挂载后加载图片
|
||||
mounted () {
|
||||
this.loadImages()
|
||||
}
|
||||
@ -184,6 +246,7 @@ header {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
z-index: 10000; /* Ensure modal is on top */
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
@ -194,6 +257,7 @@ header {
|
||||
width: 400px;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
|
||||
animation: fadeIn 0.3s;
|
||||
z-index: 10001; /* Ensure modal content is on top */
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
@ -257,6 +321,12 @@ button:hover {
|
||||
.gallery {
|
||||
column-count: 4;
|
||||
column-gap: 16px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.pointer {
|
||||
position: absolute;
|
||||
border: 2px solid;
|
||||
}
|
||||
|
||||
.gallery-item {
|
||||
@ -270,7 +340,7 @@ button:hover {
|
||||
}
|
||||
|
||||
.gallery-item:hover {
|
||||
transform: translateY(-5px);
|
||||
transform: scale(1.05);
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
@ -291,4 +361,39 @@ button:hover {
|
||||
.gallery-item.large img {
|
||||
height: 250px;
|
||||
}
|
||||
|
||||
.image-viewer {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
z-index: 10000;
|
||||
}
|
||||
|
||||
.image-viewer-content {
|
||||
position: relative;
|
||||
max-width: 95%;
|
||||
max-height: 95%;
|
||||
z-index: 10001;
|
||||
}
|
||||
|
||||
.image-viewer img {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.image-viewer .close {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
font-size: 20px;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
|
@ -9,9 +9,7 @@
|
||||
</path>
|
||||
</svg>
|
||||
<div class="ana">
|
||||
<p>
|
||||
{{ user }}
|
||||
</p>
|
||||
<p>{{ user }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="article" v-for="(item, index) in articleS" :key="index">
|
||||
@ -35,7 +33,6 @@
|
||||
next-text="下一页"
|
||||
hide-on-single-page
|
||||
/>
|
||||
|
||||
<musIc />
|
||||
</div>
|
||||
</template>
|
||||
@ -45,40 +42,66 @@ import { getSubject } from '@/api/subject'
|
||||
import { fetchUser } from '@/api/dailySentence'
|
||||
|
||||
export default {
|
||||
name: 'subJect',
|
||||
name: 'Subject',
|
||||
data () {
|
||||
return {
|
||||
articleS: [],
|
||||
total: 0,
|
||||
user: ''
|
||||
user: '',
|
||||
lastUpdateTime: localStorage.getItem('lastUpdateTime') || null
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.getList()
|
||||
// 页面加载时,从本地存储获取用户内容
|
||||
this.user = localStorage.getItem('userContent') || ''
|
||||
this.checkAndFetchUser() // 检查并获取用户内容
|
||||
this.getList() // 获取文章列表
|
||||
|
||||
// 每天早上8点获取用户内容
|
||||
const now = new Date()
|
||||
const nextUpdate = new Date()
|
||||
nextUpdate.setHours(8, 0, 0, 0) // 设置到今天8点
|
||||
if (now > nextUpdate) {
|
||||
nextUpdate.setDate(nextUpdate.getDate() + 1) // 如果现在已经过了8点,设置到明天8点
|
||||
}
|
||||
const timeToNextUpdate = nextUpdate - now
|
||||
|
||||
setTimeout(() => {
|
||||
this.fetchUser() // 立即获取一次用户内容
|
||||
setInterval(() => {
|
||||
this.fetchUser()
|
||||
}, 1000 * 60 * 60 * 24) // 每24小时重复执行一次
|
||||
}, timeToNextUpdate)
|
||||
},
|
||||
methods: {
|
||||
getList () {
|
||||
getSubject().then(res => {
|
||||
this.articleS = res.data
|
||||
this.total = res.data.length
|
||||
}).catch(error => {
|
||||
console.error('获取文章列表失败:', error)
|
||||
})
|
||||
},
|
||||
fetchUser () {
|
||||
fetchUser()
|
||||
.then(response => {
|
||||
this.user = response.data.result.content
|
||||
// 将用户内容存储在本地存储中
|
||||
// 将用户内容和更新时间存储在本地存储中
|
||||
localStorage.setItem('userContent', this.user)
|
||||
localStorage.setItem('lastUpdateTime', new Date().toISOString())
|
||||
})
|
||||
.catch(error => {
|
||||
console.log(error)
|
||||
console.error('获取用户内容失败:', error)
|
||||
})
|
||||
},
|
||||
checkAndFetchUser () {
|
||||
const lastUpdate = new Date(this.lastUpdateTime)
|
||||
const now = new Date()
|
||||
const oneDay = 1000 * 60 * 60 * 24
|
||||
|
||||
if (!this.lastUpdateTime || (now - lastUpdate > oneDay)) {
|
||||
this.fetchUser()
|
||||
} else {
|
||||
this.user = localStorage.getItem('userContent') || ''
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user