✨ 用户扩展-站点链接功能
This commit is contained in:
parent
6fad841b15
commit
4eca4793f2
@ -64,8 +64,8 @@
|
||||
<el-link rel="nofollow" :underline="false" style="margin-left: 10px;margin-bottom: 1rem;">{{ nickname }}</el-link>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="hasPermissions" command="admin-dashboard">系统管理</el-dropdown-item>
|
||||
<el-dropdown-item command="user-info">资料与账号</el-dropdown-item>
|
||||
<el-dropdown-item command="drafts">我的草稿</el-dropdown-item>
|
||||
<el-dropdown-item command="user-info">设置</el-dropdown-item>
|
||||
<el-dropdown-item command="logout" divided>退出登录</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
|
@ -45,7 +45,7 @@
|
||||
export default {
|
||||
name: "portfolios",
|
||||
props: {
|
||||
portfolios: []
|
||||
portfolios: Array
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
@ -46,7 +46,8 @@ export default {
|
||||
** Global CSS
|
||||
*/
|
||||
css: [
|
||||
'element-ui/lib/theme-chalk/index.css'
|
||||
'element-ui/lib/theme-chalk/index.css',
|
||||
'@fortawesome/fontawesome-svg-core/styles.css'
|
||||
],
|
||||
/*
|
||||
** Plugins to load before mounting the App
|
||||
@ -57,7 +58,9 @@ export default {
|
||||
{src: '~/plugins/extend'},
|
||||
{src: '~/plugins/axios'},
|
||||
{src: '~/plugins/element-ui'},
|
||||
{src: '~/plugins/vditor', ssr: false}
|
||||
{src: '~/plugins/vditor', ssr: false},
|
||||
{src: '~/plugins/fontawesome'},
|
||||
// {src: '~/plugins/vue-cropper', ssr: false}
|
||||
],
|
||||
/*
|
||||
** Nuxt.js dev-modules
|
||||
|
@ -11,6 +11,13 @@
|
||||
<img v-else class="card-profile-img" src="https://static.rymcu.com/article/1578475481946.png">
|
||||
<h3 class="mb-3">{{ user.nickname }}</h3>
|
||||
<p class="mb-4" v-html="user.signature"></p>
|
||||
<div v-if="userExtend" style="margin-bottom: 1rem;">
|
||||
<el-link v-if="userExtend.blog" class="user-link" title="博客" :underline="false" :href="userExtend.blog" target="_blank"><font-awesome-icon :icon="['fas', 'link']"></font-awesome-icon></el-link>
|
||||
<el-link v-if="userExtend.github" class="user-link" title="github" :underline="false" :href="'https://github.com/' + userExtend.github" target="_blank"><font-awesome-icon :icon="['fab', 'github']"></font-awesome-icon></el-link>
|
||||
<el-link v-if="userExtend.weibo" class="user-link" title="微博" :underline="false" :href="'https://weibo.com/n/' + userExtend.weibo" target="_blank"><font-awesome-icon :icon="['fab', 'weibo']"></font-awesome-icon></el-link>
|
||||
<el-link v-if="userExtend.weixin" class="user-link" title="微信" :underline="false" :href="userExtend.weixin"><font-awesome-icon :icon="['fab', 'weixin']" target="_blank"></font-awesome-icon></el-link>
|
||||
<el-link v-if="userExtend.qq" class="user-link" title="QQ" :underline="false" :href="userExtend.qq"><font-awesome-icon :icon="['fab', 'qq']" target="_blank"></font-awesome-icon></el-link>
|
||||
</div>
|
||||
<div v-if="oauth">
|
||||
<div v-if="oauth.idUser !== user.idUser">
|
||||
<el-button type="primary" v-if="isFollow" @click="cancelFollowUser(user.idUser)" plain>取消关注</el-button>
|
||||
@ -70,6 +77,7 @@ export default {
|
||||
store
|
||||
.dispatch('user/fetchDetail', params)
|
||||
.catch(err => error({statusCode: 404})),
|
||||
store.dispatch('user/fetchUserExtend', params),
|
||||
store.dispatch('user/fetchArticleList', params),
|
||||
store.dispatch('user/fetchPortfolioList', params),
|
||||
store.dispatch('user/fetchFollowerList', params),
|
||||
@ -79,6 +87,7 @@ export default {
|
||||
computed: {
|
||||
...mapState({
|
||||
user: state => state.user.data,
|
||||
userExtend: state => state.user.userExtend,
|
||||
articles: state => state.user.articles,
|
||||
portfolios: state => state.user.portfolios,
|
||||
followers: state => state.user.followers,
|
||||
@ -294,4 +303,9 @@ h3, .h3 {
|
||||
.tab-content {
|
||||
min-height: 50vh;
|
||||
}
|
||||
|
||||
.user-link {
|
||||
font-size: 24px;
|
||||
margin: 0 0.5rem;
|
||||
}
|
||||
</style>
|
||||
|
@ -8,7 +8,19 @@
|
||||
@select="handleSelectMenu">
|
||||
<el-menu-item index="account">
|
||||
<i class="el-icon-s-data"></i>
|
||||
<span slot="title">资料与账号</span>
|
||||
<span slot="title">基本信息</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="avatar">
|
||||
<i class="el-icon-picture-outline-round"></i>
|
||||
<span slot="title">我的头像</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="security">
|
||||
<i class="el-icon-unlock"></i>
|
||||
<span slot="title">账户安全</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="notification">
|
||||
<i class="el-icon-bell"></i>
|
||||
<span slot="title">通知方式</span>
|
||||
</el-menu-item>
|
||||
</el-menu>
|
||||
</el-col>
|
||||
|
@ -1,48 +1,11 @@
|
||||
<template>
|
||||
<client-only>
|
||||
<el-row>
|
||||
<el-col>
|
||||
<el-form :model="user" :rules="rules" ref="user" label-width="100px">
|
||||
<el-form-item style="align-items: center;text-align: center;">
|
||||
<el-upload
|
||||
class="avatar-uploader"
|
||||
:action="tokenURL.URL"
|
||||
:multiple="true"
|
||||
:with-credentials="true"
|
||||
:headers="uploadHeaders"
|
||||
:show-file-list="false"
|
||||
:data="uploadOption"
|
||||
:on-success="handleAvatarSuccess"
|
||||
:before-upload="beforeAvatarUpload">
|
||||
<div v-if="svgShow">
|
||||
<Avataaars
|
||||
id="avatarSvg"
|
||||
style="width: 178px; height: 178px;"
|
||||
:avatarStyle='avatar.acatarStyle'
|
||||
:topType='avatar.topType'
|
||||
:accessoriesType='avatar.accessoriesType'
|
||||
:hairColor='avatar.hairColor'
|
||||
:facialHairType='avatar.facialHairType'
|
||||
:clotheType='avatar.clotheType'
|
||||
:clotheColor='avatar.clotheColor'
|
||||
:eyeType='avatar.eyeType'
|
||||
:eyebrowType='avatar.eyebrowType'
|
||||
:mouthType='avatar.mouthType'
|
||||
:skinColor='avatar.skinColor'>
|
||||
</Avataaars>
|
||||
</div>
|
||||
<div v-else>
|
||||
<el-avatar v-if="avatarUrl" class="avatar" :src="avatarUrl"></el-avatar>
|
||||
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
|
||||
</div>
|
||||
</el-upload>
|
||||
<el-button style="margin-top: 1rem;" type="primary" round @click="genAvatar" plain>随机</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item label="昵称" prop="nickname">
|
||||
<el-input v-model="user.nickname" @blur="checkNickname"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="邮箱" prop="email">
|
||||
<el-input type="email" v-model="user.email" :disabled="true"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="性别">
|
||||
<el-radio-group v-model="user.sex">
|
||||
<el-radio border label="0">保密</el-radio>
|
||||
@ -57,32 +20,52 @@
|
||||
<el-button type="primary" round @click="updateUserInfo" plain>保存</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-form :model="userExtend" ref="userExtend" label-width="100px">
|
||||
<el-form-item label="博客" prop="signature">
|
||||
<el-input placeholder="设置后将会公开你的博客" v-model="userExtend.blog">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="github" prop="signature">
|
||||
<el-input placeholder="yourname" v-model="userExtend.github">
|
||||
<template slot="prepend">https://github.com/</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="微博" prop="signature">
|
||||
<el-input placeholder="yourname" v-model="userExtend.weibo">
|
||||
<template slot="prepend">https://weibo.com/n/</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="微信" prop="signature">
|
||||
<el-input placeholder="设置后将会公开你的微信" v-model="userExtend.weixin">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="QQ" prop="signature">
|
||||
<el-input placeholder="设置后将会公开你的 QQ" v-model="userExtend.qq">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item style="text-align: right;">
|
||||
<el-button type="primary" round @click="updateUserExtend" plain>保存</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</client-only>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {mapState} from 'vuex';
|
||||
import Avataaars from 'vuejs-avataaars';
|
||||
import saveSvg from 'save-svg-as-png';
|
||||
|
||||
const {generateRandomAvatar} = require('~/plugins/avataaars/generator/generateAvatar');
|
||||
export default {
|
||||
name: "account",
|
||||
components: {
|
||||
Avataaars
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
uploadHeaders: state => {
|
||||
return {'X-Upload-Token': state.uploadHeaders}
|
||||
},
|
||||
idUser: state => state.oauth.idUser
|
||||
})
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
user: {},
|
||||
userExtend: {},
|
||||
rules: {
|
||||
nickname: [
|
||||
{required: true, message: '请输入昵称', trigger: 'blur'},
|
||||
@ -93,54 +76,10 @@
|
||||
{type: 'email', message: '请输入正确的邮箱地址', trigger: ['blur', 'change']}
|
||||
]
|
||||
},
|
||||
loading: false,
|
||||
svgShow: false,
|
||||
tokenURL: {
|
||||
URL: '',
|
||||
linkToImageURL: '',
|
||||
token: ''
|
||||
},
|
||||
avatarUrl: '',
|
||||
avatar: {},
|
||||
fileList: [],
|
||||
uploadOption: {
|
||||
type: 0
|
||||
}
|
||||
loading: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
genAvatar() {
|
||||
let _ts = this;
|
||||
_ts.$set(_ts, 'svgShow', true);
|
||||
const avatar = generateRandomAvatar();
|
||||
_ts.$set(_ts, 'avatar', avatar);
|
||||
},
|
||||
handleAvatarSuccess(res) {
|
||||
let _ts = this;
|
||||
if (res && res.data && res.data.url) {
|
||||
let user = _ts.user;
|
||||
user.avatarUrl = res.data.url;
|
||||
user.avatarType = '0';
|
||||
_ts.$set(_ts, 'user', user);
|
||||
_ts.$set(_ts, 'svgShow', false);
|
||||
_ts.$set(_ts, 'avatarUrl', res.data.url);
|
||||
} else {
|
||||
_ts.$message.error('上传失败!');
|
||||
}
|
||||
},
|
||||
beforeAvatarUpload(file) {
|
||||
const isJPG = file.type === 'image/jpeg';
|
||||
const isPNG = file.type === 'image/png';
|
||||
const isLt2M = file.size / 1024 / 1024 < 2;
|
||||
|
||||
if (!(isJPG || isPNG)) {
|
||||
this.$message.error('上传图标只能是 JPG 或者 PNG 格式!');
|
||||
}
|
||||
if (!isLt2M) {
|
||||
this.$message.error('上传图标大小不能超过 2MB!');
|
||||
}
|
||||
return (isJPG || isPNG) && isLt2M;
|
||||
},
|
||||
getData() {
|
||||
let _ts = this;
|
||||
_ts.$axios.$get('/api/user-info/detail/' + _ts.idUser).then(function (res) {
|
||||
@ -149,8 +88,7 @@
|
||||
_ts.$message.error(res.message);
|
||||
} else {
|
||||
_ts.$set(_ts, 'user', res.user);
|
||||
_ts.$set(_ts, 'avatarUrl', res.user.avatarUrl);
|
||||
_ts.$set(_ts, 'svgShow', false);
|
||||
_ts.$set(_ts, 'userExtend', res.userExtend);
|
||||
}
|
||||
}
|
||||
})
|
||||
@ -170,21 +108,8 @@
|
||||
},
|
||||
updateUserInfo() {
|
||||
let _ts = this;
|
||||
let svgShow = _ts.svgShow;
|
||||
let user = _ts.user;
|
||||
if (svgShow) {
|
||||
saveSvg.svgAsPngUri(document.getElementById('avatarSvg'), {}).then(uri => {
|
||||
if (uri) {
|
||||
user.avatarType = 1;
|
||||
user.avatarUrl = uri;
|
||||
_ts.updateUser(user);
|
||||
} else {
|
||||
_ts.$message.error('头像上传失败 !');
|
||||
}
|
||||
});
|
||||
} else {
|
||||
_ts.updateUser(user);
|
||||
}
|
||||
},
|
||||
updateUser(user) {
|
||||
let _ts = this;
|
||||
@ -196,8 +121,6 @@
|
||||
_ts.$message.error(res.message);
|
||||
} else {
|
||||
_ts.$set(_ts, 'user', res.user);
|
||||
_ts.$set(_ts, 'avatarUrl', res.user.avatarUrl);
|
||||
_ts.$set(_ts, 'svgShow', false);
|
||||
_ts.$store.commit('setUserInfo', res.user);
|
||||
_ts.$message.success('更新成功 !');
|
||||
}
|
||||
@ -207,50 +130,29 @@
|
||||
_ts.$message.error('数据异常 !');
|
||||
}
|
||||
});
|
||||
},
|
||||
updateUserExtend() {
|
||||
let _ts = this;
|
||||
let userExtend = _ts.userExtend;
|
||||
_ts.$axios.$patch('/api/user-info/update-extend', userExtend).then(function (res) {
|
||||
if (res) {
|
||||
if (res.message) {
|
||||
_ts.$message.error(res.message);
|
||||
} else {
|
||||
_ts.$set(_ts, 'userExtend', res.userExtend);
|
||||
_ts.$message.success('更新成功 !');
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
let _ts = this;
|
||||
this.$store.commit('setActiveMenu', 'account');
|
||||
this.$axios.$get('/api/upload/simple/token').then(function (res) {
|
||||
if (res) {
|
||||
_ts.$store.commit('setUploadHeaders', res.uploadToken);
|
||||
_ts.$set(_ts, 'tokenURL', {
|
||||
token: res.uploadToken || '',
|
||||
URL: res.uploadURL || '',
|
||||
})
|
||||
}
|
||||
});
|
||||
this.getData();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.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>
|
||||
|
16
plugins/fontawesome.js
Normal file
16
plugins/fontawesome.js
Normal file
@ -0,0 +1,16 @@
|
||||
import Vue from 'vue'
|
||||
import { library, config } from '@fortawesome/fontawesome-svg-core'
|
||||
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
|
||||
import { fas } from '@fortawesome/free-solid-svg-icons'
|
||||
import { fab } from '@fortawesome/free-brands-svg-icons'
|
||||
|
||||
// This is important, we are going to let Nuxt.js worry about the CSS
|
||||
config.autoAddCss = false
|
||||
|
||||
// You can add your icons directly in this plugin. See other examples for how you
|
||||
// can add other styles or just individual icons.
|
||||
library.add(fas)
|
||||
library.add(fab)
|
||||
|
||||
// Register the component globally
|
||||
Vue.component('font-awesome-icon', FontAwesomeIcon)
|
4
plugins/vue-cropper.js
Normal file
4
plugins/vue-cropper.js
Normal file
@ -0,0 +1,4 @@
|
||||
import Vue from 'vue';
|
||||
import VueCropper from 'vue-cropperjs';
|
||||
import 'cropperjs/dist/cropper.css';
|
||||
Vue.component('vue-cropper', VueCropper);
|
@ -10,6 +10,7 @@ export const state = () => {
|
||||
return {
|
||||
fetching: false,
|
||||
data: [],
|
||||
userExtend: {},
|
||||
articles: {
|
||||
articles: [],
|
||||
pagination: {}
|
||||
@ -36,6 +37,9 @@ export const mutations = {
|
||||
updateDetailData(state, action) {
|
||||
state.data = action
|
||||
},
|
||||
updateUserExtendData(state, action) {
|
||||
state.userExtend = action
|
||||
},
|
||||
updateArticleList(state, action) {
|
||||
state.articles = action
|
||||
},
|
||||
@ -63,6 +67,18 @@ export const actions = {
|
||||
commit('updateFetching', false)
|
||||
})
|
||||
},
|
||||
fetchUserExtend({ commit }, params) {
|
||||
commit('updateFetching', true);
|
||||
return this.$axios
|
||||
.$get(`${USER_API_PATH}/${params.nickname}/user-extend`)
|
||||
.then(response => {
|
||||
commit('updateUserExtendData', response)
|
||||
commit('updateFetching', false)
|
||||
})
|
||||
.catch(error => {
|
||||
commit('updateFetching', false)
|
||||
})
|
||||
},
|
||||
fetchArticleList({commit}, params) {
|
||||
commit('updateFetching', true);
|
||||
return this.$axios
|
||||
|
Loading…
Reference in New Issue
Block a user