]>
git.proxmox.com Git - extjs.git/blob - extjs/build/examples/classic/personel-review/reviewapp.js
5 Ext
.BLANK_IMAGE_URL
= '../libs/ext-4.0/resources/themes/images/default/tree/s.gif';
7 Ext
.onReady(function() {
10 Ext
.regModel('Employee', {
12 {name
:'id', type
:'int'},
13 {name
:'first_name', type
:'string'},
14 {name
:'last_name', type
:'string'},
15 {name
:'title', type
:'string'}
18 hasMany
: {model
:'Review', name
:'reviews'}
22 Ext
.regModel('Review', {
24 {name
:'review_date', label
:'Date', type
:'date', dateFormat
:'d-m-Y'},
25 {name
:'attendance', label
:'Attendance', type
:'int'},
26 {name
:'attitude', label
:'Attitude', type
:'int'},
27 {name
:'communication', label
:'Communication', type
:'int'},
28 {name
:'excellence', label
:'Excellence', type
:'int'},
29 {name
:'skills', label
:'Skills', type
:'int'},
30 {name
:'teamwork', label
:'Teamwork', type
:'int'},
31 {name
:'employee_id', label
:'Employee ID', type
:'int'}
37 // Instance of a Data Store to hold Employee records
38 var employeeStore
= new Ext
.data
.Store({
39 storeId
:'employeeStore',
42 {id
:1, first_name
:'Michael', last_name
:'Scott', title
:'Regional Manager'},
43 {id
:2, first_name
:'Dwight', last_name
:'Schrute', title
:'Sales Rep'},
44 {id
:3, first_name
:'Jim', last_name
:'Halpert', title
:'Sales Rep'},
45 {id
:4, first_name
:'Pam', last_name
:'Halpert', title
:'Office Administrator'},
46 {id
:5, first_name
:'Andy', last_name
:'Bernard', title
:'Sales Rep'},
47 {id
:6, first_name
:'Stanley', last_name
:'Hudson', title
:'Sales Rep'},
48 {id
:7, first_name
:'Phyllis', last_name
:'Lapin-Vance', title
:'Sales Rep'},
49 {id
:8, first_name
:'Kevin', last_name
:'Malone', title
:'Accountant'},
50 {id
:9, first_name
:'Angela', last_name
:'Martin', title
:'Senior Accountant'},
51 {id
:10, first_name
:'Meredith', last_name
:'Palmer', title
:'Supplier Relations Rep'}
58 * @extends Ext.data.Store
59 * This is a specialized Data Store with dynamically generated fields
60 * data reformating capabilities to transform Employee and Review data
61 * into the format required by the Radar Chart.
63 * The constructor demonstrates dynamically generating store fields.
64 * populateReviewScores() populates the store using records from
65 * the reviewStore which holds all the employee review scores.
67 * calculateAverageScores() iterates through each metric in the
68 * review and calculates an average across all available reviews.
70 * Most of the actual data population and updates done by
71 * addUpdateRecordFromReviews() and removeRecordFromReviews()
72 * called when add/update/delete events are triggered on the ReviewStore.
74 Ext
.define('App.RadarStore', {
75 extend
: 'Ext.data.Store',
77 constructor: function(config
) {
78 config
= config
|| {};
79 var dynamicFields
= ['metric', 'avg']; // initalize the non-dynamic fields first
81 employeeStore
.each(function(record
){ // loops through all the employees to setup the dynamic fields
82 dynamicFields
.push('eid_' + record
.get('id'));
86 storeId
:'radarStore', // let's us look it up later using Ext.data.StoreMgr.lookup('radarStore')
91 App
.RadarStore
.superclass
.constructor.call(this, config
);
94 addUpdateRecordFromReviews: function(reviews
) {
97 Ext
.Array
.each(reviews
, function(review
, recordIndex
, all
) { // add a new radarStore record for each review record
98 var eid
= 'eid_' + review
.get('employee_id'); // creates a unique id for each employee column in the store
100 review
.fields
.each(function(field
) {
102 if(field
.name
!== "employee_id" && field
.name
!== "review_date") { // filter out the fields we don't need
103 var metricRecord
= me
.findRecord('metric', field
.name
); // checks for an existing metric record in the store
105 metricRecord
.set(eid
, review
.get(field
.name
)); // updates existing record with field value from review
107 var newRecord
= {}; // creates a new object we can populate with dynamic keys and values to create a new record
108 newRecord
[eid
] = review
.get(field
.name
);
109 newRecord
['metric'] = field
.label
;
116 this.calculateAverageScores(); // update average scores
120 * Calculates an average for each metric across all employees.
121 * We use this to create the average series always shown in the Radar Chart.
123 calculateAverageScores: function() {
124 var me
= this; // keeps the store in scope during Ext.Array.each
125 var reviewStore
= Ext
.data
.StoreMgr
.lookup('reviewStore');
127 var Review
= Ext
.ModelMgr
.getModel('Review');
129 Ext
.Array
.each(Review
.prototype.fields
.keys
, function(fieldName
) { // loop through the Review model fields and calculate average scores
130 if(fieldName
!== "employee_id" && fieldName
!== "review_date") { // ignore non-score fields
131 var avgScore
= Math
.round(reviewStore
.average(fieldName
)); // takes advantage of Ext.data.Store.average()
132 var record
= me
.findRecord('metric', fieldName
);
135 record
.set('avg', avgScore
);
137 me
.add({metric
:fieldName
, avg
:avgScore
});
143 populateReviewScores: function() {
144 var reviewStore
= Ext
.data
.StoreMgr
.lookup('reviewStore');
145 this.addUpdateRecordFromReviews(reviewStore
.data
.items
); // add all the review records to this store
148 removeRecordFromReviews: function(reviews
) {
150 Ext
.Array
.each(reviews
, function(review
, recordIndex
, all
) {
151 var eid
= 'eid_' + review
.get('employee_id');
153 me
.each(function(record
) {
154 delete record
.data
[eid
];
158 // upate average scores
159 this.calculateAverageScores();
161 }); // end App.RadarStore definition
164 /** Creates an instance of App.RadarStore here so we
165 * here so we can re-use it during the life of the app.
166 * Otherwise we'd have to create a new instance everytime
167 * refreshRadarChart() is run.
169 var radarStore
= new App
.RadarStore();
171 var reviewStore
= new Ext
.data
.Store({
172 storeId
:'reviewStore',
175 {review_date
:'01-04-2011', attendance
:10, attitude
:6, communication
:6, excellence
:3, skills
:3, teamwork
:3, employee_id
:1},
176 {review_date
:'01-04-2011', attendance
:6, attitude
:5, communication
:2, excellence
:8, skills
:9, teamwork
:5, employee_id
:2},
177 {review_date
:'01-04-2011', attendance
:5, attitude
:4, communication
:3, excellence
:5, skills
:6, teamwork
:2, employee_id
:3},
178 {review_date
:'01-04-2011', attendance
:8, attitude
:2, communication
:4, excellence
:2, skills
:5, teamwork
:6, employee_id
:4},
179 {review_date
:'01-04-2011', attendance
:4, attitude
:1, communication
:5, excellence
:7, skills
:5, teamwork
:5, employee_id
:5},
180 {review_date
:'01-04-2011', attendance
:5, attitude
:2, communication
:4, excellence
:7, skills
:9, teamwork
:8, employee_id
:6},
181 {review_date
:'01-04-2011', attendance
:10, attitude
:7, communication
:8, excellence
:7, skills
:3, teamwork
:4, employee_id
:7},
182 {review_date
:'01-04-2011', attendance
:10, attitude
:8, communication
:8, excellence
:4, skills
:8, teamwork
:7, employee_id
:8},
183 {review_date
:'01-04-2011', attendance
:6, attitude
:4, communication
:9, excellence
:7, skills
:6, teamwork
:5, employee_id
:9},
184 {review_date
:'01-04-2011', attendance
:7, attitude
:5, communication
:9, excellence
:4, skills
:2, teamwork
:4, employee_id
:10}
187 add:function(store
, records
, storeIndex
) {
188 var radarStore
= Ext
.data
.StoreMgr
.lookup('radarStore');
190 if(radarStore
) { // only add records if an instance of the rardarStore already exists
191 radarStore
.addUpdateRecordFromReviews(records
); // add a new radarStore records for new review records
193 }, // end add listener
194 update: function(store
, record
, operation
) {
195 radarStore
.addUpdateRecordFromReviews([record
]);
198 remove: function(store
, records
, storeIndex
) {
199 // update the radarStore and regenerate the radarChart
200 Ext
.data
.StoreMgr
.lookup('radarStore').removeRecordFromReviews(records
);
202 } // end remove listener
207 * App.PerformanceRadar
208 * @extends Ext.chart.Chart
209 * This is a specialized Radar Chart which we use to display employee
210 * performance reviews.
212 * The class will be registered with an xtype of 'performanceradar'
214 Ext
.define('App.PerformanceRadar', {
215 extend
: 'Ext.chart.Chart',
216 alias
: 'widget.performanceradar', // register xtype performanceradar
217 constructor: function(config
) {
218 config
= config
|| {};
220 this.setAverageSeries(config
); // make sure average is always present
226 store
: Ext
.data
.StoreMgr
.lookup('radarStore'),
243 App
.PerformanceRadar
.superclass
.constructor.call(this, config
);
245 }, // end constructor
247 setAverageSeries: function(config
) {
270 config
.series
.push(avgSeries
); // if a series is passed in then append the average to it
272 config
.series
= [avgSeries
]; // if a series isn't passed just create average
276 }); // end Ext.ux.Performance radar definition
281 * This is a specialized Panel which is used to show information about
282 * an employee and the reviews we have on record for them.
284 * This demonstrates adding 2 custom properties (tplMarkup and
285 * startingMarkup) to the class. It also overrides the initComponent
286 * method and adds a new method called updateDetail.
288 * The class will be registered with an xtype of 'employeedetail'
290 Ext
.define('App.EmployeeDetail', {
291 extend
: 'Ext.panel.Panel',
292 // register the App.EmployeeDetail class with an xtype of employeedetail
293 alias
: 'widget.employeedetail',
294 // add tplMarkup as a new property
296 '<b>{first_name} {last_name}</b> ',
297 'Title: {title}<br/><br/>',
298 '<b>Last Review</b> ',
299 'Attendance: {attendance} ',
300 'Attitude: {attitude} ',
301 'Communication: {communication} ',
302 'Excellence: {excellence} ',
303 'Skills: {skills} ',
304 'Teamwork: {teamwork}'
309 // override initComponent to create and compile the template
310 // apply styles to the body of the panel
311 initComponent: function() {
312 this.tpl
= new Ext
.Template(this.tplMarkup
);
314 // call the superclass's initComponent implementation
315 App
.EmployeeDetail
.superclass
.initComponent
.call(this);
319 Ext
.define('App.ReviewWindow', {
320 extend
: 'Ext.window.Window',
322 constructor: function(config
) {
323 config
= config
|| {};
325 title
:'Employee Performance Review',
331 id
:'employeereviewcomboform',
340 title
:'Employee Info',
347 fieldLabel
:'First Name',
352 fieldLabel
:'Last Name',
362 title
:'Performance Review',
366 fieldLabel
:'Review Date',
368 maxValue
: new Date(),
374 fieldLabel
:'Attendance',
382 fieldLabel
:'Attitude',
388 name
:'communication',
389 fieldLabel
:'Communication',
397 fieldLabel
:'Excellence',
411 fieldLabel
:'Teamwork',
422 this.up('window').close();
428 handler:function(btn
, eventObj
) {
429 var window
= btn
.up('window');
430 var form
= window
.down('form').getForm();
432 if (form
.isValid()) {
433 window
.getEl().mask('saving data...');
434 var vals
= form
.getValues();
435 var employeeStore
= Ext
.data
.StoreMgr
.lookup('employeeStore');
436 var currentEmployee
= employeeStore
.findRecord('id', vals
['employee_id']);
438 // look up id for this employee to see if they already exist
439 if(vals
['employee_id'] && currentEmployee
) {
440 currentEmployee
.set('first_name', vals
['first_name']);
441 currentEmployee
.set('last_name', vals
['last_name']);
442 currentEmployee
.set('title', vals
['title']);
444 var currentReview
= Ext
.data
.StoreMgr
.lookup('reviewStore').findRecord('employee_id', vals
['employee_id']);
445 currentReview
.set('review_date', vals
['review_date']);
446 currentReview
.set('attendance', vals
['attendance']);
447 currentReview
.set('attitude', vals
['attitude']);
448 currentReview
.set('communication', vals
['communication']);
449 currentReview
.set('excellence', vals
['excellence']);
450 currentReview
.set('skills', vals
['skills']);
451 currentReview
.set('teamwork', vals
['teamwork']);
453 var newId
= employeeStore
.getCount() + 1;
457 first_name
: vals
['first_name'],
458 last_name
: vals
['last_name'],
462 Ext
.data
.StoreMgr
.lookup('reviewStore').add({
463 review_date
: vals
['review_date'],
464 attendance
: vals
['attendance'],
465 attitude
: vals
['attitude'],
466 communication
: vals
['communication'],
467 excellence
: vals
['excellence'],
468 skills
: vals
['skills'],
469 teamwork
: vals
['teamwork'],
473 window
.getEl().unmask();
480 App
.ReviewWindow
.superclass
.constructor.call(this, config
);
487 // adds a record to the radar chart store and
488 // creates a series in the chart for selected employees
489 function refreshRadarChart(employees
) {
490 employees
= employees
|| []; // in case its called with nothing we'll at least have an empty array
491 var existingRadarChart
= Ext
.getCmp('radarchart'); // grab the radar chart component (used down below)
492 var reportsPanel
= Ext
.getCmp('reportspanel'); // grab the reports panel component (used down below)
493 var dynamicSeries
= []; // setup an array of chart series that we'll create dynamically
495 for(var index
= 0; index
< employees
.length
; index
++) {
496 var fullName
= employees
[index
].get('first_name') + ' ' + employees
[index
].get('last_name');
497 var eid
= 'eid_' + employees
[index
].get('id');
499 // add to the dynamic series we're building
505 labelDisplay
: 'over',
520 // destroy the existing chart
521 existingRadarChart
.destroy();
522 // create the new chart using the dynamic series we just made
523 var newRadarChart
= new App
.PerformanceRadar({series
:dynamicSeries
});
524 // mask the panel while we switch out charts
525 reportsPanel
.getEl().mask('updating chart...');
526 // display the new one
527 reportsPanel
.add(newRadarChart
);
528 // un mask the reports panel
529 reportsPanel
.getEl().unmask();
532 function refreshEmployeeDetails(employees
) {
533 var detailsPanel
= Ext
.getCmp('detailspanel');
534 var reviewStore
= Ext
.data
.StoreMgr
.lookup('reviewStore');
537 for(var index
= 0; index
< employees
.length
; index
++) {
538 var templateData
= Ext
.applyIf(employees
[index
].data
, reviewStore
.findRecord('employee_id', employees
[index
].get('id')).data
);
539 var employeePanel
= new App
.EmployeeDetail({
540 title
:employees
[index
].get('first_name') + ' ' + employees
[index
].get('last_name'),
541 data
:templateData
// combined employee and latest review dataTransfer
543 items
.push(employeePanel
);
546 detailsPanel
.getEl().mask('updating details...');
547 detailsPanel
.removeAll();
548 detailsPanel
.add(items
);
549 detailsPanel
.getEl().unmask();
552 // sets Up Checkbox Selection Model for the Employee Grid
553 var checkboxSelModel
= new Ext
.selection
.CheckboxModel();
555 var viewport
= new Ext
.container
.Viewport({
557 layout
: 'border', // sets up Ext.layout.container.Border
563 title
:'Employee Performance Manager',
566 tooltip
:'Add a new employee',
568 handler:function() { // display a window to add a new employee
569 new App
.ReviewWindow().show();
574 store
:Ext
.data
.StoreMgr
.lookup('employeeStore'),
578 dataIndex
:'first_name',
583 dataIndex
:'last_name',
592 xtype
:'actioncolumn',
595 icon
:'images/edit.png',
596 tooltip
:'Edit Employee',
597 handler:function(grid
, rowIndex
, colIndex
) {
598 var employee
= grid
.getStore().getAt(rowIndex
);
599 var review
= reviewStore
.findRecord('employee_id', employee
.get('id'));
600 var win
= new App
.ReviewWindow({hidden
:true});
601 var form
= win
.down('form').getForm();
602 form
.loadRecord(employee
);
603 form
.loadRecord(review
);
608 icon
:'images/delete.png',
609 tooltip
:'Delete Employee',
611 handler:function(grid
, rowIndex
, colIndex
) {
612 Ext
.Msg
.confirm('Remove Employee?', 'Are you sure you want to remove this employee?',
614 if(choice
=== 'yes') {
615 var reviewStore
= Ext
.data
.StoreMgr
.lookup('reviewStore');
617 var employee
= grid
.getStore().getAt(rowIndex
);
618 var reviewIndex
= reviewStore
.find('employee_id', employee
.get('id'));
619 reviewStore
.removeAt(reviewIndex
);
620 grid
.getStore().removeAt(rowIndex
);
627 selModel
: new Ext
.selection
.CheckboxModel(),
629 viewConfig
: {stripeRows
:true},
631 selectionchange:function(selModel
, selected
) {
632 refreshRadarChart(selected
);
633 refreshEmployeeDetails(selected
);
646 xtype
:'panel', // sets up the chart panel (starts collapsed)
649 title
:'Performance Report',
653 xtype
:'performanceradar' // this instantiates a App.PerformanceRadar object
655 }] // mainviewport items array ends here