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