diff --git a/src/filters/index.js b/src/filters/index.js index 051000c1..f6a28488 100644 --- a/src/filters/index.js +++ b/src/filters/index.js @@ -58,3 +58,11 @@ export function numberFormatter(num, digits) { export function toThousandFilter(num) { return (+num || 0).toString().replace(/^-?\d+/g, m => m.replace(/(?=(?!\b)(\d{3})+$)/g, ',')) } + +/** + * Upper case first char + * @param {String} string + */ +export function uppercaseFirst(string) { + return string.charAt(0).toUpperCase() + string.slice(1) +} diff --git a/src/icons/svg/education.svg b/src/icons/svg/education.svg new file mode 100644 index 00000000..db70f234 --- /dev/null +++ b/src/icons/svg/education.svg @@ -0,0 +1 @@ +<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1555641167698" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="977" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M702.784 879.008c-55.84 0-148.992 16.48-163.552 54.496l0 0.832c-32.448 0.864-40.032 0-54.496 0-14.528-38.048-107.68-54.528-163.552-54.528l-299.84 0 0-790.496 326.016 0c70.368 0 131.168 36.128 164.608 89.504 33.408-53.344 94.304-89.504 164.704-89.504l326.016 0 0 789.728-299.872-0.032zM484.736 252.864c0-63.744-68.832-109.024-136.288-109.024l-272.608 0 0 681.44 245.344 0c54.08-0.928 139.36 0.544 163.552 40.416l0-30.56c-1.024-37.792-0.032-89.312 0-91.36l0-473.408 0.032-17.536zM948.128 143.776l-272.544 0c-67.488 0-136.32 45.28-136.32 108.928l0 490.464c0.032 2.112 1.056 53.6 0 91.232l0 30.56c24.192-39.776 109.472-41.344 163.552-40.384l245.344 0 0-680.768z" p-id="978"></path></svg> \ No newline at end of file diff --git a/src/icons/svg/skill.svg b/src/icons/svg/skill.svg new file mode 100644 index 00000000..7ff3daa7 --- /dev/null +++ b/src/icons/svg/skill.svg @@ -0,0 +1 @@ +<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1555640763920" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1499" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M264.032 719.136l256.064 0c11.04 17.088 23.584 32.96 37.792 47.296l-293.856 0 0-47.296zM264.032 644.32l221.664 0c-4.48-15.264-7.712-31.04-9.696-47.264l-211.968 0 0 47.264zM264.032 522.272l212.64 0c2.208-16.16 5.472-32.032 10.272-47.264l-222.944 0 0 47.264zM677.344 839.168l0 41.344c0 19.776-16.064 35.872-35.776 35.872l-537.184 0c-19.744 0-35.744-16.096-35.744-35.872l0-599.168 178.016-148.128 0 157.248-93.728 0 0 47.264 140.992 0 0-230.048 347.648 0c19.744 0 35.776 16.096 35.776 35.808l0 141.408c15.232-4.768 31.072-7.968 47.296-10.208l0-131.168c0.032-45.792-37.248-83.104-83.04-83.104l-381.408 0-238.816 198.72 0 621.344c0 45.792 37.248 83.104 83.04 83.104l537.184 0c45.792 0 83.072-37.248 83.072-83.104l0-31.168c-16.224-2.208-32.064-5.408-47.296-10.144l0 0zM199.84 475.04l-61.024 0 0 47.264 61.024 0 0-47.264zM138.848 766.432l61.024 0 0-47.296-61.024 0 0 47.296zM199.84 597.088l-61.024 0 0 47.264 61.024 0 0-47.264zM887.648 490.784l-37.536-28.768-95.424 124.48-85.792-65.76-28.832 37.536 123.36 94.56 124.224-162.048zM1002.656 562.048c0-131.68-107.104-238.752-238.784-238.752-131.616 0-238.688 107.104-238.688 238.752s107.104 238.752 238.688 238.752c131.648 0 238.752-107.072 238.752-238.752l0 0zM955.36 562.048c0 105.536-85.888 191.52-191.52 191.52-105.568 0-191.552-85.92-191.552-191.52s85.824-191.52 191.552-191.52c105.632 0 191.52 85.92 191.52 191.52l0 0z" p-id="1500"></path></svg> \ No newline at end of file diff --git a/src/lang/en.js b/src/lang/en.js index 426d3d26..ae221ba8 100644 --- a/src/lang/en.js +++ b/src/lang/en.js @@ -61,12 +61,14 @@ export default { theme: 'Theme', clipboardDemo: 'Clipboard', i18n: 'I18n', - externalLink: 'External Link' + externalLink: 'External Link', + profile: 'Profile' }, navbar: { - logOut: 'Log Out', dashboard: 'Dashboard', github: 'Github', + logOut: 'Log Out', + profile: 'Profile', theme: 'Theme', size: 'Global Size' }, diff --git a/src/lang/zh.js b/src/lang/zh.js index 2055c5ab..d637b3b3 100644 --- a/src/lang/zh.js +++ b/src/lang/zh.js @@ -61,12 +61,14 @@ export default { theme: '换肤', clipboardDemo: 'Clipboard', i18n: '国际化', - externalLink: '外链' + externalLink: '外链', + profile: '个人资料页' }, navbar: { - logOut: '退出登录', dashboard: '首页', github: '项目地址', + logOut: '退出登录', + profile: '个人资料页', theme: '换肤', size: '布局大小' }, diff --git a/src/layout/components/Navbar.vue b/src/layout/components/Navbar.vue index 51972166..6cf2b701 100644 --- a/src/layout/components/Navbar.vue +++ b/src/layout/components/Navbar.vue @@ -26,6 +26,11 @@ <i class="el-icon-caret-bottom" /> </div> <el-dropdown-menu slot="dropdown"> + <router-link to="'/profile/index"> + <el-dropdown-item> + {{ $t('navbar.profile') }} + </el-dropdown-item> + </router-link> <router-link to="/"> <el-dropdown-item> {{ $t('navbar.dashboard') }} diff --git a/src/router/index.js b/src/router/index.js index 34afd5c5..d1dfda90 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -107,6 +107,20 @@ export const constantRoutes = [ meta: { title: 'guide', icon: 'guide', noCache: true } } ] + }, + { + path: '/profile', + component: Layout, + redirect: '/profile/index', + hidden: true, + children: [ + { + path: 'index', + component: () => import('@/views/profile/index'), + name: 'Profile', + meta: { title: 'profile', icon: 'user', noCache: true } + } + ] } ] diff --git a/src/views/profile/index.vue b/src/views/profile/index.vue new file mode 100644 index 00000000..663f4dda --- /dev/null +++ b/src/views/profile/index.vue @@ -0,0 +1,389 @@ +<template> + <div class="app-container"> + <el-form v-if="user" :model="user"> + <el-row :gutter="20"> + <el-col :span="6"> + <el-card> + <div class="user-profile"> + <div class="user-avatar box-center"> + <pan-thumb :image="user.avatar" :height="'100px'" :width="'100px'" :hoverable="false" /> + </div> + <div class="box-center"> + <div class="user-name text-center">{{ user.name }}</div> + <div class="user-role text-center text-muted">{{ user.role | uppercaseFirst }}</div> + </div> + <div class="box-social"> + <el-table :data="social" :show-header="false"> + <el-table-column + prop="name" + label="Name" + /> + <el-table-column label="Count" align="left" width="100"> + <template slot-scope="scope"> + {{ scope.row.count | toThousandFilter }} + </template> + </el-table-column> + </el-table> + </div> + <div class="user-follow"> + <el-button type="primary" style="width: 100%;">Follow</el-button> + </div> + </div> + </el-card> + <el-card class="box-card user-bio"> + <div slot="header" class="clearfix"> + <span>About me</span> + </div> + <div class="user-education user-bio-section"> + <div class="user-bio-section-header"><svg-icon icon-class="education" /><span>Education</span></div> + <div class="user-bio-section-body"> + <div class="text-muted"> + B.S. in Computer Science from the University of Technology + </div> + </div> + </div> + <div class="user-skills user-bio-section"> + <div class="user-bio-section-header"><svg-icon icon-class="skill" /><span>Skills</span></div> + <div class="user-bio-section-body"> + <div class="progress-item"> + <span>Vue</span> + <el-progress :percentage="70" /> + </div> + <div class="progress-item"> + <span>JavaScript</span> + <el-progress :percentage="18" /> + </div> + <div class="progress-item"> + <span>Css</span> + <el-progress :percentage="12" /> + </div> + <div class="progress-item"> + <span>ESLint</span> + <el-progress :percentage="100" status="success" /> + </div> + </div> + </div> + </el-card> + </el-col> + <el-col :span="18"> + <el-card> + <el-tabs v-model="activeActivity" @tab-click="handleClick"> + <el-tab-pane label="Activity" name="first"> + <div class="user-activity"> + <div class="post"> + <div class="user-block"> + <img class="img-circle" src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRDkaQO69Fro8SZLTVZQ75JH2R0T-sn5yIA_lKGwvvgQ0R0BoQtUQ" alt="user image"> + <span class="username text-muted"> + <a href="#">Iron Man</a> + <a href="#" class="pull-right btn-box-tool"><i class="fa fa-times" /></a> + </span> + <span class="description">Shared publicly - 7:30 PM today</span> + </div> + <p> + Lorem ipsum represents a long-held tradition for designers, + typographers and the like. Some people hate it and argue for + its demise, but others ignore the hate as they create awesome + tools to help create filler text for everyone from bacon lovers + to Charlie Sheen fans. + </p> + <ul class="list-inline"> + <li><a href="#" class="link-black text-sm"><i class="el-icon-share" /> Share</a></li> + <li><a href="#" class="link-black text-sm"><svg-icon icon-class="like" /> Like</a></li> + <li class="pull-right"> + <a href="#" class="link-black text-sm"><svg-icon icon-class="comment" /> Comments + (5)</a></li> + </ul> + <el-input v-model="input.comment1" placeholder="Type a comment" /> + </div> + <div class="post"> + <div class="user-block"> + <img class="img-circle" src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQMMN-8f9CQQ3MKJpboBJIqaiJ2Wus2Tf4w_vx9STtalxrY3qGJ" alt="user image"> + <span class="username text-muted"> + <a href="#">Captain American</a> + <a href="#" class="pull-right btn-box-tool"><i class="fa fa-times" /></a> + </span> + <span class="description">Sent you a message - yesterday</span> + </div> + <p> + Lorem ipsum represents a long-held tradition for designers, + typographers and the like. Some people hate it and argue for + its demise, but others ignore the hate as they create awesome + tools to help create filler text for everyone from bacon lovers + to Charlie Sheen fans. + </p> + <el-input v-model="input.reply" placeholder="Response"> + <el-button slot="append">Send</el-button> + </el-input> + </div> + <div class="post"> + <div class="user-block"> + <img class="img-circle img-bordered-sm" src="https://cdn3.iconfinder.com/data/icons/movies-3/32/daredevil-superhero-marvel-comics-mutant-avatar-512.png" alt="User Image"> + <span class="username"> + <a href="#">Daredevil</a> + <a href="#" class="pull-right btn-box-tool"><i class="fa fa-times" /></a> + </span> + <span class="description">Posted 4 photos - 2 days ago</span> + </div> + <div class="user-images"> + <el-carousel :interval="6000" type="card" height="200px"> + <el-carousel-item v-for="item in carouselImages" :key="item"> + <img :src="item" class="image"> + </el-carousel-item> + </el-carousel> + </div> + <ul class="list-inline"> + <li><a href="#" class="link-black text-sm"><i class="el-icon-share" /> Share</a></li> + <li><a href="#" class="link-black text-sm"><svg-icon icon-class="like" /> Like</a></li> + <li class="pull-right"> + <a href="#" class="link-black text-sm"><svg-icon icon-class="comment" /> Comments + (5)</a></li> + </ul> + <el-input v-model="input.comment2" placeholder="Type a comment" /> + </div> + </div> + </el-tab-pane> + <el-tab-pane label="Timeline" name="second"> + <div class="block"> + <el-timeline> + <el-timeline-item timestamp="2019/4/20" placement="top"> + <el-card> + <h4>Update Github template</h4> + <p>PanJiaChen committed 2019/4/20 20:46</p> + </el-card> + </el-timeline-item> + <el-timeline-item timestamp="2019/4/21" placement="top"> + <el-card> + <h4>Update Github template</h4> + <p>PanJiaChen committed 2019/4/21 20:46</p> + </el-card> + <el-card> + <h4>Update Github template</h4> + <p>PanJiaChen committed 2019/4/21 21:16</p> + </el-card> + </el-timeline-item> + <el-timeline-item timestamp="2019/4/22" placement="top"> + <el-card> + <h4>Deploy <a href="https://Panjiachen.github.io/vue-element-admin/" target="_blank">vue-template-admin</a></h4> + <p>PanJiaChen deployed 2019/4/22 10:23</p> + </el-card> + </el-timeline-item> + </el-timeline> + </div> + </el-tab-pane> + <el-tab-pane v-loading="updating" label="Account" name="third"> + <el-form-item label="Name"> + <el-input v-model="user.name" /> + </el-form-item> + <el-form-item label="Email"> + <el-input v-model="user.email" /> + </el-form-item> + <el-form-item> + <el-button type="primary" @click="onSubmit">Update</el-button> + </el-form-item> + </el-tab-pane> + </el-tabs> + </el-card> + </el-col> + </el-row> + </el-form> + </div> +</template> + +<script> +import { mapGetters } from 'vuex' +import PanThumb from '@/components/PanThumb' + +export default { + name: 'EditUser', + components: { PanThumb }, + data() { + return { + user: null, + social: [ + { + 'name': 'Followers', + 'count': 1235 + }, + { + 'name': 'Following', + 'count': 23512 + }, + { + 'name': 'Friends', + 'count': 7242 + } + ], + activeActivity: 'first', + carouselImages: [ + 'https://cdn.laravue.dev/photo1.jpg', + 'https://cdn.laravue.dev/photo2.jpg', + 'https://cdn.laravue.dev/photo3.jpg', + 'https://cdn.laravue.dev/photo4.jpg' + ], + updating: false, + input: { + comment1: '', + comment2: '', + reply: '' + } + } + }, + computed: { + ...mapGetters([ + 'name', + 'avatar', + 'roles' + ]) + }, + created() { + this.getUser() + }, + methods: { + getUser() { + this.user = { + name: this.name, + role: this.roles.join(' | '), + email: 'admin@test.com', + avatar: this.avatar + } + }, + handleClick(tab, event) { + console.log('Switching tab ', tab, event) + }, + onSubmit() { + this.updating = true + setTimeout(() => { + this.$message({ + message: 'User information has been updated successfully', + type: 'success', + duration: 5 * 1000 + }) + this.updating = false + }, 1000) + } + } +} +</script> + +<style rel="stylesheet/scss" lang="scss" scoped> +.user-profile { + .user-name { + font-weight: bold; + } + .box-center { + padding-top: 10px; + } + .user-role { + padding-top: 10px; + font-weight: 400; + font-size: 14px; + } + .box-social { + padding-top: 30px; + .el-table { + border-top: 1px solid #dfe6ec; + } + } + .user-follow { + padding-top: 20px; + } +} +.user-bio { + margin-top: 20px; + color: #606266; + span { + padding-left: 4px; + } + .user-bio-section { + font-size: 14px; + padding: 15px 0; + .user-bio-section-header { + border-bottom: 1px solid #dfe6ec; + padding-bottom: 10px; + margin-bottom: 10px; + font-weight: bold; + } + } +} +.user-activity { + .user-block { + .username, .description { + display: block; + margin-left: 50px; + padding: 2px 0; + } + img { + width: 40px; + height: 40px; + float: left; + } + :after { + clear: both; + } + .img-circle { + border-radius: 50%; + border: 2px solid #d2d6de; + padding: 2px; + } + span { + font-weight: 500; + font-size: 12px; + } + } + .post { + font-size: 14px; + border-bottom: 1px solid #d2d6de; + margin-bottom: 15px; + padding-bottom: 15px; + color: #666; + .image { + width: 100%; + } + .user-images { + padding-top: 20px; + } + } + .list-inline { + padding-left: 0; + margin-left: -5px; + list-style: none; + li { + display: inline-block; + padding-right: 5px; + padding-left: 5px; + font-size: 13px; + } + .link-black { + &:hover, &:focus { + color: #999; + } + } + } + .el-carousel__item h3 { + color: #475669; + font-size: 14px; + opacity: 0.75; + line-height: 200px; + margin: 0; + } + + .el-carousel__item:nth-child(2n) { + background-color: #99a9bf; + } + + .el-carousel__item:nth-child(2n+1) { + background-color: #d3dce6; + } +} + + .box-center { + margin: 0 auto; + display: table; +} +.text-muted { + color: #777; +} +.pull-right { + float: right !important; +} +</style>