参考https://github.com/rfjer/autoAdmin/
https://github.com/rfjer/autoAdmin/blob/master/apps/users/serializers.py
用户功能: 创建用户 <<=post 获取用户列表 <<= get 分页 搜索 修改用户 <=patch/put 删除用户 <=delete
我把分成用户注册登录是一个功能,用户列表修改是一个功能
新建运维平台项目:
1.创建数据库:
[vagrant@CentOS ~]$ sudo su - root
[root@CentOS ~]# mysql -uroot
CREATE DATABASE `devops_test` /*!40100 DEFAULT CHARACTER SET utf8 */;
创建虚拟环境:
sudo su - vagrant
sudo /usr/local/python36/bin/pip3 install virtualenv
/usr/local/python36/bin/virtualenv ./python36env
source ./python36env/bin/activate
cd /vagrant/
2.关闭防火墙:
sudo systemctl stop firewalld
sudo systemctl disable firewalld.service
3.安装工具: pip list
Django 2.2.1 pip install coreapi-cli pip install djangorestframework pip install django-apscheduler pip install tencentcloud-sdk-python pip install django-filter pip install requests -i https://pypi.douban.com/simple/ pip install pymysql pip install django-rest-swagger pip install django-cors-headers pip install djangorestframework-jwt
4.创建项目:
django-admin startproject devops (python36env) [vagrant@CentOS devops]$ python manage.py runserver 0.0.0.0:8000
pycharm设置远程连接此虚拟环境中的django项目!!
5.创建用户app: (python36env) [vagrant@CentOS devops]$ pwd /vagrant/devops (python36env) [vagrant@CentOS devops]$ django-admin startapp users (python36env) [vagrant@CentOS devops]$ mkdir apps (python36env) [vagrant@CentOS devops]$ mv users apps/ settings.py配置:
import os import sys BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.insert(0,os.path.join(BASE_DIR, "apps")) SECRET_KEY = '9vg^(z0ay7ii873g1!7--##r(r#=iisz3wn@mzkxbmx_5iw7))' DEBUG = True ALLOWED_HOSTS = [] AUTH_USER_MODEL = 'users.User' INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'rest_framework', 'rest_framework.authtoken', 'users', 'corsheaders', 'django_apscheduler', 'django_filters' ] CORS_ALLOW_CREDENTIALS = True CORS_ORIGIN_ALLOW_ALL = True CORS_ORIGIN_WHITELIST = ( 'http://127.0.0.1:8000', ) MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'corsheaders.middleware.CorsMiddleware', 'django.middleware.common.CommonMiddleware', #'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ] ROOT_URLCONF = 'devops.urls' TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, }, ] WSGI_APPLICATION = 'devops.wsgi.application' DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'devops_test', 'USER': 'root', 'PASSWORD': '123456', 'HOST': '127.0.0.1', 'PORT': 3306, 'OPTIONS':{ 'init_command':"SET sql_mode='STRICT_TRANS_TABLES'", 'charset':'utf8mb4', }, } } AUTH_PASSWORD_VALIDATORS = [ { 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', }, { 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', }, { 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', }, { 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', }, ] LANGUAGE_CODE = 'zh-hans' TIME_ZONE = 'Asia/Shanghai' USE_I18N = True USE_L10N = True USE_TZ = False STATIC_URL = '/static/' from rest_framework.settings import api_settings REST_FRAMEWORK = { 'DEFAULT_PAGINATION_CLASS': 'devops.paginations.Pagination', 'PAGE_SIZE': 10, 'DEFAULT_FILTER_BACKENDS': ( 'django_filters.rest_framework.DjangoFilterBackend', ), # 'DEFAULT_PERMISSION_CLASSES': ( # 'rest_framework.permissions.IsAuthenticated', # 'rest_framework.permissions.DjangoModelPermissions', # ), # 'DEFAULT_AUTHENTICATION_CLASSES': ( # 'rest_framework.authentication.SessionAuthentication', # 'rest_framework.authentication.BasicAuthentication', # 'rest_framework.authentication.TokenAuthentication', # ), 'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema', } ## qcloud QCLOUD_SECRETID = "AKIDFaq5EbGxiQx22qzUL2XtCJJ7j9NQuyTq" QCLOUD_SECRETKEY = "LTP8fz72lOr8D8reFerunUyGQN7f4LTP" # LOGGING = { # 'version': 1, # 'disable_existing_loggers': False, # 'loggers': { # 'reboot': { # 'handlers': ["reboot"], # 'level': 'DEBUG', # 'propagate': True # }, # "django": { # 'handlers': ["django"], # 'level': 'DEBUG', # 'propagate': True # }, # "django.server": { # 'handlers': ["django_server"], # 'level': 'DEBUG', # "propagate": True # }, # "django.db.backends": { # "propagate": False, # 'level': 'DEBUG', # 'handlers': ["db_backends"] # } # }, # 'handlers': { # "db_backends": { # 'level': 'DEBUG', # 'class': 'logging.FileHandler', # 'filename': '/tmp/db_backends.log', # 'formatter': 'default' # }, # 'reboot': { # 'level': 'DEBUG', # 'class': 'logging.StreamHandler', # 'formatter': 'simple', # }, # 'file': { # 'level': 'DEBUG', # 'class': 'logging.FileHandler', # 'filename': '/tmp/django.log', # 'formatter': 'json', # }, # 'django': { # 'level': 'DEBUG', # 'class': 'logging.FileHandler', # 'filename': '/tmp/default.log', # 'formatter': 'simple', # }, # 'django_server': { # 'level': 'DEBUG', # 'class': 'logging.FileHandler', # 'filename': '/tmp/django_server.log', # 'formatter': 'simple', # }, # }, # 'formatters': { # 'json': { # 'format': '{"levelname":"%(levelname)s","asctime":"%(asctime)s","module":"%(name)s","fullpath":"%(pathname)s","funcName":"%(funcName)s","lineno":"%(lineno)s","message":"%(message)s"}' # }, # 'reboot': { # 'format': '%(asctime)s - %(pathname)s:%(lineno)d[%(levelname)s] - %(message)s' # }, # 'simple': { # 'format': '%(name)s %(asctime)s %(levelname)s %(message)s' # }, # 'verbose': { # 'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s' # }, # "default": { # "format": '%(asctime)s %(name)s %(lineno)s %(levelname)s %(message)s', # "datefmt": "%Y-%m-%d %H:%M:%S" # } # }, # "root": { # 'handlers': ["file"], # 'level': 'DEBUG', # } # } DOMAIN = "@51reboot.com"
后端实现:
6.users/models.py:
from django.db import models # Create your models here. from django.contrib.auth.models import AbstractUser, Group class User(AbstractUser): name = models.CharField("姓名", max_length=32, null=True, help_text="姓名") phone = models.CharField("电话", max_length=11, null=True, help_text="手机号") class Meta: verbose_name = "用户" ordering = ["id"] db_table = 'auth_user' def __str__(self): return self.username
7.users/views.py:
from rest_framework import viewsets, permissions, mixins from .serializers import UserSerializer, UserRegSerializer from .filters import UserFilter from django_filters.rest_framework import DjangoFilterBackend from django.contrib.auth import get_user_model User = get_user_model() class UserViewset(mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, mixins.ListModelMixin, viewsets.GenericViewSet): """ retrieve: 获取指定user记录 list: 获取user列表 update: 更新user记录 partial_update: 更新user的部门字段 destroy: 删除user记录 """ queryset = User.objects.filter(is_superuser=False) serializer_class = UserSerializer filter_class=UserFilter filter_fields = ("username",) #有两个地方可控制你提交哪些方法:一个是此处的视图层,一个是序列化中(序列化中控制的是具体要怎么个做法动作) #UserRegViewset类想支持什么方法在此引入就好了 class UserRegViewset(viewsets.GenericViewSet, mixins.CreateModelMixin, mixins.UpdateModelMixin): """ create: 用户注册 partial_update: 修改密码 update: 修改密码 """ queryset = User.objects.all() serializer_class = UserRegSerializer
8.users/serializers.py:
from rest_framework import serializers from django.contrib.auth.models import Group from django.contrib.auth import get_user_model from django.conf import settings User = get_user_model() #控制具体动作有哪些 class UserSerializer(serializers.ModelSerializer): """ 用户序列化类 """ #控制的你是返回的格式: last_login = serializers.DateTimeField(format="%Y-%m-%d %H:%M:%S", label="上次登录时间", help_text="上次登录时间") # 控制往前端返回哪些字段: class Meta: model = User fields = ("id", "username", "name", "phone", "email", "is_active", "last_login") #想修改哪些字段可在此方法中控制: def update(self, instance, validated_data): instance.phone = validated_data.get("phone", instance.phone) instance.is_active = validated_data.get("is_active", instance.is_active) instance.save() return instance class UserRegSerializer(serializers.ModelSerializer): """ 用户注册序列化类 """ #把密码处理成密文 password = serializers.CharField(style={"input_type": "password"}, label="密码", write_only=True, help_text="密码") #验证 def validate(self, attrs): attrs["is_active"] = False #默认创建完的用户不可直接登录 #给用户自动加email地址 attrs["email"] = "{}{}".format(attrs['username'], settings.DOMAIN) return attrs #此create可不要,但不要的结果是密码直接存进去了 def create(self, validated_data): instance = super(UserRegSerializer, self).create(validated_data=validated_data) instance.set_password(validated_data["password"]) instance.save() return instance def update(self, instance, validated_data): password = validated_data.get("password", None) if password: instance.set_password(password) instance.save() return instance class Meta: model = User #序列化时返回的数据 fields = ("username", "password", "name", "id", "phone")
9.users/router.py:
from rest_framework.routers import DefaultRouter from .views import UserViewset, UserRegViewset router = DefaultRouter() router.register("users", UserViewset, basename="users") router.register("userReg", UserRegViewset, basename="userReg")
10.users/urls.py:
from django.conf.urls import url, include from rest_framework.routers import DefaultRouter from rest_framework.documentation import include_docs_urls from users.router import router as user_router # from resources.router import router as resources_router router = DefaultRouter() router.registry.extend(user_router.registry) # router.registry.extend(resources_router.registry) from rest_framework.authtoken.views import obtain_auth_token urlpatterns = [ url(r'^api/', include(router.urls)), url(r'^api-auth/', include('rest_framework.urls')), url(r'^docs/', include_docs_urls("51reboot接口文档")), url(r'^api-token-auth/', obtain_auth_token) ]
11.users/filters.py:
import django_filters from django.contrib.auth import get_user_model User = get_user_model() class UserFilter(django_filters.FilterSet): username = django_filters.CharFilter(lookup_expr="icontains") class Meta: model = User fields=["username"]
12.devops/urls.py:
import django_filters from django.contrib.auth import get_user_model User = get_user_model() class UserFilter(django_filters.FilterSet): username = django_filters.CharFilter(lookup_expr="icontains") class Meta: model = User fields=["username"]
13.devops/paginations.py:
from rest_framework.pagination import PageNumberPagination class Pagination(PageNumberPagination): def get_page_size(self, request): try: page_size = int(request.query_params.get("page_size", -1)) if page_size >= 0: return page_size except: pass return self.page_size
数据迁移报错: migration执行没有报错,但是执行migrate就报错: Migration admin.0001_initial is applied before its dependency users.0001_initial on database 'default'. 解决:删除数据库,新建一个跟原来一样名字的数据库,就解决了
启动项目:
(python36env) [vagrant@CentOS devops]$ python manage.py createsuperuser
用户名: admin
电子邮件地址: admin@51reboot.com
Password: 123456
(python36env) [vagrant@CentOS devops]$ python manage.py runserver 0.0.0.0:8000
效果如下:
一. 用户注册登陆与列表
1.后端实现:后端需要:写序列化/视图/路由
创建测试用户的数据:
(python36env) [vagrant@CentOS devops]$ python manage.py shell In [2]: from django.contrib.auth import get_user_model In [3]: User = get_user_model() In [4]: def create_user(name): ...: for i in range(1,20): ...: username = "{}-{}".format(name,i) ...: User.objects.create_user(username, "{}@51reboot.com".format(username),"12345678") ...: In [5]: create_user("rock") In [6]: create_user("panda") In [7]: create_user("wd")
In [8]: User.objects.all().delete() ---不想要时可用此命令清空数据
(1).users/serializers.py:
使用模型序列化,那create方法就可不用写(因为它默认把create做好了),但前提是我需要把数据给准备好,而这里有些数据是没有的,如email地址,而注册时我要求是填入用户名,密码,联系电话这些是必须要的,但是没有填邮件地址。那这个是可以改的---根据用户再来一个DOMAIN域名
(1)settings.py中加入DOMAIN---让自动生成邮件域名
DOMAIN = "@51reboot.com"
from rest_framework import serializers from django.contrib.auth.models import Group from django.contrib.auth import get_user_model from django.conf import settings User = get_user_model() #控制具体动作有哪些 class UserSerializer(serializers.ModelSerializer): """ 用户序列化类 """ #控制的你是返回的格式: last_login = serializers.DateTimeField(format="%Y-%m-%d %H:%M:%S", label="上次登录时间", help_text="上次登录时间") # 控制往前端返回哪些字段: class Meta: model = User fields = ("id", "username", "name", "phone", "email", "is_active", "last_login") #想修改哪些字段可在此方法中控制: def update(self, instance, validated_data): instance.phone = validated_data.get("phone", instance.phone) instance.is_active = validated_data.get("is_active", instance.is_active) instance.save() return instance class UserRegSerializer(serializers.ModelSerializer): """ 用户注册序列化类 """ #把密码处理成密文 password = serializers.CharField(style={"input_type": "password"}, label="密码", write_only=True, help_text="密码") #验证 def validate(self, attrs): attrs["is_active"] = False #默认创建完的用户不可直接登录 #给用户自动加email地址 attrs["email"] = "{}{}".format(attrs['username'], settings.DOMAIN) return attrs #此create可不要,但不要的结果是密码直接存进去了 def create(self, validated_data): instance = super(UserRegSerializer, self).create(validated_data=validated_data) instance.set_password(validated_data["password"]) instance.save() return instance def update(self, instance, validated_data): password = validated_data.get("password", None) if password: instance.set_password(password) instance.save() return instance class Meta: model = User #序列化时返回的数据 fields = ("username", "password", "name", "id", "phone")
( 2).users/views.py:
from rest_framework import viewsets, permissions, mixins from .serializers import UserSerializer, UserRegSerializer from .filters import UserFilter from django_filters.rest_framework import DjangoFilterBackend from django.contrib.auth import get_user_model User = get_user_model() class UserViewset(mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, mixins.ListModelMixin, viewsets.GenericViewSet): """ retrieve: 获取指定user记录 list: 获取user列表 update: 更新user记录 partial_update: 更新user的部门字段 destroy: 删除user记录 """ queryset = User.objects.filter(is_superuser=False) serializer_class = UserSerializer filter_class=UserFilter filter_fields = ("username",) #有两个地方可控制你提交哪些方法:一个是此处的视图层,一个是序列化中(序列化中控制的是具体要怎么个做法动作) #UserRegViewset类想支持什么方法在此引入就好了 class UserRegViewset(viewsets.GenericViewSet, mixins.CreateModelMixin, mixins.UpdateModelMixin): """ create: 用户注册 partial_update: 修改密码 update: 修改密码 """ queryset = User.objects.all() serializer_class = UserRegSerializer
(3).users/router.py:
from rest_framework.routers import DefaultRouter from .views import UserViewset, UserRegViewset router = DefaultRouter() router.register("users", UserViewset, basename="users") router.register("userReg", UserRegViewset, basename="userReg")
(4)devops/urls.py:
from django.conf.urls import url, include from rest_framework.routers import DefaultRouter from rest_framework.documentation import include_docs_urls from groupUsers .views import GroupUsersViewset from users.router import router as user_router router = DefaultRouter() router.registry.extend(user_router.registry) # from rest_framework.authtoken.views import obtain_auth_token urlpatterns = [ url(r'^api/', include(router.urls)), url(r'^', include('resources.urls')), url(r'^api-auth/', include('rest_framework.urls')), url(r'^docs/', include_docs_urls("51reboot接口文档")), url(r'^api-token-auth/', obtain_auth_token) ]
上述中是以api开头的全部交给router.urls去处理,,因为到时我前端和后端可能放在一台服务器上,然后调动的时候只要不是api开头的全部交给nginx去处理,以api开头则交给django去处理。
效果如下:
二.展示用户列表--打通前后端
1.vue环境搭建:
参考https://www.cnblogs.com/dbslinux/p/13180500.html
下载vue模版:
F:devopsdataweb>git clone https://github.com/gxhsh/vueAdmin-template.git
安装nodejs: F:devopsdatawebvue-admin-template>npm install --registry=https://registry.npm.taobao.org
F:devopsdatawebvue-admin-template>npm run dev
2.配置:
(2)src/permission.js ---取消权限
import router from './router' // import store from './store' import NProgress from 'nprogress' // Progress 进度条 import 'nprogress/nprogress.css'// Progress 进度条样式 // import { Message } from 'element-ui' // import { getToken } from '@/utils/auth' // 验权 // const whiteList = ['/login'] // 不重定向白名单 router.beforeEach((to, from, next) => { NProgress.start() next() // if (getToken()) { // if (to.path === '/login') { // next({ path: '/' }) // } else { // if (store.getters.roles.length === 0) { // store.dispatch('GetInfo').then(res => { // 拉取用户信息 // next() // }).catch(() => { // store.dispatch('FedLogOut').then(() => { // Message.error('验证失败,请重新登录') // next({ path: '/login' }) // }) // }) // } else { // next() // } // } // } else { // if (whiteList.indexOf(to.path) !== -1) { // next() // } else { // next('/login') // NProgress.done() // } // } }) router.afterEach(() => { NProgress.done() // 结束Progress })
效果如图
(3)重新指向路由config/index.js
(4)开发环境配置成本机config/dev.env.js
BASE_API: '"http://127.0.0.1:8000"',
(5)线上环境配置config/rpod.env.js
BASE_API: '"http://127.0.0.1:8000"',
(6)去掉不需要的路由router/index.js
最终效果如下--这就是我的前端页面:
注意上述图中url有#开头的路由,我可把它改成history模式---即/目录名/目录名。但如果以#开头的路由那我的nginx不用作任何处理,如果是history模式则需nginx支持--https://router.vuejs.org/zh/guide/essentials/history-mode.html,
打开 router/index.jx中的
mode: 'history',
效果如下:
3.用户展示
(1)router/index.js添加前端路由
{ path: '/users', component: Layout, name: 'users', meta: { title: '用户管理', icon: 'example' }, children: [ { path: 'user', name: 'user', component: () => import('@/views/users/user'), <<<--引用下面定义的路由 meta: { title: '用户', icon: 'table' } } ] },
(2)前端视图views/users/user.vue
<template> <div class="app-container"> 用户列表: {{ msg }} </div> </template> <script> export default { name: 'UserList', data() { return { msg: 'rock' } } } </script> <style scoped> </style>
效果如图:
浏览器装vue插件https://www.gugeapps.com/
4.获取后端数据---在api中
(1)api/user.js
import request from '@/utils/request' export function getUserList(params) { return request({ url: '/api/users/', method: 'get', params }) }
(2)users/user.vue中引入
................
<script> import { getUserList } from '@/api/user' export default { name: 'UserList', data() { return { msg: 'rock' } }, created() { this.fetchUserList() }, methods: { fetchUserList() { getUserList() } } } </script>
报如下错:
(3)解决跨域参考github
还不能解决跨域则如下配置:
CORS_ALLOW_CREDENTIALS = True
CORS_ORIGIN_ALLOW_ALL = True
CORS_ORIGIN_WHITELIST = (
'http://127.0.0.1:8000',
))
(4) 解决前端request拦截器utils/request.js
import axios from 'axios' import { Message } from 'element-ui' // import store from '../store' // import { getToken } from '@/utils/auth' // 创建axios实例 const service = axios.create({ baseURL: process.env.BASE_API, // api的base_url timeout: 15000 // 请求超时时间 }) // request拦截器 // service.interceptors.request.use(config => { // if (store.getters.token) { // config.headers['X-Token'] = getToken() // 让每个请求携带自定义token 请根据实际情况自行修改 // } // return config // }, error => { // // Do something with request error // console.log(error) // for debug // Promise.reject(error) // }) // respone拦截器 service.interceptors.response.use( response => { /** * code为非20000是抛错 可结合自己业务进行修改 */ return response.data // const res = response.data // if (res.code !== 20000) { // Message({ // message: res.message, // type: 'error', // duration: 5 * 1000 // }) // // // 50008:非法的token; 50012:其他客户端登录了; 50014:Token 过期了; // if (res.code === 50008 || res.code === 50012 || res.code === 50014) { // MessageBox.confirm('你已被登出,可以取消继续留在该页面,或者重新登录', '确定登出', { // confirmButtonText: '重新登录', // cancelButtonText: '取消', // type: 'warning' // }).then(() => { // store.dispatch('FedLogOut').then(() => { // location.reload()// 为了重新实例化vue-router对象 避免bug // }) // }) // } // return Promise.reject('error') // } else { // return response.data // } }, error => { console.log('err' + error)// for debug Message({ message: error.message, type: 'error', duration: 5 * 1000 }) return Promise.reject(error) } ) export default service
(5)users/user.vue
<template> <div class="app-container"> 用户列表: </div> </template> <script> import { getUserList } from '@/api/user' export default { name: 'UserList', data() { return { userList: [] } }, created() { this.fetchUserList() }, methods: { fetchUserList() { getUserList().then(res => { this.userList = res.results }) } } } </script>
效果如图:已拿到数据
5.将数据展示到页面----去element ui拿组件即可--https://element.eleme.io/#/
users/user.vue:
<template> <div class="app-container"> <el-table :data="userList" stripe style=" 100%"> <el-table-column prop="username" label="username"/> <el-table-column prop="name" label="姓名"/> <el-table-column prop="phone" label="电话"/> <el-table-column prop="email" label="email"/> <el-table-column prop="is_active" label="状态"> <template slot-scope="scope"> <el-switch v-model="scope.row.is_active" @change="handleUserStatusChange(scope.row)"/> </template> </el-table-column> <el-table-column prop="last_login" label="last_login"/> <el-table-column fixed="right" label="操作" width="100"> <template slot-scope="scope"> <el-button type="text" size="small" @click="handleModify(scope.row)">修改</el-button> </template> </el-table-column> </el-table> </div> </template> 。。。。。。。
效果出来了:
三.修改用户状态:
(1)api/user.jss
...... export function modifyUser(id, data) { return request({ url: `/api/users/${id}/`, method: 'patch', data }) }
(2)users/user.vue
<template> <div class="app-container"> <el-table :data="userList" stripe style=" 100%"> <el-table-column prop="username" label="username"/> <el-table-column prop="name" label="姓名"/> <el-table-column prop="phone" label="电话"/> <el-table-column prop="email" label="email"/> <el-table-column prop="is_active" label="状态"> <template slot-scope="scope"> <el-switch v-model="scope.row.is_active" @change="handleUserStatusChange(scope.row)"/> </template> </el-table-column> <el-table-column prop="last_login" label="last_login"/> <el-table-column fixed="right" label="操作" width="100"> <template slot-scope="scope"> <el-button type="text" size="small" @click="handleModify(scope.row)">修改</el-button> </template> </el-table-column> </el-table> </div> </template> <script> import { getUserList, modifyUser } from '@/api/user' export default { name: 'UserList', data() { return { userList: [] } }, created() { this.fetchUserList() }, methods: { fetchUserList() { getUserList().then(res => { this.userList = res.results }) }, handleUserStatusChange(obj) { modifyUser(obj.id, { is_active: obj.is_active }).then(() => { this.$message({ message: `修改 ${obj.name} 的状态成功`, type: 'success' }) }) } } } </script>
效果如下:
四.添加用户/修改用户--此功能把它定义成组件
https://element.eleme.io/#/zh-CN/component/installation
我要的是弹框效果
1.users/components/addUserForm.vue
<template> <div class="add-user-form"> <el-dialog :visible.sync="visible" title="用户信息" @close="handleClose"> <el-form ref="addUserForm" :model="form" :rules="rules" label-width="100px"> <el-form-item label="登陆名:" prop="username"> <el-input v-model="form.username" placeholder="请输入登陆名"/> </el-form-item> <el-form-item label="姓名:" prop="name"> <el-input v-model="form.name" placeholder="请输入姓名"/> </el-form-item> <el-form-item label="密码:" prop="password"> <el-input v-model="form.password" type="password" placeholder="请输入密码"/> </el-form-item> <el-form-item label="手机号:" prop="phone"> <el-input v-model="form.phone" placeholder="请输入手机号"/> </el-form-item> <el-form-item> <el-button type="primary" @click="submitForm">立即创建</el-button> <el-button @click="resetForm">重置</el-button> </el-form-item> </el-form> <div slot="footer" class="dialog-footer"> <el-button @click="handleClose">取 消</el-button> <el-button type="primary" @click="handleClose">确 定</el-button> </div> </el-dialog> </div> </template> <script> import { addUser } from '@/api/user' export default { name: 'AddUserForm', props: { value: { type: Boolean, default: false } }, data() { return { visible: false, form: { username: '', name: '', password: '', phone: '' }, rules: { username: [ { required: true, message: '请输入用户名', trigger: 'blur' } ], name: [ { required: true, message: '请输入用户姓名', trigger: 'blur' } ], password: [ { required: true, message: '请输入密码', trigger: 'blur' } ], phone: [ { required: true, message: '请输入联系电话', trigger: 'blur' } ] } } }, watch: { value(val) { this.visible = val } }, methods: { handleClose() { this.visible = false this.$emit('input', false) this.resetForm() }, resetForm() { this.$refs.addUserForm.resetFields() }, submitForm() { this.$refs.addUserForm.validate((valid) => { if (valid) { addUser(this.form).then(() => { this.$message({ message: `创建用户 ${this.form.name} 成功`, type: 'success' }) this.handleClose() this.$emit('fetch') }) } else { console.log('error submit!!') return false } }) } } } </script>
2.api/user.js
import request from '@/utils/request' export function getUserList(params) { return request({ url: '/api/users/', method: 'get', params }) } export function getUser(userId) { return request({ url: `/api/users/${userId}/`, method: 'get' }) } export function modifyUser(id, data) { return request({ url: `/api/users/${id}/`, method: 'patch', data }) } export function addUser(data) { return request({ url: `/api/userReg/`, method: 'post', data }) }
3.users/user.vue
<template> <div class="app-container"> <el-row> <el-col :span="12"> <el-input v-model="params.username" placeholder="搜索用户名" @keyup.enter.native="handleSearch"> <el-button slot="append" icon="el-icon-search" @click="handleSearch"/> </el-input> </el-col> <el-col :span="12" align="right" style="padding-right:20px;"> <el-button type="primary" @click="addUserVisible=true">添加用户</el-button> </el-col> </el-row> <el-table :data="userList" stripe style=" 100%"> <el-table-column prop="username" label="username"/> <el-table-column prop="name" label="姓名"/> <el-table-column prop="phone" label="电话"/> <el-table-column prop="email" label="email"/> <el-table-column prop="is_active" label="状态"> <template slot-scope="scope"> <el-switch v-model="scope.row.is_active" @change="handleUserStatusChange(scope.row)"/> </template> </el-table-column> <el-table-column prop="last_login" label="last_login"/> <el-table-column fixed="right" label="操作" width="100"> <template slot-scope="scope"> <el-button type="text" size="small" @click="handleModify(scope.row)">修改</el-button> </template> </el-table-column> </el-table> <el-row v-show="total>10" type="flex" justify="center" style="padding-top:20px;"> <el-pagination :total="total" layout="prev, pager, next" background @current-change="handleChange" /> </el-row> <AddUserForm v-model="addUserVisible" @fetch="handleFetch" /> <ModifyUserForm v-model="modifyUserVisible" :user-id="userId" @fetch="handleFetch" /> </div> </template> <script> import { getUserList, modifyUser } from '@/api/user' import AddUserForm from './components/addUserForm' import ModifyUserForm from './components/modifyUser' export default { name: 'UserList', components: { AddUserForm, ModifyUserForm }, data() { return { userList: [], addUserVisible: false, modifyUserVisible: false, userId: 0, total: 0, params: { page: 1, username: '' } } }, created() { this.fetchUserList() }, methods: { fetchUserList() { getUserList(this.params).then(res => { this.userList = res.results this.total = res.count }) }, handleUserStatusChange(obj) { modifyUser(obj.id, { is_active: obj.is_active }).then(() => { this.$message({ message: `修改 ${obj.name} 的状态成功`, type: 'success' }) }) }, handleFetch() { this.fetchUserList() }, handleModify(obj) { this.userId = obj.id this.modifyUserVisible = true }, handleChange(val) { this.params.page = val this.fetchUserList() }, handleSearch() { this.params.page = 1 this.fetchUserList() } } } </script>
效果如下:可创建用户了
4.users/components/modifyUser.vue ---用户修改功能
<template> <div class="modify-user-form"> <el-dialog :visible.sync="visible" :title="title" @close="handleClose"> <el-form ref="modifyUserForm" :model="form" :rules="rules" label-width="100px"> <el-form-item label="手机号:" prop="phone"> <el-input v-model="form.phone" placeholder="请输入手机号"/> </el-form-item> <el-form-item> <el-button type="primary" @click="submitForm">修改</el-button> <el-button @click="resetForm">重置</el-button> </el-form-item> </el-form> </el-dialog> </div> </template> <script> import { getUser, modifyUser } from '@/api/user' export default { name: 'ModifyUser', props: { value: { type: Boolean, default: false }, userId: { type: Number, default: 0 } }, data() { return { visible: false, userObj: null, form: { phone: '' }, rules: { phone: [ { required: true, message: '请输入联系电话', trigger: 'blur' } ] }, uid: 0, title: '' } }, watch: { value(val) { this.visible = val }, userId(val) { if (val === 0) return this.uid = val this.fetchUser() } }, methods: { handleClose() { this.visible = false this.$emit('input', false) this.userId = 0 this.userObj = null this.resetForm() this.title = '' }, resetForm() { this.$refs.modifyUserForm.resetFields() if (this.userId === 0) return if (this.userObj === null) return this.form.phone = this.userObj.phone }, submitForm() { this.$refs.modifyUserForm.validate((valid) => { if (valid) { modifyUser(this.userId, this.form).then(() => { this.$message({ message: `创建用户 ${this.userObj.name} 手机号成功`, type: 'success' }) this.handleClose() this.$emit('fetch') }) } else { console.log('error submit!!') return false } }) }, fetchUser() { getUser(this.uid).then(res => { this.title = `修改 ${res.name} 的信息` this.userObj = res this.form.phone = res.phone }) } } } </script>
1
2
3