Claim dms upload file with drag & drop #1731
gitea/salix/dev There was a failure building this commit Details

This commit is contained in:
Joan Sanchez 2019-09-30 14:57:54 +02:00
parent 0573fec950
commit 6d54e7a89d
19 changed files with 200 additions and 757 deletions

View File

@ -2,6 +2,7 @@ vn-icon-menu {
cursor: pointer; cursor: pointer;
vn-drop-down { vn-drop-down {
font-family: 'vn-font' font-family: 'vn-font';
outline: 0
} }
} }

View File

@ -1,5 +1,5 @@
import ngModule from '../module'; import ngModule from '../module';
import './droppable.scss';
export function directive($parse) { export function directive($parse) {
return { return {
@ -22,7 +22,7 @@ export function directive($parse) {
* Enter droppable area event * Enter droppable area event
*/ */
element.addEventListener('dragenter', event => { element.addEventListener('dragenter', event => {
element.style.backgroundColor = 'yellow'; element.classList.add('active');
event.stopImmediatePropagation(); event.stopImmediatePropagation();
event.preventDefault(); event.preventDefault();
@ -33,7 +33,7 @@ export function directive($parse) {
* Exit droppable area event * Exit droppable area event
*/ */
element.addEventListener('dragleave', event => { element.addEventListener('dragleave', event => {
element.style.backgroundColor = 'transparent'; element.classList.remove('active');
event.stopImmediatePropagation(); event.stopImmediatePropagation();
event.preventDefault(); event.preventDefault();
@ -52,37 +52,12 @@ export function directive($parse) {
* Fires when a drop events * Fires when a drop events
*/ */
element.addEventListener('drop', event => { element.addEventListener('drop', event => {
const draggedParent = this.dragged.parentNode; element.classList.remove('active');
const targetChild = element.querySelector('ul');
onDropEvent($scope, {event});
element.style.transition = 'background 2s'; event.stopPropagation();
element.style.backgroundColor = 'transparent'; event.preventDefault();
if (this.dragged === element)
return event.preventDefault();
if (targetChild) {
const targetNodes = targetChild.querySelectorAll('li');
const before = targetNodes[targetNodes.length - 1];
targetChild.insertBefore(this.dragged, before);
} else
draggedParent.removeChild(this.dragged);
onDropEvent($scope, {
dragged: {
element: this.dragged,
scope: angular.element(this.dragged).scope()
},
dropped: {
element: element,
scope: angular.element(element).scope()
}
});
event.stopImmediatePropagation();
}); });
} }
}; };

View File

@ -0,0 +1,11 @@
@import "./variables";
[vn-droppable] {
border: 2px dashed transparent;
transition: all 0.5s;
&.active {
background-color: $color-hover-cd;
border: 2px dashed $color-bg-dark;
}
}

View File

@ -5,6 +5,7 @@ body {
overflow: auto; overflow: auto;
} }
vn-app { vn-app {
height: inherit;
display: block; display: block;
& > vn-topbar { & > vn-topbar {
@ -50,11 +51,16 @@ vn-app {
} }
} }
& > .main-view { & > .main-view {
box-sizing: border-box;
height: inherit;
&.padding { &.padding {
padding-top: $topbar-height; padding-top: $topbar-height;
} }
.content-block { .content-block {
margin: $margin-medium; box-sizing: border-box;
padding: $pad-medium;
height: inherit;
form vn-horizontal { form vn-horizontal {
align-items: center; align-items: center;
@ -68,6 +74,7 @@ vn-app {
display: block; display: block;
margin: 0 auto; margin: 0 auto;
padding-left: $menu-width; padding-left: $menu-width;
height: 100%
} }
.main-with-right-menu { .main-with-right-menu {

View File

@ -1,71 +0,0 @@
<vn-watcher
vn-id="watcher"
data="$ctrl.dms">
</vn-watcher>
<form name="form" ng-submit="$ctrl.onSubmit()" margin-medium enctype="multipart/form-data">
<div compact>
<vn-card pad-large>
<vn-horizontal>
<vn-textfield vn-one vn-focus
label="Reference"
field="$ctrl.dms.reference">
</vn-textfield>
<vn-autocomplete vn-one
label="Company"
field="$ctrl.dms.companyId"
url="/api/Companies"
show-field="code"
value-field="id">
</vn-autocomplete>
</vn-horizontal>
<vn-horizontal>
<vn-autocomplete vn-one
label="Warehouse"
field="$ctrl.dms.warehouseId"
url="/api/Warehouses"
show-field="name"
value-field="id">
</vn-autocomplete>
<vn-autocomplete vn-one
label="Type"
field="$ctrl.dms.dmsTypeId"
url="/api/DmsTypes"
show-field="name"
value-field="id">
</vn-autocomplete>
</vn-horizontal>
<vn-horizontal>
<vn-textarea vn-one
label="Description"
field="$ctrl.dms.description">
</vn-textarea>
</vn-horizontal>
<vn-horizontal>
<vn-input-file vn-one
label="File"
model="$ctrl.dms.files"
on-change="$ctrl.onFileChange(files)"
accept="{{$ctrl.allowedContentTypes}}"
multiple="true">
<t-right-icons>
<vn-icon vn-none
color-secondary
title="{{$ctrl.contentTypesInfo}}"
icon="info">
</vn-icon>
</t-right-icons>
</vn-input-file>
</vn-horizontal>
<vn-vertical>
<vn-check
label="Generate identifier for original file"
field="$ctrl.dms.hasFile">
</vn-check>
</vn-vertical>
</vn-card>
<vn-button-bar>
<vn-submit label="Upload"></vn-submit>
<vn-button ui-sref="claim.card.dms.index" label="Cancel"></vn-button>
</vn-button-bar>
</div>
</form>

View File

@ -1,115 +0,0 @@
import ngModule from '../../module';
import './style.scss';
class Controller {
constructor($scope, $http, $state, $translate, vnApp) {
this.$ = $scope;
this.$http = $http;
this.$state = $state;
this.$translate = $translate;
this.vnApp = vnApp;
this.dms = {
files: [],
hasFile: false,
hasFileAttached: false
};
}
get claim() {
return this._claim;
}
set claim(value) {
this._claim = value;
if (value) {
this.setDefaultParams();
this.getAllowedContentTypes();
}
}
getAllowedContentTypes() {
this.$http.get('/api/claimDms/allowedContentTypes').then(res => {
const contentTypes = res.data.join(', ');
this.allowedContentTypes = contentTypes;
});
}
get contentTypesInfo() {
return this.$translate.instant('ContentTypesInfo', {
allowedContentTypes: this.allowedContentTypes
});
}
setDefaultParams() {
const params = {filter: {
where: {code: 'claim'}
}};
this.$http.get('/api/DmsTypes/findOne', {params}).then(res => {
const dmsTypeId = res.data && res.data.id;
const companyId = window.localStorage.defaultCompanyFk;
const warehouseId = window.localStorage.defaultWarehouseFk;
const defaultParams = {
reference: this.claim.id,
warehouseId: warehouseId,
companyId: companyId,
dmsTypeId: dmsTypeId,
description: this.$translate.instant('FileDescription', {
claimId: this.claim.id,
clientId: this.claim.client.id,
clientName: this.claim.client.name
}).toUpperCase()
};
this.dms = Object.assign(this.dms, defaultParams);
});
}
onSubmit() {
const query = `/api/claims/${this.claim.id}/uploadFile`;
const options = {
method: 'POST',
url: query,
params: this.dms,
headers: {
'Content-Type': undefined
},
transformRequest: files => {
const formData = new FormData();
for (let i = 0; i < files.length; i++)
formData.append(files[i].name, files[i]);
return formData;
},
data: this.dms.files
};
this.$http(options).then(res => {
if (res) {
this.vnApp.showSuccess(this.$translate.instant('Data saved!'));
this.$.watcher.updateOriginalData();
this.$state.go('claim.card.dms.index');
}
});
}
onFileChange(files) {
let hasFileAttached = false;
if (files.length > 0)
hasFileAttached = true;
this.$.$applyAsync(() => {
this.dms.hasFileAttached = hasFileAttached;
});
}
}
Controller.$inject = ['$scope', '$http', '$state', '$translate', 'vnApp'];
ngModule.component('vnClaimDmsCreate', {
template: require('./index.html'),
controller: Controller,
bindings: {
claim: '<'
}
});

View File

@ -1,83 +0,0 @@
import './index';
describe('Claim', () => {
describe('Component vnClaimDmsCreate', () => {
let controller;
let $scope;
let $httpBackend;
let $httpParamSerializer;
beforeEach(angular.mock.module('claim', $translateProvider => {
$translateProvider.translations('en', {});
}));
beforeEach(angular.mock.inject(($componentController, $rootScope, _$httpBackend_, _$httpParamSerializer_) => {
$scope = $rootScope.$new();
$httpBackend = _$httpBackend_;
$httpParamSerializer = _$httpParamSerializer_;
controller = $componentController('vnClaimDmsCreate', {$scope});
controller._claim = {
id: 15,
client: {id: 101, name: 'Bruce wayne'},
ticketFk: 16
};
}));
describe('claim() setter', () => {
it('should set the claim data and then call setDefaultParams() and getAllowedContentTypes()', () => {
spyOn(controller, 'setDefaultParams');
spyOn(controller, 'getAllowedContentTypes');
controller._claim = undefined;
controller.claim = {
id: 15,
client: {id: 101, name: 'Bruce wayne'},
ticketFk: 16
};
expect(controller.claim).toBeDefined();
expect(controller.setDefaultParams).toHaveBeenCalledWith();
expect(controller.getAllowedContentTypes).toHaveBeenCalledWith();
});
});
describe('setDefaultParams()', () => {
it('should perform a GET query and define the dms property on controller', () => {
const params = {filter: {
where: {code: 'claim'}
}};
let serializedParams = $httpParamSerializer(params);
$httpBackend.when('GET', `/api/DmsTypes/findOne?${serializedParams}`).respond({id: 14, code: 'claim'});
$httpBackend.expect('GET', `/api/DmsTypes/findOne?${serializedParams}`);
controller.setDefaultParams();
$httpBackend.flush();
expect(controller.dms).toBeDefined();
expect(controller.dms.reference).toEqual(15);
expect(controller.dms.dmsTypeId).toEqual(14);
});
});
describe('onFileChange()', () => {
it('should set dms hasFileAttached property to true if has any files', () => {
const files = [{id: 1, name: 'MyFile'}];
controller.onFileChange(files);
$scope.$apply();
expect(controller.dms.hasFileAttached).toBeTruthy();
});
});
describe('getAllowedContentTypes()', () => {
it('should make an HTTP GET request to get the allowed content types', () => {
const expectedResponse = ['image/png', 'image/jpg'];
$httpBackend.when('GET', `/api/claimDms/allowedContentTypes`).respond(expectedResponse);
$httpBackend.expect('GET', `/api/claimDms/allowedContentTypes`);
controller.getAllowedContentTypes();
$httpBackend.flush();
expect(controller.allowedContentTypes).toBeDefined();
expect(controller.allowedContentTypes).toEqual('image/png, image/jpg');
});
});
});
});

View File

@ -1,7 +0,0 @@
vn-ticket-request {
vn-textfield {
margin: 0!important;
max-width: 100px;
}
}

View File

@ -1,71 +0,0 @@
<vn-watcher
vn-id="watcher"
data="$ctrl.dms">
</vn-watcher>
<form name="form" ng-submit="$ctrl.onSubmit()" margin-medium enctype="multipart/form-data">
<div compact>
<vn-card pad-large>
<vn-horizontal>
<vn-textfield vn-one vn-focus
label="Reference"
field="$ctrl.dms.reference">
</vn-textfield>
<vn-autocomplete vn-one required="true"
label="Company"
field="$ctrl.dms.companyId"
url="/api/Companies"
show-field="code"
value-field="id">
</vn-autocomplete>
</vn-horizontal>
<vn-horizontal>
<vn-autocomplete vn-one required="true"
label="Warehouse"
field="$ctrl.dms.warehouseId"
url="/api/Warehouses"
show-field="name"
value-field="id">
</vn-autocomplete>
<vn-autocomplete vn-one required="true"
label="Type"
field="$ctrl.dms.dmsTypeId"
url="/api/DmsTypes"
show-field="name"
value-field="id">
</vn-autocomplete>
</vn-horizontal>
<vn-horizontal>
<vn-textarea vn-one required="true"
label="Description"
field="$ctrl.dms.description">
</vn-textarea>
</vn-horizontal>
<vn-horizontal>
<vn-input-file vn-one
label="File"
model="$ctrl.dms.files"
on-change="$ctrl.onFileChange(files)"
accept="{{$ctrl.allowedContentTypes}}"
multiple="true">
<t-right-icons>
<vn-icon vn-none
color-secondary
title="{{$ctrl.contentTypesInfo}}"
icon="info">
</vn-icon>
</t-right-icons>
</vn-input-file>
</vn-horizontal>
<vn-vertical>
<vn-check disabled="true"
label="Generate identifier for original file"
field="$ctrl.dms.hasFile">
</vn-check>
</vn-vertical>
</vn-card>
<vn-button-bar>
<vn-submit label="Save"></vn-submit>
<vn-button ui-sref="claim.card.dms.index" label="Cancel"></vn-button>
</vn-button-bar>
</div>
</form>

View File

@ -1,104 +0,0 @@
import ngModule from '../../module';
import './style.scss';
class Controller {
constructor($scope, $http, $state, $translate, vnApp) {
this.$ = $scope;
this.$http = $http;
this.$state = $state;
this.$stateParams = $state.params;
this.$translate = $translate;
this.vnApp = vnApp;
}
get claim() {
return this._claim;
}
set claim(value) {
this._claim = value;
if (value) {
this.setDefaultParams();
this.getAllowedContentTypes();
}
}
getAllowedContentTypes() {
this.$http.get('/api/claimDms/allowedContentTypes').then(res => {
const contentTypes = res.data.join(', ');
this.allowedContentTypes = contentTypes;
});
}
get contentTypesInfo() {
return this.$translate.instant('ContentTypesInfo', {
allowedContentTypes: this.allowedContentTypes
});
}
setDefaultParams() {
const path = `/api/Dms/${this.$stateParams.dmsId}`;
this.$http.get(path).then(res => {
const dms = res.data && res.data;
this.dms = {
reference: dms.reference,
warehouseId: dms.warehouseFk,
companyId: dms.companyFk,
dmsTypeId: dms.dmsTypeFk,
description: dms.description,
hasFile: dms.hasFile,
hasFileAttached: false,
files: []
};
});
}
onSubmit() {
const query = `/api/dms/${this.$stateParams.dmsId}/updateFile`;
const options = {
method: 'POST',
url: query,
params: this.dms,
headers: {
'Content-Type': undefined
},
transformRequest: files => {
const formData = new FormData();
for (let i = 0; i < files.length; i++)
formData.append(files[i].name, files[i]);
return formData;
},
data: this.dms.files
};
this.$http(options).then(res => {
if (res) {
this.vnApp.showSuccess(this.$translate.instant('Data saved!'));
this.$.watcher.updateOriginalData();
this.$state.go('claim.card.dms.index');
}
});
}
onFileChange(files) {
let hasFileAttached = false;
if (files.length > 0)
hasFileAttached = true;
this.$.$applyAsync(() => {
this.dms.hasFileAttached = hasFileAttached;
});
}
}
Controller.$inject = ['$scope', '$http', '$state', '$translate', 'vnApp'];
ngModule.component('vnClaimDmsEdit', {
template: require('./index.html'),
controller: Controller,
bindings: {
claim: '<'
}
});

View File

@ -1,86 +0,0 @@
import './index';
describe('Claim', () => {
describe('Component vnClaimDmsEdit', () => {
let controller;
let $scope;
let $httpBackend;
let $state;
beforeEach(angular.mock.module('claim', $translateProvider => {
$translateProvider.translations('en', {});
}));
beforeEach(angular.mock.inject(($componentController, $rootScope, _$httpBackend_) => {
$scope = $rootScope.$new();
$httpBackend = _$httpBackend_;
$state = {params: {dmsId: 1}};
controller = $componentController('vnClaimDmsEdit', {$scope, $state});
controller._claim = {id: 1, ticketFk: 16};
}));
describe('claim() setter', () => {
it('should set the claim data and then call setDefaultParams() and getAllowedContentTypes()', () => {
spyOn(controller, 'setDefaultParams');
spyOn(controller, 'getAllowedContentTypes');
controller._claim = undefined;
controller.claim = {
id: 15,
ticketFk: 16
};
expect(controller.setDefaultParams).toHaveBeenCalledWith();
expect(controller.claim).toBeDefined();
expect(controller.getAllowedContentTypes).toHaveBeenCalledWith();
});
});
describe('setDefaultParams()', () => {
it('should perform a GET query and define the dms property on controller', () => {
const dmsId = 1;
const expectedResponse = {
reference: 101,
warehouseFk: 1,
companyFk: 442,
dmsTypeFk: 20,
description: 'Test',
hasFile: false,
hasFileAttached: false
};
$httpBackend.when('GET', `/api/Dms/${dmsId}`).respond(expectedResponse);
$httpBackend.expect('GET', `/api/Dms/${dmsId}`).respond(expectedResponse);
controller.setDefaultParams();
$httpBackend.flush();
expect(controller.dms).toBeDefined();
expect(controller.dms.reference).toEqual(101);
expect(controller.dms.dmsTypeId).toEqual(20);
});
});
describe('onFileChange()', () => {
it('should set dms hasFileAttached property to true if has any files', () => {
const files = [{id: 1, name: 'MyFile'}];
controller.dms = {hasFileAttached: false};
controller.onFileChange(files);
$scope.$apply();
expect(controller.dms.hasFileAttached).toBeTruthy();
});
});
describe('getAllowedContentTypes()', () => {
it('should make an HTTP GET request to get the allowed content types', () => {
const expectedResponse = ['image/png', 'image/jpg'];
$httpBackend.when('GET', `/api/claimDms/allowedContentTypes`).respond(expectedResponse);
$httpBackend.expect('GET', `/api/claimDms/allowedContentTypes`);
controller.getAllowedContentTypes();
$httpBackend.flush();
expect(controller.allowedContentTypes).toBeDefined();
expect(controller.allowedContentTypes).toEqual('image/png, image/jpg');
});
});
});
});

View File

@ -1,7 +0,0 @@
vn-ticket-request {
vn-textfield {
margin: 0!important;
max-width: 100px;
}
}

View File

@ -1,113 +1,33 @@
<vn-crud-model <vn-crud-model vn-id="model" auto-load="true"
vn-id="model"
url="/api/ClaimDms" url="/api/ClaimDms"
link="{claimFk: $ctrl.$stateParams.id}" link="{claimFk: $ctrl.$stateParams.id}"
filter="::$ctrl.filter"
limit="20" limit="20"
data="$ctrl.claimDms"> data="$ctrl.photos">
</vn-crud-model> </vn-crud-model>
<vn-vertical> <vn-horizontal class="photo-list" vn-droppable="true" on-drop="$ctrl.onDrop(event)">
<vn-card pad-large> <section class="photo" ng-repeat="photo in $ctrl.photos">
<vn-vertical> <section class="image">
<vn-table model="model"> <img alt="" on-error-src
<vn-thead> ng-src="/api/dms/{{::photo.dmsFk}}/downloadFile?access_token={{::$ctrl.accessToken}}"
<vn-tr> zoom-image="/api/dms/{{::photo.dmsFk}}/downloadFile?access_token={{::$ctrl.accessToken}}">
<vn-th field="dmsFk" default-order="DESC" shrink>Id</vn-th> </section>
<vn-th shrink>Type</vn-th> <section class="actions">
<vn-th shrink number>Order</vn-th> <button class="mdl-button mdl-js-button mdl-button--fab mdl-button--mini-fab mdl-js-ripple-effect mdl-button--colored"
<vn-th shrink>Reference</vn-th>
<vn-th expand>Description</vn-th>
<vn-th shrink>Original</vn-th>
<vn-th shrink>File</vn-th>
<vn-th shrink>Employee</vn-th>
<vn-th>Created</vn-th>
<vn-th shrink></vn-th>
<vn-th shrink></vn-th>
<vn-th shrink></vn-th>
</vn-tr>
</vn-thead>
<vn-tbody>
<vn-tr ng-repeat="document in $ctrl.claimDms">
<vn-td number shrink>{{::document.dmsFk}}</vn-td>
<vn-td shrink>
<span title="{{::document.dms.dmsType.name}}">
{{::document.dms.dmsType.name}}
</span>
</vn-td>
<vn-td shrink number>
<span class="chip" title="{{::document.dms.hardCopyNumber}}"
ng-class="{'message': document.dms.hardCopyNumber}">
{{::document.dms.hardCopyNumber}}
</span>
</vn-td>
<vn-td shrink>
<span title="{{::document.dms.reference}}">
{{::document.dms.reference}}
</span>
</vn-td>
<vn-td expand>
<span title="{{::document.dms.description}}">
{{::document.dms.description}}
</span>
</vn-td>
<vn-td shrink>
<vn-check disabled="true"
field="document.dms.hasFile">
</vn-check>
</vn-td>
<vn-td shrink>
<a target="_blank"
title="{{'Download file' | translate}}"
href="api/dms/{{::document.dmsFk}}/downloadFile?access_token={{::$ctrl.accessToken}}">
{{::document.dms.file}}
</a>
</vn-td>
<vn-td shrink>
<span class="link"
ng-click="$ctrl.showWorkerDescriptor($event, document.dms.workerFk)">
{{::document.dms.worker.user.nickname | dashIfEmpty}}
</span></vn-td>
<vn-td>
{{::document.dms.created | dateTime:'dd/MM/yyyy HH:mm'}}
</vn-td>
<vn-td shrink>
<a target="_blank"
href="api/dms/{{::document.dmsFk}}/downloadFile?access_token={{::$ctrl.accessToken}}">
<vn-icon-button
icon="cloud_download"
title="{{'Download file' | translate}}">
</vn-icon-button>
</a>
</vn-td>
<vn-td shrink>
<vn-icon-button icon="edit"
ui-sref="claim.card.dms.edit({dmsId: {{::document.dmsFk}}})"
title="{{'Edit file' | translate}}">
</vn-icon-button>
</vn-td>
<vn-td shrink>
<vn-icon-button icon="delete"
ng-click="$ctrl.showDeleteConfirm($index)" ng-click="$ctrl.showDeleteConfirm($index)"
title="{{'Remove file' | translate}}" title="{{'Remove file' | translate}}"
tabindex="-1"> tabindex="-1">
</vn-icon-button> <vn-icon icon="delete"></vn-icon>
</vn-td> </button>
</vn-tr> </section>
</vn-tbody> </section>
</vn-table> <vn-empty-rows ng-if="$ctrl.photos.length == 0">
</vn-vertical> <span translate>Drag & Drop files here...</span>
<vn-pagination model="model"></vn-pagination> </vn-empty-rows>
</vn-card> </vn-horizontal>
</vn-vertical> <vn-pagination model="model"></vn-pagination>
<vn-worker-descriptor-popover <vn-worker-descriptor-popover
vn-id="workerDescriptor"> vn-id="workerDescriptor">
</vn-worker-descriptor-popover> </vn-worker-descriptor-popover>
<a ui-sref="claim.card.dms.create"
vn-tooltip="Upload file"
vn-bind="+"
fixed-bottom-right>
<vn-float-button icon="add"></vn-float-button>
</a>
<vn-confirm <vn-confirm
vn-id="confirm" vn-id="confirm"
message="This file will be deleted" message="This file will be deleted"

View File

@ -9,41 +9,6 @@ class Controller {
this.$translate = $translate; this.$translate = $translate;
this.accessToken = vnToken.token; this.accessToken = vnToken.token;
this.vnApp = vnApp; this.vnApp = vnApp;
this.filter = {
include: {
relation: 'dms',
scope: {
fields: [
'dmsTypeFk',
'workerFk',
'hardCopyNumber',
'reference',
'description',
'hasFile',
'file',
'created',
],
include: [{
relation: 'dmsType',
scope: {
fields: ['name']
}
},
{
relation: 'worker',
scope: {
fields: ['userFk'],
include: {
relation: 'user',
scope: {
fields: ['nickname']
}
},
}
}]
},
}
};
} }
showWorkerDescriptor(event, workerFk) { showWorkerDescriptor(event, workerFk) {
@ -61,14 +26,70 @@ class Controller {
deleteDms(response) { deleteDms(response) {
if (response === 'ACCEPT') { if (response === 'ACCEPT') {
const dmsFk = this.claimDms[this.dmsIndex].dmsFk; const dmsFk = this.photos[this.dmsIndex].dmsFk;
const query = `/api/claimDms/${dmsFk}/removeFile`; const query = `/api/claimDms/${dmsFk}/removeFile`;
this.$http.post(query).then(() => { this.$http.post(query).then(() => {
this.$.model.remove(this.dmsIndex); this.$.model.remove(this.dmsIndex);
this.vnApp.showSuccess(this.$translate.instant('Data saved!')); this.vnApp.showSuccess(this.$translate.instant('Photo deleted'));
}); });
} }
} }
onDrop(event) {
const files = event.dataTransfer.files;
this.setDefaultParams().then(() => {
this.dms.files = files;
this.create();
});
}
setDefaultParams() {
const params = {filter: {
where: {code: 'claim'}
}};
return this.$http.get('/api/DmsTypes/findOne', {params}).then(res => {
const dmsTypeId = res.data && res.data.id;
const companyId = window.localStorage.defaultCompanyFk;
const warehouseId = window.localStorage.defaultWarehouseFk;
this.dms = {
hasFile: false,
hasFileAttached: false,
reference: this.claim.id,
warehouseId: warehouseId,
companyId: companyId,
dmsTypeId: dmsTypeId,
description: this.$translate.instant('FileDescription', {
claimId: this.claim.id,
clientId: this.claim.client.id,
clientName: this.claim.client.name
}).toUpperCase()
};
});
}
create() {
const query = `/api/claims/${this.claim.id}/uploadFile`;
const options = {
method: 'POST',
url: query,
params: this.dms,
headers: {'Content-Type': undefined},
transformRequest: files => {
const formData = new FormData();
for (let i = 0; i < files.length; i++)
formData.append(files[i].name, files[i]);
return formData;
},
data: this.dms.files
};
this.$http(options).then(() => {
this.vnApp.showSuccess(this.$translate.instant('Photo uploaded!'));
this.$.model.refresh();
});
}
} }
Controller.$inject = ['$stateParams', '$scope', '$http', '$translate', 'vnToken', 'vnApp']; Controller.$inject = ['$stateParams', '$scope', '$http', '$translate', 'vnToken', 'vnApp'];
@ -76,4 +97,7 @@ Controller.$inject = ['$stateParams', '$scope', '$http', '$translate', 'vnToken'
ngModule.component('vnClaimDmsIndex', { ngModule.component('vnClaimDmsIndex', {
template: require('./index.html'), template: require('./index.html'),
controller: Controller, controller: Controller,
bindings: {
claim: '<'
}
}); });

View File

@ -7,17 +7,23 @@ describe('Claim', () => {
let $scope; let $scope;
let $httpBackend; let $httpBackend;
let controller; let controller;
let $httpParamSerializer;
beforeEach(angular.mock.module('claim', $translateProvider => { beforeEach(angular.mock.module('claim', $translateProvider => {
$translateProvider.translations('en', {}); $translateProvider.translations('en', {});
})); }));
beforeEach(angular.mock.inject((_$componentController_, $rootScope, _$httpBackend_) => { beforeEach(angular.mock.inject((_$componentController_, $rootScope, _$httpBackend_, _$httpParamSerializer_) => {
$componentController = _$componentController_; $componentController = _$componentController_;
$httpParamSerializer = _$httpParamSerializer_;
$httpBackend = _$httpBackend_; $httpBackend = _$httpBackend_;
$scope = $rootScope.$new(); $scope = $rootScope.$new();
controller = $componentController('vnClaimDmsIndex', {$: $scope}); controller = $componentController('vnClaimDmsIndex', {$: $scope});
controller.$.model = crudModel; controller.$.model = crudModel;
controller.claim = {
id: 1,
client: {id: 101, name: 'Bruce Wayne'}
};
})); }));
describe('deleteDms()', () => { describe('deleteDms()', () => {
@ -26,7 +32,7 @@ describe('Claim', () => {
const dmsIndex = 0; const dmsIndex = 0;
spyOn(controller.vnApp, 'showSuccess'); spyOn(controller.vnApp, 'showSuccess');
spyOn(controller.$.model, 'remove'); spyOn(controller.$.model, 'remove');
controller.claimDms = [{dmsFk: 1}]; controller.photos = [{dmsFk: 1}];
controller.dmsIndex = dmsIndex; controller.dmsIndex = dmsIndex;
$httpBackend.when('POST', `/api/claimDms/${dmsId}/removeFile`).respond({}); $httpBackend.when('POST', `/api/claimDms/${dmsId}/removeFile`).respond({});
@ -35,7 +41,42 @@ describe('Claim', () => {
$httpBackend.flush(); $httpBackend.flush();
expect(controller.$.model.remove).toHaveBeenCalledWith(dmsIndex); expect(controller.$.model.remove).toHaveBeenCalledWith(dmsIndex);
expect(controller.vnApp.showSuccess).toHaveBeenCalledWith('Data saved!'); expect(controller.vnApp.showSuccess).toHaveBeenCalledWith('Photo deleted!');
});
});
describe('setDefaultParams()', () => {
it('should make an HTTP GET query, then set all dms properties', () => {
const params = {filter: {
where: {code: 'claim'}
}};
let serializedParams = $httpParamSerializer(params);
$httpBackend.when('GET', `/api/DmsTypes/findOne?${serializedParams}`).respond({});
$httpBackend.expect('GET', `/api/DmsTypes/findOne?${serializedParams}`);
controller.setDefaultParams();
$httpBackend.flush();
expect(controller.dms).toBeDefined();
});
});
describe('create()', () => {
it('should make an HTTP Post query, then refresh the model data', () => {
const claimId = 1;
const dmsIndex = 0;
spyOn(controller.vnApp, 'showSuccess');
spyOn(controller.$.model, 'refresh');
controller.photos = [{dmsFk: 1}];
controller.dmsIndex = dmsIndex;
controller.dms = {files: []};
$httpBackend.when('POST', `/api/claims/${claimId}/uploadFile`).respond({});
$httpBackend.expect('POST', `/api/claims/${claimId}/uploadFile`);
controller.create();
$httpBackend.flush();
expect(controller.$.model.refresh).toHaveBeenCalledWith();
expect(controller.vnApp.showSuccess).toHaveBeenCalledWith('Photo uploaded!');
}); });
}); });
}); });

View File

@ -1,6 +1,20 @@
vn-client-risk-index { @import "./variables";
.totalBox {
display: table; vn-claim-dms-index {
float: right; .photo-list {
border: 2px dashed $color-font-secondary;
box-sizing: border-box;
border-radius: 0.5em;
padding: $pad-medium;
min-height: 100%;
.photo {
width: 32em;
}
}
vn-empty-rows {
color: $color-font-secondary;
font-size: 2em
} }
} }

View File

@ -1,8 +1,4 @@
Upload file: Subir fichero
Edit file: Editar fichero
Upload: Subir
File: Fichero
FileDescription: Reclamación id {{claimId}} del cliente "{{clientName}}" id {{clientId}}
Generate identifier for original file: Generar identificador para archivo original
ContentTypesInfo: "Tipos de archivo permitidos: {{allowedContentTypes}}"
Are you sure you want to continue?: ¿Seguro que quieres continuar? Are you sure you want to continue?: ¿Seguro que quieres continuar?
Drag & Drop files here...: Arrasta y suelta archivos aquí...
Photo deleted: Foto eliminada
Photo uploaded!: Foto subida!

View File

@ -7,9 +7,9 @@
"menu": [ "menu": [
{"state": "claim.card.basicData", "icon": "settings"}, {"state": "claim.card.basicData", "icon": "settings"},
{"state": "claim.card.detail", "icon": "icon-details"}, {"state": "claim.card.detail", "icon": "icon-details"},
{"state": "claim.card.dms.index", "icon": "image"},
{"state": "claim.card.development", "icon": "icon-traceability"}, {"state": "claim.card.development", "icon": "icon-traceability"},
{"state": "claim.card.action", "icon": "icon-actions"}, {"state": "claim.card.action", "icon": "icon-actions"}
{"state": "claim.card.dms.index", "icon": "image"}
], ],
"keybindings": [ "keybindings": [
{"key": "r", "state": "claim.index"} {"key": "r", "state": "claim.index"}
@ -88,22 +88,6 @@
"params": { "params": {
"claim": "$ctrl.claim" "claim": "$ctrl.claim"
} }
}, {
"url" : "/create",
"state": "claim.card.dms.create",
"component": "vn-claim-dms-create",
"description": "Upload file",
"params": {
"claim": "$ctrl.claim"
}
}, {
"url": "/:dmsId/edit",
"state": "claim.card.dms.edit",
"component": "vn-claim-dms-edit",
"description": "Edit file",
"params": {
"claim": "$ctrl.claim"
}
} }
] ]
} }

View File

@ -1,22 +1,36 @@
@import "./variables"; @import "./variables";
.photo-list { .photo-list {
justify-content: center;
align-items: flex-start; align-items: flex-start;
align-content: flex-start;
flex-wrap: wrap; flex-wrap: wrap;
.photo { .photo {
box-sizing: border-box; box-sizing: border-box;
padding: $pad-small; padding: $pad-small;
width: 33%; position: relative;
opacity: 0.7;
transition: all 0.5s;
width: 28em;
.image { .image {
border: 2px solid $color-main; border: 2px solid $color-bg-dark;
border-radius: 0.5em; border-radius: 0.2em;
overflow: hidden; overflow: hidden;
img { img, video {
max-width: 100% max-width: 100%
} }
} }
.actions {
position: absolute;
right: 1em;
top: 1em
}
}
.photo:hover {
opacity: 1
} }
} }