Add profile page
This commit is contained in:
parent
d946810c46
commit
3dfa5c6e4e
|
|
@ -41,3 +41,4 @@ rules:
|
|||
|
||||
globals:
|
||||
blessing: false
|
||||
__bs_data__: false
|
||||
|
|
|
|||
|
|
@ -3,5 +3,10 @@ export default [
|
|||
path: 'user/closet',
|
||||
component: () => import('./user/closet'),
|
||||
el: '.content'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'user/profile',
|
||||
component: () => import('./user/profile'),
|
||||
el: '.content'
|
||||
},
|
||||
];
|
||||
|
|
|
|||
299
resources/assets/src/components/user/Profile.vue
Normal file
299
resources/assets/src/components/user/Profile.vue
Normal file
|
|
@ -0,0 +1,299 @@
|
|||
<template>
|
||||
<section class="content">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div v-once class="box box-primary">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title" v-t="'user.profile.avatar.title'"></h3>
|
||||
</div><!-- /.box-header -->
|
||||
<div class="box-body" v-t="'user.profile.avatar.notice'"></div><!-- /.box-body -->
|
||||
</div>
|
||||
|
||||
<div class="box box-warning">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title" v-t="'user.profile.password.title'"></h3>
|
||||
</div><!-- /.box-header -->
|
||||
<div class="box-body">
|
||||
<div class="form-group">
|
||||
<label v-t="'user.profile.password.old'"></label>
|
||||
<input type="password" class="form-control" v-model="oldPassword" ref="oldPassword">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label v-t="'user.profile.password.new'"></label>
|
||||
<input type="password" class="form-control" v-model="newPassword" ref="newPassword">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label v-t="'user.profile.password.confirm'"></label>
|
||||
<input type="password" class="form-control" v-model="confirmPassword" ref="confirmPassword">
|
||||
</div>
|
||||
</div><!-- /.box-body -->
|
||||
<div class="box-footer">
|
||||
<button
|
||||
@click="changePassword"
|
||||
class="btn btn-primary"
|
||||
v-t="'user.profile.password.button'"
|
||||
data-test="changePassword"
|
||||
></button>
|
||||
</div>
|
||||
</div><!-- /.box -->
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="box box-primary">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title" v-t="'user.profile.nickname.title'"></h3>
|
||||
</div><!-- /.box-header -->
|
||||
<div class="box-body">
|
||||
<div class="form-group has-feedback">
|
||||
<input
|
||||
v-model="nickname"
|
||||
type="text"
|
||||
class="form-control"
|
||||
:placeholder="$t('user.profile.nickname.rule')"
|
||||
ref="nickname"
|
||||
>
|
||||
<span class="glyphicon glyphicon-user form-control-feedback"></span>
|
||||
</div>
|
||||
</div><!-- /.box-body -->
|
||||
<div class="box-footer">
|
||||
<button
|
||||
@click="changeNickName"
|
||||
class="btn btn-primary"
|
||||
v-t="'general.submit'"
|
||||
data-test="changeNickName"
|
||||
></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="box box-warning">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title" v-t="'user.profile.email.title'"></h3>
|
||||
</div><!-- /.box-header -->
|
||||
<div class="box-body">
|
||||
<div class="form-group has-feedback">
|
||||
<input
|
||||
v-model="email"
|
||||
type="email"
|
||||
class="form-control"
|
||||
:placeholder="$t('user.profile.email.new')"
|
||||
ref="email"
|
||||
>
|
||||
<span class="glyphicon glyphicon-envelope form-control-feedback"></span>
|
||||
</div>
|
||||
<div class="form-group has-feedback">
|
||||
<input
|
||||
v-model="currentPassword"
|
||||
type="password"
|
||||
class="form-control"
|
||||
:placeholder="$t('user.profile.email.password')"
|
||||
ref="currentPassword"
|
||||
>
|
||||
<span class="glyphicon glyphicon-lock form-control-feedback"></span>
|
||||
</div>
|
||||
</div><!-- /.box-body -->
|
||||
<div class="box-footer">
|
||||
<button
|
||||
@click="changeEmail"
|
||||
class="btn btn-warning"
|
||||
v-t="'user.profile.email.button'"
|
||||
data-test="changeEmail"
|
||||
></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="box box-danger">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title" v-t="'user.profile.delete.title'"></h3>
|
||||
</div><!-- /.box-header -->
|
||||
<div class="box-body">
|
||||
<template v-if="isAdmin">
|
||||
<p v-t="'user.profile.delete.admin'"></p>
|
||||
<button class="btn btn-danger" disabled v-t="'user.profile.delete.button'"></button>
|
||||
</template>
|
||||
<template v-else>
|
||||
<p v-t="{ path: 'user.profile.delete.notice', args: { site: siteName } }"></p>
|
||||
<button
|
||||
class="btn btn-danger"
|
||||
data-toggle="modal"
|
||||
data-target="#modal-delete-account"
|
||||
v-t="'user.profile.delete.button'"
|
||||
></button>
|
||||
</template>
|
||||
</div><!-- /.box-body -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="modal-delete-account" class="modal modal-danger fade" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
<h4 class="modal-title" v-t="'user.profile.delete.modal-title'"></h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div v-once v-html="nl2br($t('user.profile.delete.modal-notice'))"></div>
|
||||
<br />
|
||||
<input type="password" class="form-control" v-model="deleteConfirm" :placeholder="$t('user.profile.delete.password')">
|
||||
<br />
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-outline" data-dismiss="modal" v-t="'general.close'"></button>
|
||||
<a @click="deleteAccount" class="btn btn-outline" v-t="'general.submit'" data-test="deleteAccount"></a>
|
||||
</div>
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
</div><!-- /.modal -->
|
||||
|
||||
</section><!-- /.content -->
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from 'axios';
|
||||
import toastr from 'toastr';
|
||||
import { swal } from '../../js/notify';
|
||||
|
||||
export default {
|
||||
name: 'Profile',
|
||||
data: () => ({
|
||||
oldPassword: '',
|
||||
newPassword: '',
|
||||
confirmPassword: '',
|
||||
nickname: '',
|
||||
email: '',
|
||||
currentPassword: '',
|
||||
deleteConfirm: '',
|
||||
}),
|
||||
computed: {
|
||||
siteName: () => blessing.site_name,
|
||||
isAdmin: () => __bs_data__.admin
|
||||
},
|
||||
methods: {
|
||||
nl2br: str => str.replace(/\n/g, '<br>'),
|
||||
async changePassword() {
|
||||
const {
|
||||
oldPassword, newPassword, confirmPassword
|
||||
} = this;
|
||||
|
||||
if (!oldPassword) {
|
||||
toastr.info(this.$t('user.emptyPassword'));
|
||||
this.$refs.oldPassword.focus();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!newPassword) {
|
||||
toastr.info(this.$t('user.emptyNewPassword'));
|
||||
this.$refs.newPassword.focus();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!confirmPassword) {
|
||||
toastr.info(this.$t('auth.emptyConfirmPwd'));
|
||||
this.$refs.confirmPassword.focus();
|
||||
return;
|
||||
}
|
||||
|
||||
if (newPassword !== confirmPassword) {
|
||||
toastr.info(this.$t('auth.invalidConfirmPwd'));
|
||||
this.$refs.confirmPassword.focus();
|
||||
return;
|
||||
}
|
||||
|
||||
const { data: { errno, msg } } = await axios.post(
|
||||
'/user/profile?action=password',
|
||||
{ current_password: oldPassword, new_password: newPassword }
|
||||
);
|
||||
if (errno === 0) {
|
||||
await swal({ type: 'success', text: msg });
|
||||
return window.location = `${blessing.base_url}/auth/login`;
|
||||
} else {
|
||||
return swal({ type: 'warning', text: msg });
|
||||
}
|
||||
},
|
||||
async changeNickName() {
|
||||
const { nickname } = this;
|
||||
|
||||
if (!nickname) {
|
||||
return swal({ type: 'error', html: this.$t('user.emptyNewNickName') });
|
||||
}
|
||||
|
||||
const { dismiss } = await swal({
|
||||
text: this.$t('user.changeNickName', { new_nickname: nickname }),
|
||||
type: 'question',
|
||||
showCancelButton: true
|
||||
});
|
||||
if (dismiss) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { data: { errno, msg } } = await axios.post(
|
||||
'/user/profile?action=nickname',
|
||||
{ new_nickname: nickname }
|
||||
);
|
||||
if (errno === 0) {
|
||||
$('.nickname').each(function () {
|
||||
$(this).html(nickname);
|
||||
});
|
||||
return swal({ type: 'success', html: msg });
|
||||
} else {
|
||||
return swal({ type: 'warning', html: msg });
|
||||
}
|
||||
},
|
||||
async changeEmail() {
|
||||
const { email } = this;
|
||||
|
||||
if (!email) {
|
||||
return swal({ type: 'error', html: this.$t('user.emptyNewEmail') });
|
||||
}
|
||||
|
||||
if (!/\S+@\S+\.\S+/.test(email)) {
|
||||
return swal({ type: 'warning', html: this.$t('auth.invalidEmail') });
|
||||
}
|
||||
|
||||
const { dismiss } = await swal({
|
||||
text: this.$t('user.changeEmail', { new_email: email }),
|
||||
type: 'question',
|
||||
showCancelButton: true
|
||||
});
|
||||
if (dismiss) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { data: { errno, msg } } = await axios.post(
|
||||
'/user/profile?action=email',
|
||||
{ new_email: email, password: this.currentPassword }
|
||||
);
|
||||
if (errno === 0) {
|
||||
await swal({ type: 'success', text: msg });
|
||||
return window.location = `${blessing.base_url}/auth/login`;
|
||||
} else {
|
||||
return swal({ type: 'warning', text: msg });
|
||||
}
|
||||
},
|
||||
async deleteAccount() {
|
||||
const { deleteConfirm: password } = this;
|
||||
|
||||
if (!password) {
|
||||
return swal({ type: 'warning', html: this.$t('user.emptyDeletePassword') });
|
||||
}
|
||||
|
||||
const { data: { errno, msg } } = await axios.post(
|
||||
'/user/profile?action=delete',
|
||||
{ password }
|
||||
);
|
||||
if (errno === 0) {
|
||||
await swal({
|
||||
type: 'success',
|
||||
html: msg
|
||||
});
|
||||
window.location = `${blessing.base_url}/auth/login`;
|
||||
} else {
|
||||
return swal({ type: 'warning', html: msg });
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
179
resources/assets/tests/components/user/Profile.test.js
Normal file
179
resources/assets/tests/components/user/Profile.test.js
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
import { mount } from '@vue/test-utils';
|
||||
import Profile from '@/components/user/Profile';
|
||||
import axios from 'axios';
|
||||
import toastr from 'toastr';
|
||||
import { swal } from '@/js/notify';
|
||||
|
||||
jest.mock('axios');
|
||||
jest.mock('@/js/notify');
|
||||
|
||||
test('computed values', () => {
|
||||
window.__bs_data__ = { admin: true };
|
||||
const wrapper = mount(Profile);
|
||||
expect(wrapper.vm.siteName).toBe('Blessing Skin');
|
||||
expect(wrapper.vm.isAdmin).toBeTrue();
|
||||
window.__bs_data__ = { admin: false };
|
||||
expect(mount(Profile).vm.isAdmin).toBeFalse();
|
||||
});
|
||||
|
||||
test('convert linebreak', () => {
|
||||
const wrapper = mount(Profile);
|
||||
expect(wrapper.vm.nl2br('a\nb\nc')).toBe('a<br>b<br>c');
|
||||
});
|
||||
|
||||
test('change password', async () => {
|
||||
jest.spyOn(toastr, 'info');
|
||||
axios.post
|
||||
.mockResolvedValueOnce({ data: { errno: 1, msg: 'w' } })
|
||||
.mockResolvedValueOnce({ data: { errno: 0, msg: 'o' } });
|
||||
swal.mockResolvedValue();
|
||||
const wrapper = mount(Profile);
|
||||
const button = wrapper.find('[data-test=changePassword]');
|
||||
|
||||
button.trigger('click');
|
||||
expect(toastr.info).toBeCalledWith('user.emptyPassword');
|
||||
expect(axios.post).not.toBeCalled();
|
||||
|
||||
wrapper.setData({ oldPassword: '1' });
|
||||
button.trigger('click');
|
||||
expect(toastr.info).toBeCalledWith('user.emptyNewPassword');
|
||||
expect(axios.post).not.toBeCalled();
|
||||
|
||||
wrapper.setData({ newPassword: '1' });
|
||||
button.trigger('click');
|
||||
expect(toastr.info).toBeCalledWith('auth.emptyConfirmPwd');
|
||||
expect(axios.post).not.toBeCalled();
|
||||
|
||||
wrapper.setData({ confirmPassword: '2' });
|
||||
button.trigger('click');
|
||||
expect(toastr.info).toBeCalledWith('auth.invalidConfirmPwd');
|
||||
expect(axios.post).not.toBeCalled();
|
||||
|
||||
wrapper.setData({ confirmPassword: '1' });
|
||||
button.trigger('click');
|
||||
await wrapper.vm.$nextTick();
|
||||
expect(axios.post).toBeCalledWith(
|
||||
'/user/profile?action=password',
|
||||
{ current_password: '1', new_password: '1' }
|
||||
);
|
||||
expect(swal).toBeCalledWith({ type: 'warning', text: 'w' });
|
||||
|
||||
button.trigger('click');
|
||||
await wrapper.vm.$nextTick();
|
||||
expect(swal).toBeCalledWith({ type: 'success', text: 'o' });
|
||||
});
|
||||
|
||||
test('change nickname', async () => {
|
||||
axios.post
|
||||
.mockResolvedValueOnce({ data: { errno: 1, msg: 'w' } })
|
||||
.mockResolvedValue({ data: { errno: 0, msg: 'o' } });
|
||||
swal.mockResolvedValueOnce({})
|
||||
.mockResolvedValueOnce({ dismiss: 1 })
|
||||
.mockResolvedValue({});
|
||||
window.$ = jest.fn(() => ({
|
||||
each(fn) {
|
||||
fn();
|
||||
},
|
||||
html() {}
|
||||
}));
|
||||
const wrapper = mount(Profile);
|
||||
const button = wrapper.find('[data-test=changeNickName]');
|
||||
|
||||
button.trigger('click');
|
||||
expect(axios.post).not.toBeCalled();
|
||||
expect(swal).toBeCalledWith({ type: 'error', html: 'user.emptyNewNickName' });
|
||||
|
||||
wrapper.setData({ nickname: 'nickname' });
|
||||
button.trigger('click');
|
||||
expect(axios.post).not.toBeCalled();
|
||||
expect(swal).toBeCalledWith({
|
||||
text: 'user.changeNickName',
|
||||
type: 'question',
|
||||
showCancelButton: true
|
||||
});
|
||||
|
||||
button.trigger('click');
|
||||
await wrapper.vm.$nextTick();
|
||||
expect(axios.post).toBeCalledWith(
|
||||
'/user/profile?action=nickname',
|
||||
{ new_nickname: 'nickname' }
|
||||
);
|
||||
await wrapper.vm.$nextTick();
|
||||
expect(swal).toBeCalledWith({ type: 'warning', html: 'w' });
|
||||
|
||||
button.trigger('click');
|
||||
await wrapper.vm.$nextTick();
|
||||
await wrapper.vm.$nextTick();
|
||||
expect(swal).toBeCalledWith({ type: 'success', html: 'o' });
|
||||
});
|
||||
|
||||
test('change email', async () => {
|
||||
axios.post
|
||||
.mockResolvedValueOnce({ data: { errno: 1, msg: 'w' } })
|
||||
.mockResolvedValue({ data: { errno: 0, msg: 'o' } });
|
||||
swal.mockResolvedValueOnce({})
|
||||
.mockResolvedValueOnce({})
|
||||
.mockResolvedValueOnce({ dismiss: 1 })
|
||||
.mockResolvedValue({});
|
||||
const wrapper = mount(Profile);
|
||||
const button = wrapper.find('[data-test=changeEmail]');
|
||||
|
||||
button.trigger('click');
|
||||
expect(swal).toBeCalledWith({ type: 'error', html: 'user.emptyNewEmail' });
|
||||
expect(axios.post).not.toBeCalled();
|
||||
|
||||
wrapper.setData({ email: 'e' });
|
||||
button.trigger('click');
|
||||
expect(swal).toBeCalledWith({ type: 'warning', html: 'auth.invalidEmail' });
|
||||
expect(axios.post).not.toBeCalled();
|
||||
|
||||
wrapper.setData({ email: 'a@b.c', currentPassword: 'abc' });
|
||||
button.trigger('click');
|
||||
expect(swal).toBeCalledWith({
|
||||
text: 'user.changeEmail',
|
||||
type: 'question',
|
||||
showCancelButton: true
|
||||
});
|
||||
expect(axios.post).not.toBeCalled();
|
||||
|
||||
button.trigger('click');
|
||||
await wrapper.vm.$nextTick();
|
||||
expect(axios.post).toBeCalledWith(
|
||||
'/user/profile?action=email',
|
||||
{ new_email: 'a@b.c', password: 'abc' }
|
||||
);
|
||||
await wrapper.vm.$nextTick();
|
||||
expect(swal).toBeCalledWith({ type: 'warning', text: 'w' });
|
||||
|
||||
button.trigger('click');
|
||||
await wrapper.vm.$nextTick();
|
||||
await wrapper.vm.$nextTick(); // There are two promises, so call it twice.
|
||||
expect(swal).toBeCalledWith({ type: 'success', text: 'o' });
|
||||
});
|
||||
|
||||
test('delete account', async () => {
|
||||
window.__bs_data__ = { admin: true };
|
||||
swal.mockResolvedValue();
|
||||
axios.post
|
||||
.mockResolvedValueOnce({ data: { errno: 1, msg: 'w' } })
|
||||
.mockResolvedValue({ data: { errno: 0, msg: 'o' } });
|
||||
const wrapper = mount(Profile);
|
||||
const button = wrapper.find('[data-test=deleteAccount]');
|
||||
|
||||
button.trigger('click');
|
||||
expect(swal).toBeCalledWith({ type: 'warning', html: 'user.emptyDeletePassword' });
|
||||
expect(axios.post).not.toBeCalled();
|
||||
|
||||
wrapper.setData({ deleteConfirm: 'abc' });
|
||||
button.trigger('click');
|
||||
expect(axios.post).toBeCalledWith(
|
||||
'/user/profile?action=delete',
|
||||
{ password: 'abc' }
|
||||
);
|
||||
await wrapper.vm.$nextTick();
|
||||
expect(swal).toBeCalledWith({ type: 'warning', html: 'w' });
|
||||
|
||||
button.trigger('click');
|
||||
await wrapper.vm.$nextTick();
|
||||
expect(swal).toBeCalledWith({ type: 'success', html: 'o' });
|
||||
});
|
||||
|
|
@ -2,7 +2,8 @@ import 'jest-extended';
|
|||
import Vue from 'vue';
|
||||
|
||||
window.blessing = {
|
||||
base_url: ''
|
||||
base_url: '',
|
||||
site_name: 'Blessing Skin'
|
||||
};
|
||||
|
||||
console.log = console.warn = console.error = () => {};
|
||||
|
|
|
|||
|
|
@ -93,6 +93,39 @@ user:
|
|||
title: Which player should be applied to?
|
||||
empty: It seems that you own no player...
|
||||
add: Add new player
|
||||
profile:
|
||||
avatar:
|
||||
title: Change Avatar?
|
||||
notice: Click the gear icon「<i class="fa fa-cog"></i>」of any skin in your skinlib, then click 「Set as avatar」. We will cut the head segment of that skin for you. If there is no icon like this, please unable the extensions like ADBlock.
|
||||
|
||||
password:
|
||||
title: Change Password
|
||||
old: Old Password
|
||||
new: New Password
|
||||
confirm: Repeat Password
|
||||
button: Change Password
|
||||
|
||||
nickname:
|
||||
title: Change Nickname
|
||||
rule: Whatever you like expect special characters
|
||||
|
||||
email:
|
||||
title: Change Email
|
||||
new: New Email
|
||||
password: Current Password
|
||||
button: Change Email
|
||||
|
||||
delete:
|
||||
title: Delete Account
|
||||
notice: Sure to delete your account on :site?
|
||||
admin: Admin account can not be deleted.
|
||||
button: Delete My Account
|
||||
modal-title: You need to enter your password to continue
|
||||
modal-notice: |
|
||||
You're about to delete your account.
|
||||
This is permanent! No backups, no restores, no magic undo button.
|
||||
We warned you, ok?
|
||||
password: Current Password
|
||||
|
||||
admin:
|
||||
operationsTitle: Operations
|
||||
|
|
@ -162,6 +195,7 @@ general:
|
|||
confirm: OK
|
||||
cancel: Cancel
|
||||
submit: Submit
|
||||
close: Close
|
||||
more: More
|
||||
pagination: 'Page :page, total :total'
|
||||
searchResult: '(Search result of keyword ":keyword")'
|
||||
|
|
|
|||
|
|
@ -93,6 +93,40 @@ user:
|
|||
title: 要给哪个角色使用呢?
|
||||
empty: 你好像还没有添加任何角色哦
|
||||
add: 添加角色
|
||||
profile:
|
||||
avatar:
|
||||
title: 更改头像?
|
||||
notice: 请在衣柜中任意皮肤的右下角「<i class="fa fa-cog"></i>」处选择「设为头像」,将会自动截取该皮肤的头部作为头像哦~ 如果看不到这个图标,请关闭 ADBlock,ABP 之类的广告过滤扩展。
|
||||
|
||||
password:
|
||||
title: 更改密码
|
||||
old: 旧的密码
|
||||
new: 新密码
|
||||
confirm: 确认密码
|
||||
button: 修改密码
|
||||
|
||||
nickname:
|
||||
title: 更改昵称
|
||||
rule: 可使用除一些特殊符号外的任意字符
|
||||
|
||||
email:
|
||||
title: 更改邮箱
|
||||
new: 新邮箱
|
||||
password: 当前密码
|
||||
button: 修改邮箱
|
||||
|
||||
delete:
|
||||
title: 删除账号
|
||||
notice: 确定要删除你在 :site 上的账号吗?
|
||||
admin: 管理员账号不能被删除哟
|
||||
button: 删除我的账户
|
||||
modal-title: 这是危险操作,输入密码以继续
|
||||
modal-notice: |
|
||||
此操作不可恢复!
|
||||
你所上传至皮肤库的材质仍会被保留,但你的角色将被永久删除。
|
||||
我们不提供任何备份,或者神奇的撤销按钮。
|
||||
我们警告过你了,确定要这样做吗?
|
||||
password: 当前密码
|
||||
|
||||
admin:
|
||||
operationsTitle: 更多操作
|
||||
|
|
@ -158,6 +192,7 @@ general:
|
|||
confirm: 确定
|
||||
cancel: 取消
|
||||
submit: 提交
|
||||
close: 关闭
|
||||
more: 更多
|
||||
pagination: '第 :page 页,共 :total 页'
|
||||
searchResult: '(关键词 “:keyword” 的搜索结果)'
|
||||
|
|
|
|||
|
|
@ -91,6 +91,8 @@
|
|||
|
||||
</div><!-- ./wrapper -->
|
||||
|
||||
@yield('pre-script')
|
||||
|
||||
<!-- App Scripts -->
|
||||
@include('common.dependencies.script', ['module' => 'user'])
|
||||
|
||||
|
|
|
|||
|
|
@ -14,117 +14,18 @@
|
|||
</section>
|
||||
|
||||
<!-- Main content -->
|
||||
<section class="content">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="box box-primary">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">@lang('user.profile.avatar.title')</h3>
|
||||
</div><!-- /.box-header -->
|
||||
<div class="box-body">
|
||||
{!! trans('user.profile.avatar.notice') !!}
|
||||
</div><!-- /.box-body -->
|
||||
</div>
|
||||
|
||||
<div class="box box-warning">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">@lang('user.profile.password.title')</h3>
|
||||
</div><!-- /.box-header -->
|
||||
<div class="box-body">
|
||||
<div class="form-group">
|
||||
<label for="password">@lang('user.profile.password.old')</label>
|
||||
<input type="password" class="form-control" id="password" value="">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="new-passwd">@lang('user.profile.password.new')</label>
|
||||
<input type="password" class="form-control" id="new-passwd" value="">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="confirm-pwd">@lang('user.profile.password.confirm')</label>
|
||||
<input type="password" class="form-control" id="confirm-pwd" value="">
|
||||
</div>
|
||||
</div><!-- /.box-body -->
|
||||
<div class="box-footer">
|
||||
<button onclick="changePassword()" class="btn btn-primary">@lang('user.profile.password.button')</button>
|
||||
</div>
|
||||
</div><!-- /.box -->
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="box box-primary">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">@lang('user.profile.nickname.title')</h3>
|
||||
</div><!-- /.box-header -->
|
||||
<div class="box-body">
|
||||
<div class="form-group has-feedback">
|
||||
<input id="new-nickname" type="text" class="form-control" placeholder="{{ ($user->getNickName() == '') ? trans('user.profile.nickname.empty') : '' . trans('user.profile.nickname.rule') }}">
|
||||
<span class="glyphicon glyphicon-user form-control-feedback"></span>
|
||||
</div>
|
||||
</div><!-- /.box-body -->
|
||||
<div class="box-footer">
|
||||
<button onclick="changeNickName()" class="btn btn-primary">@lang('general.submit')</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="box box-warning">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">@lang('user.profile.email.title')</h3>
|
||||
</div><!-- /.box-header -->
|
||||
<div class="box-body">
|
||||
<div class="form-group has-feedback">
|
||||
<input id="new-email" type="email" class="form-control" placeholder="@lang('user.profile.email.new')">
|
||||
<span class="glyphicon glyphicon-envelope form-control-feedback"></span>
|
||||
</div>
|
||||
<div class="form-group has-feedback" style="display: none;">
|
||||
<input id="current-password" type="password" class="form-control" placeholder="@lang('user.profile.email.password')">
|
||||
<span class="glyphicon glyphicon-lock form-control-feedback"></span>
|
||||
</div>
|
||||
</div><!-- /.box-body -->
|
||||
<div class="box-footer">
|
||||
<button onclick="changeEmail()" class="btn btn-warning">@lang('user.profile.email.button')</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="box box-danger">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">@lang('user.profile.delete.title')</h3>
|
||||
</div><!-- /.box-header -->
|
||||
<div class="box-body">
|
||||
@if (!$user->isAdmin())
|
||||
<p>@lang('user.profile.delete.notice', ['site' => option_localized('site_name')])</p>
|
||||
<button id="delete" class="btn btn-danger" data-toggle="modal" data-target="#modal-delete-account">@lang('user.profile.delete.button')</button>
|
||||
@else
|
||||
<p>@lang('user.profile.delete.admin')</p>
|
||||
<button class="btn btn-danger" disabled="disabled">@lang('user.profile.delete.button')</button>
|
||||
@endif
|
||||
</div><!-- /.box-body -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</section><!-- /.content -->
|
||||
<section class="content"></section><!-- /.content -->
|
||||
</div><!-- /.content-wrapper -->
|
||||
|
||||
<div id="modal-delete-account" class="modal modal-danger fade" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title">@lang('user.profile.delete.modal-title')</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
{!! nl2br(trans('user.profile.delete.modal-notice')) !!}
|
||||
<br />
|
||||
<input type="password" class="form-control" id="password" placeholder="@lang('user.profile.delete.password')">
|
||||
<br />
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-outline" data-dismiss="modal">@lang('general.close')</button>
|
||||
<a onclick="deleteAccount();" class="btn btn-outline">@lang('general.submit')</a>
|
||||
</div>
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
</div><!-- /.modal -->
|
||||
|
||||
@endsection
|
||||
|
||||
@section('pre-script')
|
||||
<script>
|
||||
Object.defineProperty(window, '__bs_data__', {
|
||||
value: Object.freeze({
|
||||
admin: !!{{ $user->isAdmin() }}
|
||||
}),
|
||||
writable: false
|
||||
})
|
||||
</script>
|
||||
@endsection
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user