From 54af3cc5196a593d72688fd90d719c629ff0f05c Mon Sep 17 00:00:00 2001 From: Hongyuan Ma Date: Wed, 8 Aug 2018 21:50:52 +0800 Subject: [PATCH] add farmer apply page --- front-end/src/app.jsx | 3 + front-end/src/component/layout/theme.css | 1 + front-end/src/page/detailInfo/index.css | 9 ++ front-end/src/page/detailInfo/index.jsx | 63 +++++----- front-end/src/page/farmerApply/index.jsx | 141 +++++++++++++++++++---- front-end/src/page/machineInfo/index.jsx | 16 ++- front-end/src/page/portal/index.jsx | 8 +- front-end/src/service/user-service.jsx | 9 ++ web/apps/test_records/serializer.py | 1 - web/apps/user_operation/serializer.py | 4 + web/apps/user_operation/views.py | 46 +++++--- web/apps/users/models.py | 2 +- web/apps/users/serializer.py | 8 ++ 13 files changed, 235 insertions(+), 76 deletions(-) diff --git a/front-end/src/app.jsx b/front-end/src/app.jsx index cf10cfc..60f0002 100644 --- a/front-end/src/app.jsx +++ b/front-end/src/app.jsx @@ -17,6 +17,8 @@ import DetailInfo from './page/detailInfo/index.jsx' import MachinelInfo from './page/machineInfo/index.jsx' import Portal from './page/portal/index.jsx' +import FarmerApply from './page/farmerApply/index.jsx' + // we need to map the `scale` prop we define below // to the transform style property function mapStyles(styles) { @@ -71,6 +73,7 @@ class App extends React.Component { + {/**/} diff --git a/front-end/src/component/layout/theme.css b/front-end/src/component/layout/theme.css index edb28f9..942a4ad 100644 --- a/front-end/src/component/layout/theme.css +++ b/front-end/src/component/layout/theme.css @@ -1,5 +1,6 @@ /*---------------------------------------------- COMMON STYLES + https://www.webthemez.com/demo/insight-free-bootstrap-html5-admin-template/empty.html# ------------------------------------------------*/ body { font-family: 'Open Sans', sans-serif; diff --git a/front-end/src/page/detailInfo/index.css b/front-end/src/page/detailInfo/index.css index 758664a..e16cc40 100644 --- a/front-end/src/page/detailInfo/index.css +++ b/front-end/src/page/detailInfo/index.css @@ -66,4 +66,13 @@ .trend-span .regressive{ color: #cf1322!important; +} + + +/*catalog*/ +.catalog.ui.vertical.menu { + width: 100%; +} +.catalog.ui.menu .item{ + color: inherit; } \ No newline at end of file diff --git a/front-end/src/page/detailInfo/index.jsx b/front-end/src/page/detailInfo/index.jsx index 2a7bf6f..1711ace 100644 --- a/front-end/src/page/detailInfo/index.jsx +++ b/front-end/src/page/detailInfo/index.jsx @@ -1,7 +1,7 @@ import React from 'react'; import {Link} from 'react-router-dom'; import './index.css'; -import {Table, Divider, Segment, Icon} from 'semantic-ui-react' +import {Table, Divider, Segment, Icon, Menu, Input, Dropdown, Sticky} from 'semantic-ui-react' import PGUtil from 'util/util.jsx' import FarmerCard from 'component/farmer-card/index.jsx' import InfoList from 'component/info-list/index.jsx' @@ -45,10 +45,11 @@ class DetailInfo extends React.Component { }); } + render() { let prev = this.state.recordInfo.prev || 'none'; - let branch = this.state.recordInfo.branch || ''; - let commit = this.state.recordInfo.commit || ''; + let branch = this.state.recordInfo.branch || ''; + let commit = this.state.recordInfo.commit || ''; let date = this.state.recordInfo.date || ''; let machine = this.state.recordInfo.test_machine || {}; let dataset = this.state.recordInfo.dataset_info || {}; @@ -92,12 +93,13 @@ class DetailInfo extends React.Component { if (status == -1) { trend_span = {percentage}; - } else if (status == 1){ + } else if (status == 1) { trend_span = +{percentage}; - } else if (status == 2){ + } else if (status == 2) { trend_span = +{percentage}; - } else if (status == 3){ - trend_span = {percentage}; + } else if (status == 3) { + trend_span = + {percentage}; } return ( @@ -106,11 +108,11 @@ class DetailInfo extends React.Component {
-
Client(s) {key}: {metric} {trend_span}
+
Client(s) {key}: {metric} {trend_span}
{/**/}
{/*
*/} - {/*Improved ()*/} + {/*Improved ()*/} {/*
*/}
@@ -165,12 +167,13 @@ class DetailInfo extends React.Component { if (status == -1) { trend_span = {percentage}; - } else if (status == 1){ + } else if (status == 1) { trend_span = +{percentage}; - } else if (status == 2){ + } else if (status == 2) { trend_span = +{percentage}; - } else if (status == 3){ - trend_span = {percentage}; + } else if (status == 3) { + trend_span = + {percentage}; } return ( @@ -179,7 +182,7 @@ class DetailInfo extends React.Component {
-
Client(s) {key}: {metric} {trend_span}
+
Client(s) {key}: {metric} {trend_span}
{/**/}
{/*
*/} @@ -209,22 +212,24 @@ class DetailInfo extends React.Component { }); let prev_link - if(prev == 'none') { + if (prev == 'none') { prev_link = prev - }else{ + } else { prev_link = ( - + {prev.substring(0, 7)} ) } + return (
Branch: {branch} - Commit: {commit.substring(0, 7)} + Commit: {commit.substring(0, 7)}

NO: {this.state.recordNo}

@@ -245,7 +250,7 @@ class DetailInfo extends React.Component { Farmer Info {/*//todo add a catalog*/} - {/*
aaaa
*/} +
@@ -307,16 +312,16 @@ class DetailInfo extends React.Component {
{/*

Linux Info

*/} {/*
*/} - {/*
*/} - {/*
Description lists
*/} - {/*
A description list is perfect for defining terms.
*/} - {/*
Euismod
*/} - {/*
*/} - {/*
*/} - {/*
*/} - {/*
Malesuada porta
*/} - {/*
Etiam porta sem malesuada magna mollis euismod.
*/} - {/*
*/} + {/*
*/} + {/*
Description lists
*/} + {/*
A description list is perfect for defining terms.
*/} + {/*
Euismod
*/} + {/*
*/} + {/*
*/} + {/*
*/} + {/*
Malesuada porta
*/} + {/*
Etiam porta sem malesuada magna mollis euismod.
*/} + {/*
*/} {/*
*/} diff --git a/front-end/src/page/farmerApply/index.jsx b/front-end/src/page/farmerApply/index.jsx index df329d0..43068e3 100644 --- a/front-end/src/page/farmerApply/index.jsx +++ b/front-end/src/page/farmerApply/index.jsx @@ -1,12 +1,13 @@ import React from 'react'; +import {hashHistory} from 'React-router' import './index.css'; -import { hashHistory } from 'react-router' -import ResultFilter from 'component/result-filter/index.jsx'; -import MachineTable from 'util/machine-table/index.jsx'; +import {Link} from 'react-router-dom'; import UserInfoCard from 'component/userinfo-card/index.jsx' import Record from 'service/record-service.jsx' import PGUtil from 'util/util.jsx' import User from 'service/user-service.jsx' +import PGConstant from 'util/constant.jsx' + const _user = new User(); const _util = new PGUtil(); @@ -16,39 +17,45 @@ class FarmerApply extends React.Component { super(props); this.state = { username: '', - isLoading: false, machines:[], userinfo: {} } - + this.loadUserMachineManageList = this.loadUserMachineManageList.bind(this); } componentDidMount(){ let user = _util.getStorage('userInfo') + let _this = this this.setState({ username: user.username, + },()=>{ + _this.loadUserPortalInfo() + _this.loadUserMachineManageList(); }); console.log(user.token) - this.loadUserPortalInfo() - this.loadUserMachineManageList(); + } loadUserPortalInfo(){ - _user.getUserPortalInfo().then(res => { + let username = this.state.username + _user.getUserPortalInfo(username).then(res => { this.setState({ - userinfo: res.results, + userinfo: res, }); }, errMsg => { - _util.errorTips(errMsg); + _util.errorTips('Please make sure no fields are empty.'); }); } loadUserMachineManageList(page=1){ - _user.getUserMachineManageList().then(res => { + + let listParam = {}; + listParam.page = page; + listParam.machine_owner__username = this.state.username; + _user.getUserMachineManageList(listParam).then(res => { this.setState({ machines: res.results, total: res.count, - isLoading: false }); }, errMsg => { _util.errorTips(errMsg); @@ -59,12 +66,54 @@ class FarmerApply extends React.Component { // this.props.history.push('/login') // hashHistory.push('/login') window.location.href = '/'; - // _user.logout().then(res => { - // _util.removeStorage('userInfo'); - // window.location.href = '/login'; - // }, errMsg => { - // _util.errorTips(errMsg); - // }); + } + + onInputChange(e) { + let inputValue = e.target.value, + inputName = e.target.name; + this.setState({ + [inputName]: inputValue + }); + } + + onInputKeyUp(e) { + if (e.keyCode === 13) { + this.onSubmit(); + } + } + + onSubmit() { + // alert(1) + let machineInfo = { + os_name: this.state.os_name, + os_version: this.state.os_version, + comp_name: this.state.comp_name, + comp_version: this.state.comp_version, + machine_owner:this.state.username + } + let checkResult = true + // check success + if (checkResult) { + _user.farmerApply(machineInfo).then((res) => { + // console.dir(res) + alert('add machine success!') + hashHistory.push('/portal') + // window.location.href = this.state.redirect; + }, (err) => { + // console.log(err) + if (PGConstant.AuthorizedErrorCode === err) { + _util.errorTips('username or password is mistake!'); + }else{ + _util.errorTips('login fail'); + } + }); + } + // check failure + else { + + _util.errorTips(checkResult.msg); + } + } render() { @@ -79,7 +128,7 @@ class FarmerApply extends React.Component {
{/*Farmer Info*/} - +
@@ -88,9 +137,9 @@ class FarmerApply extends React.Component {
- +   Add a New Mchine - + {this.onLogout()}} className="list-group-item">   Logout @@ -103,7 +152,55 @@ class FarmerApply extends React.Component {

Welcome Back, {this.state.username}

- +
+
+ Apply New Machines +
+
+
+ {/**/} +
+ {/*

Login Form

*/} +
+
+ {/**/} + system name + this.onInputKeyUp(e)} + onChange={e => this.onInputChange(e)}/> +
+
+ system version + this.onInputKeyUp(e)} + onChange={e => this.onInputChange(e)}/> +
+
+ arch name + this.onInputKeyUp(e)} + onChange={e => this.onInputChange(e)}/> +
+
+ arch version + this.onInputKeyUp(e)} + onChange={e => this.onInputChange(e)}/> +
+ +
+
+ {/**/} +
+ {/**/} +
+ {/**/} +
diff --git a/front-end/src/page/machineInfo/index.jsx b/front-end/src/page/machineInfo/index.jsx index 3634145..80d4738 100644 --- a/front-end/src/page/machineInfo/index.jsx +++ b/front-end/src/page/machineInfo/index.jsx @@ -86,12 +86,18 @@ class MachineInfo extends React.Component { return (
- -
- NO: {this.state.machineNo} - {/*Add Date: {this.state.machineInfo.addtime}*/} +
+
+ NO: {this.state.machineNo} + {/*Commit: {commit.substring(0, 7)}*/} +
+
+

Farmer: {this.state.machineInfo.alias}

+
-

Farmer: {this.state.machineInfo.alias}

+ {/*
*/} + {/*Date joined: {this.state.machineInfo.add_time}*/} + {/*
*/}
diff --git a/front-end/src/page/portal/index.jsx b/front-end/src/page/portal/index.jsx index e6ba7d7..e58188d 100644 --- a/front-end/src/page/portal/index.jsx +++ b/front-end/src/page/portal/index.jsx @@ -1,7 +1,6 @@ import React from 'react'; +import {Link} from 'react-router-dom'; import './index.css'; -import { hashHistory } from 'react-router' -import ResultFilter from 'component/result-filter/index.jsx'; import MachineTable from 'util/machine-table/index.jsx'; import UserInfoCard from 'component/userinfo-card/index.jsx' import Record from 'service/record-service.jsx' @@ -82,9 +81,10 @@ class Portal extends React.Component {
- +   Add a New Mchine - + + {this.onLogout()}} className="list-group-item">   Logout diff --git a/front-end/src/service/user-service.jsx b/front-end/src/service/user-service.jsx index 4020bab..04f2b56 100644 --- a/front-end/src/service/user-service.jsx +++ b/front-end/src/service/user-service.jsx @@ -4,6 +4,15 @@ import PGConstant from 'util/constant.jsx' const _util = new PGUtil(); class User{ + farmerApply(farmerInfo){ + let url = PGConstant.base_url + '/my-machine/'; + return _util.request({ + type: 'post', + url: url, + data: farmerInfo + }); + } + login(loginInfo){ let url = PGConstant.base_url + '/login/'; return _util.request({ diff --git a/web/apps/test_records/serializer.py b/web/apps/test_records/serializer.py index a57b54c..5decb02 100644 --- a/web/apps/test_records/serializer.py +++ b/web/apps/test_records/serializer.py @@ -346,7 +346,6 @@ class TestRecordDetailSerializer(serializers.ModelSerializer): test_machine = UserMachineSerializer() hardware_info = serializers.SerializerMethodField() meta_info = MetaInfoDetailSerializer() - dataset_info = serializers.SerializerMethodField() prev = serializers.SerializerMethodField() diff --git a/web/apps/user_operation/serializer.py b/web/apps/user_operation/serializer.py index 069c175..1a18f32 100644 --- a/web/apps/user_operation/serializer.py +++ b/web/apps/user_operation/serializer.py @@ -64,6 +64,10 @@ class UserPortalInfoSerializer(serializers.ModelSerializer): reports = TestRecord.objects.filter(test_machine__machine_sn__in=machine_dict).values_list('branch__branch_name').annotate(Count('id')) return reports.count() +class CreateUserMachineSerializer(serializers.ModelSerializer): + class Meta: + model = UserMachine + fields = "__all__" class UserMachineManageSerializer(serializers.ModelSerializer): ''' diff --git a/web/apps/user_operation/views.py b/web/apps/user_operation/views.py index 0985349..e7641cf 100644 --- a/web/apps/user_operation/views.py +++ b/web/apps/user_operation/views.py @@ -11,9 +11,11 @@ from rest_framework_jwt.authentication import JSONWebTokenAuthentication from filters import MachineRecordListFilter, UserMachineListFilter from test_records.models import TestRecord from users.models import UserMachine, UserProfile +from users.serializer import CreateUserProfileSerializer from serializer import UserMachineManageSerializer, UserPortalInfoSerializer, TestRecordListSerializer, \ - UserMachineSerializer - + UserMachineSerializer, CreateUserMachineSerializer +from rest_framework.response import Response +from rest_framework import status class StandardResultsSetPagination(PageNumberPagination): page_size = 20 @@ -37,7 +39,7 @@ class UserMachineRecordByBranchListViewSet(mixins.ListModelMixin, viewsets.Gener filter_backends = (django_filters.rest_framework.DjangoFilterBackend,) filter_class = MachineRecordListFilter -class UserMachineListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet): +class UserMachineListViewSet(mixins.ListModelMixin, mixins.CreateModelMixin, viewsets.GenericViewSet): """ List test records """ @@ -49,17 +51,33 @@ class UserMachineListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet): filter_backends = (django_filters.rest_framework.DjangoFilterBackend,) filter_class = UserMachineListFilter - # def perform_create(self, serializer): - # shop_cart = serializer.save() - # goods = shop_cart.goods - # goods.goods_num -= shop_cart.nums - # goods.save() - - # def get_serializer_class(self): - # if self.action == 'create': - # return UserMachineSerializer - # else: - # return UserMachineManageSerializer + def post(self, request, *args, **kwargs): + return self.create(request, *args, **kwargs) + + def create(self, request, *args, **kwargs): + data = {} + data['os_name'] = request.data['os_name'] + data['os_version'] = request.data['os_version'] + data['comp_name'] = request.data['comp_name'] + data['comp_version'] = request.data['comp_version'] + + username = request.data['machine_owner'] + user = UserProfile.objects.filter(username=username).filter().first() + user_serializer = CreateUserProfileSerializer(user) + + data['machine_owner'] = user_serializer.data['id'] + + serializer = CreateUserMachineSerializer(data=data) + serializer.is_valid(raise_exception=True) + machine = self.perform_create(serializer) + + headers = self.get_success_headers(serializer.data) + + return Response('success', status=status.HTTP_201_CREATED, headers=headers) + + def perform_create(self, serializer): + return serializer.save() + class PublicMachineListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet): """ diff --git a/web/apps/users/models.py b/web/apps/users/models.py index 35ed109..6db5ace 100644 --- a/web/apps/users/models.py +++ b/web/apps/users/models.py @@ -20,7 +20,7 @@ class UserProfile(AbstractUser): # first_name = None # last_name = None - # user_name = models.CharField(max_length=64, verbose_name="name") + username = models.CharField(max_length=64, unique=True, verbose_name="username") # user_email = models.EmailField(max_length=256, verbose_name="email") # add_time = models.DateTimeField(default=datetime.now, verbose_name="user added time") diff --git a/web/apps/users/serializer.py b/web/apps/users/serializer.py index 1ef3ae2..e1ba40a 100644 --- a/web/apps/users/serializer.py +++ b/web/apps/users/serializer.py @@ -14,6 +14,14 @@ class AliasSerializer(serializers.ModelSerializer): model = Alias fields = ('name', ) +class CreateUserProfileSerializer(serializers.ModelSerializer): + ''' + use CreateUserProfileSerializer + ''' + class Meta: + model = UserProfile + fields = "__all__" + class UserMachineSerializer(serializers.ModelSerializer): ''' use UserMachineSerializer -- 2.39.5