customer fixes

This commit is contained in:
Shaun Chyxion 2018-03-24 00:28:29 +08:00
parent 61ebcf7ed6
commit 107963da98
17 changed files with 161 additions and 113 deletions

View File

@ -215,7 +215,9 @@ public abstract class AbstractBaseController {
if (StringUtils.isNotBlank(op) &&
val != null && val instanceof String ?
StringUtils.isNotBlank((String) val) : true) {
onSearch(search, col);
if (onSearch(search, col, val)) {
continue;
}
if ("eq".equals(op)) {
search.eq(col, val);
}
@ -279,7 +281,9 @@ public abstract class AbstractBaseController {
final String col = colProp.getKey();
final Object filterVal = filter.getValue();
if (filterVal != null) {
onSearch(search, col);
if (onSearch(search, col, filterVal)) {
continue;
}
// type convert
if (filterVal instanceof JSONArray) {
search.eq(col, joFilters.getObject(
@ -356,8 +360,8 @@ public abstract class AbstractBaseController {
return null;
}
protected void onSearch(final Search search, final String col) {
protected boolean onSearch(final Search search, final String col, final Object val) {
return false;
}
protected Map<String, String> defaultOrderCols() {

View File

@ -3,6 +3,7 @@ package com.pudonghot.ambition.crm.controller;
import java.util.List;
import java.util.Arrays;
import javax.validation.Valid;
import org.springframework.util.Assert;
import me.chyxion.tigon.mybatis.Search;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
@ -18,6 +19,7 @@ import com.pudonghot.ambition.crm.service.UserService;
import org.apache.shiro.authz.annotation.RequiresRoles;
import com.pudonghot.ambition.crm.model.CustomerProperty;
import org.springframework.beans.factory.annotation.Value;
import com.pudonghot.ambition.crm.model.ApplicationImage;
import org.springframework.web.bind.annotation.RequestParam;
import com.pudonghot.ambition.crm.service.ApplicationService;
import org.springframework.web.bind.annotation.RequestMethod;
@ -117,10 +119,11 @@ public class ApplicationController
}
@RequestMapping(value = "/add-image", method = RequestMethod.POST)
public void addImage(
@Valid ApplicationImageFormForCreate form) {
public ViewModel<ApplicationImage> addImage(
@Valid ApplicationImageFormForCreate form) {
Assert.state(!form.getImage().isEmpty(), "Image content is empty");
form.setAdmin(getAuthUser().getUser().getData().isAdmin());
((ApplicationService) queryService).addImage(form);
return new ViewModel<>(((ApplicationService) queryService).addImage(form));
}
@RequestMapping(value = "/remove-image", method = RequestMethod.POST)

View File

@ -3,21 +3,23 @@ package com.pudonghot.ambition.crm.controller;
import java.util.*;
import javax.validation.Valid;
import com.alibaba.fastjson.JSONArray;
import lombok.extern.slf4j.Slf4j;
import me.chyxion.tigon.mybatis.Search;
import me.chyxion.tigon.model.ViewModel;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import me.chyxion.tigon.model.ListResult;
import org.apache.commons.lang3.tuple.Pair;
import javax.validation.constraints.NotNull;
import org.apache.commons.lang3.StringUtils;
import com.pudonghot.ambition.crm.model.User;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.stereotype.Controller;
import com.pudonghot.ambition.crm.model.Customer;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.springframework.web.multipart.MultipartFile;
import com.pudonghot.ambition.crm.model.CustomerProperty;
import org.springframework.beans.factory.annotation.Value;
import com.pudonghot.ambition.crm.service.CustomerService;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestMethod;
@ -37,6 +39,8 @@ import com.pudonghot.ambition.crm.form.update.CustomerFormForUpdate;
public class CustomerController
extends BaseQueryController<Customer> {
@Value("${file.base-path}")
private String fileBasePath;
private static final List<String> SEARCH_COLS = Arrays.asList(
"customer.id",
"customer.name",
@ -94,7 +98,7 @@ public class CustomerController
FILTER_COLS.put("city",
Pair.of(CRITERION_COLS.get("city"), String.class));
FILTER_COLS.put("salesperson",
Pair.of(CRITERION_COLS.get("city"), String.class));
Pair.of(CRITERION_COLS.get("salesperson"), String.class));
FILTER_COLS.put("status",
Pair.of(CRITERION_COLS.get("status"), String.class));
FILTER_COLS.put("application",
@ -138,14 +142,16 @@ public class CustomerController
final Search search = new Search();
User user = getUser().getData();
// if (!user.isAdmin()) {
search.setAttr(User.ACCOUNT, user.getAccount());
// }
// search year
if (StringUtils.isNotBlank(strSearch)) {
search.setAttr("YTD_SALE", true);
}
return listViewModels(search, start, limit, strSearch, criteria, filters, orders);
final ListResult<ViewModel<Customer>> result =
listViewModels(search, start, limit, strSearch, criteria, filters, orders);
result.setAttr("fileBasePath", fileBasePath);
return result;
}
@RequiresRoles(User.ROLE_ADMIN)
@ -213,11 +219,16 @@ public class CustomerController
* {@inheritDoc}
*/
@Override
protected void onSearch(final Search search, final String col) {
protected boolean onSearch(final Search search, final String col, final Object val) {
// for search year
if (CustomerYearToDateSale.YEAR.equals(col) ||
CustomerYearToDateSale.YTD_SALE.equals(col)) {
search.setAttr("YTD_SALE", true);
}
if ("application".equals(col) && !((JSONArray) val).isEmpty()) {
search.setAttr("APPLICATIONS", val);
return true;
}
return false;
}
}

View File

@ -1,5 +1,7 @@
package com.pudonghot.ambition.crm.controller;
import java.util.List;
import java.util.Arrays;
import javax.validation.Valid;
import com.alibaba.fastjson.JSONArray;
import me.chyxion.tigon.mybatis.Search;
@ -21,9 +23,6 @@ import com.pudonghot.ambition.crm.service.CustomerPropertyService;
import com.pudonghot.ambition.crm.form.create.CustomerPropertyFormForCreate;
import com.pudonghot.ambition.crm.form.update.CustomerPropertyFormForUpdate;
import java.util.Arrays;
import java.util.List;
/**
* @author Shaun Chyxion <br>
* chyxion@163.com <br>
@ -65,22 +64,6 @@ public class CustomerPropertyController
return listViewModels(search, start, limit, strSearch, null, null, null);
}
@RequestMapping("/app-list")
public ListResult<ViewModel<CustomerProperty>> applist(
@RequestParam(value = "enabled", required = false)
final String enabled,
@RequestParam(value = "search", required = false)
final String strSearch) {
final Search search = new Search(CustomerProperty.TYPE,
CustomerProperty.Type.APPLICATION)
.asc(CustomerProperty.NAME);
if (StringUtils.isNotBlank(enabled)) {
search.eq(CustomerProperty.ENABLED, Boolean.parseBoolean(enabled));
}
return listViewModels(search, null, null, strSearch, null, null, null);
}
@RequiresRoles(User.ROLE_ADMIN)
@RequestMapping(value = "/create", method = RequestMethod.POST)
public ViewModel<CustomerProperty> create(

View File

@ -2,6 +2,7 @@ package com.pudonghot.ambition.crm.service;
import javax.validation.Valid;
import com.pudonghot.ambition.crm.model.Application;
import com.pudonghot.ambition.crm.model.ApplicationImage;
import org.hibernate.validator.constraints.NotBlank;
import me.chyxion.tigon.service.BaseCrudByFormService;
import com.pudonghot.ambition.crm.form.update.ApplicationFormForUpdate;
@ -21,7 +22,7 @@ public interface ApplicationService
* add image
* @param form form
*/
void addImage(@Valid ApplicationImageFormForCreate form);
ApplicationImage addImage(@Valid ApplicationImageFormForCreate form);
/**
* remove image

View File

@ -2,6 +2,7 @@ package com.pudonghot.ambition.crm.service.support;
import java.util.Date;
import java.util.List;
import java.util.ArrayList;
import java.io.IOException;
import java.io.InputStream;
import lombok.extern.slf4j.Slf4j;
@ -64,7 +65,13 @@ public class ApplicationServiceSupport
*/
@Override
public ViewModel<Application> update(final ApplicationFormForUpdate form) {
return update(form.copy(validatePerm(form.getId(), form.getUpdatedBy(), form.isAdmin())));
final String updatedBy = form.getUpdatedBy();
final Application application = validatePerm(form.getId(), updatedBy, form.isAdmin());
form.copy(application);
if (!form.isAdmin()) {
application.setOwner(updatedBy);
}
return update(application);
}
/**
@ -84,15 +91,15 @@ public class ApplicationServiceSupport
* {@inheritDoc}
*/
@Override
public void addImage(final ApplicationImageFormForCreate form) {
public ApplicationImage addImage(final ApplicationImageFormForCreate form) {
final String applicationId = form.getApplicationId();
final String createdBy = form.getCreatedBy();
validatePerm(applicationId, createdBy, form.isAdmin());
uploadImages(applicationId,
imageMapper.nextSort(applicationId),
new MultipartFile[] {form.getImage()},
new String[] {form.getNote()},
createdBy);
return uploadImages(applicationId,
imageMapper.nextSort(applicationId),
new MultipartFile[] {form.getImage()},
new String[] {form.getNote()},
createdBy).iterator().next();
}
/**
@ -142,37 +149,38 @@ public class ApplicationServiceSupport
}
}
private void uploadImages(final String applicationId, int sort, final MultipartFile[] images, final String[] titles, final String createdBy) {
if (images != null) {
final Date now = new Date();
final String imageFolder = imageFolder(applicationId);
int i = 0;
for (final MultipartFile image : images) {
if (!image.isEmpty()) {
try (final InputStream ins = image.getInputStream()) {
final String imageId = idSeq.get();
fileApi.uploadImage(ins, imageFolder, imageId);
final ApplicationImage appImage = new ApplicationImage();
appImage.setId(imageId);
appImage.setApplicationId(applicationId);
appImage.setSort(sort++);
appImage.setEnabled(true);
appImage.setNote(titles[i]);
appImage.setCreatedBy(createdBy);
appImage.setDateCreated(now);
imageMapper.insert(appImage);
}
catch (final IOException e) {
throw new IllegalStateException(
"Read upload image [" + image.getOriginalFilename() + "] error cased", e);
}
private List<ApplicationImage> uploadImages(final String applicationId, int sort, final MultipartFile[] images, final String[] titles, final String createdBy) {
final List<ApplicationImage> imagesRtn = new ArrayList<>();
final Date now = new Date();
final String imageFolder = imageFolder(applicationId);
int i = 0;
for (final MultipartFile image : images) {
if (!image.isEmpty()) {
try (final InputStream ins = image.getInputStream()) {
final String imageId = idSeq.get();
final ApplicationImage appImage = new ApplicationImage();
appImage.setUrl(fileApi.uploadImage(ins, imageFolder, imageId));
appImage.setId(imageId);
appImage.setApplicationId(applicationId);
appImage.setSort(sort++);
appImage.setEnabled(true);
appImage.setNote(titles[i]);
appImage.setCreatedBy(createdBy);
appImage.setDateCreated(now);
imageMapper.insert(appImage);
imagesRtn.add(appImage);
}
else {
log.info("Application image [{}] is empty, ignore.", image);
catch (final IOException e) {
throw new IllegalStateException(
"Read upload image [" + image.getOriginalFilename() + "] error cased", e);
}
++i;
}
else {
log.info("Application image [{}] is empty, ignore.", image);
}
++i;
}
return imagesRtn;
}
private String imageFolder(final String appId) {

View File

@ -51,6 +51,8 @@ public class CustomerServiceSupport
private CustomerIssueMapper customerIssueMapper;
@Autowired
private CustomerApplicationMapper customerApplicationMapper;
@Autowired
private ApplicationMapper applicationMapper;
/**
* override find by id with find by search
@ -80,11 +82,9 @@ public class CustomerServiceSupport
CustomerProperty.Type.STATUS)
.asc(CustomerProperty.SORT)));
// application list
viewModel.setAttr("applicationList",
customerPropertyMapper.list(
new Search(CustomerProperty.TYPE,
CustomerProperty.Type.APPLICATION)
.asc(CustomerProperty.NAME)));
applicationMapper.list(new Search().asc(Application.NAME)));
}
return viewModel;
@ -123,10 +123,9 @@ public class CustomerServiceSupport
statusList.add(noneStatus);
result.setAttr("statusList", statusList);
result.setAttr("applicationList", customerPropertyMapper.list(
new Search(CustomerProperty.TYPE,
CustomerProperty.Type.APPLICATION)
.asc(CustomerProperty.NAME)));
// application list
result.setAttr("applicationList",
applicationMapper.list(new Search().asc(Application.NAME)));
return result;
}
@ -144,19 +143,19 @@ public class CustomerServiceSupport
final String operator = form.getUpdatedBy();
final Date now = new Date();
for (final String applicationId : applications) {
CustomerProperty customerProperty =
customerPropertyMapper.find(new Search(applicationId)
.eq(CustomerProperty.TYPE,
CustomerProperty.Type.APPLICATION));
Assert.state(customerProperty != null,
"No customer application [" + applicationId + "] found");
final CustomerApplication application = new CustomerApplication();
application.setId(idSeq.get());
application.setCustomerId(customerId);
application.setPropertyId(applicationId);
application.setCreatedBy(operator);
application.setDateCreated(now);
customerApplicationMapper.insert(application);
final Application application =
applicationMapper.find(applicationId);
Assert.state(application != null,
"No application [" + applicationId + "] found");
Assert.state(application.isEnabled(),
"Application [" + application.getName() + "] is disabled");
final CustomerApplication customerApplication = new CustomerApplication();
customerApplication.setId(idSeq.get());
customerApplication.setCustomerId(customerId);
customerApplication.setPropertyId(applicationId);
customerApplication.setCreatedBy(operator);
customerApplication.setDateCreated(now);
customerApplicationMapper.insert(customerApplication);
}
}
return super.update(form);

View File

@ -97,6 +97,7 @@ public class TestDriver {
@Test
public void testFloat() {
ApplicationImage image = new ApplicationImage();
image.setUrl("http://www.image.com");
int sortOld = 2;
image.setSort(sortOld - 1.5f);
System.err.println(image);

View File

@ -25,7 +25,7 @@ public class CustomerProperty extends M3<String, String> {
// public static final String TYPE_STATUS = "STATUS";
public enum Type {
STATUS,
APPLICATION,
// APPLICATION,
}
// system status

View File

@ -1,5 +1,6 @@
import Ember from 'ember';
import BaseEditRoute from '../base-edit';
import $ from 'jquery';
export default BaseEditRoute.extend({
afterModel(model) {
@ -14,16 +15,35 @@ export default BaseEditRoute.extend({
[{route: 'customer-application.list', params: 1, text: 'Customer Application'},
{text: 'Edit Customer Application[' + model.name + ']'}]);
},
actions: {
addImage() {
const me = this;
me.get('controller.model.images').pushObject({});
me.set('controller.model.addImage', true);
me.set('controller.model.image', {});
},
submitAddImage() {
const me = this;
if (me.get('controller.model.image.file')) {
me.set('controller.errors', {});
me.get('store').ajaxPost('application/add-image',
new FormData($('#form_' + me.get('controller.model.id'))[0]))
.then(image => {
me.get('controller.model.images').pushObject(image);
me.set('controller.model.addImage', false);
});
}
else {
me.set('controller.errors.image', ['No image file selected']);
}
},
closeAddImage() {
const me = this;
me.set('controller.model.addImage', false);
},
removeImage(image) {
const me = this;
me.get('dialog').confirm('Are you sure to remove image?', () => {
me.get('store').ajaxPost('application/remove-image', image, () => {
me.get('store').ajaxPost('application/remove-image', image).then(() => {
me.get('message').alert('Image removed');
me.get('controller.model.images').removeObject(image);
});

View File

@ -3,9 +3,6 @@ import BaseListRoute from './../base-list';
export default BaseListRoute.extend({
breadcrumbs: [{text: 'Customer Application'}],
// model(params) {
// return this.get('store').ajaxGet('customer-property/app-list', params);
// }
actions: {
showContent(app) {
this.get('dialog').dialog({

View File

@ -1,9 +1,15 @@
<button {{action 'show'}} class="btn btn-minier btn-info2" data-rel="tooltip" title="Content Preview">
<i class="fa fa-search" aria-hidden="true"></i>
</button>
<a {{action 'show'}} class="" title="Content Preview">
{{!-- <i class="fa fa-search" aria-hidden="true"></i> --}}
{{model.name}}
</a>
{{#if show}}
{{#modal-dialog title=model.name no-cancel=true submit=(action 'close') on-close=(action 'close') close-to-parent=false}}
{{#modal-dialog title=model.name
no-cancel=true
submit-text='OK'
submit=(action 'close')
on-close=(action 'close')
close-to-parent=false}}
<div class="widget-main">
<div class="space-12"></div>
<p>{{content}}</p>

View File

@ -1,7 +1,7 @@
<div class="row widget-box no-border">
<div class="widget-body">
<div class="widget-main">
<form class="form-horizontal">
<form id={{form-id}} name={{form-id}} class="form-horizontal">
{{yield}}
</form>
</div>

View File

@ -31,6 +31,6 @@
{{image-previews previews=imageUrl}}
</div>
{{/if}}
{{#if (get this 'error-msg')}}
{{#if (and hasError error-msg)}}
{{form-input-errors-msg name=name}}
{{/if}}

View File

@ -53,7 +53,7 @@
<td>
{{!image.note}}
<div class="btn-group">
<a class="btn btn-xs btn-danger" data-rel="tooltip" title="Remove" {{action (route-action 'moveUp' image)}}>
<a class="btn btn-xs btn-danger" data-rel="tooltip" title="Remove" {{action (route-action 'removeImage' image)}}>
<i class="ace-icon fa fa-trash-o"></i>
</a>
{{#if (not-eq model.images.firstObject.id image.id)}}
@ -93,3 +93,17 @@
<hr />
{{form-footer-buttons type='update'}}
{{/form-content}}
{{#if model.addImage}}
{{#modal-dialog title='Add Image' no-cancel=true submit=(route-action 'submitAddImage') on-close=(route-action 'closeAddImage') close-to-parent=false}}
{{#form-content form-id=(concat 'form_' model.id)}}
{{input type='hidden' name='applicationId' value=model.id}}
{{#form-input name='note' label='Description'}}
{{input name='note' value=model.image.note class='col-xs-12'}}
{{/form-input}}
{{#form-input name='image' label='Image'}}
{{image-input name='image' image=model.image}}
{{/form-input}}
{{/form-content}}
{{/modal-dialog}}
{{/if}}

View File

@ -56,11 +56,11 @@
{{#each model.data as |it|}}
<tr>
<td>
{{it.name}}
{{!it.name}}
{{customer-application/preview-btn model=it file-base-path=model.fileBasePath}}
</td>
<td>
{{image-previews previews=(customer-application-images model.fileBasePath it.id it.images it.imageTitles)}}
{{customer-application/preview-btn model=it file-base-path=model.fileBasePath}}
</td>
<td>
{{editable-cell model=it field='note'}}

View File

@ -223,8 +223,13 @@
{{/if}}
{{#if tableOptions.showApplication}}
<td style="max-width: 96px; white-space: initial;">
{{#each (str-split it.applications) as |a|}}
{{option-text model.applicationList a 'id' 'name'}}
{{#each (str-split it.applications) as |aId|}}
{{#each model.applicationList as |app|}}
{{#if (eq aId app.id)}}
{{customer-application/preview-btn model=app file-base-path=model.fileBasePath}}
{{/if}}
{{/each}}
{{!option-text model.applicationList a 'id' 'name'}}
{{/each}}
</td>
{{/if}}
@ -285,11 +290,9 @@
{{#link-to 'customer-issue.create' it.id class='btn btn-xs btn-success' data-rel='tooltip' title='Write Comment'}}
<i class="ace-icon fa fa-tags bigger-120"></i>
{{/link-to}}
{{#if ajax.user.admin}}
{{#link-to 'customer.edit' it.id class='btn btn-xs btn-info' data-rel='tooltip' title='Edit Customer'}}
<i class="ace-icon fa fa-pencil bigger-120"></i>
{{/link-to}}
{{/if}}
{{#link-to 'customer.edit' it.id class='btn btn-xs btn-info' data-rel='tooltip' title='Edit Customer'}}
<i class="ace-icon fa fa-pencil bigger-120"></i>
{{/link-to}}
</div>
<div class="hidden-md hidden-lg">
<div class="inline pos-rel">
@ -306,7 +309,6 @@
</span>
{{/link-to}}
</li>
{{#if ajax.user.admin}}
<li>
{{#link-to 'customer.edit' it.id class='tooltip-info' title='Edit Customer'}}
<span class="blue">
@ -314,7 +316,6 @@
</span>
{{/link-to}}
</li>
{{/if}}
</ul>
</div>
</div>