v1.3 版本发布,代码同步后端v1.3版本
This commit is contained in:
@@ -23,3 +23,9 @@ npm run dev
|
||||
# 构建生产环境
|
||||
npm run build
|
||||
```
|
||||
|
||||
#### 反馈交流
|
||||
|
||||
- QQ交流群:<a target="_blank" href="//shang.qq.com/wpa/qunwpa?idkey=90830191a40600e3a07acdcc4864890fca50c8e3ca1772e7e288a561d576f6c4"><img border="0" src="//pub.idqqimg.com/wpa/images/group.png" alt="Quella/el-admin" title="Quella/el-admin"></a>
|
||||
|
||||
- 作者邮箱:elunez@qq.com
|
||||
25
src/api/alipay.js
Normal file
25
src/api/alipay.js
Normal file
@@ -0,0 +1,25 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function get() {
|
||||
return request({
|
||||
url: 'api/aliPay',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function update(data) {
|
||||
return request({
|
||||
url: 'api/aliPay',
|
||||
data,
|
||||
method: 'put'
|
||||
})
|
||||
}
|
||||
|
||||
// 支付
|
||||
export function toAliPay(url, data) {
|
||||
return request({
|
||||
url: 'api/' + url,
|
||||
data,
|
||||
method: 'post'
|
||||
})
|
||||
}
|
||||
16
src/api/code.js
Normal file
16
src/api/code.js
Normal file
@@ -0,0 +1,16 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function resetEmail(data) {
|
||||
return request({
|
||||
url: 'api/code/resetEmail',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function updatePass(pass) {
|
||||
return request({
|
||||
url: 'api/users/updatePass/' + pass,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
@@ -1,13 +1,5 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function uoload(data) {
|
||||
return request({
|
||||
url: 'api/pictures',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function del(id) {
|
||||
return request({
|
||||
url: 'api/pictures/' + id,
|
||||
|
||||
37
src/api/qiniu.js
Normal file
37
src/api/qiniu.js
Normal file
@@ -0,0 +1,37 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function get() {
|
||||
return request({
|
||||
url: 'api/qiNiuConfig',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function update(data) {
|
||||
return request({
|
||||
url: 'api/qiNiuConfig',
|
||||
data,
|
||||
method: 'put'
|
||||
})
|
||||
}
|
||||
|
||||
export function del(id) {
|
||||
return request({
|
||||
url: 'api/qiNiuContent/' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
export function download(id) {
|
||||
return request({
|
||||
url: 'api/qiNiuContent/download/' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function sync() {
|
||||
return request({
|
||||
url: 'api/qiNiuContent/synchronize',
|
||||
method: 'post'
|
||||
})
|
||||
}
|
||||
@@ -22,3 +22,26 @@ export function edit(data) {
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function validPass(pass) {
|
||||
return request({
|
||||
url: 'api/users/validPass/' + pass,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function updatePass(pass) {
|
||||
return request({
|
||||
url: 'api/users/updatePass/' + pass,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function updateEmail(code, data) {
|
||||
return request({
|
||||
url: 'api/users/updateEmail/' + code,
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
1
src/icons/svg/alipay.svg
Normal file
1
src/icons/svg/alipay.svg
Normal file
@@ -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="1546239206365" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1468" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M907 378.05l-12.4-14.33c-61-70.41-166.93-177.81-236.2-239.4l-14.12-12.58C609.07 80.37 562.07 63.09 512 63.09s-97.08 17.28-132.32 48.65l-14.12 12.57c-69.28 61.61-175.24 169-236.2 239.41l-12.41 14.33c-63.92 73.87-63.92 194 0 267.87l12.41 14.33C190.24 730.6 296.2 838 365.54 899.69l14.14 12.57c35.24 31.37 82.23 48.65 132.32 48.65s97.06-17.28 132.32-48.65l14.13-12.57 8.15-7.25c21.93-19.46 31.93-28.35 62.69-58.93l7.27-7.36-1.16-1.22a28.35 28.35 0 0 0-45.87-32.14c-2.92 2.78-43.63 41.53-68.73 63.91l-14.1 12.56c-24.89 22.1-58.53 34.28-94.7 34.28s-69.82-12.19-94.69-34.31l-14.14-12.58c-67.85-60.34-171.47-165.38-231-234.14l-12.4-14.32c-21.73-25.12-33.7-59.29-33.7-96.2s12-71.07 33.7-96.17l12.41-14.33c59.5-68.75 163.12-173.79 231-234.15l14.1-12.57c24.86-22.12 58.49-34.31 94.68-34.31s69.83 12.19 94.7 34.3l14.12 12.58c67.86 60.37 171.49 165.41 231 234.14l12.39 14.34c45.22 52.21 45.34 143.76 0.26 192.07l-7.15 7.69c-20.35 21.94-32.64 35.19-45.62 39.1-12.3 3.71-27.89-0.23-57.53-14.54-49.55-23.94-119.64-64-144-78 9.87-19.61 32.46-67.6 43.11-115.62l2.86-12.87H534.5v-15.06h154.78v-57.37H534.5v-72.41h-56.89v72.41H322.83v57.37h154.78v15.05H358.54V491H573c-4.63 14.52-13.16 32.57-19.19 44.37-22.13-8.73-80.75-29.33-141-29.33-37.94 0-69.92 10.28-92.49 29.71-22.37 19.27-34.19 46-34.19 77.42s11.32 58.29 32.75 77.74c21.9 19.89 53 30.41 90 30.41 42.76 0 87.09-19 128.18-54.78a326.76 326.76 0 0 0 43.61-46.35c22.9 12.75 90 50 152.61 83.47 40.83 21.85 69.5 26.18 95.87 14.47 25.09-11.14 47.07-36.53 77.49-71.68l0.47-0.54C971 572.07 971 451.9 907 378.05zM407.83 662c-60.15 0-64.83-37.38-64.83-48.82a48.21 48.21 0 0 1 12.15-31.36c11.06-12.2 28.45-18.39 51.69-18.39 50 0 95 17.21 115.39 26.35C503.71 611.69 456 662 407.83 662z" p-id="1469"></path></svg>
|
||||
|
After Width: | Height: | Size: 2.1 KiB |
1
src/icons/svg/qiniu.svg
Normal file
1
src/icons/svg/qiniu.svg
Normal file
@@ -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="1546225865881" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1276" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M892.928 499.712c-45.056-45.056-116.736-45.056-161.792 0-36.864 36.864-43.008 92.16-20.48 135.168L602.112 743.424c-51.2 51.2-137.216 45.056-194.56-10.24s-61.44-143.36-10.24-194.56L522.24 413.696l-45.056-45.056-124.928 124.928c-75.776 75.776-71.68 204.8 10.24 286.72 43.008 43.008 98.304 65.536 153.6 65.536 49.152 0 96.256-18.432 133.12-53.248L757.76 684.032c16.384 8.192 34.816 14.336 55.296 14.336 28.672 0 59.392-10.24 79.872-32.768 45.056-49.152 45.056-122.88 0-165.888zM847.872 614.4c-18.432 18.432-51.2 18.432-69.632 0-18.432-18.432-18.432-51.2 0-69.632 10.24-10.24 22.528-14.336 34.816-14.336s24.576 4.096 34.816 14.336c18.432 18.432 18.432 51.2 0 69.632z" fill="#bfbfbf" p-id="1277"></path><path d="M296.96 372.736l108.544-108.544c51.2-51.2 137.216-45.056 194.56 10.24 26.624 26.624 43.008 63.488 45.056 100.352 2.048 36.864-10.24 69.632-34.816 94.208L485.376 593.92l45.056 45.056L655.36 514.048c36.864-36.864 55.296-88.064 53.248-141.312-2.048-53.248-24.576-104.448-63.488-143.36-81.92-81.92-208.896-86.016-286.72-10.24L249.856 327.68c-43.008-22.528-98.304-16.384-135.168 20.48-45.056 45.056-45.056 116.736 0 161.792 22.528 22.528 51.2 32.768 79.872 32.768s59.392-10.24 79.872-32.768c38.912-38.912 45.056-94.208 22.528-137.216z m-65.536 90.112c-18.432 18.432-51.2 18.432-69.632 0-18.432-18.432-18.432-51.2 0-69.632 10.24-10.24 22.528-14.336 34.816-14.336 12.288 0 24.576 4.096 34.816 14.336 18.432 18.432 18.432 49.152 0 69.632z" fill="#bfbfbf" p-id="1278"></path></svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
@@ -20,8 +20,8 @@ function hasPermission(roles, permissionRoles) {
|
||||
|
||||
router.beforeEach((to, from, next) => {
|
||||
NProgress.start() // start progress bar
|
||||
if (getToken()) { // determine if there has token
|
||||
/* has token*/
|
||||
if (getToken()) {
|
||||
// 已登录且要跳转的页面是登录页
|
||||
if (to.path === '/login') {
|
||||
next({ path: '/' })
|
||||
NProgress.done() // if current page is dashboard will not trigger afterEach hook, so manually handle it
|
||||
|
||||
@@ -46,6 +46,20 @@ export const constantRouterMap = [
|
||||
meta: { title: '首页', icon: 'index', noCache: true }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/user',
|
||||
component: Layout,
|
||||
hidden: true,
|
||||
redirect: 'noredirect',
|
||||
children: [
|
||||
{
|
||||
path: 'center',
|
||||
component: () => import('@/views/system/user/center'),
|
||||
name: '个人中心',
|
||||
meta: { title: '个人中心', icon: 'user' }
|
||||
}
|
||||
]
|
||||
}
|
||||
// { path: '*', redirect: '/404', hidden: true }
|
||||
]
|
||||
|
||||
@@ -6,10 +6,14 @@ const getters = {
|
||||
visitedViews: state => state.tagsView.visitedViews,
|
||||
cachedViews: state => state.tagsView.cachedViews,
|
||||
name: state => state.user.name,
|
||||
createTime: state => state.user.createTime,
|
||||
email: state => state.user.email,
|
||||
roles: state => state.user.roles,
|
||||
permission_routers: state => state.permission.routers,
|
||||
addRouters: state => state.permission.addRouters,
|
||||
socketApi: state => state.api.socketApi,
|
||||
imagesUploadApi: state => state.api.imagesUploadApi
|
||||
imagesUploadApi: state => state.api.imagesUploadApi,
|
||||
updateAvatarApi: state => state.api.updateAvatarApi,
|
||||
qiNiuUploadApi: state => state.api.qiNiuUploadApi
|
||||
}
|
||||
export default getters
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
const baseUrl = process.env.BASE_API
|
||||
const api = {
|
||||
state: {
|
||||
// 实时控制台
|
||||
socketApi: baseUrl + '/websocket?token=kl',
|
||||
imagesUploadApi: baseUrl + '/api/pictures'
|
||||
// 图片上传
|
||||
imagesUploadApi: baseUrl + '/api/pictures',
|
||||
// 修改头像
|
||||
updateAvatarApi: baseUrl + '/api/users/updateAvatar',
|
||||
// 上传文件到七牛云
|
||||
qiNiuUploadApi: baseUrl + '/api/qiNiuContent'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
import { login, getInfo } from '@/api/login'
|
||||
import { getToken, setToken, removeToken } from '@/utils/auth'
|
||||
import { parseTime } from '@/utils/index'
|
||||
|
||||
const user = {
|
||||
state: {
|
||||
token: getToken(),
|
||||
name: '',
|
||||
email: '',
|
||||
avatar: '',
|
||||
createTime: '',
|
||||
roles: []
|
||||
},
|
||||
|
||||
@@ -21,6 +24,12 @@ const user = {
|
||||
},
|
||||
SET_ROLES: (state, roles) => {
|
||||
state.roles = roles
|
||||
},
|
||||
SET_CREATE_TIME: (state, createTime) => {
|
||||
state.createTime = createTime
|
||||
},
|
||||
SET_EMAIL: (state, email) => {
|
||||
state.email = email
|
||||
}
|
||||
},
|
||||
|
||||
@@ -46,6 +55,8 @@ const user = {
|
||||
commit('SET_ROLES', res.roles)
|
||||
commit('SET_NAME', res.username)
|
||||
commit('SET_AVATAR', res.avatar)
|
||||
commit('SET_EMAIL', res.email)
|
||||
commit('SET_CREATE_TIME', parseTime(res.createTime))
|
||||
resolve(res)
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
|
||||
@@ -15,7 +15,7 @@ export function parseTime(time) {
|
||||
var minutes = date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes()
|
||||
var seconds = date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds()
|
||||
// 拼接
|
||||
return year + '-' + month + '-' + day + ' ' + hours + ':' + minutes + ':' + seconds
|
||||
return year + '年' + month + '月' + day + '日 ' + hours + ':' + minutes + ':' + seconds
|
||||
} else {
|
||||
return ''
|
||||
}
|
||||
@@ -93,3 +93,26 @@ export function debounce(func, wait, immediate) {
|
||||
export function isExternal(path) {
|
||||
return /^(https?:|mailto:|tel:)/.test(path)
|
||||
}
|
||||
|
||||
// 替换邮箱字符
|
||||
export function regEmail(email) {
|
||||
if (String(email).indexOf('@') > 0) {
|
||||
const str = email.split('@')
|
||||
let _s = ''
|
||||
if (str[0].length > 3) {
|
||||
for (var i = 0; i < str[0].length - 3; i++) {
|
||||
_s += '*'
|
||||
}
|
||||
}
|
||||
var new_email = str[0].substr(0, 3) + _s + '@' + str[1]
|
||||
}
|
||||
return new_email
|
||||
}
|
||||
|
||||
// 替换手机字符
|
||||
export function regMobile(mobile) {
|
||||
if (mobile.length > 7) {
|
||||
var new_mobile = mobile.substr(0, 3) + '****' + mobile.substr(7)
|
||||
}
|
||||
return new_mobile
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import axios from 'axios'
|
||||
import router from '@/router'
|
||||
import { Notification, MessageBox } from 'element-ui'
|
||||
import store from '../store'
|
||||
import { getToken } from '@/utils/auth'
|
||||
@@ -51,9 +52,9 @@ service.interceptors.response.use(
|
||||
return Promise.reject(error)
|
||||
}
|
||||
}
|
||||
if (code === 403 || code === 401) {
|
||||
if (code === 401) {
|
||||
MessageBox.confirm(
|
||||
'Token 无效或已经过期,你可以取消继续留在该页面,或者重新登录',
|
||||
'登录状态已失效,你可以取消继续留在该页面,或者重新登录',
|
||||
'提示',
|
||||
{
|
||||
confirmButtonText: '重新登录',
|
||||
@@ -65,6 +66,8 @@ service.interceptors.response.use(
|
||||
location.reload() // 为了重新实例化vue-router对象 避免bug
|
||||
})
|
||||
})
|
||||
} else if (code === 403) {
|
||||
router.push({ path: '/401' })
|
||||
} else {
|
||||
const errorMsg = error.response.data.message
|
||||
if (errorMsg !== undefined) {
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
<template>
|
||||
<div class="errPage-container">
|
||||
<el-button icon="arrow-left" class="pan-back-btn" @click="back">返回</el-button>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<h1 class="text-jumbo text-ginormous">Oops!</h1>
|
||||
gif来源<a href="https://zh.airbnb.com/" target="_blank">airbnb</a> 页面
|
||||
图片来源<a href="https://zh.airbnb.com/" target="_blank">airbnb</a> 页面
|
||||
<h2>你没有权限去该页面</h2>
|
||||
<h6>如有不满请联系你领导</h6>
|
||||
<ul class="list-unstyled">
|
||||
@@ -12,7 +11,7 @@
|
||||
<li class="link-type">
|
||||
<router-link to="/dashboard">回首页</router-link>
|
||||
</li>
|
||||
<li class="link-type"><a href="https://www.taobao.com/">随便看看</a></li>
|
||||
<li class="link-type"><a href="https://www.jianshu.com/">随便看看</a></li>
|
||||
<li><a href="#" @click.prevent="dialogVisible=true">点我看图</a></li>
|
||||
</ul>
|
||||
</el-col>
|
||||
@@ -52,7 +51,7 @@ export default {
|
||||
|
||||
<style rel="stylesheet/scss" lang="scss" scoped>
|
||||
.errPage-container {
|
||||
width: 800px;
|
||||
width: 600px;
|
||||
max-width: 100%;
|
||||
margin: 100px auto;
|
||||
.pan-back-btn {
|
||||
|
||||
@@ -21,11 +21,11 @@
|
||||
首页
|
||||
</el-dropdown-item>
|
||||
</router-link>
|
||||
<a target="_blank" href="https://github.com/elunez/eladmin">
|
||||
<router-link to="/user/center">
|
||||
<el-dropdown-item>
|
||||
项目地址
|
||||
个人中心
|
||||
</el-dropdown-item>
|
||||
</a>
|
||||
</router-link>
|
||||
<el-dropdown-item divided>
|
||||
<span style="display:block;" @click="logout">退出登录</span>
|
||||
</el-dropdown-item>
|
||||
|
||||
@@ -37,7 +37,6 @@
|
||||
|
||||
<script>
|
||||
import { md5 } from '@/utils/md5'
|
||||
|
||||
export default {
|
||||
name: 'Login',
|
||||
data() {
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
<span v-else class="badge">{{ scope.row.logType }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createTime" label="创建日期" width="160px">
|
||||
<el-table-column prop="createTime" label="创建日期" width="180px">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ time(scope.row.createTime) }}</span>
|
||||
</template>
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
</span>
|
||||
<span style="color: #DE00CC">{{ item.className+' ' }}</span>
|
||||
<span v-html="item.body"/>
|
||||
<span>{{ item.exception }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -34,7 +33,7 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
height: document.documentElement.clientHeight - 132 + 'px;',
|
||||
data: [{ name: 'elAdmin-', timestamp: parseTime(new Date()), threadName: 'system-prompt-message', level: 'INFO', className: 'me.zhengjie.AppRun' + ' :', body: '(*^ω^*) 欢迎使用,暂无日志输出~', exception: '' }],
|
||||
data: [{ name: 'elAdmin-', timestamp: parseTime(new Date()), threadName: 'system-prompt-message', level: 'INFO', className: 'me.zhengjie.AppRun' + ' :', body: '(*^ω^*) 欢迎使用,暂无日志输出~' }],
|
||||
// level
|
||||
INFO: '#0000ff', WARN: '#FFFF00', ERROR: '#FF0000', DEBUG: '#DEA000'
|
||||
}
|
||||
@@ -80,7 +79,6 @@ export default {
|
||||
}, 5000)
|
||||
},
|
||||
connection(_this) {
|
||||
// 建立连接对象,注意部署到线上后也要修改对应的地址
|
||||
const socket = new SockJS(this.socketApi)// 连接服务端提供的通信接口,连接以后才可以订阅广播消息和个人消息
|
||||
// 获取STOMP子协议的客户端对象
|
||||
this.stompClient = Stomp.over(socket)
|
||||
|
||||
172
src/views/system/user/center.vue
Normal file
172
src/views/system/user/center.vue
Normal file
@@ -0,0 +1,172 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<div id="content-main" :style="'width:'+width">
|
||||
<el-card shadow="never" class="box-card user-info">
|
||||
<div class="avatar-content">
|
||||
<el-upload
|
||||
:show-file-list="false"
|
||||
:on-success="handleSuccess"
|
||||
:on-error="handleError"
|
||||
:headers="headers"
|
||||
:action="updateAvatarApi"
|
||||
class="avatar-uploader">
|
||||
<img v-if="avatar" :src="avatar" title="点击上传头像" class="avatar">
|
||||
<i v-else class="el-icon-plus avatar-uploader-icon"/>
|
||||
</el-upload>
|
||||
</div>
|
||||
<div class="user-info-content">
|
||||
<div>登录账号:{{ name }}</div>
|
||||
<div>注册时间:{{ createTime }}</div>
|
||||
<div>账号状态:<span style="color: #909399">正常</span></div>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<el-card shadow="never" class="box-card reset-pass">
|
||||
<h4 class="account-label-icon">登录密码:</h4>
|
||||
<updatePass/>
|
||||
<p>安全性高的密码可使账号更安全,建议设置同时包含字母,数字,符号的密码。</p>
|
||||
</el-card>
|
||||
|
||||
<el-card shadow="never" class="box-card reset-email">
|
||||
<h4 class="account-label-icon">邮箱验证:</h4>
|
||||
<updateEmail :email="email"/>
|
||||
<p>你的邮箱:{{ formatEmail(email) }} </p>
|
||||
<h4>绑定邮箱可用于</h4>
|
||||
<ul>
|
||||
<li>安全管理,密码重置与修改</li>
|
||||
<li>账号使用,使用邮箱登录系统</li>
|
||||
<li>站内通知,站内信接收</li>
|
||||
</ul>
|
||||
</el-card>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex'
|
||||
import { regEmail } from '@/utils/index'
|
||||
import updatePass from './center/updatePass'
|
||||
import updateEmail from './center/updateEmail'
|
||||
import { getToken } from '@/utils/auth'
|
||||
import store from '@/store'
|
||||
export default {
|
||||
name: 'Center',
|
||||
components: { updatePass, updateEmail },
|
||||
data() {
|
||||
return {
|
||||
width: document.documentElement.clientWidth - 180 + 'px;',
|
||||
headers: {
|
||||
'Authorization': 'Bearer ' + getToken()
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'avatar',
|
||||
'name',
|
||||
'email',
|
||||
'createTime',
|
||||
'updateAvatarApi'
|
||||
])
|
||||
},
|
||||
methods: {
|
||||
formatEmail(mail) {
|
||||
return regEmail(mail)
|
||||
},
|
||||
handleSuccess(response, file, fileList) {
|
||||
this.$notify({
|
||||
title: '头像修改成功',
|
||||
type: 'success',
|
||||
duration: 2500
|
||||
})
|
||||
store.dispatch('GetInfo').then(() => {})
|
||||
},
|
||||
// 监听上传失败
|
||||
handleError(e, file, fileList) {
|
||||
const msg = JSON.parse(e.message)
|
||||
this.$notify({
|
||||
title: msg.message,
|
||||
type: 'error',
|
||||
duration: 2500
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style rel="stylesheet/scss" lang="scss">
|
||||
.box-card{
|
||||
border: 0px;
|
||||
border-bottom: 1px solid #ECEDFE;
|
||||
border-radius: unset;
|
||||
h4{
|
||||
height: 26px;
|
||||
margin: 0 0 7px;
|
||||
line-height: 26px;
|
||||
font-size: 1.1rem;
|
||||
font-weight: 500;
|
||||
color: #444242;
|
||||
display: inline-block;
|
||||
}
|
||||
p{
|
||||
font-family: Lantinghei;
|
||||
font-size: 90%;
|
||||
color: #747474;
|
||||
}
|
||||
ul{
|
||||
padding: 0;
|
||||
margin: 7px 0 0;
|
||||
list-style: none;
|
||||
font-size: 80%;
|
||||
}
|
||||
li {
|
||||
float: left;
|
||||
margin: 0 30px 10px 0!important;
|
||||
}
|
||||
li:before {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
background-color: #52acd9;
|
||||
color: #52acd9;
|
||||
display: inline-block;
|
||||
border-radius: 50%;
|
||||
margin-right: 5px;
|
||||
content: '';
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
|
||||
.user-info{
|
||||
height: 170px;
|
||||
}
|
||||
|
||||
.reset-email{
|
||||
border-bottom: 0px;
|
||||
}
|
||||
|
||||
.avatar-content, .user-info-content {
|
||||
float: left;
|
||||
}
|
||||
.user-info-content{
|
||||
font-family: Lantinghei;
|
||||
position: relative;
|
||||
font-size: 14px;
|
||||
margin: 25px;
|
||||
div{
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
}
|
||||
.avatar-uploader-icon {
|
||||
font-size: 28px;
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
line-height: 120px;
|
||||
text-align: center;
|
||||
}
|
||||
.avatar {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
display: block;
|
||||
border-radius: 50%;
|
||||
}
|
||||
</style>
|
||||
150
src/views/system/user/center/updateEmail.vue
Normal file
150
src/views/system/user/center/updateEmail.vue
Normal file
@@ -0,0 +1,150 @@
|
||||
<template>
|
||||
<div style="display: inline-block">
|
||||
<el-button size="mini" class="button" type="info" @click="dialog = true">修改</el-button>
|
||||
<el-dialog :visible.sync="dialog" :title="title" width="475px" @close="cancel">
|
||||
<el-form ref="form" :model="form" :rules="rules" size="small" label-width="88px">
|
||||
<el-form-item label="新邮箱" prop="email">
|
||||
<el-input v-model="form.email" auto-complete="on" style="width: 200px;"/>
|
||||
<el-button :loading="codeLoading" :disabled="isDisabled" size="small" @click="sendCode">{{ buttonName }}</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item label="验证码" prop="code">
|
||||
<el-input v-model="form.code" style="width: 320px;"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="当前密码" prop="pass">
|
||||
<el-input v-model="form.pass" type="password" style="width: 320px;"/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="text" @click="cancel">取消</el-button>
|
||||
<el-button :loading="loading" type="primary" @click="doSubmit">确认</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import store from '@/store'
|
||||
import { md5 } from '@/utils/md5'
|
||||
import { validatEmail } from '@/utils/validate'
|
||||
import { validPass, updateEmail } from '@/api/user'
|
||||
import { resetEmail } from '@/api/code'
|
||||
export default {
|
||||
props: {
|
||||
email: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
const validatePass = (rule, value, callback) => {
|
||||
validPass(md5(value)).then(res => {
|
||||
if (res.status === 200) {
|
||||
callback()
|
||||
} else {
|
||||
callback(new Error('密码错误,请重新输入'))
|
||||
}
|
||||
})
|
||||
}
|
||||
const validMail = (rule, value, callback) => {
|
||||
if (value === '') {
|
||||
callback(new Error('新邮箱不能为空'))
|
||||
} else if (value === this.email) {
|
||||
callback(new Error('新邮箱不能与旧邮箱相同'))
|
||||
} else if (validatEmail(value)) {
|
||||
callback()
|
||||
} else {
|
||||
callback(new Error('邮箱格式错误'))
|
||||
}
|
||||
}
|
||||
return {
|
||||
loading: false, dialog: false, title: '修改邮箱', form: { pass: '', email: '', code: '' },
|
||||
user: { email: '', password: '' }, codeLoading: false,
|
||||
codeData: { type: 'email', value: '' },
|
||||
buttonName: '获取验证码', isDisabled: false, time: 60,
|
||||
rules: {
|
||||
pass: [
|
||||
{ required: true, validator: validatePass, trigger: 'blur' }
|
||||
],
|
||||
email: [
|
||||
{ required: true, validator: validMail, trigger: 'blur' }
|
||||
],
|
||||
code: [
|
||||
{ required: true, message: '验证码不能为空', trigger: 'blur' }
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
cancel() {
|
||||
this.resetForm()
|
||||
},
|
||||
sendCode() {
|
||||
if (this.form.email && this.form.email !== this.email) {
|
||||
this.codeLoading = true
|
||||
this.buttonName = '验证码发送中'
|
||||
this.codeData.value = this.form.email
|
||||
const _this = this
|
||||
resetEmail(this.codeData).then(res => {
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: '发送成功,有效期5分钟',
|
||||
type: 'success'
|
||||
})
|
||||
this.codeLoading = false
|
||||
this.isDisabled = true
|
||||
this.buttonName = this.time-- + '秒后重新发送'
|
||||
this.timer = window.setInterval(function() {
|
||||
_this.buttonName = _this.time + '秒后重新发送'
|
||||
--_this.time
|
||||
if (_this.time < 0) {
|
||||
_this.buttonName = '重新发送'
|
||||
_this.time = 60
|
||||
_this.isDisabled = false
|
||||
clearInterval(this.timer)
|
||||
}
|
||||
}, 1000)
|
||||
}).catch(err => {
|
||||
this.codeLoading = false
|
||||
console.log(err.response.data.message)
|
||||
})
|
||||
}
|
||||
},
|
||||
doSubmit() {
|
||||
this.$refs['form'].validate((valid) => {
|
||||
if (valid) {
|
||||
this.loading = true
|
||||
this.user = { email: this.form.email, password: md5(this.form.pass) }
|
||||
updateEmail(this.form.code, this.user).then(res => {
|
||||
this.loading = false
|
||||
this.resetForm()
|
||||
this.$notify({
|
||||
title: '邮箱修改成功',
|
||||
type: 'success',
|
||||
duration: 1500
|
||||
})
|
||||
store.dispatch('GetInfo').then(() => {})
|
||||
}).catch(err => {
|
||||
this.loading = false
|
||||
console.log(err.response.data.message)
|
||||
})
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
})
|
||||
},
|
||||
resetForm() {
|
||||
this.dialog = false
|
||||
this.$refs['form'].resetFields()
|
||||
clearInterval(this.timer)
|
||||
this.time = 60
|
||||
this.buttonName = '获取验证码'
|
||||
this.isDisabled = false
|
||||
this.form = { pass: '', email: '', code: '' }
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
102
src/views/system/user/center/updatePass.vue
Normal file
102
src/views/system/user/center/updatePass.vue
Normal file
@@ -0,0 +1,102 @@
|
||||
<template>
|
||||
<div style="display: inline-block">
|
||||
<el-button size="mini" class="button" type="info" @click="dialog = true">修改</el-button>
|
||||
<el-dialog :visible.sync="dialog" :title="title" width="500px" @close="cancel">
|
||||
<el-form ref="form" :model="form" :rules="rules" size="small" label-width="88px">
|
||||
<el-form-item label="旧密码" prop="oldPass">
|
||||
<el-input v-model="form.oldPass" type="password" auto-complete="on" style="width: 370px;"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="新密码" prop="newPass">
|
||||
<el-input v-model="form.newPass" type="password" auto-complete="on" style="width: 370px;"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="确认密码" prop="confirmPass">
|
||||
<el-input v-model="form.confirmPass" type="password" auto-complete="on" style="width: 370px;"/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="text" @click="cancel">取消</el-button>
|
||||
<el-button :loading="loading" type="primary" @click="doSubmit">确认</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import store from '@/store'
|
||||
import { md5 } from '@/utils/md5'
|
||||
import { validPass, updatePass } from '@/api/user'
|
||||
export default {
|
||||
data() {
|
||||
const validatePass = (rule, value, callback) => {
|
||||
validPass(md5(value)).then(res => {
|
||||
if (res.status === 200) {
|
||||
callback()
|
||||
} else {
|
||||
callback(new Error('旧密码错误,请检查'))
|
||||
}
|
||||
})
|
||||
}
|
||||
const confirmPass = (rule, value, callback) => {
|
||||
if (this.form.newPass !== value) {
|
||||
callback(new Error('两次输入的密码不一致'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
return {
|
||||
loading: false, dialog: false, title: '修改密码', form: { oldPass: '', newPass: '', confirmPass: '' },
|
||||
rules: {
|
||||
oldPass: [
|
||||
{ required: true, validator: validatePass, trigger: 'blur' }
|
||||
],
|
||||
newPass: [
|
||||
{ required: true, message: '请输入新密码', trigger: 'blur' },
|
||||
{ min: 6, max: 20, message: '长度在 6 到 20 个字符', trigger: 'blur' }
|
||||
],
|
||||
confirmPass: [
|
||||
{ required: true, validator: confirmPass, trigger: 'blur' }
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
cancel() {
|
||||
this.resetForm()
|
||||
},
|
||||
doSubmit() {
|
||||
this.$refs['form'].validate((valid) => {
|
||||
if (valid) {
|
||||
this.loading = true
|
||||
updatePass(md5(this.form.confirmPass)).then(res => {
|
||||
this.resetForm()
|
||||
this.$notify({
|
||||
title: '密码修改成功,请重新登录',
|
||||
type: 'success',
|
||||
duration: 1500
|
||||
})
|
||||
setTimeout(() => {
|
||||
store.dispatch('LogOut').then(() => {
|
||||
location.reload() // 为了重新实例化vue-router对象 避免bug
|
||||
})
|
||||
}, 1500)
|
||||
}).catch(err => {
|
||||
this.loading = false
|
||||
console.log(err.response.data.message)
|
||||
})
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
})
|
||||
},
|
||||
resetForm() {
|
||||
this.dialog = false
|
||||
this.$refs['form'].resetFields()
|
||||
this.form = { oldPass: '', newPass: '', confirmPass: '' }
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
30
src/views/tools/aliPay/index.vue
Normal file
30
src/views/tools/aliPay/index.vue
Normal file
@@ -0,0 +1,30 @@
|
||||
<template>
|
||||
<el-tabs v-model="activeName" style="padding-left: 5px;">
|
||||
<el-tab-pane label="参数配置" name="first">
|
||||
<Config/>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="支付测试" name="second">
|
||||
<ToPay/>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="使用说明" name="third">
|
||||
<Description/>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Config from './module/config'
|
||||
import ToPay from './module/toPay'
|
||||
import Description from './module/description'
|
||||
export default {
|
||||
components: { Config, ToPay, Description },
|
||||
data() {
|
||||
return {
|
||||
activeName: 'second'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
96
src/views/tools/aliPay/module/config.vue
Normal file
96
src/views/tools/aliPay/module/config.vue
Normal file
@@ -0,0 +1,96 @@
|
||||
<template>
|
||||
<el-form ref="form" :model="form" :rules="rules" style="margin-top: 6px;" size="small" label-width="100px">
|
||||
<el-form-item label="appID" prop="appID">
|
||||
<el-input v-model="form.appID" style="width: 40%"/>
|
||||
<span style="color: #C0C0C0;margin-left: 10px;">应用APPID,收款账号既是APPID对应支付宝账号</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="商家账号" prop="sysServiceProviderId">
|
||||
<el-input v-model="form.sysServiceProviderId" style="width: 40%;"/>
|
||||
<span style="color: #C0C0C0;margin-left: 10px;">商家账号</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="商户私钥" prop="privateKey">
|
||||
<el-input v-model="form.privateKey" type="password" style="width: 40%;"/>
|
||||
<span style="color: #C0C0C0;margin-left: 10px;">商户私钥,你的PKCS8格式RSA2私钥</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="支付宝公钥" prop="publicKey">
|
||||
<el-input v-model="form.publicKey" type="password" style="width: 40%;"/>
|
||||
<span style="color: #C0C0C0;margin-left: 10px;">支付宝公钥</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="回调地址" prop="returnUrl">
|
||||
<el-input v-model="form.returnUrl" style="width: 40%;"/>
|
||||
<span style="color: #C0C0C0;margin-left: 10px;">订单完成后返回的地址</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="异步通知" prop="notifyUrl">
|
||||
<el-input v-model="form.notifyUrl" style="width: 40%;"/>
|
||||
<span style="color: #C0C0C0;margin-left: 10px;">支付结果异步通知地址</span>
|
||||
</el-form-item>
|
||||
<el-button :loading="loading" style="margin-left:5%;" size="medium" type="success" @click="doSubmit">保存配置</el-button>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { get, update } from '@/api/alipay'
|
||||
export default {
|
||||
name: 'Config',
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
form: { appID: '', sysServiceProviderId: '', privateKey: '', publicKey: '', returnUrl: '', notifyUrl: '' },
|
||||
rules: {
|
||||
appID: [
|
||||
{ required: true, message: '请输入appID', trigger: 'blur' }
|
||||
],
|
||||
sysServiceProviderId: [
|
||||
{ required: true, message: '请输入商家账号', trigger: 'blur' }
|
||||
],
|
||||
privateKey: [
|
||||
{ required: true, message: '商户私钥不能为空', trigger: 'blur' }
|
||||
],
|
||||
publicKey: [
|
||||
{ required: true, message: '支付宝公钥不能为空', trigger: 'blur' }
|
||||
],
|
||||
returnUrl: [
|
||||
{ required: true, message: '回调地址不能为空', trigger: 'blur' }
|
||||
],
|
||||
notifyUrl: [
|
||||
{ required: true, message: '回调地址不能为空', trigger: 'blur' }
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.init()
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
get().then(res => {
|
||||
this.form = res
|
||||
})
|
||||
},
|
||||
doSubmit() {
|
||||
this.$refs['form'].validate((valid) => {
|
||||
if (valid) {
|
||||
this.loading = true
|
||||
update(this.form).then(res => {
|
||||
this.$notify({
|
||||
title: '修改成功',
|
||||
type: 'success',
|
||||
duration: 2500
|
||||
})
|
||||
this.loading = false
|
||||
}).catch(err => {
|
||||
this.loading = false
|
||||
console.log(err.response.data.message)
|
||||
})
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
35
src/views/tools/aliPay/module/description.vue
Normal file
35
src/views/tools/aliPay/module/description.vue
Normal file
@@ -0,0 +1,35 @@
|
||||
<template>
|
||||
<div>
|
||||
<blockquote class="my-blockquote">注意</blockquote>
|
||||
<pre class="my-code">
|
||||
测试所用参数都是沙箱环境,仅供测试所用,申请地址:<a style="color: #00a0e9" href="https://openhome.alipay.com/platform/appDaily.htm?tab=info" target="_blank">支付宝开发平台</a>
|
||||
如需付款测试,请使用
|
||||
账号:uuxesw9745@sandbox.com
|
||||
密码:111111
|
||||
支付密码:111111
|
||||
文明测试谢谢</pre>
|
||||
<blockquote class="my-blockquote"> 支付设置</blockquote>
|
||||
<pre class="my-code">
|
||||
支付提供两个测试地址
|
||||
PC端与手机端,并且使用如下代码识别
|
||||
if (/(Android)/i.test(navigator.userAgent)){ // 判断是否为Android手机
|
||||
url = "/aliPay/toPayAsWeb"
|
||||
}else if(/(iPhone|iPad|iPod|iOS)/i.test(navigator.userAgent)){ // 判断是否为苹果手机
|
||||
url = "/aliPay/toPayAsWeb"
|
||||
} else {
|
||||
url = "/aliPay/toPayAsPC"
|
||||
}</pre>
|
||||
<blockquote class="my-blockquote">更多帮助</blockquote>
|
||||
<pre class="my-code">更多帮助请查看系统源码</pre>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import '@/styles/description.scss'
|
||||
export default {
|
||||
name: 'Description'
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
84
src/views/tools/aliPay/module/toPay.vue
Normal file
84
src/views/tools/aliPay/module/toPay.vue
Normal file
@@ -0,0 +1,84 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-form ref="form" :model="form" :rules="rules" style="margin-top: 6px;" size="small" label-width="90px">
|
||||
<el-form-item label="商品名称" prop="subject">
|
||||
<el-input v-model="form.subject" style="width: 35%"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="商品价格" prop="totalAmount">
|
||||
<el-input v-model="form.totalAmount" style="width: 35%"/>
|
||||
<span style="color: #C0C0C0;margin-left: 10px;">测试允许区间(0,5000]</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="商品描述" prop="body">
|
||||
<el-input v-model="form.body" style="width: 35%" rows="8" type="textarea"/>
|
||||
</el-form-item>
|
||||
<el-button :loading="loading" style="margin-left:2%;" size="medium" type="success" @click="doSubmit">去支付</el-button>
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { toAliPay } from '@/api/alipay'
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
url: '',
|
||||
// 新窗口的引用
|
||||
newWin: null,
|
||||
loading: false, form: { subject: '', totalAmount: '', body: '' },
|
||||
rules: {
|
||||
subject: [
|
||||
{ required: true, message: '商品名称不能为空', trigger: 'blur' }
|
||||
],
|
||||
totalAmount: [
|
||||
{ required: true, message: '商品价格不能为空', trigger: 'blur' }
|
||||
],
|
||||
body: [
|
||||
{ required: true, message: '商品描述不能为空', trigger: 'blur' }
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
url(newVal, oldVal) {
|
||||
if (newVal && this.newWin) {
|
||||
this.newWin.sessionStorage.clear()
|
||||
this.newWin.location.href = newVal
|
||||
// 重定向后把url和newWin重置
|
||||
this.url = ''
|
||||
this.newWin = null
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
doSubmit() {
|
||||
this.$refs['form'].validate((valid) => {
|
||||
if (valid) {
|
||||
this.loading = true
|
||||
// 先打开一个空的新窗口,再请求
|
||||
this.newWin = window.open()
|
||||
let url = ''
|
||||
if (/(Android)/i.test(navigator.userAgent)) { // 判断是否为Android手机
|
||||
url = 'aliPay/toPayAsWeb'
|
||||
} else if (/(iPhone|iPad|iPod|iOS)/i.test(navigator.userAgent)) { // 判断是否为苹果手机
|
||||
url = 'aliPay/toPayAsWeb'
|
||||
} else {
|
||||
url = 'aliPay/toPayAsPC'
|
||||
}
|
||||
toAliPay(url, this.form).then(res => {
|
||||
this.loading = false
|
||||
this.url = res
|
||||
}).catch(err => {
|
||||
this.loading = false
|
||||
console.log(err.response.data.message)
|
||||
})
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
@@ -1,9 +1,9 @@
|
||||
<template>
|
||||
<el-tabs v-model="activeName" style="padding-left: 5px;" @tab-click="handleClick">
|
||||
<el-tabs v-model="activeName" style="padding-left: 5px;">
|
||||
<el-tab-pane label="邮箱配置" name="first">
|
||||
<Config/>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="邮件测试" name="second">
|
||||
<el-tab-pane label="发送邮件" name="second">
|
||||
<Send/>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="使用说明" name="third">
|
||||
@@ -20,12 +20,7 @@ export default {
|
||||
components: { Config, Send, Description },
|
||||
data() {
|
||||
return {
|
||||
activeName: 'first'
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleClick(tab, event) {
|
||||
console.log(tab, event)
|
||||
activeName: 'second'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +44,10 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'imagesUploadApi'
|
||||
// sm.ms图床
|
||||
'imagesUploadApi',
|
||||
// 七牛云 按需选择
|
||||
'qiNiuUploadApi'
|
||||
])
|
||||
},
|
||||
mounted() {
|
||||
@@ -54,6 +57,7 @@ export default {
|
||||
editor.customConfig.uploadImgHeaders = this.headers
|
||||
// 自定义文件名,不可修改,修改后会上传失败
|
||||
editor.customConfig.uploadFileName = 'file'
|
||||
// 上传到哪儿,按需选择
|
||||
editor.customConfig.uploadImgServer = this.imagesUploadApi // 上传图片到服务器
|
||||
editor.customConfig.onchange = (html) => {
|
||||
this.form.content = html
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<el-table-column prop="size" label="文件大小"/>
|
||||
<el-table-column prop="height" label="高度"/>
|
||||
<el-table-column prop="width" label="宽度"/>
|
||||
<el-table-column prop="createTime" label="创建日期">
|
||||
<el-table-column width="180px" prop="createTime" label="创建日期">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ time(scope.row.createTime) }}</span>
|
||||
</template>
|
||||
|
||||
@@ -51,7 +51,7 @@ export default {
|
||||
this.pictures.push({ uid, id })
|
||||
},
|
||||
handleBeforeRemove(file, fileList) {
|
||||
for (var i = 0; i < this.pictures.length; i++) {
|
||||
for (let i = 0; i < this.pictures.length; i++) {
|
||||
if (this.pictures[i].uid === file.uid) {
|
||||
del(this.pictures[i].id).then(res => {})
|
||||
return true
|
||||
|
||||
@@ -21,7 +21,6 @@ export default {
|
||||
methods: {
|
||||
checkPermission,
|
||||
toQuery() {
|
||||
console.log(this.query)
|
||||
this.$parent.page = 0
|
||||
this.$parent.init()
|
||||
}
|
||||
|
||||
30
src/views/tools/qiniu/index.vue
Normal file
30
src/views/tools/qiniu/index.vue
Normal file
@@ -0,0 +1,30 @@
|
||||
<template>
|
||||
<el-tabs v-model="activeName" style="padding-left: 5px;">
|
||||
<el-tab-pane label="存储配置" name="first">
|
||||
<Config/>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="文件列表" name="second">
|
||||
<List/>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="使用说明" name="third">
|
||||
<Description/>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Config from './module/config'
|
||||
import List from './module/list'
|
||||
import Description from './module/description'
|
||||
export default {
|
||||
components: { Config, List, Description },
|
||||
data() {
|
||||
return {
|
||||
activeName: 'second'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
100
src/views/tools/qiniu/module/config.vue
Normal file
100
src/views/tools/qiniu/module/config.vue
Normal file
@@ -0,0 +1,100 @@
|
||||
<template>
|
||||
<el-form ref="form" :model="form" :rules="rules" style="margin-top: 6px;" size="small" label-width="130px">
|
||||
<el-form-item label="Access Key" prop="accessKey">
|
||||
<el-input v-model="form.accessKey" style="width: 35%"/>
|
||||
<span style="color: #C0C0C0;margin-left: 10px;">accessKey,在安全中心,秘钥管理中查看</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="Secret Key" prop="secretKey">
|
||||
<el-input v-model="form.secretKey" type="password" style="width: 35%;"/>
|
||||
<span style="color: #C0C0C0;margin-left: 10px;">secretKey,在安全中心,秘钥管理中查看</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="空间名称" prop="bucket">
|
||||
<el-input v-model="form.bucket" style="width: 35%;"/>
|
||||
<span style="color: #C0C0C0;margin-left: 10px;">存储空间名称作为唯一的 Bucket 识别符</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="外链域名" prop="host">
|
||||
<el-input v-model="form.host" style="width: 35%;"/>
|
||||
<span style="color: #C0C0C0;margin-left: 10px;">外链域名,可自定义,需在七牛云绑定</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="存储区域" prop="port">
|
||||
<el-select v-model="form.zone" placeholder="请选择存储区域">
|
||||
<el-option
|
||||
v-for="item in zones"
|
||||
:key="item"
|
||||
:label="item"
|
||||
:value="item"/>
|
||||
</el-select>
|
||||
<span style="color: #C0C0C0;margin-left: 10px;">北美区域尚未支持自定义数据处理服务,一旦创建区域无法修改,请谨慎选择</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="空间类型" prop="host">
|
||||
<el-radio v-model="form.type" label="公开">公开</el-radio>
|
||||
<el-radio v-model="form.type" label="私有" >私有</el-radio>
|
||||
<span style="color: #C0C0C0;margin-left: 10px;">公开和私有仅对 Bucket 的读文件生效,修改、删除、写入等对 Bucket 的操作均需要拥有者的授权才能进行操作</span>
|
||||
</el-form-item>
|
||||
<el-button :loading="loading" style="margin-left:5%;" size="medium" type="success" @click="doSubmit">保存配置</el-button>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { get, update } from '@/api/qiniu'
|
||||
export default {
|
||||
name: 'Config',
|
||||
data() {
|
||||
return {
|
||||
zones: ['华东', '华北', '华南', '北美', '东南亚'],
|
||||
loading: false, form: { accessKey: '', secretKey: '', bucket: '', host: '', zone: '', type: '' },
|
||||
rules: {
|
||||
accessKey: [
|
||||
{ required: true, message: '请输入accessKey', trigger: 'blur' }
|
||||
],
|
||||
secretKey: [
|
||||
{ required: true, message: '请输入secretKey', trigger: 'blur' }
|
||||
],
|
||||
bucket: [
|
||||
{ required: true, message: '请输入空间名称', trigger: 'blur' }
|
||||
],
|
||||
host: [
|
||||
{ required: true, message: '请输入外链域名', trigger: 'blur' }
|
||||
],
|
||||
type: [
|
||||
{ required: true, message: '空间类型不能为空', trigger: 'blur' }
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.init()
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
get().then(res => {
|
||||
this.form = res
|
||||
})
|
||||
},
|
||||
doSubmit() {
|
||||
this.$refs['form'].validate((valid) => {
|
||||
if (valid) {
|
||||
this.loading = true
|
||||
update(this.form).then(res => {
|
||||
this.$notify({
|
||||
title: '修改成功',
|
||||
type: 'success',
|
||||
duration: 2500
|
||||
})
|
||||
this.loading = false
|
||||
}).catch(err => {
|
||||
this.loading = false
|
||||
console.log(err.response.data.message)
|
||||
})
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
66
src/views/tools/qiniu/module/description.vue
Normal file
66
src/views/tools/qiniu/module/description.vue
Normal file
@@ -0,0 +1,66 @@
|
||||
<template>
|
||||
<div>
|
||||
<blockquote class="my-blockquote">注意</blockquote>
|
||||
<pre class="my-code">
|
||||
1、尽量使用英文文件名进行上传,中文文件名在私有空间下下载会出现问题
|
||||
2、配置时外链域名需带上协议,也就是必须http/https开头
|
||||
3、如果七牛云中存在数据,使用同步按钮即可将数据同步到数据库
|
||||
4、本次集成了七牛云的常用操作,如:上传,下载,删除,同步,支持私有空间上传下载
|
||||
5、项目中配置存入数据库,如需测试,请使用临时空间进行测试,测试完成及时修改配置,反正数据泄露</pre>
|
||||
<blockquote class="my-blockquote"> 开始使用</blockquote>
|
||||
<pre class="my-code">
|
||||
#引入依赖
|
||||
<dependency>
|
||||
<groupId>com.qiniu</groupId>
|
||||
<artifactId>qiniu-java-sdk</artifactId>
|
||||
<version>[7.2.0, 7.2.99]</version>
|
||||
<dependency>
|
||||
#简单的上传文件
|
||||
//构造一个带指定Zone对象的配置类
|
||||
Configuration cfg = new Configuration(Zone.zone0());
|
||||
//...其他参数参考类注释
|
||||
UploadManager uploadManager = new UploadManager(cfg);
|
||||
//...生成上传凭证,然后准备上传
|
||||
String accessKey = "your access key";
|
||||
String secretKey = "your secret key";
|
||||
String bucket = "your bucket name";
|
||||
//默认不指定key的情况下,以文件内容的hash值作为文件名
|
||||
String key = null;
|
||||
try {
|
||||
byte[] uploadBytes = "hello qiniu cloud".getBytes("utf-8");
|
||||
Auth auth = Auth.create(accessKey, secretKey);
|
||||
String upToken = auth.uploadToken(bucket);
|
||||
try {
|
||||
Response response = uploadManager.put(uploadBytes, key, upToken);
|
||||
//解析上传成功的结果
|
||||
DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class);
|
||||
System.out.println(putRet.key);
|
||||
System.out.println(putRet.hash);
|
||||
} catch (QiniuException ex) {
|
||||
Response r = ex.response;
|
||||
System.err.println(r.toString());
|
||||
try {
|
||||
System.err.println(r.bodyString());
|
||||
} catch (QiniuException ex2) {
|
||||
//ignore
|
||||
}
|
||||
}
|
||||
} catch (UnsupportedEncodingException ex) {
|
||||
//ignore
|
||||
}</pre>
|
||||
<blockquote class="my-blockquote">更多帮助</blockquote>
|
||||
<pre class="my-code">更多帮助请查看系统源码,或者七牛云java开发文档
|
||||
七牛云官网:<a style="color: #00a2d4" href="https://sso.qiniu.com/" target="_blank">https://sso.qiniu.com/</a>
|
||||
七牛云java开发文档:<a style="color: #00a2d4" href="https://developer.qiniu.com/kodo/sdk/1239/java#3" target="_blank">https://developer.qiniu.com/kodo/sdk/1239/java#3</a></pre>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import '@/styles/description.scss'
|
||||
export default {
|
||||
name: 'Description'
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
133
src/views/tools/qiniu/module/list.vue
Normal file
133
src/views/tools/qiniu/module/list.vue
Normal file
@@ -0,0 +1,133 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<search :query="query"/>
|
||||
<!--表格渲染-->
|
||||
<el-table v-loading="loading" :data="data" size="small" border style="width: 100%;">
|
||||
<el-table-column :show-overflow-tooltip="true" prop="key" label="文件名"/>
|
||||
<el-table-column prop="bucket" label="空间名称"/>
|
||||
<el-table-column :show-overflow-tooltip="true" prop="url" label="地址/私有空间需下载访问">
|
||||
<template slot-scope="scope">
|
||||
<a :href="scope.row.url" style="color: #42b983" target="_blank">{{ scope.row.url }}</a>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="size" label="文件大小"/>
|
||||
<el-table-column prop="type" label="空间类型"/>
|
||||
<el-table-column width="180px" prop="updateTime" label="更新日期">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ time(scope.row.updateTime) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="160px" align="center">
|
||||
<template slot-scope="scope">
|
||||
<el-button
|
||||
:loading="downloadLoading"
|
||||
size="mini"
|
||||
@click="download(scope.row.id)">下载</el-button>
|
||||
<el-popover
|
||||
v-if="checkPermission(['ADMIN','PICTURE_ALL','PICTURE_DELETE'])"
|
||||
v-model="scope.row.delPopover"
|
||||
placement="top"
|
||||
width="180">
|
||||
<p>确定删除本条数据吗?</p>
|
||||
<div style="text-align: right; margin: 0">
|
||||
<el-button size="mini" type="text" @click="scope.row.delPopover = false">取消</el-button>
|
||||
<el-button :loading="delLoading" type="primary" size="mini" @click="subDelete(scope.$index, scope.row)">确定</el-button>
|
||||
</div>
|
||||
<el-button slot="reference" type="danger" size="mini" @click="scope.row.delPopover = true">删除</el-button>
|
||||
</el-popover>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!--分页组件-->
|
||||
<el-pagination
|
||||
:total="total"
|
||||
style="margin-top: 8px;"
|
||||
layout="total, prev, pager, next, sizes"
|
||||
@size-change="sizeChange"
|
||||
@current-change="pageChange"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import checkPermission from '@/utils/permission' // 权限判断函数
|
||||
import initData from '../../../../mixins/initData'
|
||||
import { del, download } from '@/api/qiniu'
|
||||
import { parseTime } from '@/utils/index'
|
||||
import search from './module/search'
|
||||
export default {
|
||||
components: { search },
|
||||
mixins: [initData],
|
||||
data() {
|
||||
return {
|
||||
url: '',
|
||||
// 新窗口的引用
|
||||
newWin: null,
|
||||
downloadLoading: false, delLoading: false, sup_this: this
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
url(newVal, oldVal) {
|
||||
if (newVal && this.newWin) {
|
||||
this.newWin.sessionStorage.clear()
|
||||
this.newWin.location.href = newVal
|
||||
// 重定向后把url和newWin重置
|
||||
this.url = ''
|
||||
this.newWin = null
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.$nextTick(() => {
|
||||
this.init()
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
checkPermission,
|
||||
beforeInit() {
|
||||
this.url = 'api/qiNiuContent'
|
||||
const sort = 'id,desc'
|
||||
const query = this.query
|
||||
const value = query.value
|
||||
this.params = { page: this.page, size: this.size, sort: sort }
|
||||
if (value) { this.params['key'] = value }
|
||||
return true
|
||||
},
|
||||
subDelete(index, row) {
|
||||
this.delLoading = true
|
||||
del(row.id).then(res => {
|
||||
this.delLoading = false
|
||||
row.delPopover = false
|
||||
this.init()
|
||||
this.$notify({
|
||||
title: '删除成功',
|
||||
type: 'success',
|
||||
duration: 2500
|
||||
})
|
||||
}).catch(err => {
|
||||
this.delLoading = false
|
||||
row.delPopover = false
|
||||
console.log(err.response.data.message)
|
||||
})
|
||||
},
|
||||
download(id) {
|
||||
this.downloadLoading = true
|
||||
// 先打开一个空的新窗口,再请求
|
||||
this.newWin = window.open()
|
||||
download(id).then(res => {
|
||||
this.downloadLoading = false
|
||||
this.url = res
|
||||
}).catch(err => {
|
||||
this.downloadLoading = false
|
||||
console.log(err.response.data.message)
|
||||
})
|
||||
},
|
||||
time(time) {
|
||||
return parseTime(time)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
90
src/views/tools/qiniu/module/module/add.vue
Normal file
90
src/views/tools/qiniu/module/module/add.vue
Normal file
@@ -0,0 +1,90 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-button class="filter-item" size="mini" type="primary" icon="el-icon-upload" @click="dialog = true">上传文件</el-button>
|
||||
<el-dialog :visible.sync="dialog" width="400px" @close="doSubmit">
|
||||
<el-upload
|
||||
:before-remove="handleBeforeRemove"
|
||||
:on-success="handleSuccess"
|
||||
:on-error="handleError"
|
||||
:file-list="fileList"
|
||||
:headers="headers"
|
||||
:action="qiNiuUploadApi"
|
||||
class="upload-demo"
|
||||
multiple>
|
||||
<el-button size="small" type="primary">点击上传</el-button>
|
||||
<div slot="tip" style="display: block;width: 330px" class="el-upload__tip">请勿上传违法文件,且文件不超过5M</div>
|
||||
</el-upload>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="doSubmit">确认</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { mapGetters } from 'vuex'
|
||||
import { del } from '@/api/qiniu'
|
||||
import { getToken } from '@/utils/auth'
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
headers: {
|
||||
'Authorization': 'Bearer ' + getToken()
|
||||
},
|
||||
dialog: false,
|
||||
dialogImageUrl: '',
|
||||
dialogVisible: false,
|
||||
fileList: [],
|
||||
files: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'qiNiuUploadApi'
|
||||
])
|
||||
},
|
||||
methods: {
|
||||
handleSuccess(response, file, fileList) {
|
||||
const uid = file.uid
|
||||
const id = response.id
|
||||
this.files.push({ uid, id })
|
||||
},
|
||||
handleBeforeRemove(file, fileList) {
|
||||
for (let i = 0; i < this.files.length; i++) {
|
||||
if (this.files[i].uid === file.uid) {
|
||||
del(this.files[i].id).then(res => {})
|
||||
return true
|
||||
}
|
||||
}
|
||||
},
|
||||
handlePictureCardPreview(file) {
|
||||
this.dialogImageUrl = file.url
|
||||
this.dialogVisible = true
|
||||
},
|
||||
// 刷新列表数据
|
||||
doSubmit() {
|
||||
this.fileList = []
|
||||
this.dialogVisible = false
|
||||
this.dialogImageUrl = ''
|
||||
this.dialog = false
|
||||
this.$parent.$parent.init()
|
||||
},
|
||||
// 监听上传失败
|
||||
handleError(e, file, fileList) {
|
||||
const msg = JSON.parse(e.message)
|
||||
this.$notify({
|
||||
title: msg.message,
|
||||
type: 'error',
|
||||
duration: 2500
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
div{
|
||||
display: inline-block;
|
||||
margin-left: 5px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
</style>
|
||||
54
src/views/tools/qiniu/module/module/search.vue
Normal file
54
src/views/tools/qiniu/module/module/search.vue
Normal file
@@ -0,0 +1,54 @@
|
||||
<template>
|
||||
<div class="head-container">
|
||||
<el-input v-model="query.value" clearable placeholder="输入文件名称搜索" style="width: 200px;" class="filter-item" @keyup.enter.native="toQuery"/>
|
||||
<el-button class="filter-item" size="mini" type="primary" icon="el-icon-search" @click="toQuery">搜索</el-button>
|
||||
<add/>
|
||||
<el-button :icon="icon" class="filter-item" size="mini" type="primary" @click="synchronize">{{ buttonName }}</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import add from './add'
|
||||
import { sync } from '@/api/qiniu'
|
||||
// 查询条件
|
||||
export default {
|
||||
components: { add },
|
||||
props: {
|
||||
query: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
icon: 'el-icon-refresh',
|
||||
buttonName: '同步数据'
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toQuery() {
|
||||
this.$parent.page = 0
|
||||
this.$parent.init()
|
||||
},
|
||||
synchronize() {
|
||||
this.icon = 'el-icon-loading'
|
||||
this.buttonName = '同步中'
|
||||
sync().then(res => {
|
||||
this.icon = 'el-icon-refresh'
|
||||
this.buttonName = '同步数据'
|
||||
this.$message({
|
||||
showClose: true,
|
||||
message: '数据同步成功',
|
||||
type: 'success',
|
||||
duration: 1500
|
||||
})
|
||||
this.toQuery()
|
||||
}).catch(err => {
|
||||
this.icon = 'el-icon-refresh'
|
||||
this.buttonName = '同步数据'
|
||||
console.log(err.response.data.message)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user