add application attachments
This commit is contained in:
parent
135f3362bb
commit
4986ccd6c7
@ -9,16 +9,13 @@ import javax.validation.constraints.Max;
|
||||
import javax.validation.constraints.Min;
|
||||
import me.chyxion.tigon.model.ViewModel;
|
||||
import me.chyxion.tigon.model.ListResult;
|
||||
import com.pudonghot.ambition.crm.model.*;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import com.pudonghot.ambition.crm.model.User;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import com.pudonghot.ambition.crm.model.Application;
|
||||
import org.hibernate.validator.constraints.NotBlank;
|
||||
import com.pudonghot.ambition.crm.service.UserService;
|
||||
import org.apache.shiro.authz.annotation.RequiresRoles;
|
||||
import com.pudonghot.ambition.crm.model.CustomerProperty;
|
||||
import com.pudonghot.ambition.crm.model.ApplicationImage;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import com.pudonghot.ambition.crm.service.ApplicationService;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
@ -28,6 +25,8 @@ import com.pudonghot.ambition.crm.form.create.ApplicationFormForCreate;
|
||||
import com.pudonghot.ambition.crm.form.update.ApplicationFormForUpdate;
|
||||
import com.pudonghot.ambition.crm.form.create.ApplicationImageFormForCreate;
|
||||
import com.pudonghot.ambition.crm.form.update.ApplicationImageFormForUpdate;
|
||||
import com.pudonghot.ambition.crm.form.create.ApplicationAttachmentFormForCreate;
|
||||
import com.pudonghot.ambition.crm.form.update.ApplicationAttachmentFormForUpdate;
|
||||
|
||||
/**
|
||||
* @author Shaun Chyxion <br>
|
||||
@ -129,6 +128,26 @@ public class ApplicationController
|
||||
((ApplicationService) queryService).updateImage(form);
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/add-attachment", method = RequestMethod.POST)
|
||||
public ViewModel<ApplicationAttachment> addAttachment(
|
||||
@Valid ApplicationAttachmentFormForCreate form) {
|
||||
Assert.state(!form.getAttachment().isEmpty(), "Image content is empty");
|
||||
form.setAdmin(getAuthUser().getUser().getData().isAdmin());
|
||||
return new ViewModel<>(((ApplicationService) queryService).addAttachment(form));
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/remove-attachment", method = RequestMethod.POST)
|
||||
public void removeAttachment(@NotBlank @RequestParam("id") String id) {
|
||||
final User user = getAuthUser().getUser().getData();
|
||||
((ApplicationService) queryService).removeAttachment(id, user.getId(), user.isAdmin());
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/update-attachment", method = RequestMethod.POST)
|
||||
public void updateImage(@Valid ApplicationAttachmentFormForUpdate form) {
|
||||
form.setAdmin(getAuthUser().getUser().getData().isAdmin());
|
||||
((ApplicationService) queryService).updateAttachment(form);
|
||||
}
|
||||
|
||||
@RequiresRoles(User.ROLE_ADMIN)
|
||||
@RequestMapping(value = "/delete", method = RequestMethod.POST)
|
||||
public void delete(@NotBlank @RequestParam("id") String id) {
|
||||
|
@ -2,13 +2,16 @@ package com.pudonghot.ambition.crm.service;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import com.pudonghot.ambition.crm.model.Application;
|
||||
import com.pudonghot.ambition.crm.model.ApplicationImage;
|
||||
import org.hibernate.validator.constraints.NotBlank;
|
||||
import me.chyxion.tigon.service.BaseCrudByFormService;
|
||||
import com.pudonghot.ambition.crm.model.ApplicationImage;
|
||||
import com.pudonghot.ambition.crm.model.ApplicationAttachment;
|
||||
import com.pudonghot.ambition.crm.form.update.ApplicationFormForUpdate;
|
||||
import com.pudonghot.ambition.crm.form.create.ApplicationFormForCreate;
|
||||
import com.pudonghot.ambition.crm.form.create.ApplicationImageFormForCreate;
|
||||
import com.pudonghot.ambition.crm.form.update.ApplicationImageFormForUpdate;
|
||||
import com.pudonghot.ambition.crm.form.create.ApplicationAttachmentFormForCreate;
|
||||
import com.pudonghot.ambition.crm.form.update.ApplicationAttachmentFormForUpdate;
|
||||
|
||||
/**
|
||||
* @author Shaun Chyxion <br>
|
||||
@ -37,5 +40,26 @@ public interface ApplicationService
|
||||
* @param form form
|
||||
*/
|
||||
void updateImage(@Valid ApplicationImageFormForUpdate form);
|
||||
|
||||
|
||||
/**
|
||||
* add attachment
|
||||
* @param form form
|
||||
*/
|
||||
ApplicationAttachment addAttachment(@Valid ApplicationAttachmentFormForCreate form);
|
||||
|
||||
/**
|
||||
* remove attachment
|
||||
* @param id attachment id
|
||||
* @param userId user id
|
||||
* @param admin admin
|
||||
*/
|
||||
void removeAttachment(@NotBlank String id, String userId, boolean admin);
|
||||
|
||||
/**
|
||||
* update attachment
|
||||
* @param form form
|
||||
*/
|
||||
void updateAttachment(@Valid ApplicationAttachmentFormForUpdate form);
|
||||
}
|
||||
|
||||
|
@ -7,10 +7,13 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import me.chyxion.tigon.mybatis.Search;
|
||||
import org.springframework.util.Assert;
|
||||
import me.chyxion.tigon.model.ViewModel;
|
||||
import com.pudonghot.ambition.crm.model.*;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import com.pudonghot.ambition.crm.mapper.*;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
@ -24,8 +27,11 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
import com.pudonghot.ambition.crm.service.CustomerPermissionService;
|
||||
import com.pudonghot.ambition.crm.form.update.ApplicationFormForUpdate;
|
||||
import com.pudonghot.ambition.crm.form.create.ApplicationFormForCreate;
|
||||
import com.pudonghot.ambition.crm.form.update.ApplicationFileFormForUpdate;
|
||||
import com.pudonghot.ambition.crm.form.create.ApplicationImageFormForCreate;
|
||||
import com.pudonghot.ambition.crm.form.update.ApplicationImageFormForUpdate;
|
||||
import com.pudonghot.ambition.crm.form.create.ApplicationAttachmentFormForCreate;
|
||||
import com.pudonghot.ambition.crm.form.update.ApplicationAttachmentFormForUpdate;
|
||||
|
||||
/**
|
||||
* @author Shaun Chyxion <br>
|
||||
@ -41,6 +47,8 @@ public class ApplicationServiceSupport
|
||||
@Autowired
|
||||
private ApplicationImageMapper imageMapper;
|
||||
@Autowired
|
||||
private ApplicationAttachmentMapper attachmentMapper;
|
||||
@Autowired
|
||||
private DiskFileApi fileApi;
|
||||
@Autowired
|
||||
private CustomerMapper customerMapper;
|
||||
@ -62,7 +70,8 @@ public class ApplicationServiceSupport
|
||||
final Date now = new Date();
|
||||
application.setDateUpdated(now);
|
||||
|
||||
uploadImages(id, 1, form.getImages(), form.getImageTitles(), form.getCreatedBy());
|
||||
uploadFiles(id, 1, form.getImages(), form.getImageTitles(), form.getCreatedBy(), ApplicationImage::new, imageMapper::insert);
|
||||
uploadFiles(id, 1, form.getAttachments(), form.getAttachmentTitles(), form.getCreatedBy(), ApplicationAttachment::new, attachmentMapper::insert);
|
||||
mapper.insert(application);
|
||||
return toViewModel(application);
|
||||
}
|
||||
@ -117,11 +126,13 @@ public class ApplicationServiceSupport
|
||||
*/
|
||||
@Override
|
||||
public ViewModel<Application> findViewModel(final String id) {
|
||||
final List<ApplicationImage> images = imageMapper.list(
|
||||
final Search search =
|
||||
new Search(ApplicationImage.APPLICATION_ID, id)
|
||||
.asc(ApplicationImage.SORT));
|
||||
.asc(ApplicationImage.SORT);
|
||||
|
||||
return super.findViewModel(id)
|
||||
.setAttr("images", images);
|
||||
.setAttr("images", imageMapper.list(search))
|
||||
.setAttr("attachments", attachmentMapper.list(search));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -132,11 +143,21 @@ public class ApplicationServiceSupport
|
||||
final String applicationId = form.getApplicationId();
|
||||
final String createdBy = form.getCreatedBy();
|
||||
validatePerm(applicationId, createdBy, form.isAdmin());
|
||||
return uploadImages(applicationId,
|
||||
return uploadFiles(applicationId,
|
||||
imageMapper.nextSort(applicationId),
|
||||
new MultipartFile[] {form.getImage()},
|
||||
new String[] {form.getNote()},
|
||||
createdBy).iterator().next();
|
||||
createdBy,
|
||||
ApplicationImage::new,
|
||||
imageMapper::insert).iterator().next();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void updateImage(final ApplicationImageFormForUpdate form) {
|
||||
updateFile(form, imageMapper::find, imageMapper::listSort, imageMapper::update);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -145,23 +166,128 @@ public class ApplicationServiceSupport
|
||||
@Override
|
||||
@Transactional(rollbackFor = Throwable.class)
|
||||
public void removeImage(final String id, final String userId, final boolean admin) {
|
||||
final ApplicationImage appImage = imageMapper.find(id);
|
||||
Assert.state(appImage != null, "No application image [" + id + "] found");
|
||||
final String applicationId = appImage.getApplicationId();
|
||||
validatePerm(applicationId, userId, admin);
|
||||
fileApi.delete(imageFolder(applicationId) + "/" + id);
|
||||
imageMapper.delete(id);
|
||||
imageMapper.updateSort(applicationId);
|
||||
removeFile(id, userId, admin, imageMapper::find, imageMapper::delete, imageMapper::updateSort);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void updateImage(final ApplicationImageFormForUpdate form) {
|
||||
public ApplicationAttachment addAttachment(final ApplicationAttachmentFormForCreate form) {
|
||||
final String applicationId = form.getApplicationId();
|
||||
final String createdBy = form.getCreatedBy();
|
||||
validatePerm(applicationId, createdBy, form.isAdmin());
|
||||
return uploadFiles(applicationId,
|
||||
attachmentMapper.nextSort(applicationId),
|
||||
new MultipartFile[] {form.getAttachment()},
|
||||
new String[] {form.getNote()},
|
||||
createdBy,
|
||||
ApplicationAttachment::new,
|
||||
attachmentMapper::insert).iterator().next();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void updateAttachment(final ApplicationAttachmentFormForUpdate form) {
|
||||
updateFile(form, attachmentMapper::find, attachmentMapper::listSort, attachmentMapper::update);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Throwable.class)
|
||||
public void removeAttachment(final String id, final String userId, final boolean admin) {
|
||||
removeFile(id, userId, admin, attachmentMapper::find, attachmentMapper::delete, attachmentMapper::updateSort);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Throwable.class)
|
||||
public int delete(final String id) {
|
||||
log.info("Delete application [{}].", id);
|
||||
final Application app = find(id);
|
||||
Assert.state(app != null, "No application [" + id + "] found");
|
||||
Assert.state(!app.isEnabled(), "Application [" + id + "] is enabled");
|
||||
Assert.state(customerApplicationMapper.count(
|
||||
new Search(CustomerApplication.APPLICATION_ID, id)) == 0,
|
||||
"Application [" + id + "] is in using");
|
||||
final Search appFileSearch = new Search(ApplicationImage.APPLICATION_ID, id);
|
||||
imageMapper.list(appFileSearch).forEach(
|
||||
image -> fileApi.deleteById(image.getFileId()));
|
||||
imageMapper.delete(appFileSearch);
|
||||
|
||||
attachmentMapper.list(appFileSearch).forEach(
|
||||
attachment -> fileApi.deleteById(attachment.getFileId()));
|
||||
attachmentMapper.delete(appFileSearch);
|
||||
return mapper.delete(id);
|
||||
}
|
||||
|
||||
private <T extends ApplicationFile> List<T> uploadFiles(
|
||||
final String applicationId,
|
||||
int sort,
|
||||
final MultipartFile[] files,
|
||||
final String[] titles,
|
||||
final String createdBy,
|
||||
Supplier<T> constructor,
|
||||
Consumer<T> insert) {
|
||||
|
||||
final List<T> appFiles = new ArrayList<>();
|
||||
final Date now = new Date();
|
||||
final String fileFolder = fileFolder(applicationId);
|
||||
int i = 0;
|
||||
for (final MultipartFile file : files) {
|
||||
if (!file.isEmpty()) {
|
||||
final String originalFilename = file.getOriginalFilename();
|
||||
try (final InputStream ins = file.getInputStream()) {
|
||||
final String fileId = idSeq.get();
|
||||
final T appFile = constructor.get();
|
||||
final FileInfo fileInfo = fileApi.upload(ins,
|
||||
file.getSize(),
|
||||
fileFolder,
|
||||
fileId,
|
||||
file.getContentType(),
|
||||
FilenameUtils.getExtension(originalFilename),
|
||||
originalFilename);
|
||||
appFile.setId(fileId);
|
||||
appFile.setApplicationId(applicationId);
|
||||
appFile.setFileId(fileInfo.getId());
|
||||
appFile.setUrl(fileInfo.getUrl());
|
||||
appFile.setSort(sort++);
|
||||
appFile.setEnabled(true);
|
||||
appFile.setNote(StringUtils.defaultIfBlank(titles[i], originalFilename));
|
||||
appFile.setCreatedBy(createdBy);
|
||||
appFile.setDateCreated(now);
|
||||
// insert
|
||||
insert.accept(appFile);
|
||||
appFiles.add(appFile);
|
||||
}
|
||||
catch (final IOException e) {
|
||||
throw new IllegalStateException(
|
||||
"Read upload file [" + originalFilename + "] error cased", e);
|
||||
}
|
||||
}
|
||||
else {
|
||||
log.info("Application file [{}] is empty, ignore.", file);
|
||||
}
|
||||
++i;
|
||||
}
|
||||
return appFiles;
|
||||
}
|
||||
|
||||
private <T extends ApplicationFile> void updateFile(
|
||||
final ApplicationFileFormForUpdate form,
|
||||
final Function<String, T> finder,
|
||||
final Function<String, List<T>> listSort,
|
||||
final Consumer<T> updater) {
|
||||
|
||||
final String id = form.getId();
|
||||
final ApplicationImage appImage = imageMapper.find(id);
|
||||
Assert.state(appImage != null, "No application image [" + id + "] found");
|
||||
final T appImage = finder.apply(id);
|
||||
Assert.state(appImage != null, "No application file [" + id + "] found");
|
||||
final String applicationId = appImage.getApplicationId();
|
||||
final String updatedBy = form.getUpdatedBy();
|
||||
validatePerm(applicationId, updatedBy, form.isAdmin());
|
||||
@ -180,75 +306,31 @@ public class ApplicationServiceSupport
|
||||
appImage.setNote(form.getNote());
|
||||
appImage.setDateUpdated(new Date());
|
||||
appImage.setUpdatedBy(updatedBy);
|
||||
imageMapper.update(appImage);
|
||||
|
||||
updater.accept(appImage);
|
||||
|
||||
if (sortUpdated) {
|
||||
imageMapper.listSort(applicationId).forEach(imageMapper::update);
|
||||
listSort.apply(applicationId).forEach(updater);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Throwable.class)
|
||||
public int delete(final String id) {
|
||||
log.info("Delete application [{}].", id);
|
||||
final Application app = find(id);
|
||||
Assert.state(app != null, "No application [" + id + "] found");
|
||||
Assert.state(!app.isEnabled(), "Application [" + id + "] is enabled");
|
||||
Assert.state(customerApplicationMapper.count(
|
||||
new Search(CustomerApplication.APPLICATION_ID, id)) == 0,
|
||||
"Application [" + id + "] is in using");
|
||||
final Search appImageSearch = new Search(ApplicationImage.APPLICATION_ID, id);
|
||||
imageMapper.list(appImageSearch).forEach(
|
||||
image -> fileApi.deleteById(image.getFileId()));
|
||||
imageMapper.delete(appImageSearch);
|
||||
return mapper.delete(id);
|
||||
private <T extends ApplicationFile> void removeFile(
|
||||
final String id,
|
||||
final String userId,
|
||||
final boolean admin,
|
||||
final Function<String, T> finder,
|
||||
final Function<String, Integer> deleter,
|
||||
final Function<String, Integer> sortUpdater) {
|
||||
final T appFile = finder.apply(id);
|
||||
Assert.state(appFile != null, "No application file [" + id + "] found");
|
||||
final String applicationId = appFile.getApplicationId();
|
||||
validatePerm(applicationId, userId, admin);
|
||||
fileApi.delete(fileFolder(applicationId) + "/" + id);
|
||||
deleter.apply(id);
|
||||
sortUpdater.apply(applicationId);
|
||||
}
|
||||
|
||||
private List<ApplicationImage> uploadImages(
|
||||
final String applicationId,
|
||||
int sort,
|
||||
final MultipartFile[] images,
|
||||
final String[] titles,
|
||||
final String createdBy) {
|
||||
|
||||
final List<ApplicationImage> imagesRtn = new ArrayList<>();
|
||||
final Date now = new Date();
|
||||
final String imageFolder = imageFolder(applicationId);
|
||||
int i = 0;
|
||||
for (final MultipartFile image : images) {
|
||||
if (!image.isEmpty()) {
|
||||
try (final InputStream ins = image.getInputStream()) {
|
||||
final String imageId = idSeq.get();
|
||||
final ApplicationImage appImage = new ApplicationImage();
|
||||
final FileInfo fileInfo = fileApi.uploadImage(ins, imageFolder, imageId);
|
||||
appImage.setId(imageId);
|
||||
appImage.setApplicationId(applicationId);
|
||||
appImage.setFileId(fileInfo.getId());
|
||||
appImage.setUrl(fileInfo.getUrl());
|
||||
appImage.setSort(sort++);
|
||||
appImage.setEnabled(true);
|
||||
appImage.setNote(titles[i]);
|
||||
appImage.setCreatedBy(createdBy);
|
||||
appImage.setDateCreated(now);
|
||||
imageMapper.insert(appImage);
|
||||
imagesRtn.add(appImage);
|
||||
}
|
||||
catch (final IOException e) {
|
||||
throw new IllegalStateException(
|
||||
"Read upload image [" + image.getOriginalFilename() + "] error cased", e);
|
||||
}
|
||||
}
|
||||
else {
|
||||
log.info("Application image [{}] is empty, ignore.", image);
|
||||
}
|
||||
++i;
|
||||
}
|
||||
return imagesRtn;
|
||||
}
|
||||
|
||||
private String imageFolder(final String appId) {
|
||||
private String fileFolder(final String appId) {
|
||||
return "app/" + appId;
|
||||
}
|
||||
|
||||
|
@ -19,4 +19,5 @@ spring.http.multipart.max-request-size=1024MB
|
||||
|
||||
# File
|
||||
file.base-path=http://127.0.0.1:1217/lm-f/
|
||||
file.base-dir=/Users/chyxion/Workspaces/ambition-crm/files/
|
||||
# file.base-dir=/Users/chyxion/Workspaces/ambition-crm/files/
|
||||
file.base-dir=/Users/donghuang/Documents/Workspaces/ambition-crm/files/
|
||||
|
@ -0,0 +1,14 @@
|
||||
package com.pudonghot.ambition.crm.mapper;
|
||||
|
||||
import me.chyxion.tigon.mybatis.BaseMapper;
|
||||
import com.pudonghot.ambition.crm.model.ApplicationAttachment;
|
||||
|
||||
/**
|
||||
* @author Shaun Chyxion <br>
|
||||
* chyxion@163.com <br>
|
||||
* Mar 11, 2018 11:39:49
|
||||
*/
|
||||
public interface ApplicationAttachmentMapper
|
||||
extends ApplicationFileMapper<ApplicationAttachment>,
|
||||
BaseMapper<String, ApplicationAttachment> {
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
/**
|
||||
* @author Donghuang <br>
|
||||
* donghuang@wacai.com <br>
|
||||
* May 17, 2018 17:09:24
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE mapper PUBLIC
|
||||
"-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.pudonghot.ambition.crm.mapper.ApplicationAttachmentMapper">
|
||||
|
||||
<select id="nextSort" resultType="int">
|
||||
<include refid="com.pudonghot.ambition.crm.mapper.ApplicationFileMapper.nextSort" />
|
||||
</select>
|
||||
|
||||
<update id="updateSort">
|
||||
<include refid="com.pudonghot.ambition.crm.mapper.ApplicationFileMapper.updateSort" />
|
||||
</update>
|
||||
|
||||
<select id="listSort" resultType="com.pudonghot.ambition.crm.model.ApplicationAttachment">
|
||||
<include refid="com.pudonghot.ambition.crm.mapper.ApplicationFileMapper.listSort" />
|
||||
</select>
|
||||
</mapper>
|
@ -0,0 +1,38 @@
|
||||
package com.pudonghot.ambition.crm.mapper;
|
||||
|
||||
import java.util.List;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.hibernate.validator.constraints.NotBlank;
|
||||
import com.pudonghot.ambition.crm.model.ApplicationFile;
|
||||
|
||||
/**
|
||||
* @author Shaun Chyxion <br>
|
||||
* chyxion@163.com <br>
|
||||
* Mar 11, 2018 11:39:49
|
||||
*/
|
||||
interface ApplicationFileMapper<T extends ApplicationFile> {
|
||||
|
||||
/**
|
||||
* find next sort
|
||||
* @param applicationId application id
|
||||
* @return next sort
|
||||
*/
|
||||
int nextSort(@NotBlank @Param("applicationId") String applicationId);
|
||||
|
||||
/**
|
||||
* update sort
|
||||
* @param applicationId application id
|
||||
* @return effected rows
|
||||
*/
|
||||
int updateSort(@NotBlank @Param("applicationId") String applicationId);
|
||||
|
||||
/**
|
||||
* list application files
|
||||
* @param applicationId
|
||||
* @return images
|
||||
*/
|
||||
List<T> listSort(
|
||||
@NotBlank
|
||||
@Param("applicationId")
|
||||
String applicationId);
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
/**
|
||||
* @author Shaun Chyxion <br>
|
||||
* chyxion@163.com <br>
|
||||
* May 17, 2018 17:29:10
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE mapper PUBLIC
|
||||
"-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.pudonghot.ambition.crm.mapper.ApplicationFileMapper">
|
||||
|
||||
<sql id="nextSort">
|
||||
select if (application_id, max(sort) + 1, 1)
|
||||
from <include refid="table" />
|
||||
where application_id = #{applicationId}
|
||||
</sql>
|
||||
|
||||
<sql id="updateSort">
|
||||
update <include refid="table" /> a
|
||||
join (
|
||||
select id, @cur_row := @cur_row + 1 sort
|
||||
from <include refid="table" />
|
||||
join (select @cur_row := 0) r
|
||||
where application_id = #{applicationId}
|
||||
order by <include refid="table" />.sort) s
|
||||
on a.id = s.id
|
||||
set a.sort = s.sort
|
||||
</sql>
|
||||
|
||||
<sql id="listSort">
|
||||
select id, file_id,
|
||||
url, application_id,
|
||||
created_by, date_created,
|
||||
updated_by, date_updated,
|
||||
enabled, note,
|
||||
@cur_row := @cur_row + 1 sort
|
||||
from <include refid="table" />
|
||||
join (select @cur_row := 0) r
|
||||
where application_id = #{applicationId}
|
||||
order by <include refid="table" />.sort
|
||||
</sql>
|
||||
</mapper>
|
@ -1,9 +1,6 @@
|
||||
package com.pudonghot.ambition.crm.mapper;
|
||||
|
||||
import java.util.List;
|
||||
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;
|
||||
|
||||
/**
|
||||
@ -11,29 +8,7 @@ import com.pudonghot.ambition.crm.model.ApplicationImage;
|
||||
* chyxion@163.com <br>
|
||||
* Mar 11, 2018 11:39:49
|
||||
*/
|
||||
public interface ApplicationImageMapper extends BaseMapper<String, ApplicationImage> {
|
||||
|
||||
/**
|
||||
* find next sort
|
||||
* @param applicationId application id
|
||||
* @return next sort
|
||||
*/
|
||||
int nextSort(@NotBlank @Param("applicationId") String applicationId);
|
||||
|
||||
/**
|
||||
* update sort
|
||||
* @param applicationId application id
|
||||
* @return effected rows
|
||||
*/
|
||||
int updateSort(@NotBlank @Param("applicationId") String applicationId);
|
||||
|
||||
/**
|
||||
* list application images
|
||||
* @param applicationId
|
||||
* @return images
|
||||
*/
|
||||
List<ApplicationImage> listSort(
|
||||
@NotBlank
|
||||
@Param("applicationId")
|
||||
String applicationId);
|
||||
public interface ApplicationImageMapper
|
||||
extends ApplicationFileMapper<ApplicationImage>,
|
||||
BaseMapper<String, ApplicationImage> {
|
||||
}
|
||||
|
@ -12,33 +12,14 @@
|
||||
<mapper namespace="com.pudonghot.ambition.crm.mapper.ApplicationImageMapper">
|
||||
|
||||
<select id="nextSort" resultType="int">
|
||||
select if (application_id, max(sort) + 1, 1)
|
||||
from <include refid="table" />
|
||||
where application_id = #{applicationId}
|
||||
<include refid="com.pudonghot.ambition.crm.mapper.ApplicationFileMapper.nextSort" />
|
||||
</select>
|
||||
|
||||
<update id="updateSort">
|
||||
update crm_application_image a
|
||||
join (
|
||||
select id, @cur_row := @cur_row + 1 sort
|
||||
from crm_application_image
|
||||
join (select @cur_row := 0) r
|
||||
where application_id = #{applicationId}
|
||||
order by crm_application_image.sort) s
|
||||
on a.id = s.id
|
||||
set a.sort = s.sort
|
||||
<include refid="com.pudonghot.ambition.crm.mapper.ApplicationFileMapper.updateSort" />
|
||||
</update>
|
||||
|
||||
<select id="listSort" resultType="com.pudonghot.ambition.crm.model.ApplicationImage">
|
||||
select id, file_id,
|
||||
url, application_id,
|
||||
created_by, date_created,
|
||||
updated_by, date_updated,
|
||||
enabled, note,
|
||||
@cur_row := @cur_row + 1 sort
|
||||
from <include refid="table" />
|
||||
join (select @cur_row := 0) r
|
||||
where application_id = #{applicationId}
|
||||
order by crm_application_image.sort
|
||||
<include refid="com.pudonghot.ambition.crm.mapper.ApplicationFileMapper.listSort" />
|
||||
</select>
|
||||
</mapper>
|
||||
|
@ -22,7 +22,18 @@
|
||||
(select group_concat(note order by sort separator 0x1d) from
|
||||
crm_application_image
|
||||
where application_id = a.id
|
||||
group by application_id) image_titles
|
||||
group by application_id) image_titles,
|
||||
|
||||
(select group_concat(url order by sort separator 0x1d) from
|
||||
crm_application_attachment
|
||||
where application_id = a.id
|
||||
group by application_id) attachments,
|
||||
|
||||
(select group_concat(note order by sort separator 0x1d) from
|
||||
crm_application_attachment
|
||||
where application_id = a.id
|
||||
group by application_id) attachment_titles
|
||||
|
||||
from
|
||||
<include refid="table" /> a
|
||||
<include refid="Tigon.search" />
|
||||
|
@ -1,10 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:context="http://www.springframework.org/schema/context"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/context
|
||||
http://www.springframework.org/schema/context/spring-context.xsd">
|
||||
<!--<context:component-scan base-package="cn.com.flaginfo.umsapp.ota" /> -->
|
||||
http://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||
</beans>
|
||||
|
@ -0,0 +1,27 @@
|
||||
package com.pudonghot.ambition.crm.form.create;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import me.chyxion.tigon.form.FC2;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import org.hibernate.validator.constraints.NotBlank;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
/**
|
||||
* @author Donghuang <br>
|
||||
* donghuang@wacai.com <br>
|
||||
* May 17, 2018 17:12:56
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class ApplicationAttachmentFormForCreate extends FC2<String> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
// Properties
|
||||
// current user is admin
|
||||
private boolean admin;
|
||||
@NotBlank
|
||||
private String applicationId;
|
||||
@NotNull
|
||||
private MultipartFile attachment;
|
||||
}
|
@ -30,4 +30,6 @@ public class ApplicationFormForCreate extends FC2<String> {
|
||||
private String owner;
|
||||
private String[] imageTitles;
|
||||
private MultipartFile[] images;
|
||||
private String[] attachmentTitles;
|
||||
private MultipartFile[] attachments;
|
||||
}
|
||||
|
@ -0,0 +1,15 @@
|
||||
package com.pudonghot.ambition.crm.form.update;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @author Donghuang <br>
|
||||
* donghuang@wacai.com <br>
|
||||
* May 17, 2018 17:12:46
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class ApplicationAttachmentFormForUpdate extends ApplicationFileFormForUpdate {
|
||||
private static final long serialVersionUID = 1L;
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package com.pudonghot.ambition.crm.form.update;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import me.chyxion.tigon.form.FU2;
|
||||
|
||||
/**
|
||||
* @author Shaun Chyxion <br>
|
||||
* chyxion@163.com <br>
|
||||
* May 17, 2018 17:50:22
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class ApplicationFileFormForUpdate extends FU2<String, String> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
// current user is admin
|
||||
private boolean admin;
|
||||
private float sort;
|
||||
}
|
@ -2,7 +2,6 @@ package com.pudonghot.ambition.crm.form.update;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import me.chyxion.tigon.form.FU2;
|
||||
|
||||
/**
|
||||
* @version 0.0.1
|
||||
@ -13,10 +12,6 @@ import me.chyxion.tigon.form.FU2;
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class ApplicationImageFormForUpdate extends FU2<String, String> {
|
||||
public class ApplicationImageFormForUpdate extends ApplicationFileFormForUpdate {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
// current user is admin
|
||||
private boolean admin;
|
||||
private float sort;
|
||||
}
|
||||
|
@ -32,4 +32,8 @@ public class Application extends M3<String, String> {
|
||||
private String images;
|
||||
@Transient
|
||||
private String imageTitles;
|
||||
@Transient
|
||||
private String attachments;
|
||||
@Transient
|
||||
private String attachmentTitles;
|
||||
}
|
||||
|
@ -0,0 +1,17 @@
|
||||
package com.pudonghot.ambition.crm.model;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import me.chyxion.tigon.mybatis.Table;
|
||||
|
||||
/**
|
||||
* @author Shaun Chyxion <br>
|
||||
* chyxion@163.com <br>
|
||||
* May 17, 2018 17:02:51
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Table("crm_application_attachment")
|
||||
public class ApplicationAttachment extends ApplicationFile {
|
||||
private static final long serialVersionUID = 1L;
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package com.pudonghot.ambition.crm.model;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import me.chyxion.tigon.model.M3;
|
||||
|
||||
/**
|
||||
* @author Donghuang <br>
|
||||
* donghuang@wacai.com <br>
|
||||
* May 17, 2018 17:23:39
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class ApplicationFile extends M3<String, String> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
// Column Names
|
||||
public static final String FILE_ID = "file_id";
|
||||
public static final String URL = "url";
|
||||
public static final String APPLICATION_ID = "application_id";
|
||||
public static final String SORT = "sort";
|
||||
|
||||
// Properties
|
||||
private String fileId;
|
||||
private String url;
|
||||
private String applicationId;
|
||||
private float sort;
|
||||
}
|
@ -2,7 +2,6 @@ package com.pudonghot.ambition.crm.model;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import me.chyxion.tigon.model.M3;
|
||||
import me.chyxion.tigon.mybatis.Table;
|
||||
|
||||
/**
|
||||
@ -13,18 +12,6 @@ import me.chyxion.tigon.mybatis.Table;
|
||||
@Getter
|
||||
@Setter
|
||||
@Table("crm_application_image")
|
||||
public class ApplicationImage extends M3<String, String> {
|
||||
public class ApplicationImage extends ApplicationFile {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
// Column Names
|
||||
public static final String FILE_ID = "file_id";
|
||||
public static final String URL = "url";
|
||||
public static final String APPLICATION_ID = "application_id";
|
||||
public static final String SORT = "sort";
|
||||
|
||||
// Properties
|
||||
private String fileId;
|
||||
private String url;
|
||||
private String applicationId;
|
||||
private float sort;
|
||||
}
|
||||
|
51
web/app/components/file-input.js
Normal file
51
web/app/components/file-input.js
Normal file
@ -0,0 +1,51 @@
|
||||
import Ember from 'ember';
|
||||
import Component from '@ember/component';
|
||||
import { computed } from '@ember/object';
|
||||
|
||||
export default Component.extend({
|
||||
file: {},
|
||||
value: computed.alias('file.file'),
|
||||
'no-file': 'Choose file',
|
||||
'btn-choose': 'Choose file',
|
||||
didReceiveAttrs() {
|
||||
const me = this;
|
||||
me._super(...arguments);
|
||||
},
|
||||
didInsertElement() {
|
||||
let me = this;
|
||||
me._super(...arguments);
|
||||
|
||||
me.$('input[type=file]').ace_file_input({
|
||||
no_file: me.get('no-file'),
|
||||
btn_choose: me.get('btn-choose'),
|
||||
btn_change: null,
|
||||
droppable: true,
|
||||
style: 'well',
|
||||
no_icon: 'ace-icon fa fa-files-o',
|
||||
|
||||
// thumbnail: 'large',
|
||||
// allowExt: ['jpg', 'jpeg', 'png', 'gif'],
|
||||
// allowMime: ['image/jpg', 'image/jpeg', 'image/png', 'image/gif'],
|
||||
|
||||
before_change: function() {
|
||||
let filename = me.$(this).val();
|
||||
me.set('value', filename);
|
||||
return true;
|
||||
},
|
||||
before_remove: function() {
|
||||
let filename = me.$(this).val();
|
||||
me.set('value', null);
|
||||
return true;
|
||||
}
|
||||
}).on('file.error.ace', function(e, info) {
|
||||
if (me.$(this)[0] === e.target) {
|
||||
if (info.error_count['ext'] > 0 || info.error_count['mime'] > 0) {
|
||||
me.get('message').warn('Invalid file');
|
||||
}
|
||||
else if(info.error_count['size'] > 0) {
|
||||
me.get('message').warn('File size too large');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
@ -15,17 +15,22 @@ export default BaseRoute.extend({
|
||||
return RSVP.hash({
|
||||
enabled: true,
|
||||
images: [{}],
|
||||
attachments: [{}],
|
||||
users: this.get('store').ajaxGet('user/list-for-select')
|
||||
});
|
||||
},
|
||||
actions: {
|
||||
addImage() {
|
||||
const me = this;
|
||||
me.get('controller.model.images').pushObject({});
|
||||
this.get('controller.model.images').pushObject({});
|
||||
},
|
||||
removeImage(image) {
|
||||
const me = this;
|
||||
me.get('controller.model.images').removeObject(image);
|
||||
this.get('controller.model.images').removeObject(image);
|
||||
},
|
||||
addAttachment() {
|
||||
this.get('controller.model.attachments').pushObject({});
|
||||
},
|
||||
removeAttachment(attachment) {
|
||||
this.get('controller.model.attachments').removeObject(attachment);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -23,6 +23,7 @@ export default BaseEditRoute.extend({
|
||||
},
|
||||
submitAddImage() {
|
||||
const me = this;
|
||||
me.set('controller.errors', {});
|
||||
if (me.get('controller.model.image.file')) {
|
||||
me.set('controller.errors', {});
|
||||
me.get('store').ajaxPost('application/add-image',
|
||||
@ -49,30 +50,79 @@ export default BaseEditRoute.extend({
|
||||
});
|
||||
});
|
||||
},
|
||||
moveUp(image) {
|
||||
let me = this;
|
||||
let images = me.get('controller.model.images');
|
||||
if (images && images.length > 1) {
|
||||
let index = images.indexOf(image);
|
||||
images.removeObject(image);
|
||||
images.insertAt(index - 1, image);
|
||||
--image.sort;
|
||||
me.updateImage(image);
|
||||
moveImageUp(image) {
|
||||
const me = this;
|
||||
me.moveUp(me.get('controller.model.images'), image, 'updateImage');
|
||||
},
|
||||
moveImageDown(image) {
|
||||
const me = this;
|
||||
me.moveDown(me.get('controller.model.images'), image, 'updateImage');
|
||||
},
|
||||
// attachments
|
||||
addAttachment() {
|
||||
const me = this;
|
||||
me.set('controller.model.addAttachment', true);
|
||||
me.set('controller.model.attachment', {});
|
||||
},
|
||||
submitAddAttachment() {
|
||||
const me = this;
|
||||
me.set('controller.errors', {});
|
||||
if (me.get('controller.model.attachment.file')) {
|
||||
me.get('store').ajaxPost('application/add-attachment',
|
||||
new FormData($('#form_' + me.get('controller.model.id'))[0]))
|
||||
.then(attachment => {
|
||||
me.get('controller.model.attachments').pushObject(attachment);
|
||||
me.set('controller.model.addAttachment', false);
|
||||
});
|
||||
}
|
||||
else {
|
||||
me.set('controller.errors.attachment', ['No attachment file selected']);
|
||||
}
|
||||
},
|
||||
moveDown(image) {
|
||||
let me = this;
|
||||
let images = me.get('controller.model.images');
|
||||
if (images && images.length > 1) {
|
||||
let index = images.indexOf(image);
|
||||
images.removeObject(image);
|
||||
images.insertAt(index + 1, image);
|
||||
++image.sort;
|
||||
me.updateImage(image);
|
||||
}
|
||||
closeAddAttachment() {
|
||||
const me = this;
|
||||
me.set('controller.model.addAttachment', false);
|
||||
},
|
||||
removeAttachment(attachment) {
|
||||
const me = this;
|
||||
me.get('dialog').confirm('Are you sure to remove attachment?', () => {
|
||||
me.get('store').ajaxPost('application/remove-attachment', attachment).then(() => {
|
||||
me.get('message').alert('Attachment removed');
|
||||
me.get('controller.model.attachments').removeObject(attachment);
|
||||
});
|
||||
});
|
||||
},
|
||||
moveAttachmentUp(attachment) {
|
||||
const me = this;
|
||||
me.moveUp(me.get('controller.model.attachments'), attachment, 'updateAttachment');
|
||||
},
|
||||
moveAttachmentDown(attachment) {
|
||||
const me = this;
|
||||
me.moveDown(me.get('controller.model.attachments'), attachment, 'updateAttachment');
|
||||
}
|
||||
},
|
||||
updateImage(image) {
|
||||
this.get('ajax').doPost('application/update-image', image, false);
|
||||
},
|
||||
updateAttachment(attachment) {
|
||||
this.get('ajax').doPost('application/update-attachment', attachment, false);
|
||||
},
|
||||
moveUp(files, file, update) {
|
||||
if (files && files.length > 1) {
|
||||
let index = files.indexOf(file);
|
||||
files.removeObject(file);
|
||||
files.insertAt(index - 1, file);
|
||||
--file.sort;
|
||||
this[update](file);
|
||||
}
|
||||
},
|
||||
moveDown(files, file, update) {
|
||||
if (files && files.length > 1) {
|
||||
let index = files.indexOf(file);
|
||||
files.removeObject(file);
|
||||
files.insertAt(index + 1, file);
|
||||
++file.sort;
|
||||
this[update](file);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -38,6 +38,22 @@
|
||||
<div class="space-12"></div>
|
||||
{{/each}}
|
||||
{{/with}}
|
||||
<hr />
|
||||
{{#with (customer-application-images model.attachments model.attachmentTitles) as |attachments|}}
|
||||
{{#if attachments.length}}
|
||||
<div class="row">
|
||||
{{#each attachments as |attachment index|}}
|
||||
<div class="col-xs-12">
|
||||
<a href="{{attachment.image}}" title="{{attachment.title}}" target="_blank">
|
||||
<i class="ace-icon fa fa-paperclip bigger-120 grey"></i>
|
||||
{{if attachment.title attachment.title 'Attachment'}}
|
||||
</a>
|
||||
<div class="space-2"></div>
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
{{/if}}
|
||||
{{/with}}
|
||||
</div>
|
||||
{{/modal-dialog}}
|
||||
{{/if}}
|
||||
|
1
web/app/templates/components/file-input.hbs
Normal file
1
web/app/templates/components/file-input.hbs
Normal file
@ -0,0 +1 @@
|
||||
{{input type='file' name=name}}
|
@ -1,5 +1,5 @@
|
||||
<label for="{{if name name idField}}" class="{{get this 'label-class'}} control-label no-padding-right"> {{label}} </label>
|
||||
<div class="{{get this 'input-class'}}">
|
||||
<label for="{{if name name idField}}" class="{{label-class}} control-label no-padding-right"> {{label}} </label>
|
||||
<div class="{{input-class}}">
|
||||
|
||||
{{#if hasBlock}}
|
||||
{{yield}}
|
||||
|
@ -40,6 +40,34 @@
|
||||
</div>
|
||||
{{/form-input}}
|
||||
|
||||
{{#form-input name='attachment' label='Attachments'}}
|
||||
<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 Attachment" {{action (route-action 'addAttachment')}}>
|
||||
<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.attachments as |attachment i|}}
|
||||
<div class="col-xs-6 no-padding-left">
|
||||
<div class="space-4"></div>
|
||||
{{input name=(concat 'attachmentTitles[' i ']') class='width-80' placeholder='Attachment name' value=image.title}}
|
||||
|
||||
<a href="#" class="red" data-rel="tooltip" title="Remove Attachment" {{action (route-action 'removeAttachment' attachment)}}>
|
||||
<i class="ace-icon fa fa-times bigger-125"></i>
|
||||
</a>
|
||||
<div class="space-2"></div>
|
||||
{{!input type='file'}}
|
||||
{{file-input name=(concat 'attachments[' i ']') file=attachment}}
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/form-input}}
|
||||
<hr />
|
||||
{{form-footer-buttons}}
|
||||
{{/form-content}}
|
||||
|
@ -71,12 +71,83 @@
|
||||
<i class="ace-icon fa fa-trash-o"></i>
|
||||
</a>
|
||||
{{#if (not-eq model.images.firstObject.id image.id)}}
|
||||
<a class="btn btn-xs btn-info" data-rel="tooltip" title="Move Up" {{action (route-action 'moveUp' image)}}>
|
||||
<a class="btn btn-xs btn-info" data-rel="tooltip" title="Move Up" {{action (route-action 'moveImageUp' image)}}>
|
||||
<i class="ace-icon fa fa-arrow-up bigger-90"></i>
|
||||
</a>
|
||||
{{/if}}
|
||||
{{#if (not-eq model.images.lastObject.id image.id)}}
|
||||
<a class="btn btn-xs btn-success" data-rel="tooltip" title="Move Down" {{action (route-action 'moveDown' image)}}>
|
||||
<a class="btn btn-xs btn-success" data-rel="tooltip" title="Move Down" {{action (route-action 'moveImageDown' image)}}>
|
||||
<i class="ace-icon fa fa-arrow-down bigger-90"></i>
|
||||
</a>
|
||||
{{/if}}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{{/each}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/form-input}}
|
||||
|
||||
{{#form-input label='Attachments' name='attachments'}}
|
||||
<div class="widget-box transparent" style="opacity: 1;">
|
||||
<!-- #section:custom/widget-box.options -->
|
||||
<div class="widget-header">
|
||||
<div class="widget-toolbar action-buttons">
|
||||
<a href="#" data-rel="tooltip" title="Add Attachment" {{action (route-action 'addAttachment')}}>
|
||||
<i class="ace-icon fa fa-plus-circle green"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- /section:custom/widget-box.options -->
|
||||
<div class="widget-body">
|
||||
<div class="widget-main no-padding">
|
||||
<table class="table table-striped table-bordered table-hover">
|
||||
<thead class="thin-border-bottom">
|
||||
<tr>
|
||||
<th style="width: 86px;">
|
||||
<i class="ace-icon fa fa-paperclip bigger-110 hidden-480"></i>
|
||||
Attachment
|
||||
</th>
|
||||
<th>
|
||||
<i class="ace-icon fa fa-sticky-note-o bigger-110 hidden-480"></i>
|
||||
Description
|
||||
</th>
|
||||
<th style="width: 106px;">
|
||||
<i class="ace-icon fa fa-cogs bigger-110 hidden-480"></i>
|
||||
Settings
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
{{#each model.attachments as |attachment|}}
|
||||
<tr>
|
||||
<td>
|
||||
{{!image-previews images=image.url}}
|
||||
<a href="{{attachment.url}}" target="_blank">
|
||||
<i class="ace-icon fa fa-download bigger-110 grey"></i>
|
||||
Download
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
{{editable-cell model=attachment field='note' post-url='application/update-attachment'}}
|
||||
</td>
|
||||
<td>
|
||||
<div class="btn-group">
|
||||
<a class="btn btn-xs btn-danger" data-rel="tooltip" title="Remove" {{action (route-action 'removeAttachment' attachment)}}>
|
||||
<i class="ace-icon fa fa-trash-o"></i>
|
||||
</a>
|
||||
{{#if (not-eq model.images.firstObject.id attachment.id)}}
|
||||
<a class="btn btn-xs btn-info" data-rel="tooltip" title="Move Up" {{action (route-action 'moveAttachmentUp' attachment)}}>
|
||||
<i class="ace-icon fa fa-arrow-up bigger-90"></i>
|
||||
</a>
|
||||
{{/if}}
|
||||
{{#if (not-eq model.images.lastObject.id attachment.id)}}
|
||||
<a class="btn btn-xs btn-success" data-rel="tooltip" title="Move Down" {{action (route-action 'moveAttachmentDown' attachment)}}>
|
||||
<i class="ace-icon fa fa-arrow-down bigger-90"></i>
|
||||
</a>
|
||||
{{/if}}
|
||||
@ -109,3 +180,17 @@
|
||||
{{/form-content}}
|
||||
{{/modal-dialog}}
|
||||
{{/if}}
|
||||
|
||||
{{#if model.addAttachment}}
|
||||
{{#modal-dialog title='Add Attachment' no-cancel=true submit=(route-action 'submitAddAttachment') on-close=(route-action 'closeAddAttachment') close-to-parent=false}}
|
||||
{{#form-content form-id=(concat 'form_' model.id)}}
|
||||
{{input type='hidden' name='applicationId' value=model.id}}
|
||||
{{#form-input name='note' label='Description'}}
|
||||
{{input name='note' value=model.attachment.note class='col-xs-12'}}
|
||||
{{/form-input}}
|
||||
{{#form-input name='attachment' label='Attachment'}}
|
||||
{{file-input name='attachment' file=model.attachment}}
|
||||
{{/form-input}}
|
||||
{{/form-content}}
|
||||
{{/modal-dialog}}
|
||||
{{/if}}
|
||||
|
24
web/tests/integration/components/file-input-test.js
Normal file
24
web/tests/integration/components/file-input-test.js
Normal file
@ -0,0 +1,24 @@
|
||||
import { moduleForComponent, test } from 'ember-qunit';
|
||||
import hbs from 'htmlbars-inline-precompile';
|
||||
|
||||
moduleForComponent('file-input', 'Integration | Component | file input', {
|
||||
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`{{file-input}}`);
|
||||
|
||||
assert.equal(this.$().text().trim(), '');
|
||||
|
||||
// Template block usage:
|
||||
this.render(hbs`
|
||||
{{#file-input}}
|
||||
template block text
|
||||
{{/file-input}}
|
||||
`);
|
||||
|
||||
assert.equal(this.$().text().trim(), 'template block text');
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user