Completes POCONSOLE-47. Adds fluid shot page and latest stroke page

This commit is contained in:
Patrick McDonagh
2016-11-21 17:28:01 -06:00
parent 5456dca799
commit 80378a8027
13 changed files with 472 additions and 9 deletions

View File

@@ -18,3 +18,4 @@ manager.create_api(Note, methods=['GET', 'POST', 'DELETE', 'PUT'], allow_delete_
manager.create_api(EventConfig, methods=['GET', 'POST', 'DELETE', 'PUT'])
manager.create_api(Event, methods=['GET', 'POST', 'DELETE'], allow_delete_many=True)
manager.create_api(RunStatus, methods=['GET', 'POST', 'DELETE'], allow_delete_many=True)
manager.create_api(FluidShot, methods=['GET', 'POST', 'DELETE', 'PUT'], allow_delete_many=True)

View File

@@ -347,3 +347,20 @@ class RunStatus(db.Model):
"created_on": self.created_on,
"updated_on": self.updated_on,
}
class FluidShot(db.Model):
__tablename__ = "fluid_shots"
_id = db.Column(db.Integer, primary_key=True)
pump_intake_pressure = db.Column(db.Float)
created_on = db.Column(db.DateTime(), default=datetime.utcnow)
updated_on = db.Column(db.DateTime(), default=datetime.utcnow, onupdate=datetime.utcnow)
@property
def serialize(self):
return {
"_id": self._id,
"pump_intake_pressure": self.pump_intake_pressure,
"created_on": self.created_on,
"updated_on": self.updated_on,
}

View File

@@ -34,12 +34,13 @@
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li ng-class="{active: Page.page() == 'dashboard'}"><a href="/#/"><i class="fa fa-home"></i> Dashboard</a></li>
<li ng-class="{active: Page.page() == 'cards'}"><a href="/#/cards"><i class="fa fa-folder-open-o"></i> Cards</a></li>
<li ng-class="{active: Page.page() == 'cards'}"><a href="/#/cards"><i class="fa fa-retweet"></i> Cards</a></li>
<li ng-class="{active: Page.page() == 'tags'}"><a href="/#/tags"><i class="fa fa-tags"></i> Tags</a></li>
<li ng-class="{active: Page.page() == 'gaugeoff'}"><a href="/#/gaugeoff"><i class="fa fa-folder-open-o"></i> Gauge Off</a></li>
<li ng-class="{active: Page.page() == 'welltest'}"><a href="/#/welltest"><i class="fa fa-folder-open-o"></i> Well Test</a></li>
<li ng-class="{active: Page.page() == 'events'}"><a href="/#/events"><i class="fa fa-folder-open-o"></i> Events</a></li>
<li ng-class="{active: Page.page() == 'notes'}"><a href="/#/notes"><i class="fa fa-folder-open-o"></i> Notes</a></li>
<li ng-class="{active: Page.page() == 'gaugeoff'}"><a href="/#/gaugeoff"><i class="fa fa-tachometer"></i> Gauge Off</a></li>
<li ng-class="{active: Page.page() == 'welltest'}"><a href="/#/welltest"><i class="fa fa-flask"></i> Well Test</a></li>
<li ng-class="{active: Page.page() == 'fluidshot'}"><a href="/#/fluid_shots"><i class="fa fa-sort-amount-desc"></i> Fluid Shots</a></li>
<li ng-class="{active: Page.page() == 'events'}"><a href="/#/events"><i class="fa fa-warning"></i> Events</a></li>
<li ng-class="{active: Page.page() == 'notes'}"><a href="/#/notes"><i class="fa fa-sticky-note-o"></i> Notes</a></li>
<li ng-class="{active: Page.page() == 'docs'}"><a href="/#/docs"><i class="fa fa-folder-open-o"></i> Docs</a></li>
</ul>
@@ -82,6 +83,7 @@
<script src="js/cards.factory.js"></script>
<script src="js/welltest.factory.js"></script>
<script src="js/notes.factory.js"></script>
<script src="js/fluidshot.factory.js"></script>
<script src="js/config.controller.js"></script>
<script src="js/dashboard.controller.js"></script>
@@ -93,6 +95,7 @@
<script src="js/welltest.controller.js"></script>
<script src="js/events.controller.js"></script>
<script src="js/notes.controller.js"></script>
<script src="js/fluidshot.controller.js"></script>
</body>

View File

@@ -41,7 +41,7 @@ poconsole.controller('cardListCtrl', function($scope, $routeParams, Card, Page)
};
});
poconsole.controller('cardDataCtrl', function($scope, $routeParams, Card, Page, tags) {
poconsole.controller('cardDataCtrl', function($scope, $routeParams, Card, Page, Tag) {
Page.setTitle('Card Data');
Page.setPage('cards');
@@ -100,7 +100,7 @@ poconsole.controller('cardDataCtrl', function($scope, $routeParams, Card, Page,
$scope.surfaceOptions = graphOptions.surf;
$scope.downholeOptions = graphOptions.down;
var getTagsAtTime = tags.getTagsAtTime(cData.created_on);
var getTagsAtTime = Tag.getTagsAtTime(cData.created_on);
getTagsAtTime.then(function(tagdata){
$scope.tagData = {};
for(var i=0; i < tagdata.length; i++){

View File

@@ -27,6 +27,14 @@ poconsole.factory('Card', function($q, $http, $log){
return deferred.promise;
};
service.getLatestCard = function(){
var deferred = $q.defer();
$http.get('/api/cards?q={"order_by":[{"field":"created_on","direction":"desc"}], "limit":1}').success(function(data) {
deferred.resolve(data.objects[0]);
});
return deferred.promise;
};
service.getCardGraphOptions = function(surface, downhole){
var limits = {
sMaxPos: surface.map(function(x){return x.position;}).reduce(function(y,z){return Math.max(y,z);})+ 20,

View File

@@ -48,3 +48,55 @@ poconsole.controller('todaysTotalsCtrl', function($scope, $route, $http, Page, $
};
$scope.loadTotals();
});
poconsole.controller('latestStrokeCtrl', function($scope, $routeParams, Card, Page, Tag) {
Page.setTitle('Latest Card');
Page.setPage('dashboard');
var getLatestCard = Card.getLatestCard();
getLatestCard.then(function(cData){
$scope.stroke_time = new Date(cData.created_on);
$scope.stroke_number = cData.stroke_number;
$scope._id = cData._id;
$scope.stroke_type = cData.stroke_type;
var surf_pos = JSON.parse(cData.surf_pos);
var surf_lod = JSON.parse(cData.surf_lod);
var down_pos = JSON.parse(cData.down_pos);
var down_lod = JSON.parse(cData.down_lod);
var cd = $scope.stroke_time;
$scope.current_date = cd.getFullYear() + "-" + (cd.getMonth()+1) + "-" + cd.getDate();
var surface_card = surf_pos.map(function(a, i){
return {position:surf_pos[i], load:surf_lod[i]};
});
var downhole_card = down_pos.map(function(a, i){
return {position:down_pos[i], load:down_lod[i]};
});
$scope.card_graph_data = {
surface: surface_card,
downhole: downhole_card
};
var graphOptions = Card.getCardGraphOptions(surface_card, downhole_card);
$scope.surfaceOptions = graphOptions.surf;
$scope.downholeOptions = graphOptions.down;
var getLatestTags = Tag.getCurrentValues();
getLatestTags.then(function(tagdata){
console.log(tagdata);
tagdata = tagdata.vals;
$scope.tagData = {};
for(var i=0; i < tagdata.length; i++){
$scope.tagData[tagdata[i].tag_name] = tagdata[i];
$scope.tagData[tagdata[i].tag_name].created_on = Date.create($scope.tagData[tagdata[i].tag_name].created_on);
$scope.tagData[tagdata[i].tag_name].percentage = (tagdata[i].max_expected - tagdata[i].value) / (tagdata[i].max_expected - tagdata[i].min_expected) * 100.0;
}
});
});
});

View File

@@ -0,0 +1,71 @@
poconsole.controller('fluidShotCtrl', function($scope, Page, FluidShot) {
Page.setTitle('Fluid Shots');
Page.setPage('fluidshot');
$scope.loadFluidShotData = function(page_number){
var getData = FluidShot.getFluidShotPage(page_number);
getData.then(function(d){
for(var j = 0; j < d.objects.length; j++){
d.objects[j].created_on = Date.create(d.objects[j].created_on + "Z", { fromUTC: true });
}
$scope.fluid_shots = d.objects;
$scope.num_pages = d.total_pages;
$scope.page_list = [];
$scope.page_num = d.page;
$scope.total = d.total;
});
};
$scope.loadFluidShotData(1);
$scope.startCreateFluidShot = function(){
$scope.newFluidShot = {
'pump_intake_pressure': 1000,
'created_on': Date.create()
};
};
$scope.submitNewFluidShot = function(){
var temp_date = Date.create($scope.newFluidShot.created_on);
$scope.newFluidShot.created_on = temp_date.utc().format('{yyyy}-{MM}-{dd}T{HH}:{mm}:00.00000');
var createFluidShot = FluidShot.createFluidShot($scope.newFluidShot);
createFluidShot.then(function(response_data){
console.log("Response from API");
console.log(response_data);
$scope.loadFluidShotData(1);
});
};
$scope.startEditFluidShot = function(id){
var getEditFluidShotData = FluidShot.getFluidShot(id);
getEditFluidShotData.then(function(d){
$scope.editFluidShot = d;
$scope.editFluidShot.created_on = Date.utc.create($scope.editFluidShot.created_on);
});
};
$scope.submitEditFluidShot = function(){
var temp_date = Date.create($scope.editFluidShot.created_on);
$scope.editFluidShot.created_on = temp_date.utc().format('{yyyy}-{MM}-{dd}T{HH}:{mm}:00.00000');
var updateFluidShot = FluidShot.updateFluidShot($scope.editFluidShot);
updateFluidShot.then(function(response_data){
console.log("Response from API");
console.log(response_data);
$scope.loadFluidShotData(1);
});
};
$scope.openDeleteFluidShot = function(id){
var getDeleteFluidShotData = FluidShot.getFluidShot(id);
getDeleteFluidShotData.then(function(d){
$scope.deleteFluidShot = d;
});
};
$scope.submitDeleteFluidShot = function(){
var deleteSelectedFluidShot = FluidShot.deleteFluidShot($scope.deleteFluidShot._id);
deleteSelectedFluidShot.then(function(data){
$scope.loadFluidShotData(1);
});
};
});

View File

@@ -0,0 +1,57 @@
poconsole.factory('FluidShot',function($q, $http, $log){
var service = {};
service.getFluidShotPage = function(page_number) {
var deferred = $q.defer();
$http.get('/api/fluid_shots?q={"order_by":[{"field":"created_on","direction":"desc"}]}&page=' + page_number).success(function(data) {
deferred.resolve(data);
});
return deferred.promise;
};
service.getFluidShot = function(id){
var deferred = $q.defer();
$http.get('/api/fluid_shots/' + id).success(function(data) {
deferred.resolve(data);
});
return deferred.promise;
};
service.createFluidShot = function(t){
var deferred = $q.defer();
var well_test = {
'pump_intake_pressure': t.pump_intake_pressure,
'created_on': t.created_on
};
$http.post('/api/fluid_shots', well_test).success(function(data){
deferred.resolve(data);
});
return deferred.promise;
};
service.updateFluidShot = function(t){
var deferred = $q.defer();
var well_test = {
'pump_intake_pressure': t.duration_hours,
'created_on': t.created_on
};
$http.put('/api/fluid_shots/'+ t._id, data=well_test).success(function(data){
deferred.resolve(data);
});
return deferred.promise;
};
service.deleteFluidShot = function(id){
var deferred = $q.defer();
var url = '/api/fluid_shots/' + id;
$http.delete(url).success(function(data) {
deferred.resolve({
data: data
});
});
return deferred.promise;
};
return service;
});

View File

@@ -37,6 +37,12 @@ tagserver.config([
}).when('/totals', {
templateUrl: '/templates/totals.html',
controller: 'todaysTotalsCtrl'
}).when('/fluid_shots', {
templateUrl: '/templates/fluidshot.html',
controller: 'fluidShotCtrl'
}).when('/latest_stroke', {
templateUrl: '/templates/latestcard.html',
controller: 'latestStrokeCtrl'
}).when('/', {
templateUrl: '/templates/dashboard.html',
controller: 'dashboardCtrl'

View File

@@ -23,7 +23,7 @@
<div class="row">
<ul class="nav nav-tabs" role="tablist">
<li class="active"><a href="/#/">Current Tag Values</a></li>
<li><a href="/#/">Last Stroke</a></li>
<li><a href="/#/latest_stroke">Last Stroke</a></li>
<li><a href="/#/totals">Daily Totals</a></li>
</ul>
<br />

View File

@@ -0,0 +1,123 @@
<div class="modal fade" id="addModal">
<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">&times;</span></button>
<h4 class="modal-title">Add a New Fluid Shot...</h4>
</div>
<div class="modal-body">
<div class="well" ng-if="message"><h3 class="text-danger">{{message}}</h3></div>
<form>
<div class="form-group">
<label for="pump_intake_pressure">Pump Intake Pressure</label>
<input type="number" ng-model="newFluidShot.pump_intake_pressure" class="form-control" id="pump_intake_pressure" />
</div>
<div class="form-group">
<label for="created_on">Shot Taken At</label>
<br />
<quick-datepicker id="created_on" ng-model='newFluidShot.created_on'></quick-datepicker>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary" ng-click="submitNewFluidShot();" data-dismiss="modal">Submit Fluid Shot</button>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
<div class="modal fade" id="editModal">
<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">&times;</span></button>
<h4 class="modal-title">Edit a Fluid Shot...</h4>
</div>
<div class="modal-body">
<div class="well" ng-if="message"><h3 class="text-danger">{{message}}</h3></div>
<form>
<div class="form-group">
<label for="pump_intake_pressure">Pump Intake Pressure</label>
<input type="number" ng-model="editFluidShot.pump_intake_pressure" class="form-control" id="pump_intake_pressure" />
</div>
<div class="form-group">
<label for="created_on">Shot Taken At</label>
<br />
<quick-datepicker id="created_on" ng-model='editFluidShot.created_on'></quick-datepicker>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary" ng-click="submitEditFluidShot();" data-dismiss="modal">Submit Fluid Shot Edits</button>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
<div class="modal fade" id="deleteModal">
<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">&times;</span></button>
<h4 class="modal-title">Are you sure?</h4>
</div>
<div class="modal-body">
<div class="well" ng-if="message"><h3 class="text-danger">{{message}}</h3></div>
<h3>Are you sure you want to delete the Fluid Shot at {{deleteFluidShot.created_on}}?</h3>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" data-dismiss="modal">NO!!!!!!</button>
<button type="button" class="btn btn-danger" ng-click="submitDeleteFluidShot(deleteFluidShot._id);" data-dismiss="modal">Yes, delete it!</button>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
<div class='container'>
<div class="row">
<div class="col-md-12">
<h1>Fluid Shot Data</h1>
</div>
</div>
<div class='row'>
<div class='col-md-12'>
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#addModal">
New Fluid Shot
</button>
<dir-pagination-controls on-page-change="loadFluidShotData(newPageNumber)" max-size="15"></dir-pagination-controls>
<div class="table-responsive">
<table class="table table-striped">
<thead>
<tr>
<th>Date</th>
<th>Pump Intake Pressure</th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<tr dir-paginate="shot in fluid_shots | itemsPerPage:per_page" total-items="total" current-page="page_num">
<td nowrap>{{ shot.created_on | date: 'medium' }}</td>
<td nowrap>{{ shot.pump_intake_pressure }} PSI</td>
<td><button data-toggle="modal" data-target="#editModal" ng-click="startEditFluidShot(shot._id)" class="btn btn-primary">Edit</button></td>
<td><button data-toggle="modal" data-target="#deleteModal" ng-click="openDeleteFluidShot(shot._id)" class="btn btn-danger">Delete</button></td>
</tr>
</tbody>
</table>
<div ng-if="fluid_shots.length==0" class="well" style="text-align:center">No stored fluid shot yet.</div>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,125 @@
<div class="container">
<div class="row">
<div class="col-md-12">
<ul class="nav nav-tabs" role="tablist">
<li><a href="/#/">Current Tag Values</a></li>
<li class="active"><a href="/#/latest_stroke">Last Stroke</a></li>
<li><a href="/#/totals">Daily Totals</a></li>
</ul>
</div>
</div>
<div class="row">
<div class="col-sm-2">
<ul class="list-group">
<li class="list-group-item animate" ng-repeat="date in dates" ng-class="{'active':date.ind==current_date}">
<a ng-if="date.ind!=current_date" href="/#/cards/{{date.ind}}">{{date.dtime | date: 'EEE. MMM. d yyyy'}}</a>
<span ng-if="date.ind==current_date">{{date.dtime | date: 'EEE. MMM. d yyyy'}}</span>
</li>
</ul>
</div>
<div class="col-sm-10 pull-right">
<div ng-if="loading" class="well"><img src="/img/loading.gif" style="display: table-cell; vertical-align: middle"/></div>
<div ng-if="!loading">
<div ng-if="error" class="well"><h2>Error: {{error}}</h2></div>
<div ng-if="!error">
<h5><a href="/#/cards/{{_id - 1}}" class="pull-left"><< Prev. Card</a></h5>
<h1 style="text-align:center;">{{stroke_time | date: 'medium'}}</h1>
<div class="row">
<div class="col-sm-4">
<div id="Status" class="gauge well" style="width:95%; text-align:center; margin:10px;"><h4>Status:</h4><h3>{{stroke_type}}</h3><h6>at {{stroke_time | date: "medium"}}</h6></div>
</div>
<div class="col-sm-4">
<div id="FillageGauge" class="gauge well" style="width:95%; text-align:center; margin:10px;"><h4>Pump Fillage:</h4><h3>{{tagData['Pump Fill Percent'].value | number:3}} %</h3><h6>at {{tagData['Pump Fill Percent'].created_on | date: "medium"}}</h6></div>
</div>
<div class="col-sm-4">
<div id="FAPGauge" class="gauge well" style="width:95%; text-align:center; margin:10px;"><h4>Fluid Above Pump:</h4><h3>{{tagData['Fluid Level'].value | number:3}} ft.</h3><h6>at {{tagData['Fluid Level'].created_on | date: "medium"}}</h6></div>
</div>
<div class="col-sm-4">
<div id="PRHPGauge" class="gauge well" style="width:95%; text-align:center; margin:10px;"><h4>Polished Rod HP:</h4><h3>{{tagData['Polished Rod HP'].value | number:3}} HP</h3><h6>at {{tagData['Polished Rod HP'].created_on | date: "medium"}}</h6></div>
</div>
<div class="col-sm-4">
<div id="PMPHPGauge" class="gauge well" style="width:95%; text-align:center; margin:10px;"><h4>Pump HP:</h4><h3>{{tagData['Downhole Pump HP'].value | number:3}} HP</h3><h6>at {{tagData['Downhole Pump HP'].created_on | date: "medium"}}</h6></div>
</div>
<div class="col-sm-4">
<div id="SpeedGauge" class="gauge well" style="width:95%; text-align:center; margin:10px;"><h4>Speed:</h4><h3>{{tagData['Stroke Speed'].value | number:3}} SPM</h3><h6>at {{tagData['Stroke Speed'].created_on | date: "medium"}}</h6></div>
</div>
<div class="col-sm-4">
<div id="FluidLoadGauge" class="gauge well" style="width:95%; text-align:center; margin:10px;"><h4>Fluid Load:</h4><h3>{{tagData['Fluid Load'].value | number:3}} lbs.</h3><h6>at {{tagData['Fluid Load'].created_on | date: "medium"}}</h6></div>
</div>
<div class="col-sm-4">
<div id="LastUpdated" class="gauge well" style="width:95%; text-align:center; margin:10px;"><h4>Current Stroke:</h4><h3>{{stroke_time | date: "medium"}}</h3></div>
</div>
<div class="col-sm-12">
<div class="progress" style="margin:10px;">
<div class="progress-bar progress-bar-striped active"
id="surface_stroke_length"
role="progressbar"
aria-valuenow="{{ tagData['Surface Stroke Length'].value }}"
aria-valuemin="{{ tagData['Surface Stroke Length'].min_expected }}"
aria-valuemax="{{ tagData['Surface Stroke Length'].max_expected }}"
style="width: {{ tagData['Surface Stroke Length'].percentage }}%;">
Surface Stroke Length: {{ tagData['Surface Stroke Length'].value | number:3 }} in.
</div>
</div>
<div class="progress" style="margin:10px;">
<div class="progress-bar progress-bar-striped active"
id="downhole_gross_stroke"
role="progressbar"
aria-valuenow="{{ tagData['Downhole Gross Stroke'].value }}"
aria-valuemin="{{ tagData['Downhole Gross Stroke'].min_expected }}"
aria-valuemax="{{ tagData['Downhole Gross Stroke'].max_expected }}"
style="width: {{ tagData['Downhole Gross Stroke'].percentage }}%;">
Downhole Gross Stroke: {{ tagData['Downhole Gross Stroke'].value | number:3 }} in.
</div>
</div>
<div class="progress" style="margin:10px;">
<div class="progress-bar progress-bar-striped active"
id="downhole_adjusted_gross_stroke"
role="progressbar"
aria-valuenow="{{ tagData['Downhole Adjusted Gross Stroke'].value }}"
aria-valuemin="{{ tagData['Downhole Adjusted Gross Stroke'].min_expected }}"
aria-valuemax="{{ tagData['Downhole Adjusted Gross Stroke'].max_expected }}"
style="width: {{ tagData['Downhole Adjusted Gross Stroke'].percentage }}%;">
Downhole Adjusted Gross Stroke: {{ tagData['Downhole Adjusted Gross Stroke'].value | number:3 }} in.
</div>
</div>
<div class="progress" style="margin:10px;">
<div class="progress-bar progress-bar-striped active"
id="downhole_net_stroke"
role="progressbar"
aria-valuenow="{{ tagData['Downhole Net Stroke'].value }}"
aria-valuemin="{{ tagData['Downhole Net Stroke'].min_expected }}"
aria-valuemax="{{ tagData['Downhole Net Stroke'].max_expected }}"
style="width: {{ tagData['Downhole Net Stroke'].percentage }}%;">
Downhole Net Stroke: {{ tagData['Downhole Net Stroke'].value | number:3 }} in.
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12">
<h1>Surface Card</h1>
<div class="surfaceCard" style="height:500px">
<linechart data="card_graph_data" options="surfaceOptions"></linechart>
</div>
</div>
<div class="col-sm-12">
<h1>Downhole Card</h1>
<div class="downholeCard" style="height:500px">
<linechart data="card_graph_data" options="downholeOptions"></linechart>
</div>
</div>
</div>
</div>
</div>
</div>
</div><!--col-sm-10-->
</div>

View File

@@ -12,7 +12,7 @@
<div class="row">
<ul class="nav nav-tabs" role="tablist">
<li><a href="/#/">Current Tag Values</a></li>
<li><a href="/#/">Last Stroke</a></li>
<li><a href="/#/latest_stroke">Last Stroke</a></li>
<li class="active"><a href="/#/totals">Daily Totals</a></li>
</ul>
<br />