add user avatar
This commit is contained in:
parent
269f13a369
commit
f7fbc3036b
|
@ -8,3 +8,4 @@ frontend/dist
|
|||
|
||||
# django
|
||||
db.sqlite3
|
||||
/media/*
|
||||
|
|
|
@ -25,7 +25,7 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|||
SECRET_KEY = 'l%o*o21h_a5^f+3xblzzfch*&2k_4pcak(o#t2@vymeb_mcy3$'
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = ENV == 'DEV'
|
||||
DEBUG = not ENV == 'PROD'
|
||||
|
||||
ALLOWED_HOSTS = [] if DEBUG else ['127.0.0.1', 'localhost', 'code.wh.sdu.edu.cn']
|
||||
|
||||
|
@ -138,6 +138,10 @@ STATICFILES_DIRS = [
|
|||
os.path.join(BASE_DIR, 'frontend', 'dist', 'static'),
|
||||
]
|
||||
|
||||
MEDIA_URL = '/media/'
|
||||
|
||||
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
|
||||
|
||||
# Django Restfull Framework
|
||||
REST_FRAMEWORK = {
|
||||
'EXCEPTION_HANDLER': 'utils.handler.custom_exception_handler',
|
||||
|
|
|
@ -14,13 +14,19 @@ Including another URLconf
|
|||
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
||||
"""
|
||||
from django.contrib import admin
|
||||
from django.urls import path, include
|
||||
from django.urls import path, include, re_path
|
||||
from django.views.generic.base import TemplateView
|
||||
from django.views.static import serve
|
||||
from . import settings
|
||||
|
||||
from utils.views import UploadFileAPI
|
||||
|
||||
urlpatterns = [
|
||||
path('', TemplateView.as_view(template_name='index.html')),
|
||||
re_path(r'^media/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT}),
|
||||
path('api-auth/', include('rest_framework.urls')),
|
||||
path('admin/', admin.site.urls),
|
||||
path('api/user/', include('user.urls', namespace='user')),
|
||||
path('api/booking/', include('booking.urls', namespace='booking')),
|
||||
path('api/file/', UploadFileAPI.as_view())
|
||||
]
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
from django.core.management.base import BaseCommand
|
||||
from booking.models import Setting
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'init the settings'
|
||||
|
||||
def handle(self, *args, **options):
|
||||
if (Setting.objects.all().count() == 0):
|
||||
Setting.objects.create()
|
||||
self.stdout.write(self.style.SUCCESS('Successfully init'))
|
|
@ -1,7 +1,6 @@
|
|||
# Generated by Django 2.1.7 on 2019-04-19 21:07
|
||||
# Generated by Django 2.2.1 on 2019-05-24 20:40
|
||||
|
||||
import datetime
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import uuid
|
||||
|
@ -12,7 +11,6 @@ class Migration(migrations.Migration):
|
|||
initial = True
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
|
@ -26,11 +24,9 @@ class Migration(migrations.Migration):
|
|||
('date', models.DateField(verbose_name='日期')),
|
||||
('arrive_time', models.TimeField(blank=True, null=True, verbose_name='到达时间')),
|
||||
('leave_time', models.TimeField(blank=True, null=True, verbose_name='离开时间')),
|
||||
('is_valid', models.BooleanField(default=True, verbose_name='是否有效')),
|
||||
('is_cancel', models.BooleanField(default=False, verbose_name='是否取消')),
|
||||
('status', models.CharField(choices=[('PENDING', '正在申请'), ('SUCCESS', '申请成功'), ('FAILED', '申请失败'), ('CANCELED', '被取消')], default='PENDING', max_length=10, verbose_name='状态')),
|
||||
('cancel_datetime', models.DateTimeField(blank=True, null=True, verbose_name='取消日期时间')),
|
||||
('cancel_reason', models.CharField(max_length=512, verbose_name='取消理由')),
|
||||
('cancel_by', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='cancel_by', to=settings.AUTH_USER_MODEL, verbose_name='取消人')),
|
||||
('cancel_reason', models.CharField(blank=True, max_length=512, null=True, verbose_name='取消理由')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '预约',
|
||||
|
@ -42,25 +38,13 @@ class Migration(migrations.Migration):
|
|||
fields=[
|
||||
('id', models.CharField(default=uuid.uuid1, max_length=36, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(blank=True, max_length=128, verbose_name='名称')),
|
||||
('decription', models.CharField(blank=True, max_length=512, verbose_name='说明')),
|
||||
('description', models.TextField(blank=True, max_length=512, verbose_name='说明')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '房间',
|
||||
'verbose_name_plural': '房间',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Seat',
|
||||
fields=[
|
||||
('id', models.CharField(default=uuid.uuid1, max_length=36, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('creaeted_datetime', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
|
||||
('room', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='booking.Room', verbose_name='房间')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '座位',
|
||||
'verbose_name_plural': '座位',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Setting',
|
||||
fields=[
|
||||
|
@ -77,24 +61,17 @@ class Migration(migrations.Migration):
|
|||
'verbose_name_plural': '预约设置',
|
||||
},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='booking',
|
||||
name='room',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='booking.Room', verbose_name='房间'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='booking',
|
||||
name='seat',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='booking.Seat', verbose_name='座位'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='booking',
|
||||
name='seats',
|
||||
field=models.ManyToManyField(related_name='seats', to='booking.Seat', verbose_name='多个座位'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='booking',
|
||||
name='user',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='user', to=settings.AUTH_USER_MODEL, verbose_name='预约人'),
|
||||
migrations.CreateModel(
|
||||
name='Seat',
|
||||
fields=[
|
||||
('id', models.CharField(default=uuid.uuid1, max_length=36, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(blank=True, max_length=128, verbose_name='名称')),
|
||||
('created_datetime', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
|
||||
('room', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='booking.Room', verbose_name='房间')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '座位',
|
||||
'verbose_name_plural': '座位',
|
||||
},
|
||||
),
|
||||
]
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
# Generated by Django 2.1.7 on 2019-04-22 15:05
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('booking', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='room',
|
||||
name='decription',
|
||||
field=models.TextField(blank=True, max_length=512, verbose_name='说明'),
|
||||
),
|
||||
]
|
|
@ -0,0 +1,38 @@
|
|||
# Generated by Django 2.2.1 on 2019-05-24 20:40
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
('booking', '0001_initial'),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='booking',
|
||||
name='cancel_by',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='cancel_by', to=settings.AUTH_USER_MODEL, verbose_name='取消人'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='booking',
|
||||
name='room',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='booking.Room', verbose_name='房间'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='booking',
|
||||
name='seats',
|
||||
field=models.ManyToManyField(related_name='seats', to='booking.Seat', verbose_name='多个座位'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='booking',
|
||||
name='user',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='user', to=settings.AUTH_USER_MODEL, verbose_name='预约人'),
|
||||
),
|
||||
]
|
|
@ -1,17 +0,0 @@
|
|||
# Generated by Django 2.1.7 on 2019-04-22 15:36
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('booking', '0002_auto_20190422_1505'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='booking',
|
||||
name='is_valid',
|
||||
),
|
||||
]
|
|
@ -1,25 +0,0 @@
|
|||
# Generated by Django 2.1.7 on 2019-04-22 15:56
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('booking', '0003_remove_booking_is_valid'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='booking',
|
||||
name='cancel_by',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='cancel_by', to=settings.AUTH_USER_MODEL, verbose_name='取消人'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='booking',
|
||||
name='cancel_reason',
|
||||
field=models.CharField(blank=True, max_length=512, null=True, verbose_name='取消理由'),
|
||||
),
|
||||
]
|
|
@ -1,18 +0,0 @@
|
|||
# Generated by Django 2.1.7 on 2019-04-22 15:56
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('booking', '0004_auto_20190422_1556'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='booking',
|
||||
name='seats',
|
||||
field=models.ManyToManyField(blank=True, null=True, related_name='seats', to='booking.Seat', verbose_name='多个座位'),
|
||||
),
|
||||
]
|
|
@ -1,19 +0,0 @@
|
|||
# Generated by Django 2.1.7 on 2019-04-22 16:36
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('booking', '0005_auto_20190422_1556'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='booking',
|
||||
name='room',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='booking.Room', verbose_name='房间'),
|
||||
),
|
||||
]
|
|
@ -1,18 +0,0 @@
|
|||
# Generated by Django 2.1.7 on 2019-04-22 16:36
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('booking', '0006_auto_20190422_1636'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='booking',
|
||||
name='seats',
|
||||
field=models.ManyToManyField(blank=True, related_name='seats', to='booking.Seat', verbose_name='多个座位'),
|
||||
),
|
||||
]
|
|
@ -1,22 +0,0 @@
|
|||
# Generated by Django 2.1.7 on 2019-04-22 16:49
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('booking', '0007_auto_20190422_1636'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='booking',
|
||||
name='seat',
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='booking',
|
||||
name='seats',
|
||||
field=models.ManyToManyField(related_name='seats', to='booking.Seat', verbose_name='多个座位'),
|
||||
),
|
||||
]
|
|
@ -1,18 +0,0 @@
|
|||
# Generated by Django 2.1.7 on 2019-04-22 17:34
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('booking', '0008_auto_20190422_1649'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameField(
|
||||
model_name='seat',
|
||||
old_name='creaeted_datetime',
|
||||
new_name='created_datetime',
|
||||
),
|
||||
]
|
|
@ -1,18 +0,0 @@
|
|||
# Generated by Django 2.1.7 on 2019-04-26 19:47
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('booking', '0009_auto_20190422_1734'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameField(
|
||||
model_name='room',
|
||||
old_name='decription',
|
||||
new_name='description',
|
||||
),
|
||||
]
|
|
@ -1,18 +0,0 @@
|
|||
# Generated by Django 2.1.7 on 2019-04-27 10:59
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('booking', '0010_auto_20190426_1947'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='seat',
|
||||
name='name',
|
||||
field=models.CharField(blank=True, max_length=128, verbose_name='名称'),
|
||||
),
|
||||
]
|
|
@ -1,22 +0,0 @@
|
|||
# Generated by Django 2.1.7 on 2019-04-30 09:25
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('booking', '0011_seat_name'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='booking',
|
||||
name='is_cancel',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='booking',
|
||||
name='status',
|
||||
field=models.CharField(choices=[('PENDING', '正在申请'), ('SUCCESS', '申请成功'), ('FAILED', '申请失败'), ('CANCELED', '被取消')], default='PENDING', max_length=10, verbose_name='状态'),
|
||||
),
|
||||
]
|
|
@ -1,3 +0,0 @@
|
|||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
|
@ -1,10 +1,10 @@
|
|||
import fetchAPI from '../utils/fetch'
|
||||
|
||||
export default {
|
||||
getSettingDetail() {
|
||||
getSettingDetail () {
|
||||
return fetchAPI('booking/setting/1/', 'get')
|
||||
},
|
||||
updateSettingDetail(setting) {
|
||||
updateSettingDetail (setting) {
|
||||
return fetchAPI('booking/setting/1/', 'put', setting)
|
||||
}
|
||||
}
|
|
@ -17,5 +17,11 @@ export default {
|
|||
return fetchAPI('user/resetPassword/', 'post', {
|
||||
new_password
|
||||
})
|
||||
},
|
||||
getUserAvatar () {
|
||||
return fetchAPI('user/avatar/', 'get')
|
||||
},
|
||||
updateUserAvatar (data) {
|
||||
return fetchAPI('user/avatar/', 'post', data)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,18 +20,18 @@ const user = {
|
|||
},
|
||||
actions: {
|
||||
// 登录
|
||||
Login ({ commit }, user) {
|
||||
Login ({ dispatch, commit }, user) {
|
||||
return new Promise((resolve, reject) => {
|
||||
api.login(user.username, user.password)
|
||||
.then(data => {
|
||||
if (data.role !== 'ADMIN') {
|
||||
if (!data.is_staff) {
|
||||
notification.error({
|
||||
message: '错误',
|
||||
description: '不是管理员账户',
|
||||
description: '不是管理员或教师账户',
|
||||
key: 'ERROR'
|
||||
})
|
||||
this.Logout().then(() => {})
|
||||
reject('Not admin account')
|
||||
dispatch('Logout').then(() => {})
|
||||
reject('Not a admin or teacher account')
|
||||
} else {
|
||||
commit('SET_ID', data.id)
|
||||
commit('SET_USERNAME', data.username)
|
||||
|
@ -43,18 +43,18 @@ const user = {
|
|||
},
|
||||
|
||||
// 获取用户信息
|
||||
GetInfo ({ commit }) {
|
||||
GetInfo ({ dispatch, commit }) {
|
||||
return new Promise((resolve, reject) => {
|
||||
api.getUser(this.state.user.id)
|
||||
.then(data => {
|
||||
if (data.role !== 'ADMIN') {
|
||||
if (!data.is_staff) {
|
||||
notification.error({
|
||||
message: '错误',
|
||||
description: '不是管理员账户',
|
||||
description: '不是管理员或教师账户',
|
||||
key: 'ERROR'
|
||||
})
|
||||
this.Logout().then(() => {})
|
||||
reject('Not admin account')
|
||||
dispatch('Logout').then(() => {})
|
||||
reject('Not a admin or teacher account')
|
||||
} else {
|
||||
commit('SET_ID', data.id)
|
||||
commit('SET_USERNAME', data.username)
|
||||
|
|
|
@ -8,7 +8,7 @@ const BASE_URL = '/api/'
|
|||
* @param name
|
||||
* @returns {*}
|
||||
*/
|
||||
function getCookie (name) {
|
||||
export function getCookie (name) {
|
||||
var cookieValue = null
|
||||
if (document.cookie && document.cookie !== '') {
|
||||
var cookies = document.cookie.split(';')
|
||||
|
|
|
@ -102,7 +102,7 @@
|
|||
<a-form-item
|
||||
label="角色"
|
||||
v-bind="layout">
|
||||
<a-tooltip title="只有管理员才能够进入Booking Admin" placement="right">
|
||||
<a-tooltip title="只有管理员和教师才能够进入Booking Admin" placement="right">
|
||||
<a-select
|
||||
v-decorator="[
|
||||
'role',
|
||||
|
@ -119,44 +119,26 @@
|
|||
</a-tooltip>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label="职员"
|
||||
label="教师"
|
||||
v-bind="layout">
|
||||
<a-tooltip title="标识是否能够进入Admin" placement="right">
|
||||
<a-radio-group
|
||||
v-decorator="[
|
||||
'is_staff',
|
||||
<a-select
|
||||
showSearch
|
||||
placeholder="搜索用户名邮箱"
|
||||
:showArrow="false"
|
||||
:filterOption="false"
|
||||
:notFoundContent="null"
|
||||
mode="multiple"
|
||||
:disabled="form.getFieldValue('role') !== 'STUDENT'"
|
||||
@search="handleSearch"
|
||||
v-decorator="[
|
||||
'teacher',
|
||||
{
|
||||
rules: [
|
||||
{required: true, message: '请选择'},
|
||||
],
|
||||
validateTrigger: 'blur',
|
||||
initialValue: isEdit ? account.is_staff : false
|
||||
initialValue: isEdit ? account.teacher : []
|
||||
}
|
||||
]">
|
||||
<a-radio :value="true">是</a-radio>
|
||||
<a-radio :value="false">否</a-radio>
|
||||
</a-radio-group>
|
||||
</a-tooltip>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label="超级管理员"
|
||||
v-bind="layout">
|
||||
<a-tooltip title="标识是否拥有全部权限" placement="right">
|
||||
<a-radio-group
|
||||
v-decorator="[
|
||||
'is_superuser',
|
||||
{
|
||||
rules: [
|
||||
{required: true, message: '请选择'},
|
||||
],
|
||||
validateTrigger: 'blur',
|
||||
initialValue: isEdit ? account.is_superuser : false
|
||||
}
|
||||
]">
|
||||
<a-radio :value="true">是</a-radio>
|
||||
<a-radio :value="false">否</a-radio>
|
||||
</a-radio-group>
|
||||
</a-tooltip>
|
||||
<a-select-option v-for="item in teacherList" :value="item.id">{{item.username}} {{item.email}}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label="状态"
|
||||
|
@ -255,6 +237,11 @@
|
|||
},
|
||||
form: this.$form.createForm(this),
|
||||
roleList: [],
|
||||
teacherList: [],
|
||||
params: {
|
||||
search: '',
|
||||
role: 'TEACHER'
|
||||
},
|
||||
account: {}
|
||||
}
|
||||
},
|
||||
|
@ -262,26 +249,33 @@
|
|||
api.getRoleList()
|
||||
.then(data => {
|
||||
this.roleList = data
|
||||
if (this.isEdit) this.getData()
|
||||
this.getData()
|
||||
if (this.isEdit) {
|
||||
api.getUser(this.id)
|
||||
.then(data => {
|
||||
this.account = data
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
getData () {
|
||||
api.getUser(this.id)
|
||||
api.getUserList(this.params)
|
||||
.then(data => {
|
||||
this.account = data
|
||||
this.teacherList = data.results
|
||||
})
|
||||
},
|
||||
handleSubmit (e) {
|
||||
e.preventDefault()
|
||||
this.form.validateFields((error, data) => {
|
||||
if (!error) {
|
||||
console.log(data)
|
||||
if (this.isEdit) {
|
||||
api.updateUser(this.account.id, data)
|
||||
.then(data => {
|
||||
this.$notification.success({
|
||||
message: '成功',
|
||||
description: `更新用户${this.account.id}成功`,
|
||||
description: `更新用户成功`,
|
||||
key: 'SUCCESS'
|
||||
})
|
||||
this.$router.push({ name: 'account' })
|
||||
|
@ -291,7 +285,7 @@
|
|||
.then(data => {
|
||||
this.$notification.success({
|
||||
message: '成功',
|
||||
description: `新建用户${this.account.id}成功`,
|
||||
description: `新建用户成功`,
|
||||
key: 'SUCCESS'
|
||||
})
|
||||
this.$router.push({ name: 'account' })
|
||||
|
@ -305,7 +299,7 @@
|
|||
.then(data => {
|
||||
this.$notification.success({
|
||||
message: '成功',
|
||||
description: `删除用户${this.account.id}成功`,
|
||||
description: `删除用户成功`,
|
||||
key: 'SUCCESS'
|
||||
})
|
||||
this.$router.push({ name: 'account' })
|
||||
|
@ -343,6 +337,10 @@
|
|||
}
|
||||
callback()
|
||||
return true
|
||||
},
|
||||
handleSearch (value) {
|
||||
this.params.search = value
|
||||
this.getData()
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
|
|
@ -49,6 +49,13 @@
|
|||
</a-spin>
|
||||
</div>
|
||||
<a-row class="btn-row">
|
||||
<div style="float: left;">
|
||||
<span style="vertical-align: -6px;">提示:
|
||||
<span class="box white"></span>可选时间
|
||||
<span class="box green"></span>不可选时间
|
||||
<span class="box blue"></span>已选时间
|
||||
</span>
|
||||
</div>
|
||||
<a-button
|
||||
style="float: right"
|
||||
type="primary"
|
||||
|
@ -242,5 +249,26 @@
|
|||
|
||||
.btn-row {
|
||||
margin: 10px 0;
|
||||
|
||||
.box {
|
||||
display: inline-block;
|
||||
margin: 0 2px 0 8px;
|
||||
vertical-align: -2px;
|
||||
height: 14px;
|
||||
width: 14px;
|
||||
border: solid 1px rgba(128, 128, 128, 0.3);
|
||||
}
|
||||
|
||||
.green {
|
||||
background-color: @success-color;
|
||||
}
|
||||
|
||||
.blue {
|
||||
background-color: @primary-color;
|
||||
}
|
||||
|
||||
.white {
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -8,7 +8,23 @@
|
|||
<a-form-item
|
||||
label="头像"
|
||||
v-bind="layout">
|
||||
TODO
|
||||
<a-upload
|
||||
name="file"
|
||||
action="/api/file/"
|
||||
:withCredentials="true"
|
||||
:headers="headers"
|
||||
accept="image/*"
|
||||
listType="picture-card"
|
||||
:showUploadList="false"
|
||||
:beforeUpload="beforeUpload"
|
||||
@change="handleImageChange">
|
||||
<img v-if="image.url" :src="image.url" alt="头像" width="200px"/>
|
||||
<div v-else style="width: 100px">
|
||||
<a-icon :type="status.image.loading ? 'loading' : 'plus'"></a-icon>
|
||||
<div class="text">选择图片</div>
|
||||
</div>
|
||||
</a-upload>
|
||||
<span>支持图片文件,不大于10MB</span>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
<a-divider>重置密码</a-divider>
|
||||
|
@ -58,6 +74,7 @@
|
|||
|
||||
<script>
|
||||
import api from '../../api/user'
|
||||
import { getCookie } from '../../utils/fetch'
|
||||
|
||||
export default {
|
||||
name: 'UserSetting',
|
||||
|
@ -69,11 +86,26 @@
|
|||
},
|
||||
reset: {
|
||||
form: this.$form.createForm(this),
|
||||
},
|
||||
status: {
|
||||
image: {
|
||||
loading: false
|
||||
}
|
||||
},
|
||||
image: {
|
||||
url: '',
|
||||
id: ''
|
||||
},
|
||||
headers: {
|
||||
'X-CSRFToken': getCookie('csrftoken')
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
|
||||
api.getUserAvatar()
|
||||
.then(data => {
|
||||
this.image = data
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
handleSubmit (e) {
|
||||
|
@ -107,7 +139,38 @@
|
|||
}
|
||||
callback()
|
||||
return true
|
||||
}
|
||||
},
|
||||
handleImageChange (info) {
|
||||
if (info.file.status === 'uploading') {
|
||||
this.loading = true
|
||||
} else if (info.file.status === 'done') {
|
||||
this.image.id = info.file.response.id
|
||||
this.image.url = info.file.response.url.toString()
|
||||
this.loading = false
|
||||
api.updateUserAvatar({ id: this.image.id })
|
||||
.then(data => {
|
||||
this.$notification.success({ message: '成功', description: '上传头像成功', key: 'SUCCESS' })
|
||||
})
|
||||
} else if (info.file.status === 'error') {
|
||||
this.$message.error(`${info.file.name} 上传失败.`)
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
beforeUpload (file) {
|
||||
const isImage = /image\/*/.test(file.type)
|
||||
if (!isImage) {
|
||||
this.$message.error('图片格式不正确')
|
||||
}
|
||||
const isLt10M = file.size / 1024 / 1024 <= 10
|
||||
if (!isLt10M) {
|
||||
this.$message.error('图片大小请小于10MB')
|
||||
}
|
||||
const isNameLt256 = file.name.length < 256
|
||||
if (!isNameLt256) {
|
||||
this.$message.error('图片名称请小于256个字符')
|
||||
}
|
||||
return isImage && isLt10M && isNameLt256
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -59,7 +59,11 @@ module.exports = {
|
|||
devServer: {
|
||||
proxy: {
|
||||
'/api': {
|
||||
// target: 'https://mock.ihx.me/mock/5baf3052f7da7e07e04a5116/antd-pro',
|
||||
target: 'http://localhost:8000',
|
||||
ws: false,
|
||||
changeOrigin: true
|
||||
},
|
||||
'/media': {
|
||||
target: 'http://localhost:8000',
|
||||
ws: false,
|
||||
changeOrigin: true
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
# Generated by Django 2.1.7 on 2019-04-19 21:07
|
||||
# Generated by Django 2.2.1 on 2019-05-24 20:40
|
||||
|
||||
from django.conf import settings
|
||||
import django.contrib.auth.models
|
||||
import django.contrib.auth.validators
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import django.utils.timezone
|
||||
|
||||
|
||||
|
@ -11,7 +13,8 @@ class Migration(migrations.Migration):
|
|||
initial = True
|
||||
|
||||
dependencies = [
|
||||
('auth', '0009_alter_user_last_name_max_length'),
|
||||
('auth', '0011_update_proxy_permissions'),
|
||||
('utils', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
|
@ -27,9 +30,11 @@ class Migration(migrations.Migration):
|
|||
('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
|
||||
('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
|
||||
('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
|
||||
('role', models.CharField(choices=[('TEACHER', '老师'), ('LEADER', '队长'), ('MEMBER', '成员')], max_length=10, verbose_name='角色')),
|
||||
('role', models.CharField(choices=[('TEACHER', '教师'), ('STUDENT', '学生'), ('ADMIN', '管理员')], max_length=10, verbose_name='角色')),
|
||||
('point', models.IntegerField(default=20, verbose_name='积分')),
|
||||
('avatar', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='utils.UploadFile', verbose_name='头像')),
|
||||
('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups')),
|
||||
('teacher', models.ManyToManyField(blank=True, related_name='_user_teacher_+', to=settings.AUTH_USER_MODEL, verbose_name='教师')),
|
||||
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions')),
|
||||
],
|
||||
options={
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
# Generated by Django 2.1.7 on 2019-04-26 19:47
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('user', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='user',
|
||||
name='role',
|
||||
field=models.CharField(choices=[('TEACHER', '老师'), ('LEADER', '队长'), ('MEMBER', '成员'), ('ADMIN', '管理员')], max_length=10, verbose_name='角色'),
|
||||
),
|
||||
]
|
|
@ -1,15 +1,16 @@
|
|||
from django.contrib.auth.models import AbstractUser
|
||||
from django.db import models
|
||||
|
||||
from utils.models import UploadFile
|
||||
|
||||
class User(AbstractUser):
|
||||
ROLE_CHOICE = [
|
||||
('TEACHER', '老师'),
|
||||
('LEADER', '队长'),
|
||||
('MEMBER', '成员'),
|
||||
('TEACHER', '教师'),
|
||||
('STUDENT', '学生'),
|
||||
('ADMIN', '管理员'),
|
||||
]
|
||||
role = models.CharField('角色', max_length=10, choices=ROLE_CHOICE)
|
||||
teacher = models.ManyToManyField(verbose_name='教师', to='self', related_name='students', blank=True)
|
||||
first_name = None
|
||||
last_name = None
|
||||
point = models.IntegerField('积分', default=20)
|
||||
avatar = models.ForeignKey(verbose_name='头像', to=UploadFile, on_delete=models.CASCADE, null=True)
|
||||
|
|
|
@ -8,7 +8,8 @@ class UserSerializer(serializers.ModelSerializer):
|
|||
model = models.User
|
||||
exclude = ('groups', 'user_permissions')
|
||||
extra_kwargs = {
|
||||
'password': {'write_only': True, 'required': False}
|
||||
'password': {'write_only': True, 'required': False},
|
||||
'teacher': {'required': False}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
|
@ -11,5 +11,6 @@ urlpatterns = [
|
|||
path('logout/', views.Logout.as_view()),
|
||||
path('getInfo/', views.GetInfo.as_view()),
|
||||
path('resetPassword/', views.ResetPassword.as_view()),
|
||||
path('checkUsername/', views.CheckUsername.as_view())
|
||||
path('checkUsername/', views.CheckUsername.as_view()),
|
||||
path('avatar/', views.Avatar.as_view()),
|
||||
]
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
from django.contrib import auth
|
||||
from django.db.models import QuerySet
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django_filters.rest_framework import DjangoFilterBackend
|
||||
from django.shortcuts import get_object_or_404, get_list_or_404
|
||||
from rest_framework import generics
|
||||
from rest_framework import permissions
|
||||
from rest_framework import views
|
||||
|
@ -14,6 +14,7 @@ from rest_framework.serializers import Serializer
|
|||
from . import models
|
||||
from . import serializers
|
||||
|
||||
from utils.models import UploadFile
|
||||
|
||||
class User(generics.ListCreateAPIView):
|
||||
"""
|
||||
|
@ -42,7 +43,27 @@ class User(generics.ListCreateAPIView):
|
|||
|
||||
def perform_create(self, serializer):
|
||||
user = serializer.validated_data
|
||||
models.User.objects.create_user(**user)
|
||||
role = user.get('role')
|
||||
is_staff = False
|
||||
is_superuser = False
|
||||
if role == 'TEACHER':
|
||||
is_staff = True
|
||||
elif role == 'ADMIN':
|
||||
is_staff = True
|
||||
is_superuser = True
|
||||
u = models.User.objects.create_user(
|
||||
username=user['username'],
|
||||
password=user['password'],
|
||||
role=user['role'],
|
||||
email=user['email'],
|
||||
is_staff=is_staff,
|
||||
is_superuser=is_superuser,
|
||||
is_active=user['is_active'],
|
||||
point=user['point']
|
||||
)
|
||||
teacher_list = user.get('teacher')
|
||||
for teacher in teacher_list:
|
||||
u.teacher.add(teacher)
|
||||
|
||||
|
||||
class UserDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||
|
@ -59,10 +80,23 @@ class UserDetail(generics.RetrieveUpdateDestroyAPIView):
|
|||
serializer.save()
|
||||
data = serializer.validated_data
|
||||
password = data.get('password')
|
||||
user = get_object_or_404(models.User, id=self.kwargs['pk'])
|
||||
if password:
|
||||
user = get_object_or_404(models.User, id=self.kwargs['pk'])
|
||||
user.set_password(password)
|
||||
user.save()
|
||||
role = user.role
|
||||
if role != 'STUDENT':
|
||||
user.teacher.clear()
|
||||
is_staff = False
|
||||
is_superuser = False
|
||||
if role == 'TEACHER':
|
||||
is_staff = True
|
||||
elif role == 'ADMIN':
|
||||
is_staff = True
|
||||
is_superuser = True
|
||||
user.is_staff = is_staff
|
||||
user.is_superuser = is_superuser
|
||||
user.save()
|
||||
|
||||
|
||||
class RoleList(generics.GenericAPIView):
|
||||
|
@ -155,3 +189,25 @@ class CheckUsername(views.APIView):
|
|||
return Response(models.User.objects.filter(username=username).exists())
|
||||
else:
|
||||
raise ValidationError("Did not get username.")
|
||||
|
||||
|
||||
class Avatar(views.APIView):
|
||||
"""
|
||||
获得更新用户头像
|
||||
"""
|
||||
permission_classes = (permissions.IsAuthenticated,)
|
||||
|
||||
def get(self, request):
|
||||
avatar = request.user.avatar
|
||||
return Response({
|
||||
'id': avatar.id if avatar else None,
|
||||
'url': avatar.get_url() if avatar else None
|
||||
})
|
||||
|
||||
def post(self, request):
|
||||
file_id = request.data.get('id')
|
||||
file = get_object_or_404(UploadFile, id=file_id)
|
||||
user = request.user
|
||||
user.avatar = file
|
||||
user.save()
|
||||
return Response(serializers.UserSerializer(user).data)
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
default_app_config = 'utils.apps.UtilsConfig'
|
|
@ -1,3 +1,8 @@
|
|||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
||||
from . import models
|
||||
|
||||
|
||||
@admin.register(models.UploadFile)
|
||||
class UploadFileAdmin(admin.ModelAdmin):
|
||||
pass
|
||||
|
|
|
@ -3,3 +3,4 @@ from django.apps import AppConfig
|
|||
|
||||
class UtilsConfig(AppConfig):
|
||||
name = 'utils'
|
||||
verbose_name = '其他'
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
# Generated by Django 2.2.1 on 2019-05-24 20:37
|
||||
|
||||
from django.db import migrations, models
|
||||
import uuid
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='UploadFile',
|
||||
fields=[
|
||||
('datetime', models.DateTimeField(auto_created=True, verbose_name='上传日期')),
|
||||
('id', models.UUIDField(default=uuid.uuid1, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('file', models.FileField(max_length=1024, upload_to='media', verbose_name='文件')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '上传文件',
|
||||
'verbose_name_plural': '上传文件',
|
||||
},
|
||||
),
|
||||
]
|
|
@ -0,0 +1,19 @@
|
|||
# Generated by Django 2.2.1 on 2019-05-24 21:15
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('utils', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='uploadfile',
|
||||
name='name',
|
||||
field=models.CharField(default='', max_length=256, verbose_name='文件名'),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 2.2.1 on 2019-05-24 21:19
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('utils', '0002_uploadfile_name'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='uploadfile',
|
||||
name='datetime',
|
||||
field=models.DateTimeField(auto_now_add=True, verbose_name='上传日期'),
|
||||
),
|
||||
]
|
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 2.2.1 on 2019-05-24 21:19
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('utils', '0003_auto_20190524_2119'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='uploadfile',
|
||||
name='file',
|
||||
field=models.FileField(max_length=1024, upload_to='file', verbose_name='文件'),
|
||||
),
|
||||
]
|
|
@ -1,3 +1,24 @@
|
|||
from django.db import models
|
||||
import uuid
|
||||
|
||||
# Create your models here.
|
||||
from django.db import models
|
||||
from BookingService import settings
|
||||
|
||||
class UploadFile(models.Model):
|
||||
id = models.UUIDField('ID', default=uuid.uuid1, primary_key=True)
|
||||
name = models.CharField('文件名', max_length=256)
|
||||
file = models.FileField('文件', upload_to='file', max_length=1024)
|
||||
datetime = models.DateTimeField('上传日期', auto_now_add=True)
|
||||
|
||||
class Meta:
|
||||
verbose_name = '上传文件'
|
||||
verbose_name_plural = verbose_name
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
def delete(self, using=None, keep_parents=False):
|
||||
self.file.delete()
|
||||
super(UploadFile, self).delete()
|
||||
|
||||
def get_url(self):
|
||||
return f'{settings.MEDIA_URL}{self.file}'
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
|
@ -1,3 +1,23 @@
|
|||
from django.shortcuts import render
|
||||
import time
|
||||
from rest_framework import permissions
|
||||
from rest_framework import views
|
||||
from rest_framework.response import Response
|
||||
|
||||
# Create your views here.
|
||||
from utils.models import UploadFile
|
||||
|
||||
|
||||
class UploadFileAPI(views.APIView):
|
||||
permission_classes = (permissions.IsAuthenticated,)
|
||||
|
||||
def post(self, request):
|
||||
file = request.FILES['file']
|
||||
filename = file.name
|
||||
file.name = f'{int(time.time())}_{filename}'
|
||||
f = UploadFile.objects.create(
|
||||
name=filename,
|
||||
file=file,
|
||||
)
|
||||
return Response({
|
||||
'id': f.id,
|
||||
'url': f.get_url()
|
||||
})
|
||||
|
|
Loading…
Reference in New Issue