add image preview
This commit is contained in:
parent
267fb19f2e
commit
2bf6f74181
@ -1,17 +1,20 @@
|
||||
package com.pudonghot.ambition.crm.controller;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
import java.net.URLDecoder;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Collections;
|
||||
import java.lang.reflect.Array;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.chyxion.tigon.model.M1;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import me.chyxion.tigon.mybatis.Search;
|
||||
import com.alibaba.fastjson.JSONException;
|
||||
import com.alibaba.fastjson.util.TypeUtils;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import org.apache.commons.lang3.CharEncoding;
|
||||
@ -107,12 +110,11 @@ public abstract class AbstractBaseController {
|
||||
*/
|
||||
protected InputStream getInputStream(MultipartFile file) {
|
||||
try {
|
||||
return file == null || file.isEmpty() ?
|
||||
null : file.getInputStream();
|
||||
return file != null && !file.isEmpty() ? file.getInputStream() : null;
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new IllegalStateException(
|
||||
"Read Multipart File Stream Error Caused", e);
|
||||
"Read multipart file stream error caused", e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -123,13 +125,13 @@ public abstract class AbstractBaseController {
|
||||
protected String decodeParam(String param) {
|
||||
if (StringUtils.isNotBlank(param)) {
|
||||
try {
|
||||
log.debug("Decode Param [{}].", param);
|
||||
log.debug("Decode param [{}].", param);
|
||||
param = URLDecoder.decode(param, CharEncoding.UTF_8);
|
||||
log.debug("Decode Param Result [{}].", param);
|
||||
log.debug("Decode param result [{}].", param);
|
||||
}
|
||||
catch (UnsupportedEncodingException e) {
|
||||
throw new IllegalStateException(
|
||||
"Decode [" + param + "] Error Caused", e);
|
||||
"Decode [" + param + "] error caused", e);
|
||||
}
|
||||
}
|
||||
return param;
|
||||
@ -139,14 +141,12 @@ public abstract class AbstractBaseController {
|
||||
* @param start start
|
||||
* @param limit limit
|
||||
* @param search search
|
||||
* @param strSorters sorters
|
||||
* @return search
|
||||
*/
|
||||
protected Search search(final Integer start,
|
||||
final Integer limit,
|
||||
final String search,
|
||||
final String strSorters) {
|
||||
return search(null, start, limit, search, strSorters);
|
||||
final String search) {
|
||||
return search(null, start, limit, search, null, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -155,14 +155,16 @@ public abstract class AbstractBaseController {
|
||||
* @param start start
|
||||
* @param limit limit
|
||||
* @param strSearch search
|
||||
* @param strSorters sorters
|
||||
* @param strOrders orders
|
||||
* @return search
|
||||
*/
|
||||
protected Search search(Search search,
|
||||
final Integer start,
|
||||
final Integer limit,
|
||||
final String strSearch,
|
||||
final String strSorters) {
|
||||
final String strCriteria,
|
||||
final String strFilters,
|
||||
final String strOrders) {
|
||||
|
||||
if (search == null) {
|
||||
search = new Search();
|
||||
@ -175,27 +177,140 @@ public abstract class AbstractBaseController {
|
||||
}
|
||||
if (StringUtils.isNotBlank(strSearch)) {
|
||||
final Search orSearch = new Search();
|
||||
for (String col : searchCols()) {
|
||||
for (final String col : searchCols()) {
|
||||
orSearch.or(new Search().like(col, decodeLike(strSearch)));
|
||||
}
|
||||
search.and(orSearch);
|
||||
}
|
||||
if (StringUtils.isNotBlank(strSorters)) {
|
||||
Map<String, String> sorterCols = sorterCols();
|
||||
final JSONArray jaSorters;
|
||||
criteria(search, strCriteria);
|
||||
filters(search, strFilters);
|
||||
order(search, strOrders) ;
|
||||
return search;
|
||||
}
|
||||
|
||||
protected Search criteria(final Search search, final String strCriteria) {
|
||||
if (StringUtils.isBlank(strCriteria)) {
|
||||
log.debug("No criteria given.");
|
||||
return search;
|
||||
}
|
||||
|
||||
final List<Object[]> criteria;
|
||||
try {
|
||||
criteria = JSON.parseArray(decodeParam(strCriteria), Object[].class);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new IllegalStateException(
|
||||
"Invalid criteria [" + strCriteria + "]", e);
|
||||
}
|
||||
|
||||
for (final Object[] criterion : criteria) {
|
||||
if (criterion.length == 3) {
|
||||
final String field = (String) criterion[0];
|
||||
if (StringUtils.isNotBlank(field)) {
|
||||
final Pair<String, Class<?>> colProp = criterionCol(field);
|
||||
final String col = colProp.getKey();
|
||||
if (StringUtils.isNotBlank(col)) {
|
||||
final String op = (String) criterion[1];
|
||||
final Object val = TypeUtils.castToJavaBean(criterion[2], colProp.getValue());
|
||||
if (StringUtils.isNotBlank(op) &&
|
||||
val != null && val instanceof String ?
|
||||
StringUtils.isNotBlank((String) val) : true) {
|
||||
onSearch(search, col);
|
||||
if ("eq".equals(op)) {
|
||||
search.eq(col, val);
|
||||
}
|
||||
else if ("gt".equals(op)) {
|
||||
search.gt(col, val);
|
||||
}
|
||||
else if ("gte".equals(op)) {
|
||||
search.gte(col, val);
|
||||
}
|
||||
else if ("lt".equals(op)) {
|
||||
search.lt(col, val);
|
||||
}
|
||||
else if ("lte".equals(op)) {
|
||||
search.lt(col, val);
|
||||
}
|
||||
else if ("ne".equals(op)) {
|
||||
search.ne(col, val);
|
||||
}
|
||||
else if ("like".equals(op)) {
|
||||
search.like(col, (String) val, true);
|
||||
}
|
||||
else {
|
||||
log.warn("Unknown criterion op [{}], ignore.", op);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
log.warn("Criterion col is blank, ignore.");
|
||||
}
|
||||
}
|
||||
else {
|
||||
log.warn("Invalid criterion [{}], ignore.", criterion);
|
||||
}
|
||||
}
|
||||
return search;
|
||||
}
|
||||
|
||||
protected JSONObject filters(String filters) {
|
||||
try {
|
||||
return JSON.parseObject(decodeParam(filters));
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new IllegalStateException(
|
||||
"Invalid filters [" + filters + "]", e);
|
||||
}
|
||||
}
|
||||
|
||||
protected Search filters(final Search search, final String strFilters) {
|
||||
|
||||
if (StringUtils.isBlank(strFilters)) {
|
||||
log.debug("No filters given, ignore.");
|
||||
return defaultFilter(search);
|
||||
}
|
||||
|
||||
final JSONObject joFilters = filters(strFilters);
|
||||
for (Map.Entry<String, Object> filter : joFilters.entrySet()) {
|
||||
final String field = filter.getKey();
|
||||
final Pair<String, Class<?>> colProp = filterCol(filter.getKey());
|
||||
if (colProp != null) {
|
||||
final String col = colProp.getKey();
|
||||
final Object filterVal = filter.getValue();
|
||||
if (filterVal != null) {
|
||||
onSearch(search, col);
|
||||
// type convert
|
||||
if (filterVal instanceof JSONArray) {
|
||||
search.eq(col, joFilters.getObject(
|
||||
field, Array.newInstance(colProp.getValue(), 0).getClass()));
|
||||
}
|
||||
else {
|
||||
search.eq(col, filterVal);
|
||||
}
|
||||
}
|
||||
}
|
||||
return search;
|
||||
}
|
||||
return search;
|
||||
}
|
||||
|
||||
protected Search order(final Search search, final String strOrders) {
|
||||
if (StringUtils.isNotBlank(strOrders)) {
|
||||
final JSONArray jaOrders;
|
||||
try {
|
||||
jaSorters = JSON.parseArray(decodeParam(strSorters));
|
||||
jaOrders = JSON.parseArray(decodeParam(strOrders));
|
||||
}
|
||||
catch (JSONException e) {
|
||||
throw new IllegalStateException(
|
||||
"Invalid Sorters JSONArray Params [" + strSorters + "]", e);
|
||||
"Invalid orders params [" + strOrders + "]", e);
|
||||
}
|
||||
for (Object objSorter : jaSorters) {
|
||||
final JSONObject joSorter = (JSONObject) objSorter;
|
||||
for (final Object objOrder : jaOrders) {
|
||||
final JSONObject joSorter = (JSONObject) objOrder;
|
||||
if (!joSorter.isEmpty()) {
|
||||
final Map.Entry<String, Object> sortEntry =
|
||||
joSorter.entrySet().iterator().next();
|
||||
final String col = sorterCols.get(sortEntry.getKey());
|
||||
final String col = orderCol(sortEntry.getKey());
|
||||
if (StringUtils.isNotBlank(col)) {
|
||||
final String dir = (String) sortEntry.getValue();
|
||||
if ("asc".equalsIgnoreCase(dir)) {
|
||||
@ -208,20 +323,48 @@ public abstract class AbstractBaseController {
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
defaultOrder(search);
|
||||
}
|
||||
return search;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return simple search cols
|
||||
*/
|
||||
protected String[] searchCols() {
|
||||
return new String[]{ };
|
||||
protected List<String> searchCols() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return simple search cols
|
||||
*/
|
||||
protected Map<String, String> sorterCols() {
|
||||
return Collections.emptyMap();
|
||||
protected Search defaultFilter(final Search search) {
|
||||
return search;
|
||||
}
|
||||
|
||||
protected Search defaultOrder(final Search search) {
|
||||
return search;
|
||||
}
|
||||
|
||||
protected Pair<String, Class<?>> criterionCol(final String field) {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected Pair<String, Class<?>> filterCol(final String field) {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected String orderCol(final String field) {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void onSearch(final Search search, final String col) {
|
||||
|
||||
}
|
||||
|
||||
protected Map<String, String> defaultOrderCols() {
|
||||
final Map<String, String> cols = new HashMap<>();
|
||||
cols.put(M1.ID, M1.ID);
|
||||
cols.put("dateCreated", M1.DATE_CREATED);
|
||||
cols.put("dateUpdated", M1.DATE_UPDATED);
|
||||
return cols;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
package com.pudonghot.ambition.crm.controller;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Arrays;
|
||||
import javax.validation.Valid;
|
||||
import me.chyxion.tigon.mybatis.Search;
|
||||
import javax.validation.constraints.Max;
|
||||
@ -8,14 +10,18 @@ import me.chyxion.tigon.model.ViewModel;
|
||||
import me.chyxion.tigon.model.ListResult;
|
||||
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.Application;
|
||||
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 org.springframework.web.bind.annotation.RequestParam;
|
||||
import com.pudonghot.ambition.crm.service.ApplicationService;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import com.pudonghot.ambition.crm.form.create.ApplicationFormForCreate;
|
||||
import com.pudonghot.ambition.crm.form.update.ApplicationFormForUpdate;
|
||||
|
||||
@ -29,6 +35,14 @@ import com.pudonghot.ambition.crm.form.update.ApplicationFormForUpdate;
|
||||
public class ApplicationController
|
||||
extends BaseQueryController<Application> {
|
||||
|
||||
@Value("${file.base-path}")
|
||||
private String fileBasePath;
|
||||
@Autowired
|
||||
private UserService userService;
|
||||
private final List<String> SEARCH_COLS =
|
||||
Arrays.asList(CustomerProperty.NAME,
|
||||
CustomerProperty.NOTE);
|
||||
|
||||
@RequestMapping("/list")
|
||||
public ListResult<ViewModel<Application>> list(
|
||||
@Min(0)
|
||||
@ -38,6 +52,8 @@ public class ApplicationController
|
||||
@Max(2048)
|
||||
@RequestParam(value = "limit", defaultValue = "16")
|
||||
final int limit,
|
||||
@RequestParam(value = "filters", required = false)
|
||||
final String filters,
|
||||
@RequestParam(value = "search", required = false)
|
||||
final String strSearch) {
|
||||
|
||||
@ -47,8 +63,12 @@ public class ApplicationController
|
||||
if (!user.isAdmin()) {
|
||||
search.eq(Application.OWNER, user.getId());
|
||||
}
|
||||
|
||||
return listViewModels(search, start, limit, strSearch, null);
|
||||
final ListResult<ViewModel<Application>> result =
|
||||
listViewModels(search, start, limit, strSearch, null, filters, null);
|
||||
result.setAttr("fileBasePath", fileBasePath);
|
||||
result.setAttr("users", userService.listViewModels(
|
||||
new Search().asc(User.EMPLOYEE_ID)));
|
||||
return result;
|
||||
}
|
||||
|
||||
@RequestMapping("/list-for-select")
|
||||
@ -63,7 +83,7 @@ public class ApplicationController
|
||||
if (StringUtils.isNotBlank(enabled)) {
|
||||
search.eq(CustomerProperty.ENABLED, Boolean.parseBoolean(enabled));
|
||||
}
|
||||
return listViewModels(search, null, null, strSearch, null);
|
||||
return listViewModels(search, null, null, strSearch, null, null, null);
|
||||
}
|
||||
|
||||
@RequiresRoles(User.ROLE_ADMIN)
|
||||
@ -77,6 +97,7 @@ public class ApplicationController
|
||||
@RequestMapping(value = "/update", method = RequestMethod.POST)
|
||||
public void update(
|
||||
@Valid ApplicationFormForUpdate form) {
|
||||
form.setAdmin(getAuthUser().getUser().getData().isAdmin());
|
||||
((ApplicationService) queryService).update(form);
|
||||
}
|
||||
|
||||
@ -84,10 +105,15 @@ public class ApplicationController
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
protected String[] searchCols() {
|
||||
return new String[] {
|
||||
CustomerProperty.NAME,
|
||||
CustomerProperty.NOTE
|
||||
};
|
||||
protected List<String> searchCols() {
|
||||
return SEARCH_COLS;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
protected Pair<String, Class<?>> filterCol(final String field) {
|
||||
return Application.OWNER.equals(field) ? Pair.of(field, String.class) : null;
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,12 @@
|
||||
package com.pudonghot.ambition.crm.controller;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.chyxion.tigon.mybatis.Search;
|
||||
import me.chyxion.tigon.model.BaseModel;
|
||||
import me.chyxion.tigon.model.ViewModel;
|
||||
import me.chyxion.tigon.model.ListResult;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import me.chyxion.tigon.service.BaseQueryService;
|
||||
import org.hibernate.validator.constraints.NotBlank;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@ -17,12 +18,31 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
||||
* chyxion@163.com <br>
|
||||
* May 10, 2016 4:50:58 PM
|
||||
*/
|
||||
@Slf4j
|
||||
public class BaseQueryController<Model extends BaseModel<String>>
|
||||
extends BaseController {
|
||||
|
||||
@Autowired
|
||||
protected BaseQueryService<String, Model> queryService;
|
||||
|
||||
/**
|
||||
* find model by id
|
||||
* @param id model id
|
||||
* @return model
|
||||
*/
|
||||
@RequestMapping("/find")
|
||||
public ViewModel<Model> find(@NotBlank @RequestParam("id") String id) {
|
||||
return queryService.findViewModel(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return models count
|
||||
*/
|
||||
@RequestMapping("/count")
|
||||
public int count() {
|
||||
return queryService.count(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* list view models
|
||||
* @param start start
|
||||
@ -34,40 +54,48 @@ public class BaseQueryController<Model extends BaseModel<String>>
|
||||
final Integer start,
|
||||
final Integer limit,
|
||||
final String paramSearch) {
|
||||
return listViewModels(start, limit, paramSearch, null);
|
||||
return listViewModels(start, limit, paramSearch, null, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* list view models
|
||||
* @param start start
|
||||
* @param limit limit
|
||||
* @param strSearch search
|
||||
* @param strSorters sorters
|
||||
* @return search
|
||||
* @param strCriteria criteria
|
||||
* @param strFilters filters
|
||||
* @param strOrders orders
|
||||
* @return list result
|
||||
*/
|
||||
protected ListResult<ViewModel<Model>> listViewModels(
|
||||
final Integer start,
|
||||
final Integer limit,
|
||||
final String strSearch,
|
||||
final String strSorters) {
|
||||
return listViewModels(null, start, limit, strSearch, strSorters);
|
||||
final String strCriteria,
|
||||
final String strFilters,
|
||||
final String strOrders) {
|
||||
return listViewModels(null, start, limit, strSearch, strCriteria, strFilters, strOrders);
|
||||
}
|
||||
|
||||
/**
|
||||
* list view models
|
||||
* @param search search
|
||||
* @param start start
|
||||
* @param limit limit
|
||||
* @param strSearch search
|
||||
* @return view models
|
||||
* @param strCriteria criteria
|
||||
* @param strFilters filters
|
||||
* @param strOrders orders
|
||||
* @return list result
|
||||
*/
|
||||
protected ListResult<ViewModel<Model>> listViewModels(
|
||||
final Search search,
|
||||
final Integer start,
|
||||
final Integer limit,
|
||||
final String strSearch,
|
||||
final String strSorters) {
|
||||
return listViewModels(search(search, start, limit, strSearch, strSorters));
|
||||
final String strCriteria,
|
||||
final String strFilters,
|
||||
final String strOrders) {
|
||||
return listViewModels(search(
|
||||
search, start, limit, strSearch, strCriteria, strFilters, strOrders));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -78,22 +106,4 @@ public class BaseQueryController<Model extends BaseModel<String>>
|
||||
protected ListResult<ViewModel<Model>> listViewModels(Search search) {
|
||||
return queryService.listViewModelsPage(search);
|
||||
}
|
||||
|
||||
/**
|
||||
* find model by id
|
||||
* @param id model id
|
||||
* @return model
|
||||
*/
|
||||
@RequestMapping("/find")
|
||||
public ViewModel<Model> find(@NotNull @RequestParam("id") String id) {
|
||||
return queryService.findViewModel(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return models count
|
||||
*/
|
||||
@RequestMapping("/count")
|
||||
public int count() {
|
||||
return queryService.count(null);
|
||||
}
|
||||
}
|
||||
|
@ -2,9 +2,8 @@ package com.pudonghot.ambition.crm.controller;
|
||||
|
||||
import java.util.*;
|
||||
import javax.validation.Valid;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import me.chyxion.tigon.mybatis.Search;
|
||||
import me.chyxion.tigon.model.ViewModel;
|
||||
import javax.validation.constraints.Max;
|
||||
@ -13,6 +12,7 @@ import me.chyxion.tigon.model.ListResult;
|
||||
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;
|
||||
@ -37,7 +37,7 @@ import com.pudonghot.ambition.crm.form.update.CustomerFormForUpdate;
|
||||
public class CustomerController
|
||||
extends BaseQueryController<Customer> {
|
||||
|
||||
private static final String[] SEARCH_COLS = new String[] {
|
||||
private static final List<String> SEARCH_COLS = Arrays.asList(
|
||||
"customer.id",
|
||||
"customer.name",
|
||||
"customer.city",
|
||||
@ -48,26 +48,25 @@ public class CustomerController
|
||||
"customer.salesperson",
|
||||
"year",
|
||||
// status text
|
||||
"prop.name"
|
||||
};
|
||||
"prop.name");
|
||||
|
||||
private static final Map<String, String> SORT_COLS = new HashMap<>();
|
||||
private static final Map<String, String> ORDER_COLS = new HashMap<>();
|
||||
static {
|
||||
SORT_COLS.put(Customer.ID, "customer.id");
|
||||
SORT_COLS.put("dateAdded", "year(customer.date_added)");
|
||||
SORT_COLS.put(CustomerYearToDateSale.YEAR, CustomerYearToDateSale.YEAR);
|
||||
SORT_COLS.put("countryCode", "customer.country_code");
|
||||
SORT_COLS.put(Customer.MS, "customer.ms");
|
||||
SORT_COLS.put(Customer.REGION, "customer.region");
|
||||
SORT_COLS.put(Customer.SALESPERSON, "customer.salesperson");
|
||||
SORT_COLS.put("sumYtdSales", Customer.SUM_YTD_SALES);
|
||||
SORT_COLS.put("status", "prop.sort");
|
||||
SORT_COLS.put("application", "application_names");
|
||||
ORDER_COLS.put(Customer.ID, "customer.id");
|
||||
ORDER_COLS.put("dateAdded", "year(customer.date_added)");
|
||||
ORDER_COLS.put(CustomerYearToDateSale.YEAR, CustomerYearToDateSale.YEAR);
|
||||
ORDER_COLS.put("countryCode", "customer.country_code");
|
||||
ORDER_COLS.put(Customer.MS, "customer.ms");
|
||||
ORDER_COLS.put(Customer.REGION, "customer.region");
|
||||
ORDER_COLS.put(Customer.SALESPERSON, "customer.salesperson");
|
||||
ORDER_COLS.put("sumYtdSales", Customer.SUM_YTD_SALES);
|
||||
ORDER_COLS.put("status", "prop.sort");
|
||||
ORDER_COLS.put("application", "application_names");
|
||||
}
|
||||
|
||||
private static final Map<String, String> CRITERION_COLS;
|
||||
static {
|
||||
CRITERION_COLS = new HashMap<>(SORT_COLS);
|
||||
CRITERION_COLS = new HashMap<>(ORDER_COLS);
|
||||
CRITERION_COLS.put(Customer.NAME, "customer.name");
|
||||
CRITERION_COLS.put(Customer.STATE, "customer.state");
|
||||
CRITERION_COLS.put(Customer.CITY, "customer.city");
|
||||
@ -77,6 +76,48 @@ public class CustomerController
|
||||
CRITERION_COLS.put("issue", "issue.artificial");
|
||||
}
|
||||
|
||||
// filters
|
||||
private static final Map<String, Pair<String, Class<?>>> FILTER_COLS = new HashMap<>();
|
||||
static {
|
||||
FILTER_COLS.put("dateAdded",
|
||||
Pair.of(CRITERION_COLS.get("dateAdded"), Integer.class));
|
||||
FILTER_COLS.put("year",
|
||||
Pair.of(CRITERION_COLS.get("year"), String.class));
|
||||
FILTER_COLS.put("ms",
|
||||
Pair.of(CRITERION_COLS.get("ms"), String.class));
|
||||
FILTER_COLS.put("region",
|
||||
Pair.of(CRITERION_COLS.get("region"), String.class));
|
||||
FILTER_COLS.put("countryCode",
|
||||
Pair.of(CRITERION_COLS.get("countryCode"), String.class));
|
||||
FILTER_COLS.put("state",
|
||||
Pair.of(CRITERION_COLS.get("state"), String.class));
|
||||
FILTER_COLS.put("city",
|
||||
Pair.of(CRITERION_COLS.get("city"), String.class));
|
||||
FILTER_COLS.put("salesperson",
|
||||
Pair.of(CRITERION_COLS.get("city"), String.class));
|
||||
FILTER_COLS.put("status",
|
||||
Pair.of(CRITERION_COLS.get("status"), String.class));
|
||||
FILTER_COLS.put("application",
|
||||
Pair.of(CRITERION_COLS.get("application"), String.class));
|
||||
FILTER_COLS.put("issue",
|
||||
Pair.of(CRITERION_COLS.get("issue"), Boolean.class));
|
||||
|
||||
// filter(search, joFilters, "dateAdded", Integer[].class);
|
||||
// filter(search, joFilters, "year");
|
||||
//
|
||||
// filter(search, joFilters, "ms");
|
||||
// filter(search, joFilters, "region");
|
||||
// filter(search, joFilters, "countryCode");
|
||||
// filter(search, joFilters, "state");
|
||||
// filter(search, joFilters, "city");
|
||||
// filter(search, joFilters, "salesperson");
|
||||
// filter(search, joFilters, "status");
|
||||
// filter(search, joFilters, "application");
|
||||
//
|
||||
// filter(search, joFilters, "issue", Boolean[].class);
|
||||
|
||||
}
|
||||
|
||||
@RequestMapping("/list")
|
||||
public ListResult<ViewModel<Customer>> list(
|
||||
@Min(0)
|
||||
@ -92,10 +133,10 @@ public class CustomerController
|
||||
final String criteria,
|
||||
@RequestParam(value = "filters", required = false)
|
||||
final String filters,
|
||||
@RequestParam(value = "sorters", required = false)
|
||||
final String sorters) {
|
||||
@RequestParam(value = "orders", required = false)
|
||||
final String orders) {
|
||||
|
||||
final Search search = filters(new Search(), filters);
|
||||
final Search search = new Search();
|
||||
User user = getUser().getData();
|
||||
// if (!user.isAdmin()) {
|
||||
search.setAttr(User.ACCOUNT, user.getAccount());
|
||||
@ -104,9 +145,7 @@ public class CustomerController
|
||||
if (StringUtils.isNotBlank(strSearch)) {
|
||||
search.setAttr("YTD_SALE", true);
|
||||
}
|
||||
final ListResult<ViewModel<Customer>> result =
|
||||
listViewModels(search(criteria(search, criteria), start, limit, strSearch, sorters));
|
||||
return result;
|
||||
return listViewModels(search, start, limit, strSearch, criteria, filters, orders);
|
||||
}
|
||||
|
||||
@RequiresRoles(User.ROLE_ADMIN)
|
||||
@ -135,7 +174,7 @@ public class CustomerController
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
protected String[] searchCols() {
|
||||
protected List<String> searchCols() {
|
||||
return SEARCH_COLS;
|
||||
}
|
||||
|
||||
@ -143,174 +182,42 @@ public class CustomerController
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
protected Map<String, String> sorterCols() {
|
||||
return SORT_COLS;
|
||||
protected Pair<String, Class<?>> filterCol(final String field) {
|
||||
return FILTER_COLS.get(field);
|
||||
}
|
||||
|
||||
private String criterionCol(String col) {
|
||||
return CRITERION_COLS.get(col);
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected Pair<String, Class<?>> criterionCol(final String col) {
|
||||
return Pair.of(CRITERION_COLS.get(col), Object.class);
|
||||
}
|
||||
|
||||
private Search criteria(final Search search, final String strCriteria) {
|
||||
|
||||
if (StringUtils.isBlank(strCriteria)) {
|
||||
log.debug("No Criteria Given.");
|
||||
return search;
|
||||
}
|
||||
|
||||
final List<String[]> criteria;
|
||||
try {
|
||||
criteria = JSON.parseArray(decodeParam(strCriteria), String[].class);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new IllegalStateException(
|
||||
"Invalid Criteria [" + strCriteria + "]", e);
|
||||
}
|
||||
|
||||
for (String[] criterion : criteria) {
|
||||
if (criterion.length == 3) {
|
||||
final String col = criterion[0];
|
||||
if (StringUtils.isNotBlank(col)) {
|
||||
final String criterionCol = criterionCol(col);
|
||||
if (StringUtils.isNotBlank(criterionCol)) {
|
||||
// for search year
|
||||
if (CustomerYearToDateSale.YEAR.equals(criterionCol) ||
|
||||
CustomerYearToDateSale.YTD_SALE.equals(criterionCol)) {
|
||||
search.setAttr("YTD_SALE", true);
|
||||
}
|
||||
final String op = criterion[1];
|
||||
final String val = criterion[2];
|
||||
if (StringUtils.isNotBlank(op) && StringUtils.isNotBlank(val)) {
|
||||
if ("eq".equals(op)) {
|
||||
search.eq(criterionCol, val);
|
||||
}
|
||||
else if ("gt".equals(op)) {
|
||||
search.gt(criterionCol, val);
|
||||
}
|
||||
else if ("gte".equals(op)) {
|
||||
search.gte(criterionCol, val);
|
||||
}
|
||||
else if ("lt".equals(op)) {
|
||||
search.lt(criterionCol, val);
|
||||
}
|
||||
else if ("lte".equals(op)) {
|
||||
search.lt(criterionCol, val);
|
||||
}
|
||||
else if ("ne".equals(op)) {
|
||||
search.ne(criterionCol, val);
|
||||
}
|
||||
else if ("like".equals(op)) {
|
||||
search.like(criterionCol, val, true);
|
||||
}
|
||||
else {
|
||||
log.warn("Unknown Criterion Op [{}], Ignore.", op);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
log.warn("Criterion Col Is Blank, Ignore.");
|
||||
}
|
||||
}
|
||||
else {
|
||||
log.warn("Invalid Criterion [{}], Ignore.", criterion);
|
||||
}
|
||||
}
|
||||
return search;
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
protected String orderCol(final String field) {
|
||||
return ORDER_COLS.get(field);
|
||||
}
|
||||
|
||||
private Search filters(final Search search, final String strFilters) {
|
||||
|
||||
if (StringUtils.isBlank(strFilters)) {
|
||||
log.debug("No filters given.");
|
||||
defaultFilter(search, "status");
|
||||
return search;
|
||||
}
|
||||
|
||||
final JSONObject joFilters;
|
||||
try {
|
||||
joFilters = JSON.parseObject(decodeParam(strFilters));
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new IllegalStateException(
|
||||
"Invalid Filters [" + strFilters + "]", e);
|
||||
}
|
||||
|
||||
filter(search, joFilters, "dateAdded", Integer[].class);
|
||||
filter(search, joFilters, "year");
|
||||
filter(search, joFilters, "ms");
|
||||
filter(search, joFilters, "region");
|
||||
filter(search, joFilters, "countryCode");
|
||||
filter(search, joFilters, "state");
|
||||
filter(search, joFilters, "city");
|
||||
filter(search, joFilters, "salesperson");
|
||||
filter(search, joFilters, "status");
|
||||
filter(search, joFilters, "application");
|
||||
filter(search, joFilters, "issue", Boolean[].class);
|
||||
|
||||
return search;
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
protected Search defaultFilter(final Search search) {
|
||||
return search.ne(CRITERION_COLS.get("status"), CustomerProperty.STATUS_NA_ID);
|
||||
}
|
||||
|
||||
private Search filter(final Search search, final JSONObject joFilters, final String field) {
|
||||
return filter(search, joFilters, field, String[].class);
|
||||
}
|
||||
|
||||
private <T> Search filter(final Search search, final JSONObject joFilters, final String field, Class<T[]> clazz) {
|
||||
final String col = CRITERION_COLS.get(field);
|
||||
if (StringUtils.isNotBlank(col)) {
|
||||
final T[] filters =
|
||||
joFilters.getObject(field, clazz);
|
||||
if (filters != null && filters.length > 0) {
|
||||
log.info("Col [{}] filters [{}] found.", col, filters);
|
||||
if ("application".equals(col)) {
|
||||
search.setAttr("APPLICATIONS", filters);
|
||||
}
|
||||
else {
|
||||
in(search, col, filters);
|
||||
}
|
||||
}
|
||||
else {
|
||||
defaultFilter(search, field);
|
||||
}
|
||||
|
||||
// filter year
|
||||
if (CustomerYearToDateSale.YEAR.equals(col)) {
|
||||
search.setAttr("YTD_SALE", true);
|
||||
}
|
||||
}
|
||||
return search;
|
||||
}
|
||||
|
||||
private void defaultFilter(final Search search, final String field) {
|
||||
// default no NA
|
||||
if ("status".equals(field)) {
|
||||
search.ne(CRITERION_COLS.get(field), CustomerProperty.STATUS_NA_ID);
|
||||
}
|
||||
}
|
||||
|
||||
private void in(final Search search, final String col, final Object[] values) {
|
||||
final Set<Object> setValues = new HashSet<>(Arrays.asList(values));
|
||||
final Iterator<Object> valIt = setValues.iterator();
|
||||
if (setValues.size() == 1) {
|
||||
final Object val = valIt.next();
|
||||
search.eq(col, "null".equals(val) ? null : val);
|
||||
}
|
||||
else {
|
||||
boolean nullValue = false;
|
||||
while (valIt.hasNext()) {
|
||||
final Object val = valIt.next();
|
||||
if (val == null || "null".equals(val)) {
|
||||
nullValue = true;
|
||||
valIt.remove();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (nullValue) {
|
||||
search.and(new Search(col, setValues).or(col, null));
|
||||
}
|
||||
else {
|
||||
search.in(col, setValues);
|
||||
}
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
protected void onSearch(final Search search, final String col) {
|
||||
// for search year
|
||||
if (CustomerYearToDateSale.YEAR.equals(col) ||
|
||||
CustomerYearToDateSale.YTD_SALE.equals(col)) {
|
||||
search.setAttr("YTD_SALE", true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
package com.pudonghot.ambition.crm.controller;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Arrays;
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.Max;
|
||||
import me.chyxion.tigon.model.ViewModel;
|
||||
@ -24,6 +26,11 @@ import com.pudonghot.ambition.crm.form.update.CustomerIssueFormForUpdate;
|
||||
public class CustomerIssueController
|
||||
extends BaseQueryController<CustomerIssue> {
|
||||
|
||||
private static final List<String> SEARCH_COLS =
|
||||
Arrays.asList(
|
||||
CustomerIssue.ISSUE,
|
||||
CustomerIssue.NOTE);
|
||||
|
||||
@RequestMapping("/list")
|
||||
public ListResult<ViewModel<CustomerIssue>> list(
|
||||
@Min(0)
|
||||
@ -54,10 +61,7 @@ public class CustomerIssueController
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
protected String[] searchCols() {
|
||||
return new String[] {
|
||||
CustomerIssue.ISSUE,
|
||||
CustomerIssue.NOTE
|
||||
};
|
||||
protected List<String> searchCols() {
|
||||
return SEARCH_COLS;
|
||||
}
|
||||
}
|
||||
|
@ -21,6 +21,9 @@ 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>
|
||||
@ -31,6 +34,11 @@ import com.pudonghot.ambition.crm.form.update.CustomerPropertyFormForUpdate;
|
||||
public class CustomerPropertyController
|
||||
extends BaseQueryController<CustomerProperty> {
|
||||
|
||||
private static final List<String> SEARCH_COLS =
|
||||
Arrays.asList(
|
||||
CustomerProperty.NAME,
|
||||
CustomerProperty.NOTE);
|
||||
|
||||
@RequestMapping("/list")
|
||||
public ListResult<ViewModel<CustomerProperty>> list(
|
||||
@Min(0)
|
||||
@ -54,7 +62,7 @@ public class CustomerPropertyController
|
||||
Boolean.parseBoolean(enabled));
|
||||
}
|
||||
((CustomerPropertyService) queryService).initSystemStatus(getUserId());
|
||||
return listViewModels(search, start, limit, strSearch, null);
|
||||
return listViewModels(search, start, limit, strSearch, null, null, null);
|
||||
}
|
||||
|
||||
@RequestMapping("/app-list")
|
||||
@ -70,7 +78,7 @@ public class CustomerPropertyController
|
||||
if (StringUtils.isNotBlank(enabled)) {
|
||||
search.eq(CustomerProperty.ENABLED, Boolean.parseBoolean(enabled));
|
||||
}
|
||||
return listViewModels(search, null, null, strSearch, null);
|
||||
return listViewModels(search, null, null, strSearch, null, null, null);
|
||||
}
|
||||
|
||||
@RequiresRoles(User.ROLE_ADMIN)
|
||||
@ -100,10 +108,7 @@ public class CustomerPropertyController
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
protected String[] searchCols() {
|
||||
return new String[] {
|
||||
CustomerProperty.NAME,
|
||||
CustomerProperty.NOTE
|
||||
};
|
||||
protected List<String> searchCols() {
|
||||
return SEARCH_COLS;
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,9 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import com.pudonghot.ambition.crm.form.create.HomePageFormForCreate;
|
||||
import com.pudonghot.ambition.crm.form.update.HomePageFormForUpdate;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Shaun Chyxion <br>
|
||||
* chyxion@163.com <br>
|
||||
@ -29,10 +32,10 @@ import com.pudonghot.ambition.crm.form.update.HomePageFormForUpdate;
|
||||
@RequestMapping("/home-page")
|
||||
public class HomePageController
|
||||
extends BaseQueryController<HomePage> {
|
||||
private static final String[] SEARCH_COLS = new String[] {
|
||||
HomePage.NAME,
|
||||
HomePage.NOTE
|
||||
};
|
||||
private static final List<String> SEARCH_COLS =
|
||||
Arrays.asList(
|
||||
HomePage.NAME,
|
||||
HomePage.NOTE);
|
||||
|
||||
@RequestMapping("/list")
|
||||
@RequiresRoles(User.ROLE_ADMIN)
|
||||
@ -47,7 +50,7 @@ public class HomePageController
|
||||
@RequestParam(value = "search", required = false)
|
||||
final String search) {
|
||||
|
||||
return listViewModels(start, limit, search, null);
|
||||
return listViewModels(start, limit, search);
|
||||
}
|
||||
|
||||
@RequiresRoles(User.ROLE_ADMIN)
|
||||
@ -85,7 +88,7 @@ public class HomePageController
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
protected String[] searchCols() {
|
||||
protected List<String> searchCols() {
|
||||
return SEARCH_COLS;
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.pudonghot.ambition.crm.controller;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Arrays;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.chyxion.tigon.model.ViewModel;
|
||||
import javax.validation.constraints.Max;
|
||||
@ -23,6 +24,14 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
||||
public class ImportRecordController
|
||||
extends BaseQueryController<ImportRecord> {
|
||||
|
||||
private final List<String> SEARCH_COLS =
|
||||
Arrays.asList("r.type",
|
||||
"r.note",
|
||||
"u.name",
|
||||
"u.en_name",
|
||||
"u.account",
|
||||
"u.employee_id" );
|
||||
|
||||
@RequestMapping("/list")
|
||||
@RequiresRoles(User.ROLE_ADMIN)
|
||||
public ViewModel<List<ViewModel<ImportRecord>>> list(
|
||||
@ -36,7 +45,7 @@ public class ImportRecordController
|
||||
@RequestParam(value = "search", required = false)
|
||||
final String search) {
|
||||
|
||||
return listViewModels(search(start, limit, search, null)
|
||||
return listViewModels(search(start, limit, search)
|
||||
.table("r")
|
||||
.desc(ImportRecord.DATE_CREATED));
|
||||
}
|
||||
@ -45,7 +54,8 @@ public class ImportRecordController
|
||||
* {@inheritDoc}
|
||||
* @return search cols
|
||||
*/
|
||||
protected String[] searchCols() {
|
||||
return new String[] { "r.type", "r.note", "u.name", "u.en_name", "u.account", "u.employee_id" };
|
||||
@Override
|
||||
protected List<String> searchCols() {
|
||||
return SEARCH_COLS;
|
||||
}
|
||||
}
|
||||
|
@ -1,17 +1,20 @@
|
||||
package com.pudonghot.ambition.crm.controller;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.List;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import javax.validation.Valid;
|
||||
import me.chyxion.tigon.mybatis.Search;
|
||||
import javax.validation.constraints.Max;
|
||||
import javax.validation.constraints.Min;
|
||||
import me.chyxion.tigon.model.ViewModel;
|
||||
import me.chyxion.tigon.model.ListResult;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import com.pudonghot.ambition.crm.model.User;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.hibernate.validator.constraints.NotBlank;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.hibernate.validator.constraints.NotBlank;
|
||||
import com.pudonghot.ambition.crm.service.UserService;
|
||||
import org.apache.shiro.authz.annotation.RequiresRoles;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
@ -31,22 +34,22 @@ import com.pudonghot.ambition.crm.form.update.UserFormForUpdatePassword;
|
||||
public class UserController
|
||||
extends BaseQueryController<User> {
|
||||
|
||||
private static final Map<String, String> SORT_COLS = new HashMap<>();
|
||||
private static final String[] SEARCH_COLS = new String[] {
|
||||
private static final List<String> SEARCH_COLS = Arrays.asList(
|
||||
User.NAME,
|
||||
User.EN_NAME,
|
||||
User.ACCOUNT,
|
||||
User.EMPLOYEE_ID,
|
||||
User.MOBILE,
|
||||
User.EMAIL,
|
||||
User.NOTE
|
||||
};
|
||||
// User.MOBILE,
|
||||
// User.EMAIL,
|
||||
User.NOTE);
|
||||
|
||||
private static final Map<String, String> ORDER_COLS = new HashMap<>();
|
||||
|
||||
static {
|
||||
SORT_COLS.put(User.ACCOUNT, User.ACCOUNT);
|
||||
SORT_COLS.put("employeeId", User.EMPLOYEE_ID);
|
||||
SORT_COLS.put(User.MOBILE, User.MOBILE);
|
||||
SORT_COLS.put("enName", User.EN_NAME);
|
||||
ORDER_COLS.put(User.ACCOUNT, User.ACCOUNT);
|
||||
ORDER_COLS.put("employeeId", User.EMPLOYEE_ID);
|
||||
ORDER_COLS.put(User.MOBILE, User.MOBILE);
|
||||
ORDER_COLS.put("enName", User.EN_NAME);
|
||||
}
|
||||
|
||||
@RequestMapping("/list")
|
||||
@ -61,9 +64,14 @@ public class UserController
|
||||
final int limit,
|
||||
@RequestParam(value = "search", required = false)
|
||||
final String search,
|
||||
@RequestParam(value = "sorters", required = false)
|
||||
final String sorters) {
|
||||
return listViewModels(start, limit, search, sorters);
|
||||
@RequestParam(value = "orders", required = false)
|
||||
final String orders) {
|
||||
return listViewModels(start, limit, search, null, null, orders);
|
||||
}
|
||||
|
||||
@RequestMapping("/list-for-select")
|
||||
public List<ViewModel<User>> listForSelect() {
|
||||
return queryService.listViewModels(new Search().asc(User.EMPLOYEE_ID));
|
||||
}
|
||||
|
||||
@RequiresRoles(User.ROLE_ADMIN)
|
||||
@ -100,7 +108,7 @@ public class UserController
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
protected String[] searchCols() {
|
||||
protected List<String> searchCols() {
|
||||
return SEARCH_COLS;
|
||||
}
|
||||
|
||||
@ -108,7 +116,7 @@ public class UserController
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
protected Map<String, String> sorterCols() {
|
||||
return SORT_COLS;
|
||||
protected String orderCol(final String field) {
|
||||
return ORDER_COLS.get(field);
|
||||
}
|
||||
}
|
||||
|
@ -35,6 +35,12 @@ import com.pudonghot.ambition.crm.form.update.WeekGoalFormForUpdate;
|
||||
public class WeekGoalController
|
||||
extends BaseQueryController<WeekGoal> {
|
||||
|
||||
private static final List<String> SEARCH_COLS =
|
||||
Arrays.asList("u.name",
|
||||
"u.en_name",
|
||||
"u.account",
|
||||
"u.employee_id");
|
||||
|
||||
@RequestMapping("/list")
|
||||
public ViewModel<List<ViewModel<WeekGoal>>> list(
|
||||
@Min(0)
|
||||
@ -50,7 +56,7 @@ public class WeekGoalController
|
||||
final String strSearch) {
|
||||
final List<String> employeeIds = employeeIdsFilter(filters);
|
||||
return addYearSum(((WeekGoalService) queryService).listJoinUser(
|
||||
listFilters(search(start, limit, strSearch, null), employeeIds)), employeeIds);
|
||||
listFilters(search(start, limit, strSearch), employeeIds)), employeeIds);
|
||||
}
|
||||
|
||||
@RequestMapping("/mine")
|
||||
@ -116,8 +122,8 @@ public class WeekGoalController
|
||||
* @return search cols
|
||||
*/
|
||||
@Override
|
||||
protected String[] searchCols() {
|
||||
return new String[] { "u.name", "u.en_name", "u.account", "u.employee_id" };
|
||||
protected List<String> searchCols() {
|
||||
return SEARCH_COLS;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -4,6 +4,7 @@ import java.util.Date;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.util.Assert;
|
||||
import me.chyxion.tigon.model.ViewModel;
|
||||
import org.springframework.stereotype.Service;
|
||||
import com.pudonghot.ambition.file.AmbitionFileApi;
|
||||
@ -45,12 +46,31 @@ public class ApplicationServiceSupport
|
||||
final Date now = new Date();
|
||||
application.setDateUpdated(now);
|
||||
|
||||
final MultipartFile[] images = form.getImages();
|
||||
uploadImages(id, 0, form.getImages(), form.getImageTitles(), form.getCreatedBy());
|
||||
mapper.insert(application);
|
||||
return toViewModel(application);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public ViewModel<Application> update(final ApplicationFormForUpdate form) {
|
||||
final String id = form.getId();
|
||||
final Application application = find(id);
|
||||
Assert.state(application != null, "No application [" + id + "] found");
|
||||
final String updatedBy = form.getUpdatedBy();
|
||||
Assert.state(form.isAdmin() || application.getOwner().equals(updatedBy),
|
||||
"No permission to update application");
|
||||
|
||||
uploadImages(id, imageMapper.nextSort(id), form.getImages(), form.getImageTitles(), updatedBy);
|
||||
return update(form.copy(application));
|
||||
}
|
||||
|
||||
private void uploadImages(final String id, int sort, final MultipartFile[] images, final String[] titles, final String createdBy) {
|
||||
if (images != null) {
|
||||
final String createdBy = form.getCreatedBy();
|
||||
int sort = 0;
|
||||
final Date now = new Date();
|
||||
final String imageFolder = imageFolder(id);
|
||||
final String[] imageTitles = form.getImageTitles();
|
||||
int i = 0;
|
||||
for (final MultipartFile image : images) {
|
||||
if (!image.isEmpty()) {
|
||||
@ -61,7 +81,8 @@ public class ApplicationServiceSupport
|
||||
appImage.setId(imageId);
|
||||
appImage.setApplicationId(id);
|
||||
appImage.setSort(sort++);
|
||||
appImage.setNote(imageTitles[i]);
|
||||
appImage.setEnabled(true);
|
||||
appImage.setNote(titles[i]);
|
||||
appImage.setCreatedBy(createdBy);
|
||||
appImage.setDateCreated(now);
|
||||
imageMapper.insert(appImage);
|
||||
@ -74,16 +95,6 @@ public class ApplicationServiceSupport
|
||||
++i;
|
||||
}
|
||||
}
|
||||
mapper.insert(application);
|
||||
return toViewModel(application);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public ViewModel<Application> update(final ApplicationFormForUpdate form) {
|
||||
return null;
|
||||
}
|
||||
|
||||
private String imageFolder(final String appId) {
|
||||
|
@ -1,6 +1,8 @@
|
||||
package com.pudonghot.ambition.crm.mapper;
|
||||
|
||||
import me.chyxion.tigon.mybatis.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.hibernate.validator.constraints.NotBlank;
|
||||
import com.pudonghot.ambition.crm.model.ApplicationImage;
|
||||
|
||||
/**
|
||||
@ -10,4 +12,10 @@ import com.pudonghot.ambition.crm.model.ApplicationImage;
|
||||
*/
|
||||
public interface ApplicationImageMapper extends BaseMapper<String, ApplicationImage> {
|
||||
|
||||
/**
|
||||
* find next sort
|
||||
* @param applicationId application id
|
||||
* @return next sort
|
||||
*/
|
||||
int nextSort(@NotBlank @Param("applicationId") String applicationId);
|
||||
}
|
||||
|
@ -10,4 +10,11 @@
|
||||
"-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.pudonghot.ambition.crm.mapper.ApplicationImageMapper">
|
||||
|
||||
<select id="nextSort" resultType="int">
|
||||
select if (application_id, max(sort) + 1, 0)
|
||||
from <include refid="table" />
|
||||
where application_id = #{applicationId}
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
|
@ -10,4 +10,22 @@
|
||||
"-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.pudonghot.ambition.crm.mapper.ApplicationMapper">
|
||||
|
||||
<select id="list" resultType="com.pudonghot.ambition.crm.model.Application">
|
||||
select
|
||||
<include refid="cols" />,
|
||||
(select group_concat(id order by sort separator 0x1d) from
|
||||
crm_application_image
|
||||
where application_id = a.id
|
||||
group by application_id) images,
|
||||
|
||||
(select group_concat(note order by sort separator 0x1d) from
|
||||
crm_application_image
|
||||
where application_id = a.id
|
||||
group by application_id) image_titles
|
||||
from
|
||||
<include refid="table" /> a
|
||||
<include refid="Tigon.search" />
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
|
@ -21,6 +21,8 @@ import org.springframework.web.multipart.MultipartFile;
|
||||
public class ApplicationFormForUpdate extends FU2<String, String> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
// current user is admin
|
||||
private boolean admin;
|
||||
@NotBlank
|
||||
@Length(max = 64)
|
||||
private String name;
|
||||
|
@ -4,6 +4,7 @@ import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import me.chyxion.tigon.model.M3;
|
||||
import me.chyxion.tigon.mybatis.Table;
|
||||
import me.chyxion.tigon.mybatis.Transient;
|
||||
|
||||
/**
|
||||
* @author Donghuang <br>
|
||||
@ -25,4 +26,10 @@ public class Application extends M3<String, String> {
|
||||
private String name;
|
||||
private String content;
|
||||
private String owner;
|
||||
|
||||
// Transient Props
|
||||
@Transient
|
||||
private String images;
|
||||
@Transient
|
||||
private String imageTitles;
|
||||
}
|
||||
|
21
web/app/components/customer-application/preview-btn.js
Normal file
21
web/app/components/customer-application/preview-btn.js
Normal file
@ -0,0 +1,21 @@
|
||||
import Component from '@ember/component';
|
||||
import { htmlSafe } from '@ember/string';
|
||||
|
||||
export default Component.extend({
|
||||
tagName: '',
|
||||
didReceiveAttrs() {
|
||||
const me = this;
|
||||
me._super(...arguments);
|
||||
me.set('content', htmlSafe(me.get('model.content')));
|
||||
},
|
||||
actions: {
|
||||
show() {
|
||||
let me = this;
|
||||
me.set('show', true);
|
||||
},
|
||||
close() {
|
||||
let me = this;
|
||||
me.set('show', false);
|
||||
}
|
||||
}
|
||||
});
|
@ -32,6 +32,7 @@ export default BaseFormInput.extend({
|
||||
allowClear: me.get('nullable'),
|
||||
placeholder: me.get('placeholder') || me.get('label') || 'Please select...'
|
||||
}).on('change', function(e) {
|
||||
console.log('select2 change: ', e);
|
||||
if (e.removed) {
|
||||
me.unselect(me.findOption(e.removed.id));
|
||||
}
|
||||
@ -64,7 +65,7 @@ export default BaseFormInput.extend({
|
||||
if (me.get('multiple')) {
|
||||
const vals = me.getVal();
|
||||
if (isArray(vals)) {
|
||||
vals.forEach(v => me.select(me.findOption(v)));
|
||||
vals.each(v => me.select(me.findOption(v)));
|
||||
}
|
||||
else {
|
||||
me.setVal(me.getSelected());
|
||||
@ -101,6 +102,6 @@ export default BaseFormInput.extend({
|
||||
getSelected() {
|
||||
const me = this;
|
||||
const selected = me.get('options').filter(o => o.selected).mapBy(me.get('value-field'));
|
||||
return me.get('multiple') ? selected : selected[0];
|
||||
return selected.length > 1 ? selected : selected.length == 1 ? selected[0] : null;
|
||||
}
|
||||
});
|
||||
|
@ -1,18 +1,25 @@
|
||||
import Ember from 'ember';
|
||||
import Component from '@ember/component';
|
||||
import { computed } from '@ember/object';
|
||||
import $ from 'jquery'
|
||||
|
||||
export default Ember.Component.extend({
|
||||
export default Component.extend({
|
||||
tagName: 'span',
|
||||
classNames: ['inline'],
|
||||
index: 0,
|
||||
images: computed.alias('previews'),
|
||||
'image-height': 22,
|
||||
imageHeight: computed.alias('image-height'),
|
||||
'image-style': 'border-radius: 8%; border: 1px solid #DCDCDC; max-width: 32px;',
|
||||
imageStyle: computed.alias('image-style'),
|
||||
didReceiveAttrs() {
|
||||
let me = this;
|
||||
let previews = me.get('previews');
|
||||
if (Ember.$.type(previews) === 'string') {
|
||||
let images = me.get('images');
|
||||
if (Ember.$.type(images) === 'string') {
|
||||
let sep = me.get('separator');
|
||||
me.set('previews', sep ? previews.split(sep) : [previews]);
|
||||
me.set('images', sep ? images.split(sep) : [images]);
|
||||
}
|
||||
},
|
||||
imageHeight: 22,
|
||||
imageStyle: 'border-radius: 8%; border: 1px solid #DCDCDC; max-width: 32px;',
|
||||
didInsertElement() {
|
||||
let me = this;
|
||||
me._super(...arguments);
|
||||
|
@ -1,16 +1,22 @@
|
||||
import Ember from 'ember';
|
||||
import Component from '@ember/component'
|
||||
import BaseComponentMixin from '../mixins/components/base-component';
|
||||
|
||||
export default Ember.Component.extend(BaseComponentMixin, {
|
||||
export default Component.extend(BaseComponentMixin, {
|
||||
classNames: ['modal', 'fade'],
|
||||
'init-modal': true,
|
||||
transitionToParentRouteAfterClose: true,
|
||||
'close-to-parent': true,
|
||||
'cancel-text': 'Cancel',
|
||||
'submit-text': 'Submit',
|
||||
keyboard: true,
|
||||
didInsertElement() {
|
||||
let me = this;
|
||||
me._super(...arguments);
|
||||
if (me.get('init-modal')) {
|
||||
me.$().modal().on('hidden.bs.modal', ()=> {
|
||||
me.$() && me.get('transitionToParentRouteAfterClose') &&
|
||||
me.$().modal({
|
||||
backdrop: me.get('backdrop'),
|
||||
keyboard: me.get('keyboard')
|
||||
}).on('hidden.bs.modal', ()=> {
|
||||
me.$() && me.get('close-to-parent') &&
|
||||
me.get('router').transitionTo(
|
||||
me.get('parentRouteName') ||
|
||||
me.get('routeName').replace(/\.[^.]+$/, ''));
|
||||
|
@ -10,7 +10,8 @@ const OptionTextComponent = Component.extend({
|
||||
me._super(...arguments);
|
||||
let val = me.get('value');
|
||||
if (val) {
|
||||
const option = (me.get('options') || []).findBy(me.get('value-field'), val);
|
||||
const valueField = me.get('value-field');
|
||||
const option = (me.get('options') || []).findBy(valueField, val);
|
||||
if (option) {
|
||||
let text = option[me.get('text-field')];
|
||||
let textExp = me.get('text-exp');
|
||||
|
@ -3,7 +3,7 @@ import BaseComponentMixin from '../mixins/components/base-component';
|
||||
|
||||
export default Ember.Component.extend(BaseComponentMixin, {
|
||||
tagName: 'th',
|
||||
order: Ember.computed('route.controller.sorters', function() {
|
||||
order: Ember.computed('route.controller.orders', function() {
|
||||
return this.getDir();
|
||||
}),
|
||||
sorting: Ember.computed.none('order'),
|
||||
@ -14,44 +14,44 @@ export default Ember.Component.extend(BaseComponentMixin, {
|
||||
getDir() {
|
||||
let me = this;
|
||||
let name = me.get('name');
|
||||
let sorters = me.getSorters();
|
||||
if (sorters && sorters.length) {
|
||||
let sorter = sorters.find(sorter => sorter.hasOwnProperty(name));
|
||||
if (sorter) {
|
||||
return sorter[name];
|
||||
let orders = me.getOrders();
|
||||
if (orders && orders.length) {
|
||||
let order = orders.find(order => order.hasOwnProperty(name));
|
||||
if (order) {
|
||||
return order[name];
|
||||
}
|
||||
}
|
||||
},
|
||||
getSorters() {
|
||||
getOrders() {
|
||||
let me = this;
|
||||
let strSorters = me.get('route.controller.sorters');
|
||||
if (strSorters) {
|
||||
return JSON.parse(strSorters);
|
||||
let strOrders = me.get('route.controller.orders');
|
||||
if (strOrders) {
|
||||
return JSON.parse(strOrders);
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
sort() {
|
||||
let me = this;
|
||||
let sorters = me.getSorters() || [];
|
||||
let orders = me.getOrders() || [];
|
||||
let name = me.get('name');
|
||||
if (sorters.length) {
|
||||
sorters = sorters.filter(sorter => !sorter.hasOwnProperty(name));
|
||||
if (orders.length) {
|
||||
orders = orders.filter(order => !order.hasOwnProperty(name));
|
||||
}
|
||||
let sorter = {};
|
||||
sorter[name] =
|
||||
let order = {};
|
||||
order[name] =
|
||||
me.get('order') === 'asc' ?
|
||||
'desc' : 'asc';
|
||||
// prepend sort
|
||||
sorters.unshift(sorter);
|
||||
me.set('route.controller.sorters', JSON.stringify(sorters));
|
||||
orders.unshift(order);
|
||||
me.set('route.controller.orders', JSON.stringify(orders));
|
||||
},
|
||||
removeSort() {
|
||||
let me = this;
|
||||
let sorters = me.getSorters();
|
||||
if (sorters) {
|
||||
let orders = me.getOrders();
|
||||
if (orders) {
|
||||
let name = me.get('name');
|
||||
me.set('route.controller.sorters',
|
||||
JSON.stringify(sorters.filter(sorter => !sorter.hasOwnProperty(name))));
|
||||
me.set('route.controller.orders',
|
||||
JSON.stringify(orders.filter(order => !order.hasOwnProperty(name))));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
16
web/app/helpers/customer-application-images.js
Normal file
16
web/app/helpers/customer-application-images.js
Normal file
@ -0,0 +1,16 @@
|
||||
import { helper } from '@ember/component/helper';
|
||||
|
||||
export function customerApplicationImages([fileBasePath, appId, images, titles]) {
|
||||
if (images) {
|
||||
titles = titles ? titles.split(String.fromCharCode(0x1d)) : [];
|
||||
return images.split(String.fromCharCode(0x1d)).map((image, i) => {
|
||||
return {
|
||||
image: fileBasePath + 'app/' + appId + '/' + image,
|
||||
title: titles[i]
|
||||
}
|
||||
});
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
export default helper(customerApplicationImages);
|
@ -6,7 +6,10 @@ export default BaseRoute.extend({
|
||||
search: {
|
||||
refreshModel: true
|
||||
},
|
||||
sorters: {
|
||||
filters: {
|
||||
refreshModel: true
|
||||
},
|
||||
orders: {
|
||||
refreshModel: true
|
||||
}
|
||||
},
|
||||
|
@ -1,6 +1,7 @@
|
||||
import Ember from 'ember';
|
||||
import BaseRoute from '../base';
|
||||
import EmberObject, { computed } from '@ember/object';
|
||||
import RSVP from 'rsvp';
|
||||
|
||||
export default BaseRoute.extend({
|
||||
breadcrumbs: [{route: 'customer-application.list', params: 1, text: 'Customer Application'},
|
||||
@ -11,9 +12,10 @@ export default BaseRoute.extend({
|
||||
})
|
||||
}),
|
||||
model() {
|
||||
return this.get('modelClass').create({
|
||||
return RSVP.hash({
|
||||
enabled: true,
|
||||
images: [{}]
|
||||
images: [{}],
|
||||
users: this.get('store').ajaxGet('user/list-for-select')
|
||||
});
|
||||
},
|
||||
actions: {
|
||||
|
@ -2,10 +2,23 @@ import Ember from 'ember';
|
||||
import BaseEditRoute from '../base-edit';
|
||||
|
||||
export default BaseEditRoute.extend({
|
||||
service: Ember.inject.service('customer-property.service'),
|
||||
afterModel(model) {
|
||||
const me = this;
|
||||
me._super(...arguments);
|
||||
model.images = [{}];
|
||||
this.set('breadcrumbs',
|
||||
[{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({});
|
||||
},
|
||||
removeImage(image) {
|
||||
const me = this;
|
||||
me.get('controller.model.images').removeObject(image);
|
||||
},
|
||||
}
|
||||
});
|
||||
|
@ -6,4 +6,18 @@ export default BaseListRoute.extend({
|
||||
// model(params) {
|
||||
// return this.get('store').ajaxGet('customer-property/app-list', params);
|
||||
// }
|
||||
actions: {
|
||||
showContent(app) {
|
||||
this.get('dialog').dialog({
|
||||
title: app.name,
|
||||
message: `<p>${app.content}</p>`,
|
||||
buttons: {
|
||||
ok: {
|
||||
label: 'OK',
|
||||
className: 'btn-info'
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -65,9 +65,6 @@ export default BaseListRoute.extend({
|
||||
queryParams: {
|
||||
criteria: {
|
||||
refreshModel: true
|
||||
},
|
||||
filters: {
|
||||
refreshModel: true
|
||||
}
|
||||
},
|
||||
breadcrumbs: [{text: 'Customers'}],
|
||||
|
@ -0,0 +1,18 @@
|
||||
<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>
|
||||
|
||||
{{#if show}}
|
||||
{{#modal-dialog title=model.name no-cancel=true submit=(action 'close') on-close=(action 'close') close-to-parent=false}}
|
||||
<div class="widget-main">
|
||||
<div class="space-12"></div>
|
||||
<p>{{content}}</p>
|
||||
<hr />
|
||||
{{#with (customer-application-images file-base-path model.id model.images model.imageTitles) as |images|}}
|
||||
{{#each images as |image index|}}
|
||||
{{image-previews cover-title=true image-height=192 image-style='border-radius: 2%; border: 1px solid #DCDCDC; max-width: 480px;' previews=images index=index}}
|
||||
{{/each}}
|
||||
{{/with}}
|
||||
</div>
|
||||
{{/modal-dialog}}
|
||||
{{/if}}
|
@ -1,12 +1,23 @@
|
||||
{{#if previews}}
|
||||
<a href="{{previews.firstObject}}" data-rel="{{elementId}}_preview">
|
||||
<img height="{{imageHeight}}" style="{{imageStyle}}" src="{{previews.firstObject}}" />
|
||||
</a>
|
||||
<div class="dropdown-menu">
|
||||
{{#each previews as |preview index|}}
|
||||
{{#if (gt index 0)}}
|
||||
<a href="{{preview}}" data-rel="{{elementId}}_preview"></a>
|
||||
{{#if images}}
|
||||
<ul class="ace-thumbnails clearfix0">
|
||||
{{#each images as |image i|}}
|
||||
{{#if (eq i index)}}
|
||||
<li class="no-margin no-padding clearfix" style="float: inherit; overflow: inherit; border-width: 0">
|
||||
<a href="{{if image.image image.image iamge}}"
|
||||
title={{image.title}} data-rel="{{elementId}}_preview">
|
||||
<img height="{{image-height}}" style="{{image-style}}"
|
||||
src="{{if image.image image.image image}}"
|
||||
title={{image.title}} />
|
||||
{{#if (and cover-title image.title)}}
|
||||
<div class="text">
|
||||
<div class="inner">{{image.title}}</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
</a>
|
||||
</li>
|
||||
{{else}}
|
||||
<a style="display: none" href="{{if image.image image.image image}}" data-rel="{{elementId}}_preview" title={{image.title}}></a>
|
||||
{{/if}}
|
||||
{{/each}}
|
||||
</div>
|
||||
</ul>
|
||||
{{/if}}
|
@ -1,25 +1,33 @@
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header" style="padding: 9px;">
|
||||
{{#if (not (get this 'no-close'))}}
|
||||
<button type="button" class="bootbox-close-button close" data-dismiss="modal" aria-hidden="true">
|
||||
×
|
||||
</button>
|
||||
{{/if}}
|
||||
<h4 class="blue">{{title}}</h4>
|
||||
</div>
|
||||
|
||||
<div class="modal-body no-padding">
|
||||
{{yield}}
|
||||
</div>
|
||||
|
||||
{{#if (not (get this 'no-footer'))}}
|
||||
<div class="modal-footer no-margin-top">
|
||||
{{#if (not (get this 'no-cancel'))}}
|
||||
<button type="button" class="btn btn-sm btn-secondary" data-dismiss="modal">
|
||||
<i class="ace-icon fa fa-times"></i>
|
||||
Cancel
|
||||
{{cancel-text}}
|
||||
</button>
|
||||
<button type="button" class="btn btn-sm btn-primary" {{action (if submit submit (route-action 'submit'))}}>
|
||||
{{/if}}
|
||||
{{#if (not (get this 'no-submit'))}}
|
||||
<button type="button" class="btn btn-sm btn-primary"
|
||||
{{action (if submit submit (route-action 'submit'))}}>
|
||||
<i class="ace-icon fa fa-check"></i>
|
||||
OK
|
||||
{{submit-text}}
|
||||
</button>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -11,8 +11,9 @@
|
||||
col-width=12
|
||||
label=(if label label text)
|
||||
options=options
|
||||
value-field=(get this 'value-field')
|
||||
text-field=(get this 'text-field')
|
||||
value-field=value-field
|
||||
text-field=text-field
|
||||
text-exp=text-exp
|
||||
}}
|
||||
</form>
|
||||
</div>
|
||||
|
@ -1,5 +1,4 @@
|
||||
{{#form-content}}
|
||||
{{form-input type='hidden' name='type'}}
|
||||
{{form-input name='name' label='Name'}}
|
||||
{{#form-input name='content' label='Content'}}
|
||||
{{wysiwyg-editor model=model name='content'}}
|
||||
@ -16,7 +15,6 @@
|
||||
</div>
|
||||
<div class="widget-body">
|
||||
<div class="widget-main padding-4">
|
||||
<!-- #section:pages/profile.feed -->
|
||||
{{#each model.images as |image i|}}
|
||||
<div class="col-xs-6 no-padding-left">
|
||||
<div class="space-4"></div>
|
||||
@ -29,12 +27,20 @@
|
||||
{{image-input name=(concat 'images[' i ']') image=image}}
|
||||
</div>
|
||||
{{/each}}
|
||||
<!-- /section:pages/profile.feed -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/form-input}}
|
||||
{{form-input name='note' label='Remark'}}
|
||||
{{form-input-select2
|
||||
nullable=true
|
||||
name='owner'
|
||||
label='Owner'
|
||||
options=model.users
|
||||
value-field='id'
|
||||
text-field='name'
|
||||
text-exp='$.employeeId ($.name)'
|
||||
}}
|
||||
<hr />
|
||||
{{form-footer-buttons}}
|
||||
{{/form-content}}
|
||||
|
@ -1,7 +1,39 @@
|
||||
{{#form-content}}
|
||||
{{input type='hidden' name='id' value=model.id}}
|
||||
{{form-input type='hidden' name='type'}}
|
||||
{{form-input name='name' label='Name'}}
|
||||
{{#form-input name='content' label='Content'}}
|
||||
{{wysiwyg-editor model=model name='content'}}
|
||||
{{/form-input}}
|
||||
|
||||
{{#form-input name='image' label='Images'}}
|
||||
<div class="widget-box transparent">
|
||||
<div class="widget-header widget-header-small">
|
||||
<div class="widget-toolbar action-buttons">
|
||||
<a href="#" data-rel="tooltip" title="Add Image" {{action (route-action 'addImage')}}>
|
||||
<i class="ace-icon fa fa-plus-circle green"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="widget-body">
|
||||
<div class="widget-main padding-4">
|
||||
{{#each model.images as |image i|}}
|
||||
<div class="col-xs-6 no-padding-left">
|
||||
<div class="space-4"></div>
|
||||
{{input name=(concat 'imageTitles[' i ']') class='width-80' placeholder='Image title' value=image.title}}
|
||||
|
||||
<a href="#" class="red" data-rel="tooltip" title="Remove Image" {{action (route-action 'removeImage' image)}}>
|
||||
<i class="ace-icon fa fa-times bigger-125"></i>
|
||||
</a>
|
||||
<div class="space-2"></div>
|
||||
{{image-input name=(concat 'images[' i ']') image=image}}
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/form-input}}
|
||||
|
||||
|
||||
{{form-input-enabled label='Enabled' enabledText='TRUE' disabledText='FALSE'}}
|
||||
{{form-input name='note' label='Remark'}}
|
||||
<hr />
|
||||
|
@ -22,20 +22,33 @@
|
||||
<th>
|
||||
Name
|
||||
</th>
|
||||
<th>
|
||||
Content
|
||||
</th>
|
||||
<th>
|
||||
<i class="ace-icon fa fa-sticky-note-o bigger-110 hidden-480"></i>
|
||||
Remark
|
||||
</th>
|
||||
{{#if ajax.user.admin}}
|
||||
<th>
|
||||
<i class="ace-icon fa fa-id-badge bigger-110 hidden-480"></i>
|
||||
{{th-filter name='owner'
|
||||
text='Owner'
|
||||
label='Owner Filter'
|
||||
options=model.users
|
||||
value-field='id'
|
||||
text-exp='$.employeeId ($.name)'
|
||||
}}
|
||||
</th>
|
||||
{{/if}}
|
||||
<th>
|
||||
<i class="ace-icon fa fa-exchange bigger-110 hidden-480"></i>
|
||||
Enabled
|
||||
</th>
|
||||
{{#if ajax.user.admin}}
|
||||
<th>
|
||||
<i class="ace-icon fa fa-cogs bigger-110 hidden-480"></i>
|
||||
Settings
|
||||
</th>
|
||||
{{/if}}
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
@ -46,16 +59,20 @@
|
||||
{{it.name}}
|
||||
</td>
|
||||
<td>
|
||||
{{#if ajax.user.admin}}
|
||||
{{editable-cell model=it field='note'}}
|
||||
{{else}}
|
||||
{{it.note}}
|
||||
{{/if}}
|
||||
{{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'}}
|
||||
</td>
|
||||
{{#if ajax.user.admin}}
|
||||
<td>
|
||||
{{option-text model.users it.owner 'id' 'name' '$.employeeId ($.name)'}}
|
||||
</td>
|
||||
{{/if}}
|
||||
<td>
|
||||
{{status-cell model=it enabledText='TRUE' disabledText='FALSE'}}
|
||||
</td>
|
||||
{{#if ajax.user.admin}}
|
||||
<td>
|
||||
<div class="hidden-sm hidden-xs btn-group">
|
||||
{{status-toggle-button model=it}}
|
||||
@ -111,7 +128,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
{{/if}}
|
||||
</tr>
|
||||
{{/each}}
|
||||
</tbody>
|
||||
|
@ -0,0 +1,24 @@
|
||||
import { moduleForComponent, test } from 'ember-qunit';
|
||||
import hbs from 'htmlbars-inline-precompile';
|
||||
|
||||
moduleForComponent('customer-application/preview-btn', 'Integration | Component | customer application/preview btn', {
|
||||
integration: true
|
||||
});
|
||||
|
||||
test('it renders', function(assert) {
|
||||
// Set any properties with this.set('myProperty', 'value');
|
||||
// Handle any actions with this.on('myAction', function(val) { ... });
|
||||
|
||||
this.render(hbs`{{customer-application/preview-btn}}`);
|
||||
|
||||
assert.equal(this.$().text().trim(), '');
|
||||
|
||||
// Template block usage:
|
||||
this.render(hbs`
|
||||
{{#customer-application/preview-btn}}
|
||||
template block text
|
||||
{{/customer-application/preview-btn}}
|
||||
`);
|
||||
|
||||
assert.equal(this.$().text().trim(), 'template block text');
|
||||
});
|
@ -0,0 +1,17 @@
|
||||
|
||||
import { moduleForComponent, test } from 'ember-qunit';
|
||||
import hbs from 'htmlbars-inline-precompile';
|
||||
|
||||
moduleForComponent('customer-application-images', 'helper:customer-application-images', {
|
||||
integration: true
|
||||
});
|
||||
|
||||
// Replace this with your real tests.
|
||||
test('it renders', function(assert) {
|
||||
this.set('inputValue', '1234');
|
||||
|
||||
this.render(hbs`{{customer-application-images inputValue}}`);
|
||||
|
||||
assert.equal(this.$().text().trim(), '1234');
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user