Browse Source
Update 2016-08-14.21.24
Update 2016-08-14.21.24
Add Sortable Project Features Add sortable Feature Tasks Filter Unfinished features list only to 'on progress' and 'done' project status Export project features to Excel (xlsx) Add Option CRUD with vuejs ajax (single page application) Add Laravel Excel and Laravel Dompdf Remove top-nav Refactor ManageProjectsTest classpull/1/head
31 changed files with 1720 additions and 115 deletions
-
6app/Entities/BaseRepository.php
-
2app/Entities/Projects/Feature.php
-
16app/Entities/Projects/FeaturesRepository.php
-
2app/Entities/Projects/Project.php
-
15app/Entities/Projects/ProjectsRepository.php
-
6app/Entities/Projects/TasksRepository.php
-
10app/Http/Controllers/Projects/FeaturesController.php
-
26app/Http/Controllers/Projects/ProjectsController.php
-
3app/Http/routes.php
-
61app/Http/routes/options-vue.php
-
3app/Http/routes/projects.php
-
2app/Services/FormField.php
-
4composer.json
-
404composer.lock
-
4config/app.php
-
691config/excel.php
-
4database/factories/ModelFactory.php
-
32public/assets/js/sb-admin-2.js
-
1resources/lang/id/project.php
-
2resources/views/features/partials/feature-show.blade.php
-
32resources/views/features/partials/feature-tasks-operation.blade.php
-
27resources/views/features/partials/feature-tasks.blade.php
-
1resources/views/layouts/app.blade.php
-
12resources/views/layouts/guest.blade.php
-
8resources/views/layouts/partials/sidebar.blade.php
-
172resources/views/options/index-vue-div.blade.php
-
170resources/views/options/index-vue.blade.php
-
71resources/views/projects/features-export.blade.php
-
41resources/views/projects/features.blade.php
-
3resources/views/projects/partials/nav-tabs.blade.php
-
4tests/ManageProjectsTest.php
@ -0,0 +1,61 @@ |
|||
<?php |
|||
|
|||
/** |
|||
* Vue js Trial |
|||
*/ |
|||
/** Index Page */ |
|||
Route::get('options-vue', function() { |
|||
return view('options.index-vue'); |
|||
}); |
|||
|
|||
Route::group(['prefix'=>'api/options'], function() { |
|||
Route::match(['GET','POST'], '/', function() { |
|||
if (Request::isMethod('GET')) |
|||
return App\Entities\Options\Option::all(); |
|||
else { |
|||
return App\Entities\Options\Option::create(Request::only('key','value')); |
|||
} |
|||
}); |
|||
|
|||
Route::match(['GET','PATCH','DELETE'], '/{id}', function($id) { |
|||
if (Request::isMethod('GET')) |
|||
return App\Entities\Options\Option::findOrFail($id); |
|||
else if (Request::isMethod('PATCH')) { |
|||
App\Entities\Options\Option::findOrFail($id)->update(Request::only('key','value')); |
|||
return Response::json(Request::all()); |
|||
} else { |
|||
return App\Entities\Options\Option::destroy($id); |
|||
} |
|||
}); |
|||
}); |
|||
|
|||
// /** Fetch all options (API) */
|
|||
// Route::get('api/options', function() {
|
|||
// return App\Entities\Options\Option::all();
|
|||
// });
|
|||
|
|||
// /** Create new options (API) */
|
|||
// use App\Http\Requests\Options\CreateRequest;
|
|||
// Route::post('api/options', function(CreateRequest $req) {
|
|||
// return App\Entities\Options\Option::create($req->only('key','value'));
|
|||
// });
|
|||
|
|||
// /** get one option (API) */
|
|||
// Route::get('api/options/{id}', function($id) {
|
|||
// return App\Entities\Options\Option::findOrFail($id);
|
|||
// });
|
|||
|
|||
// /** update one option (API) */
|
|||
// use Illuminate\Http\Request;
|
|||
// Route::patch('api/options/{id}', function(Request $req, $id) {
|
|||
// return App\Entities\Options\Option::findOrFail($id)->update($req->only('key','value'));
|
|||
// });
|
|||
|
|||
// /** delete one option (API) */
|
|||
// Route::delete('api/options/{id}', function($id) {
|
|||
// App\Entities\Options\Option::destroy($id);
|
|||
// return 'ok';
|
|||
// });
|
|||
|
|||
|
|||
/** end of Vue js Trial */ |
|||
@ -0,0 +1,691 @@ |
|||
<?php |
|||
|
|||
return array( |
|||
|
|||
'cache' => array( |
|||
|
|||
/* |
|||
|-------------------------------------------------------------------------- |
|||
| Enable/Disable cell caching |
|||
|-------------------------------------------------------------------------- |
|||
*/ |
|||
'enable' => true, |
|||
|
|||
/* |
|||
|-------------------------------------------------------------------------- |
|||
| Caching driver |
|||
|-------------------------------------------------------------------------- |
|||
| |
|||
| Set the caching driver |
|||
| |
|||
| Available methods: |
|||
| memory|gzip|serialized|igbinary|discISAM|apc|memcache|temp|wincache|sqlite|sqlite3 |
|||
| |
|||
*/ |
|||
'driver' => 'memory', |
|||
|
|||
/* |
|||
|-------------------------------------------------------------------------- |
|||
| Cache settings |
|||
|-------------------------------------------------------------------------- |
|||
*/ |
|||
'settings' => array( |
|||
|
|||
'memoryCacheSize' => '32MB', |
|||
'cacheTime' => 600 |
|||
|
|||
), |
|||
|
|||
/* |
|||
|-------------------------------------------------------------------------- |
|||
| Memcache settings |
|||
|-------------------------------------------------------------------------- |
|||
*/ |
|||
'memcache' => array( |
|||
|
|||
'host' => 'localhost', |
|||
'port' => 11211, |
|||
|
|||
), |
|||
|
|||
/* |
|||
|-------------------------------------------------------------------------- |
|||
| Cache dir (for discISAM) |
|||
|-------------------------------------------------------------------------- |
|||
*/ |
|||
|
|||
'dir' => storage_path('cache') |
|||
), |
|||
|
|||
'properties' => array( |
|||
'creator' => 'Nafies Luthfi', |
|||
'lastModifiedBy' => 'Nafies Luthfi', |
|||
'title' => 'Spreadsheet', |
|||
'description' => 'Default spreadsheet export', |
|||
'subject' => 'Spreadsheet export', |
|||
'keywords' => 'maatwebsite, excel, export', |
|||
'category' => 'Excel', |
|||
'manager' => 'Nafies Luthfi', |
|||
'company' => 'JasaWebsiteBanjarmasin.com', |
|||
), |
|||
|
|||
/* |
|||
|-------------------------------------------------------------------------- |
|||
| Sheets settings |
|||
|-------------------------------------------------------------------------- |
|||
*/ |
|||
'sheets' => array( |
|||
|
|||
/* |
|||
|-------------------------------------------------------------------------- |
|||
| Default page setup |
|||
|-------------------------------------------------------------------------- |
|||
*/ |
|||
'pageSetup' => array( |
|||
'orientation' => 'portrait', |
|||
'paperSize' => '9', |
|||
'scale' => '100', |
|||
'fitToPage' => false, |
|||
'fitToHeight' => true, |
|||
'fitToWidth' => true, |
|||
'columnsToRepeatAtLeft' => array('', ''), |
|||
'rowsToRepeatAtTop' => array(0, 0), |
|||
'horizontalCentered' => false, |
|||
'verticalCentered' => false, |
|||
'printArea' => null, |
|||
'firstPageNumber' => null, |
|||
), |
|||
), |
|||
|
|||
/* |
|||
|-------------------------------------------------------------------------- |
|||
| Creator |
|||
|-------------------------------------------------------------------------- |
|||
| |
|||
| The default creator of a new Excel file |
|||
| |
|||
*/ |
|||
|
|||
'creator' => 'Maatwebsite', |
|||
|
|||
'csv' => array( |
|||
/* |
|||
|-------------------------------------------------------------------------- |
|||
| Delimiter |
|||
|-------------------------------------------------------------------------- |
|||
| |
|||
| The default delimiter which will be used to read out a CSV file |
|||
| |
|||
*/ |
|||
|
|||
'delimiter' => ',', |
|||
|
|||
/* |
|||
|-------------------------------------------------------------------------- |
|||
| Enclosure |
|||
|-------------------------------------------------------------------------- |
|||
*/ |
|||
|
|||
'enclosure' => '"', |
|||
|
|||
/* |
|||
|-------------------------------------------------------------------------- |
|||
| Line endings |
|||
|-------------------------------------------------------------------------- |
|||
*/ |
|||
|
|||
'line_ending' => "\r\n", |
|||
|
|||
/* |
|||
|-------------------------------------------------------------------------- |
|||
| setUseBom |
|||
|-------------------------------------------------------------------------- |
|||
*/ |
|||
|
|||
'use_bom' => false |
|||
), |
|||
|
|||
'export' => array( |
|||
|
|||
/* |
|||
|-------------------------------------------------------------------------- |
|||
| Autosize columns |
|||
|-------------------------------------------------------------------------- |
|||
| |
|||
| Disable/enable column autosize or set the autosizing for |
|||
| an array of columns ( array('A', 'B') ) |
|||
| |
|||
*/ |
|||
'autosize' => true, |
|||
|
|||
/* |
|||
|-------------------------------------------------------------------------- |
|||
| Autosize method |
|||
|-------------------------------------------------------------------------- |
|||
| |
|||
| --> PHPExcel_Shared_Font::AUTOSIZE_METHOD_APPROX |
|||
| The default is based on an estimate, which does its calculation based |
|||
| on the number of characters in the cell value (applying any calculation |
|||
| and format mask, and allowing for wordwrap and rotation) and with an |
|||
| "arbitrary" adjustment based on the font (Arial, Calibri or Verdana, |
|||
| defaulting to Calibri if any other font is used) and a proportional |
|||
| adjustment for the font size. |
|||
| |
|||
| --> PHPExcel_Shared_Font::AUTOSIZE_METHOD_EXACT |
|||
| The second method is more accurate, based on actual style formatting as |
|||
| well (bold, italic, etc), and is calculated by generating a gd2 imagettf |
|||
| bounding box and using its dimensions to determine the size; but this |
|||
| method is significantly slower, and its accuracy is still dependent on |
|||
| having the appropriate fonts installed. |
|||
| |
|||
*/ |
|||
'autosize-method' => PHPExcel_Shared_Font::AUTOSIZE_METHOD_APPROX, |
|||
|
|||
/* |
|||
|-------------------------------------------------------------------------- |
|||
| Auto generate table heading |
|||
|-------------------------------------------------------------------------- |
|||
| |
|||
| If set to true, the array indices (or model attribute names) |
|||
| will automatically be used as first row (table heading) |
|||
| |
|||
*/ |
|||
'generate_heading_by_indices' => true, |
|||
|
|||
/* |
|||
|-------------------------------------------------------------------------- |
|||
| Auto set alignment on merged cells |
|||
|-------------------------------------------------------------------------- |
|||
*/ |
|||
'merged_cell_alignment' => 'left', |
|||
|
|||
/* |
|||
|-------------------------------------------------------------------------- |
|||
| Pre-calculate formulas during export |
|||
|-------------------------------------------------------------------------- |
|||
*/ |
|||
'calculate' => false, |
|||
|
|||
/* |
|||
|-------------------------------------------------------------------------- |
|||
| Include Charts during export |
|||
|-------------------------------------------------------------------------- |
|||
*/ |
|||
'includeCharts' => false, |
|||
|
|||
/* |
|||
|-------------------------------------------------------------------------- |
|||
| Default sheet settings |
|||
|-------------------------------------------------------------------------- |
|||
*/ |
|||
'sheets' => array( |
|||
|
|||
/* |
|||
|-------------------------------------------------------------------------- |
|||
| Default page margin |
|||
|-------------------------------------------------------------------------- |
|||
| |
|||
| 1) When set to false, default margins will be used |
|||
| 2) It's possible to enter a single margin which will |
|||
| be used for all margins. |
|||
| 3) Alternatively you can pass an array with 4 margins |
|||
| Default order: array(top, right, bottom, left) |
|||
| |
|||
*/ |
|||
'page_margin' => false, |
|||
|
|||
/* |
|||
|-------------------------------------------------------------------------- |
|||
| Value in source array that stands for blank cell |
|||
|-------------------------------------------------------------------------- |
|||
*/ |
|||
'nullValue' => null, |
|||
|
|||
/* |
|||
|-------------------------------------------------------------------------- |
|||
| Insert array starting from this cell address as the top left coordinate |
|||
|-------------------------------------------------------------------------- |
|||
*/ |
|||
'startCell' => 'A1', |
|||
|
|||
/* |
|||
|-------------------------------------------------------------------------- |
|||
| Apply strict comparison when testing for null values in the array |
|||
|-------------------------------------------------------------------------- |
|||
*/ |
|||
'strictNullComparison' => false |
|||
), |
|||
|
|||
/* |
|||
|-------------------------------------------------------------------------- |
|||
| Store settings |
|||
|-------------------------------------------------------------------------- |
|||
*/ |
|||
|
|||
'store' => array( |
|||
|
|||
/* |
|||
|-------------------------------------------------------------------------- |
|||
| Path |
|||
|-------------------------------------------------------------------------- |
|||
| |
|||
| The path we want to save excel file to |
|||
| |
|||
*/ |
|||
'path' => storage_path('exports'), |
|||
|
|||
/* |
|||
|-------------------------------------------------------------------------- |
|||
| Return info |
|||
|-------------------------------------------------------------------------- |
|||
| |
|||
| Whether we want to return information about the stored file or not |
|||
| |
|||
*/ |
|||
'returnInfo' => false |
|||
|
|||
), |
|||
|
|||
/* |
|||
|-------------------------------------------------------------------------- |
|||
| PDF Settings |
|||
|-------------------------------------------------------------------------- |
|||
*/ |
|||
'pdf' => array( |
|||
|
|||
/* |
|||
|-------------------------------------------------------------------------- |
|||
| PDF Drivers |
|||
|-------------------------------------------------------------------------- |
|||
| Supported: DomPDF, tcPDF, mPDF |
|||
*/ |
|||
'driver' => 'DomPDF', |
|||
|
|||
/* |
|||
|-------------------------------------------------------------------------- |
|||
| PDF Driver settings |
|||
|-------------------------------------------------------------------------- |
|||
*/ |
|||
'drivers' => array( |
|||
|
|||
/* |
|||
|-------------------------------------------------------------------------- |
|||
| DomPDF settings |
|||
|-------------------------------------------------------------------------- |
|||
*/ |
|||
'DomPDF' => array( |
|||
'path' => base_path('vendor/dompdf/dompdf/') |
|||
), |
|||
|
|||
/* |
|||
|-------------------------------------------------------------------------- |
|||
| tcPDF settings |
|||
|-------------------------------------------------------------------------- |
|||
*/ |
|||
'tcPDF' => array( |
|||
'path' => base_path('vendor/tecnick.com/tcpdf/') |
|||
), |
|||
|
|||
/* |
|||
|-------------------------------------------------------------------------- |
|||
| mPDF settings |
|||
|-------------------------------------------------------------------------- |
|||
*/ |
|||
'mPDF' => array( |
|||
'path' => base_path('vendor/mpdf/mpdf/') |
|||
), |
|||
) |
|||
) |
|||
), |
|||
|
|||
'filters' => array( |
|||
/* |
|||
|-------------------------------------------------------------------------- |
|||
| Register read filters |
|||
|-------------------------------------------------------------------------- |
|||
*/ |
|||
|
|||
'registered' => array( |
|||
'chunk' => 'Maatwebsite\Excel\Filters\ChunkReadFilter' |
|||
), |
|||
|
|||
/* |
|||
|-------------------------------------------------------------------------- |
|||
| Enable certain filters for every file read |
|||
|-------------------------------------------------------------------------- |
|||
*/ |
|||
|
|||
'enabled' => array() |
|||
), |
|||
|
|||
'import' => array( |
|||
|
|||
/* |
|||
|-------------------------------------------------------------------------- |
|||
| Has heading |
|||
|-------------------------------------------------------------------------- |
|||
| |
|||
| The sheet has a heading (first) row which we can use as attribute names |
|||
| |
|||
| Options: true|false|slugged|slugged_with_count|ascii|numeric|hashed|trans|original |
|||
| |
|||
*/ |
|||
|
|||
'heading' => 'slugged', |
|||
|
|||
/* |
|||
|-------------------------------------------------------------------------- |
|||
| First Row with data or heading of data |
|||
|-------------------------------------------------------------------------- |
|||
| |
|||
| If the heading row is not the first row, or the data doesn't start |
|||
| on the first row, here you can change the start row. |
|||
| |
|||
*/ |
|||
|
|||
'startRow' => 1, |
|||
|
|||
/* |
|||
|-------------------------------------------------------------------------- |
|||
| Cell name word separator |
|||
|-------------------------------------------------------------------------- |
|||
| |
|||
| The default separator which is used for the cell names |
|||
| Note: only applies to 'heading' settings 'true' && 'slugged' |
|||
| |
|||
*/ |
|||
|
|||
'separator' => '_', |
|||
|
|||
/* |
|||
|-------------------------------------------------------------------------- |
|||
| Include Charts during import |
|||
|-------------------------------------------------------------------------- |
|||
*/ |
|||
|
|||
'includeCharts' => false, |
|||
|
|||
/* |
|||
|-------------------------------------------------------------------------- |
|||
| Sheet heading conversion |
|||
|-------------------------------------------------------------------------- |
|||
| |
|||
| Convert headings to ASCII |
|||
| Note: only applies to 'heading' settings 'true' && 'slugged' |
|||
| |
|||
*/ |
|||
|
|||
'to_ascii' => true, |
|||
|
|||
/* |
|||
|-------------------------------------------------------------------------- |
|||
| Import encoding |
|||
|-------------------------------------------------------------------------- |
|||
*/ |
|||
|
|||
'encoding' => array( |
|||
|
|||
'input' => 'UTF-8', |
|||
'output' => 'UTF-8' |
|||
|
|||
), |
|||
|
|||
/* |
|||
|-------------------------------------------------------------------------- |
|||
| Calculate |
|||
|-------------------------------------------------------------------------- |
|||
| |
|||
| By default cells with formulas will be calculated. |
|||
| |
|||
*/ |
|||
|
|||
'calculate' => true, |
|||
|
|||
/* |
|||
|-------------------------------------------------------------------------- |
|||
| Ignore empty cells |
|||
|-------------------------------------------------------------------------- |
|||
| |
|||
| By default empty cells are not ignored |
|||
| |
|||
*/ |
|||
|
|||
'ignoreEmpty' => false, |
|||
|
|||
/* |
|||
|-------------------------------------------------------------------------- |
|||
| Force sheet collection |
|||
|-------------------------------------------------------------------------- |
|||
| |
|||
| For a sheet collection even when there is only 1 sheets. |
|||
| When set to false and only 1 sheet found, the parsed file will return |
|||
| a row collection instead of a sheet collection. |
|||
| When set to true, it will return a sheet collection instead. |
|||
| |
|||
*/ |
|||
'force_sheets_collection' => false, |
|||
|
|||
/* |
|||
|-------------------------------------------------------------------------- |
|||
| Date format |
|||
|-------------------------------------------------------------------------- |
|||
| |
|||
| The format dates will be parsed to |
|||
| |
|||
*/ |
|||
|
|||
'dates' => array( |
|||
|
|||
/* |
|||
|-------------------------------------------------------------------------- |
|||
| Enable/disable date formatting |
|||
|-------------------------------------------------------------------------- |
|||
*/ |
|||
'enabled' => true, |
|||
|
|||
/* |
|||
|-------------------------------------------------------------------------- |
|||
| Default date format |
|||
|-------------------------------------------------------------------------- |
|||
| |
|||
| If set to false, a carbon object will return |
|||
| |
|||
*/ |
|||
'format' => false, |
|||
|
|||
/* |
|||
|-------------------------------------------------------------------------- |
|||
| Date columns |
|||
|-------------------------------------------------------------------------- |
|||
*/ |
|||
'columns' => array() |
|||
), |
|||
|
|||
/* |
|||
|-------------------------------------------------------------------------- |
|||
| Import sheets by config |
|||
|-------------------------------------------------------------------------- |
|||
*/ |
|||
'sheets' => array( |
|||
|
|||
/* |
|||
|-------------------------------------------------------------------------- |
|||
| Example sheet |
|||
|-------------------------------------------------------------------------- |
|||
| |
|||
| Example sheet "test" will grab the firstname at cell A2 |
|||
| |
|||
*/ |
|||
|
|||
'test' => array( |
|||
|
|||
'firstname' => 'A2' |
|||
|
|||
) |
|||
|
|||
) |
|||
), |
|||
|
|||
'views' => array( |
|||
|
|||
/* |
|||
|-------------------------------------------------------------------------- |
|||
| Styles |
|||
|-------------------------------------------------------------------------- |
|||
| |
|||
| The default styles which will be used when parsing a view |
|||
| |
|||
*/ |
|||
|
|||
'styles' => array( |
|||
|
|||
/* |
|||
|-------------------------------------------------------------------------- |
|||
| Table headings |
|||
|-------------------------------------------------------------------------- |
|||
*/ |
|||
'th' => array( |
|||
'font' => array( |
|||
'bold' => true, |
|||
'size' => 12, |
|||
) |
|||
), |
|||
|
|||
/* |
|||
|-------------------------------------------------------------------------- |
|||
| Strong tags |
|||
|-------------------------------------------------------------------------- |
|||
*/ |
|||
'strong' => array( |
|||
'font' => array( |
|||
'bold' => true, |
|||
'size' => 12, |
|||
) |
|||
), |
|||
|
|||
/* |
|||
|-------------------------------------------------------------------------- |
|||
| Bold tags |
|||
|-------------------------------------------------------------------------- |
|||
*/ |
|||
'b' => array( |
|||
'font' => array( |
|||
'bold' => true, |
|||
'size' => 12, |
|||
) |
|||
), |
|||
|
|||
/* |
|||
|-------------------------------------------------------------------------- |
|||
| Italic tags |
|||
|-------------------------------------------------------------------------- |
|||
*/ |
|||
'i' => array( |
|||
'font' => array( |
|||
'italic' => true, |
|||
'size' => 12, |
|||
) |
|||
), |
|||
|
|||
/* |
|||
|-------------------------------------------------------------------------- |
|||
| Heading 1 |
|||
|-------------------------------------------------------------------------- |
|||
*/ |
|||
'h1' => array( |
|||
'font' => array( |
|||
'bold' => true, |
|||
'size' => 24, |
|||
) |
|||
), |
|||
|
|||
/* |
|||
|-------------------------------------------------------------------------- |
|||
| Heading 2 |
|||
|-------------------------------------------------------------------------- |
|||
*/ |
|||
'h2' => array( |
|||
'font' => array( |
|||
'bold' => true, |
|||
'size' => 18, |
|||
) |
|||
), |
|||
|
|||
/* |
|||
|-------------------------------------------------------------------------- |
|||
| Heading 2 |
|||
|-------------------------------------------------------------------------- |
|||
*/ |
|||
'h3' => array( |
|||
'font' => array( |
|||
'bold' => true, |
|||
'size' => 13.5, |
|||
) |
|||
), |
|||
|
|||
/* |
|||
|-------------------------------------------------------------------------- |
|||
| Heading 4 |
|||
|-------------------------------------------------------------------------- |
|||
*/ |
|||
'h4' => array( |
|||
'font' => array( |
|||
'bold' => true, |
|||
'size' => 12, |
|||
) |
|||
), |
|||
|
|||
/* |
|||
|-------------------------------------------------------------------------- |
|||
| Heading 5 |
|||
|-------------------------------------------------------------------------- |
|||
*/ |
|||
'h5' => array( |
|||
'font' => array( |
|||
'bold' => true, |
|||
'size' => 10, |
|||
) |
|||
), |
|||
|
|||
/* |
|||
|-------------------------------------------------------------------------- |
|||
| Heading 6 |
|||
|-------------------------------------------------------------------------- |
|||
*/ |
|||
'h6' => array( |
|||
'font' => array( |
|||
'bold' => true, |
|||
'size' => 7.5, |
|||
) |
|||
), |
|||
|
|||
/* |
|||
|-------------------------------------------------------------------------- |
|||
| Hyperlinks |
|||
|-------------------------------------------------------------------------- |
|||
*/ |
|||
'a' => array( |
|||
'font' => array( |
|||
'underline' => true, |
|||
'color' => array('argb' => 'FF0000FF'), |
|||
) |
|||
), |
|||
|
|||
/* |
|||
|-------------------------------------------------------------------------- |
|||
| Horizontal rules |
|||
|-------------------------------------------------------------------------- |
|||
*/ |
|||
'hr' => array( |
|||
'borders' => array( |
|||
'bottom' => array( |
|||
'style' => 'thin', |
|||
'color' => array('FF000000') |
|||
), |
|||
) |
|||
) |
|||
) |
|||
|
|||
) |
|||
|
|||
); |
|||
@ -0,0 +1,172 @@ |
|||
@extends('layouts.guest') |
|||
|
|||
@section('content') |
|||
<h1 class="page-header">Options</h1> |
|||
|
|||
<div id="vue-el"> |
|||
<div class="row"> |
|||
<div class="col-md-8"> |
|||
<!-- <div class="alert alert-success" transition="success" v-if="add_success">Add new option success.</div> |
|||
<div class="alert alert-success" transition="success" v-if="update_success">Update option success.</div> --> |
|||
<div class="row"> |
|||
<div class="col-md-1">ID</div> |
|||
<div class="col-md-4">Key</div> |
|||
<div class="col-md-5">Value</div> |
|||
<div class="col-md-2">Option</div> |
|||
</div> |
|||
<div class="row" v-for="option in options"> |
|||
<options-row :option="option" :options="options"></options-row> |
|||
</div> |
|||
<div class="row"> |
|||
<options-new :newOption="newOption" :options="options"></options-new> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<template id="option-row-template"> |
|||
<div v-show="!inEditMode"> |
|||
<div class="col-md-1">@{{ option.id }}</div> |
|||
<div class="col-md-4">@{{ option.key }}</div> |
|||
<div class="col-md-5">@{{ option.value }}</div> |
|||
<div class="col-md-2"> |
|||
<button class="btn btn-info btn-xs" v-on:click="editForm">Edit</button> |
|||
</div> |
|||
</div> |
|||
<div v-show="inEditMode"> |
|||
<div class="col-md-1">@{{ option.id }}</div> |
|||
<div class="col-md-4"> |
|||
<input v-model="option.key" v-on:keyup.esc="cancelEditMode" type="text" class="form-control" /> |
|||
</div> |
|||
<div class="col-md-5"> |
|||
<input v-model="option.value" v-on:keyup.esc="cancelEditMode" type="text" class="form-control" /> |
|||
</div> |
|||
<div class="col-md-2"> |
|||
<button class="btn btn-info btn-xs" v-on:click="update(option)">update</button> |
|||
<button class="btn btn-danger btn-xs" v-on:click="deleteOpt(option)">x</button> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<template id="option-new-template"> |
|||
<form action="#" method="post" v-on:submit.prevent="addNewOption"> |
|||
<div class="col-md-1"> </div> |
|||
<div class="col-md-4"> |
|||
<input type="text" id="key" name="key" class="form-control" v-model="newOption.key" placeholder="Add new Option key"> |
|||
</div> |
|||
<div class="col-md-5"> |
|||
<textarea id="value" name="value" class="form-control" v-model="newOption.value" placeholder="Add new Option value"></textarea> |
|||
</div> |
|||
<div class="col-md-2"> |
|||
<input type="submit" value="Submit" class="btn btn-success"> |
|||
</div> |
|||
</form> |
|||
</template> |
|||
|
|||
@endsection |
|||
@section('ext_js') |
|||
{!! Html::script(url('assets/js/plugins/vue.min.js')) !!} |
|||
{!! Html::script(url('assets/js/plugins/vue-resource.min.js')) !!} |
|||
@endsection |
|||
@section('script') |
|||
<script> |
|||
|
|||
Vue.component('options-row', { |
|||
data: function() { |
|||
return { |
|||
inEditMode: false |
|||
} |
|||
}, |
|||
props: ['option','options'], |
|||
template: '#option-row-template', |
|||
methods: { |
|||
editForm: function() { |
|||
this.inEditMode = true; |
|||
}, |
|||
update: function(option) { |
|||
this.$http.patch('api/options/' + option.id, option); |
|||
|
|||
this.inEditMode = false; |
|||
}, |
|||
cancelEditMode: function() { |
|||
this.inEditMode = false; |
|||
}, |
|||
deleteOpt: function(option) { |
|||
var confirmBox = confirm('Delete this option?'); |
|||
|
|||
if (confirmBox) { |
|||
this.$http.delete('api/options/' + option.id); |
|||
// console.log (this.options);
|
|||
this.options.$remove(option); |
|||
// this.options.splice(id, 1);
|
|||
// console.log (this.options);
|
|||
// this.fetchOptions();
|
|||
} |
|||
|
|||
this.inEditMode = false; |
|||
} |
|||
} |
|||
}); |
|||
|
|||
Vue.component('options-new', { |
|||
data: function() { |
|||
return { |
|||
newOption: { |
|||
key: '', |
|||
value: '' |
|||
} |
|||
} |
|||
}, |
|||
props: ['options'], |
|||
template: '#option-new-template', |
|||
|
|||
methods: { |
|||
addNewOption: function() { |
|||
// New Option Input
|
|||
var option = this.newOption; |
|||
|
|||
// Clear form
|
|||
this.newOption = { key: '', value: '' } |
|||
|
|||
// Send post request
|
|||
this.$http.post('api/options', option, function(data) { |
|||
this.options.push(data); |
|||
}); |
|||
} |
|||
} |
|||
}); |
|||
|
|||
var vm = new Vue({ |
|||
http: { |
|||
headers: { |
|||
'X-CSRF-Token': "{{ csrf_token() }}" |
|||
} |
|||
}, |
|||
|
|||
el: "#vue-el", |
|||
|
|||
methods: { |
|||
fetchOptions: function() { |
|||
this.$http.get('api/options', function(data) { |
|||
this.$set('options', data); |
|||
}); |
|||
} |
|||
}, |
|||
|
|||
ready: function() { |
|||
this.fetchOptions(); |
|||
} |
|||
}); |
|||
</script> |
|||
@endsection |
|||
|
|||
@section('style') |
|||
<style> |
|||
.success-transition { |
|||
transition: all .5s ease-in-out; |
|||
} |
|||
.success-enter, .success-leave { |
|||
opacity: 0; |
|||
} |
|||
</style> |
|||
@endsection |
|||
@ -0,0 +1,170 @@ |
|||
@extends('layouts.guest') |
|||
|
|||
@section('content') |
|||
<h1 class="page-header">Options</h1> |
|||
|
|||
<div id="vue-el"> |
|||
<div class="row"> |
|||
<div class="col-md-8"> |
|||
<div class="row"> |
|||
<div class="col-md-1">ID</div> |
|||
<div class="col-md-4">Key</div> |
|||
<div class="col-md-5">Value</div> |
|||
<div class="col-md-2">Option</div> |
|||
</div> |
|||
<div class="row" v-for="option in options"> |
|||
<options-row :option="option" :options="options"></options-row> |
|||
</div> |
|||
<div class="row"> |
|||
<options-new :newOption="newOption" :options="options"></options-new> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<template id="option-row-template"> |
|||
<div v-show="!inEditMode"> |
|||
<div class="col-md-1">@{{ option.id }}</div> |
|||
<div class="col-md-4">@{{ option.key }}</div> |
|||
<div class="col-md-5">@{{ option.value }}</div> |
|||
<div class="col-md-2"> |
|||
<button class="btn btn-info btn-xs" v-on:click="editForm">Edit</button> |
|||
</div> |
|||
</div> |
|||
<div v-show="inEditMode"> |
|||
<div class="col-md-1">@{{ option.id }}</div> |
|||
<div class="col-md-4"> |
|||
<input v-model="option.key" v-on:keyup.esc="cancelEditMode" type="text" class="form-control" /> |
|||
</div> |
|||
<div class="col-md-5"> |
|||
<input v-model="option.value" v-on:keyup.esc="cancelEditMode" type="text" class="form-control" /> |
|||
</div> |
|||
<div class="col-md-2"> |
|||
<button class="btn btn-info btn-xs" v-on:click="update(option)">update</button> |
|||
<button class="btn btn-danger btn-xs" v-on:click="deleteOpt(option)">x</button> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<template id="option-new-template"> |
|||
<form action="#" method="post" v-on:submit.prevent="addNewOption"> |
|||
<div class="col-md-1"> </div> |
|||
<div class="col-md-4"> |
|||
<input type="text" id="key" name="key" class="form-control" v-model="newOption.key" placeholder="Add new Option key"> |
|||
</div> |
|||
<div class="col-md-5"> |
|||
<textarea id="value" name="value" class="form-control" v-model="newOption.value" placeholder="Add new Option value"></textarea> |
|||
</div> |
|||
<div class="col-md-2"> |
|||
<input type="submit" value="Submit" class="btn btn-success"> |
|||
</div> |
|||
</form> |
|||
</template> |
|||
|
|||
@endsection |
|||
@section('ext_js') |
|||
{!! Html::script(url('assets/js/plugins/vue.min.js')) !!} |
|||
{!! Html::script(url('assets/js/plugins/vue-resource.min.js')) !!} |
|||
@endsection |
|||
@section('script') |
|||
<script> |
|||
|
|||
Vue.component('options-row', { |
|||
data: function() { |
|||
return { |
|||
inEditMode: false |
|||
} |
|||
}, |
|||
props: ['option','options'], |
|||
template: '#option-row-template', |
|||
methods: { |
|||
editForm: function() { |
|||
this.inEditMode = true; |
|||
}, |
|||
update: function(option) { |
|||
this.$http.patch('api/options/' + option.id, option); |
|||
|
|||
this.inEditMode = false; |
|||
}, |
|||
cancelEditMode: function() { |
|||
this.inEditMode = false; |
|||
}, |
|||
deleteOpt: function(option) { |
|||
var confirmBox = confirm('Delete this option?'); |
|||
|
|||
if (confirmBox) { |
|||
this.$http.delete('api/options/' + option.id); |
|||
// console.log (this.options);
|
|||
this.options.$remove(option); |
|||
// this.options.splice(id, 1);
|
|||
// console.log (this.options);
|
|||
// this.fetchOptions();
|
|||
} |
|||
|
|||
this.inEditMode = false; |
|||
} |
|||
} |
|||
}); |
|||
|
|||
Vue.component('options-new', { |
|||
data: function() { |
|||
return { |
|||
newOption: { |
|||
key: '', |
|||
value: '' |
|||
} |
|||
} |
|||
}, |
|||
props: ['options'], |
|||
template: '#option-new-template', |
|||
|
|||
methods: { |
|||
addNewOption: function() { |
|||
// New Option Input
|
|||
var option = this.newOption; |
|||
|
|||
// Clear form
|
|||
this.newOption = { key: '', value: '' } |
|||
|
|||
// Send post request
|
|||
this.$http.post('api/options', option, function(data) { |
|||
this.options.push(data); |
|||
}); |
|||
} |
|||
} |
|||
}); |
|||
|
|||
var vm = new Vue({ |
|||
http: { |
|||
headers: { |
|||
'X-CSRF-Token': "{{ csrf_token() }}" |
|||
} |
|||
}, |
|||
|
|||
el: "#vue-el", |
|||
|
|||
methods: { |
|||
fetchOptions: function() { |
|||
this.$http.get('api/options', function(data) { |
|||
this.$set('options', data); |
|||
}); |
|||
} |
|||
}, |
|||
|
|||
ready: function() { |
|||
this.fetchOptions(); |
|||
} |
|||
}); |
|||
</script> |
|||
@endsection |
|||
|
|||
@section('style') |
|||
<style> |
|||
.success-transition { |
|||
transition: all .5s ease-in-out; |
|||
} |
|||
.success-enter, .success-leave { |
|||
opacity: 0; |
|||
} |
|||
</style> |
|||
@endsection |
|||
@ -0,0 +1,71 @@ |
|||
<?php |
|||
// $filename = str_slug(trans('project.features') . '-' . $project->name) . '.xls';
|
|||
// header("Content-Disposition: attachment; filename=\"$filename\"");
|
|||
// header("Content-Type: application/vnd.ms-excel");
|
|||
?>
|
|||
<!DOCTYPE html> |
|||
<html> |
|||
<head> |
|||
<meta charset="utf-8"> |
|||
{{-- <meta http-equiv="X-UA-Compatible" content="IE=edge"> --}} |
|||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> |
|||
<title>{{ $project->name }}</title> |
|||
<style> |
|||
th, td { |
|||
padding: 5px; |
|||
} |
|||
</style> |
|||
</head> |
|||
<body> |
|||
<table border="1" class="table table-condensed table-striped"> |
|||
<thead> |
|||
<tr> |
|||
<td colspan="4" style="text-align:center"> |
|||
<h1>{{ trans('project.features') }} {{ $project->name }}</h1> |
|||
</td> |
|||
</tr> |
|||
<tr> |
|||
<th>{{ trans('app.table_no') }}</th> |
|||
<th>{{ trans('feature.name') }}</th> |
|||
{{-- <th class="text-center">{{ trans('feature.progress') }}</th> --}} |
|||
<th class="text-right">{{ trans('feature.price') }}</th> |
|||
<th>{{ trans('app.notes') }}</th> |
|||
</tr> |
|||
</thead> |
|||
<tbody id="sort-features"> |
|||
@forelse($features as $key => $feature) |
|||
<tr> |
|||
<td rowspan="{{ $feature->tasks->count() + 1 }}">{{ 1 + $key }}</td> |
|||
<td> |
|||
{{ $feature->name }} |
|||
</td> |
|||
{{-- <td class="text-center">{{ formatDecimal($feature->progress = $feature->tasks->avg('progress')) }} %</td> --}} |
|||
<td rowspan="{{ $feature->tasks->count() + 1 }}" class="text-right">{{ $feature->price }}</td> |
|||
<td style="wrap-text: true;">{!! nl2br($feature->description) !!}</td> |
|||
</tr> |
|||
|
|||
@if ($feature->tasks->count()) |
|||
@foreach($feature->tasks as $task) |
|||
<tr> |
|||
<td></td> |
|||
<td>{{ $task->name }}</td> |
|||
<td></td> |
|||
<td style="wrap-text: true;">{!! nl2br($task->description) !!}</td> |
|||
</tr> |
|||
@endforeach |
|||
@endif |
|||
@empty |
|||
<tr><td colspan="7">{{ trans('feature.empty') }}</td></tr> |
|||
@endforelse |
|||
</tbody> |
|||
<tfoot> |
|||
<tr> |
|||
<th class="text-right" colspan="2">Total</th> |
|||
{{-- <th class="text-center">{{ formatDecimal($features->avg('progress')) }} %</th> --}} |
|||
<th class="text-right">{{ $features->sum('price') }}</th> |
|||
<th></th> |
|||
</tr> |
|||
</tfoot> |
|||
</table> |
|||
</body> |
|||
</html> |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue