add sound

This commit is contained in:
Shaun Chyxion 2020-08-16 15:44:47 +08:00
parent b4320ffa21
commit 264af78bbd
43 changed files with 638 additions and 62 deletions

View File

@ -0,0 +1,64 @@
package com.pudonghot.yo.cms.controller;
import java.io.File;
import com.wacai.tigon.form.FormList;
import org.springframework.http.MediaType;
import com.pudonghot.yo.model.domain.Sound;
import org.apache.commons.io.FilenameUtils;
import org.springframework.core.io.Resource;
import javax.servlet.http.HttpServletRequest;
import com.wacai.tigon.web.controller.ArgQuery;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.core.io.FileSystemResource;
import com.pudonghot.yo.cms.form.create.FormCreateSound;
import com.pudonghot.yo.cms.form.update.FormUpdateSound;
import com.wacai.tigon.web.controller.BaseCrudController;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @author Donghuang
* @date Aug 16, 2020 12:58:27
*/
@Controller
@RequestMapping("/sound")
public class SoundController
extends BaseCrudController<Integer,
Sound,
FormList,
FormCreateSound,
FormUpdateSound> {
@Value("${yo.cms.sound.base-path}")
private String basePath;
@Value("${yo.cms.sound.store-dir}")
private String storeDir;
@GetMapping("/file/**")
public ResponseEntity<Resource> get(
final HttpServletRequest request) {
final String fileName = request.getRequestURL()
.toString()
.split("/file/")[1];
return ResponseEntity.ok()
.contentType(new MediaType("audio",
FilenameUtils.getExtension(fileName)))
.body(new FileSystemResource(
new File(storeDir, fileName)));
}
/**
* {@inheritDoc}
*/
@Override
protected void after(final ArgQuery<?> arg) {
super.after(arg);
if (arg.getType() == ArgQuery.Type.LIST) {
arg.getResult().attr("basePath", basePath);
}
}
}

View File

@ -0,0 +1,19 @@
package com.pudonghot.yo.cms.form.create;
import lombok.Getter;
import lombok.Setter;
import javax.validation.constraints.NotNull;
import com.pudonghot.yo.cms.form.BaseCreateForm;
import org.springframework.web.multipart.MultipartFile;
/**
* @author Donghuang
* @date Aug 16, 2020 12:58:27
*/
@Getter
@Setter
public class FormCreateSound extends BaseCreateForm {
private static final long serialVersionUID = 1L;
@NotNull
private MultipartFile file;
}

View File

@ -0,0 +1,19 @@
package com.pudonghot.yo.cms.form.update;
import lombok.Getter;
import lombok.Setter;
import javax.validation.constraints.NotNull;
import com.pudonghot.yo.cms.form.BaseUpdateForm;
import org.springframework.web.multipart.MultipartFile;
/**
* @author Donghuang
* @date Aug 16, 2020 12:58:27
*/
@Getter
@Setter
public class FormUpdateSound extends BaseUpdateForm {
private static final long serialVersionUID = 1L;
@NotNull
private MultipartFile file;
}

View File

@ -0,0 +1,18 @@
package com.pudonghot.yo.cms.service;
import com.pudonghot.yo.model.domain.Sound;
import com.pudonghot.yo.cms.form.create.FormCreateSound;
import com.pudonghot.yo.cms.form.update.FormUpdateSound;
import com.wacai.tigon.service.BaseCrudByFormService;
/**
* @author Donghuang
* @date Aug 16, 2020 12:58:27
*/
public interface SoundService
extends BaseCrudByFormService<Integer,
Sound,
FormCreateSound,
FormUpdateSound> {
}

View File

@ -0,0 +1,125 @@
package com.pudonghot.yo.cms.service.impl;
import java.io.File;
import java.io.IOException;
import lombok.extern.slf4j.Slf4j;
import java.util.function.Consumer;
import org.apache.shiro.util.Assert;
import com.wacai.tigon.mybatis.Search;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import com.pudonghot.yo.mapper.SoundMapper;
import com.pudonghot.yo.util.FileSizeUtils;
import com.wacai.tigon.sequence.IdSequence;
import com.pudonghot.yo.model.domain.Sound;
import org.springframework.stereotype.Service;
import com.pudonghot.yo.cms.service.SoundService;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.web.multipart.MultipartFile;
import com.pudonghot.yo.cms.form.create.FormCreateSound;
import com.pudonghot.yo.cms.form.update.FormUpdateSound;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.annotation.Autowired;
import com.wacai.tigon.service.support.BaseCrudByFormServiceSupport;
/**
* @author Donghuang
* @date Aug 16, 2020 12:58:27
*/
@Slf4j
@Service
public class SoundServiceImpl
extends BaseCrudByFormServiceSupport<Integer,
Sound,
FormCreateSound,
FormUpdateSound,
SoundMapper>
implements SoundService {
@Value("${yo.cms.sound.store-dir}")
private String soundStoreDir;
@Autowired
private IdSequence idSeq;
/**
* {@inheritDoc}
*/
@Override
protected void beforeCreate(final FormCreateSound form, final Sound model) {
super.beforeCreate(form, model);
final MultipartFile file = form.getFile();
Assert.state(file != null, "Sound file required");
Assert.state(!file.isEmpty(), "Sound file is empty");
saveFile(file, model);
}
/**
* {@inheritDoc}
*/
@Override
protected void beforeUpdate(final FormUpdateSound form, final Sound model) {
super.beforeUpdate(form, model);
final MultipartFile file = form.getFile();
if (file != null && !file.isEmpty()) {
delete(model);
saveFile(file, model);
}
}
/**
* save file
* @param file file
*/
private void saveFile(final MultipartFile file, final Sound sound) {
final String dateDir = DateFormatUtils.format(
System.currentTimeMillis(), "yyyy/MM/dd");
final File fileDir = new File(soundStoreDir, dateDir);
if (!fileDir.exists()) {
fileDir.mkdirs();
}
final String fileName = idSeq.get() + "." +
FilenameUtils.getExtension(file.getOriginalFilename());
try {
file.transferTo(new File(fileDir, fileName));
}
catch (final IOException e) {
throw new IllegalStateException(
"Save upload file error caused", e);
}
sound.setPath(dateDir + "/" + fileName);
sound.setContentType(file.getContentType());
final long size = file.getSize();
sound.setFileSize(size);
sound.setFileSizeHumanReadable(
FileSizeUtils.humanReadable(size));
}
/**
* {@inheritDoc}
*/
@Override
public int delete(final Integer id) {
delete(find(id));
return super.delete(id);
}
/**
* {@inheritDoc}
*/
@Override
public int delete(final Search search) {
scan(search, (Consumer<Sound>) sound -> delete(sound.getId()));
return 0;
}
private void delete(final Sound sound) {
log.info("Delete sound file [{}].", sound);
FileUtils.deleteQuietly(new File(soundStoreDir, sound.getPath()));
}
}

View File

@ -39,3 +39,6 @@ tigon.shiro.filter-chain=${site.context-path}/auth/login=anon \
/assets/**=anon \
/**=user
yo.cms.sound.store-dir=/Users/chyxion/cms-sound
yo.cms.sound.base-path=http://localhost:8180/sound/file/

View File

@ -8,51 +8,53 @@ spring.servlet.multipart.max-file-size=256MB
spring.servlet.multipart.max-request-size=256MB
# Data source
tigon.codegen.datasource.url=jdbc:mysql://172.18.4.35/yoqw?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai
tigon.codegen.datasource.url=jdbc:mysql://localhost/yoqw?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai
tigon.codegen.datasource.username=yoqw
tigon.codegen.datasource.password=yoqw_query!
# Code gen
tigon.codegen.base-package=com.pudonghot.corona
tigon.codegen.default-gen-items=model,form,mapper,service,controller
tigon.codegen.base-package=com.pudonghot.yo
tigon.codegen.default-gen-items=model,form,mapper,service,service-impl,controller
tigon.codegen.mapper.cache-enabled=false
# Model
tigon.codegen.table-prefix=co
tigon.codegen.table-prefix=br
tigon.codegen.model.project-dir=lib/model
tigon.codegen.model.base-package=com.pudonghot.corona
tigon.codegen.model.base-package=com.pudonghot.yo.model.domain
tigon.codegen.model.base-class.name=BaseDomain
tigon.codegen.model.base-class.fields=id,active,createdTime,updatedTime,createdBy,updatedBy,note
tigon.codegen.model.base-class.full-name=com.pudonghot.corona.model.common.BaseDomain
tigon.codegen.model.base-class.import-required=true
tigon.codegen.model.base-class.full-name=com.pudonghot.yo.model.domain.BaseDomain
tigon.codegen.model.base-class.import-required=false
# Form Create
tigon.codegen.form-create.project-dir=lib/model
tigon.codegen.form-create.base-package=com.pudonghot.corona
tigon.codegen.form-create.base-class.name=CreateFormBase
tigon.codegen.form-create.base-class.full-name=com.pudonghot.corona.form.common.CreateFormBase
tigon.codegen.form-create.project-dir=cms
tigon.codegen.form-create.base-package=com.pudonghot.yo.cms.form.create
tigon.codegen.form-create.base-class.name=BaseCreateForm
tigon.codegen.form-create.base-class.full-name=com.pudonghot.yo.cms.form.BaseCreateForm
tigon.codegen.form-create.base-class.import-required=true
# Form Update
tigon.codegen.form-update.project-dir=lib/model
tigon.codegen.form-update.base-package=com.pudonghot.corona
tigon.codegen.form-update.base-class.name=UpdateFormBase
tigon.codegen.form-update.base-class.full-name=com.pudonghot.corona.form.common.UpdateFormBase
tigon.codegen.form-update.project-dir=cms
tigon.codegen.form-update.base-package=com.pudonghot.yo.cms.form.update
tigon.codegen.form-update.base-class.name=BaseUpdateForm
tigon.codegen.form-update.base-class.full-name=com.pudonghot.yo.cms.form.BaseUpdateForm
tigon.codegen.form-update.base-class.import-required=true
# Mapper
tigon.codegen.mapper.project-dir=lib/mapper
tigon.codegen.mapper.base-package=com.pudonghot.corona
tigon.codegen.mapper.base-package=com.pudonghot.yo.mapper
# Service
tigon.codegen.service.project-dir=cms
tigon.codegen.service.base-package=com.pudonghot.corona.cms
tigon.codegen.service.base-package=com.pudonghot.yo.cms.service
# Service Impl
tigon.codegen.service-impl.project-dir=cms
tigon.codegen.service-impl.base-package=com.pudonghot.corona.cms
tigon.codegen.service-impl.base-package=com.pudonghot.yo.cms.service.impl
# Controller
tigon.codegen.controller.project-dir=cms
tigon.codegen.controller.base-package=com.pudonghot.corona.cms
tigon.codegen.controller.base-package=com.pudonghot.yo.cms.controller
# File Doc
tigon.codegen.file-doc.gen=true

View File

@ -0,0 +1,12 @@
package com.pudonghot.yo.mapper;
import com.wacai.tigon.mybatis.BaseMapper;
import com.pudonghot.yo.model.domain.Sound;
/**
* @author Donghuang
* @date Aug 16, 2020 12:58:27
*/
public interface SoundMapper extends BaseMapper<Integer, Sound> {
}

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/**
* @author Donghuang
* @date Aug 16, 2020 12:58:27
*/
-->
<!DOCTYPE mapper PUBLIC
"-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.pudonghot.yo.mapper.SoundMapper">
</mapper>

View File

@ -0,0 +1,25 @@
package com.pudonghot.yo.mapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import com.wacai.tigon.mybatis.Search;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests;
/**
* @author Donghuang
* @date Aug 16, 2020 12:58:27
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath*:spring/spring-*.xml")
public class SoundMapperTest extends AbstractTransactionalJUnit4SpringContextTests {
@Autowired
private SoundMapper mapper;
@Test
public void mapperTest() {
mapper.list(new Search().limit(8));
}
}

View File

@ -3,7 +3,6 @@ package com.pudonghot.yo.model.domain;
import lombok.Getter;
import lombok.Setter;
import com.wacai.tigon.mybatis.Table;
import com.wacai.tigon.mybatis.NotUpdate;
import lombok.experimental.FieldNameConstants;
/**
@ -14,13 +13,9 @@ import lombok.experimental.FieldNameConstants;
@Setter
@Table("br_ivr_menu")
@FieldNameConstants(prefix = "")
public class IvrMenu extends BaseDomain {
@NotUpdate
private Integer tenantId;
@NotUpdate
private String tenantCode;
private String name;
public class IvrMenu extends TenantDomain {
private String name;
/**
* 长问候语音
*/

View File

@ -0,0 +1,22 @@
package com.pudonghot.yo.model.domain;
import lombok.Getter;
import lombok.Setter;
import com.wacai.tigon.mybatis.Table;
import lombok.experimental.FieldNameConstants;
/**
* @author Donghuang
* @date Aug 16, 2020 12:58:27
*/
@Getter
@Setter
@Table("br_sound")
@FieldNameConstants(prefix = "")
public class Sound extends TenantDomain {
private static final long serialVersionUID = 1L;
private String path;
private String contentType;
private long fileSize;
private String fileSizeHumanReadable;
}

View File

@ -3,56 +3,56 @@
{
"item": "model",
"projectDir": "${modelProjectDir}",
"template": "/codegen/model.ftl",
"template": "/templates/codegen/model.ftl",
"result": "src/main/java/${modelPkgDir}/${Model}.java"
},
{
"item": "form",
"projectDir": "${formCreateProjectDir}",
"template": "/codegen/form-create.ftl",
"template": "/templates/codegen/form-create.ftl",
"result": "src/main/java/${formCreatePkgDir}/FormCreate${Model}.java"
},
{
"item": "form",
"projectDir": "${formUpdateProjectDir}",
"template": "/codegen/form-update.ftl",
"template": "/templates/codegen/form-update.ftl",
"result": "src/main/java/${formUpdatePkgDir}/FormUpdate${Model}.java"
},
{
"item": "mapper",
"projectDir": "${mapperProjectDir}",
"template": "/codegen/mapper.ftl",
"template": "/templates/codegen/mapper.ftl",
"result": "src/main/java/${mapperPkgDir}/${Model}Mapper.java"
},
{
"item": "mapper",
"projectDir": "${mapperProjectDir}",
"template": "/codegen/mapper-xml.ftl",
"template": "/templates/codegen/mapper-xml.ftl",
"result": "src/main/java/${mapperPkgDir}/${Model}Mapper.xml"
},
{
"item": "mapper",
"projectDir": "${mapperProjectDir}",
"template": "/codegen/mapper-test.ftl",
"template": "/templates/codegen/mapper-test.ftl",
"result": "src/test/java/${mapperPkgDir}/${Model}MapperTest.java"
},
{
"item": "service",
"projectDir": "${serviceProjectDir}",
"template": "/codegen/service.ftl",
"template": "/templates/codegen/service.ftl",
"result": "src/main/java/${servicePkgDir}/${Model}Service.java"
},
{
"item": "service",
"projectDir": "${serviceImplProjectDir}",
"template": "/codegen/service-impl.ftl",
"template": "/templates/codegen/service-impl.ftl",
"result": "src/main/java/${serviceImplPkgDir}/${Model}ServiceImpl.java"
},
{
"item": "controller",
"projectDir": "${controllerProjectDir}",
"template": "/codegen/controller.ftl",
"template": "/templates/codegen/controller.ftl",
"result": "src/main/java/${controllerPkgDir}/${Model}Controller.java"
}
]
}
}

View File

@ -1,4 +1,4 @@
package ${controllerPkg}.controller;
package ${controllerPkg};
<#list cols as prop>
<#if prop.javaType == 'Date'>

View File

@ -1,9 +1,9 @@
package ${controllerPkg}.controller;
package ${controllerPkg};
import ${modelPkg}.model.${ModelName};
import ${modelPkg}.${ModelName};
import ${formListFullName};
import ${formCreatePkg}.form.create.FormCreate${ModelName};
import ${formUpdatePkg}.form.update.FormUpdate${ModelName};
import ${formCreatePkg}.FormCreate${ModelName};
import ${formUpdatePkg}.FormUpdate${ModelName};
import ${baseControllerFullName};
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

View File

@ -1,4 +1,4 @@
package ${formCreatePkg}.form.create;
package ${formCreatePkg};
<#import "/codegen/commons.ftl" as CodeGen>
import lombok.Getter;

View File

@ -1,4 +1,4 @@
package ${formUpdatePkg}.form.update;
package ${formUpdatePkg};
<#import "/codegen/commons.ftl" as CodeGen>
import lombok.Getter;

View File

@ -1,4 +1,4 @@
package ${mapperPkg}.mapper;
package ${mapperPkg};
import org.junit.Test;
import org.junit.runner.RunWith;

View File

@ -7,7 +7,7 @@ ${objDoc}
<!DOCTYPE mapper PUBLIC
"-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="${mapperPkg}.mapper.${ModelName}Mapper">
<mapper namespace="${mapperPkg}.${ModelName}Mapper">
<#if cacheEnabled>
<!-- Redis Cache -->

View File

@ -1,7 +1,7 @@
package ${mapperPkg}.mapper;
package ${mapperPkg};
import ${baseMapperFullName};
import ${modelPkg}.model.${ModelName};
import ${modelPkg}.${ModelName};
<#if objDoc?has_content>
${objDoc}

View File

@ -1,4 +1,4 @@
package ${modelPkg}.model;
package ${modelPkg};
<#import "/codegen/commons.ftl" as CodeGen>
import lombok.Getter;

View File

@ -1,11 +1,11 @@
package ${servicePkg}.service.impl;
package ${serviceImplPkg};
import org.springframework.stereotype.Service;
import ${modelPkg}.model.${ModelName};
import ${mapperPkg}.mapper.${ModelName}Mapper;
import ${servicePkg}.service.${ModelName}Service;
import ${formCreatePkg}.form.create.FormCreate${ModelName};
import ${formUpdatePkg}.form.update.FormUpdate${ModelName};
import ${modelPkg}.${ModelName};
import ${mapperPkg}.${ModelName}Mapper;
import ${servicePkg}.${ModelName}Service;
import ${formCreatePkg}.FormCreate${ModelName};
import ${formUpdatePkg}.FormUpdate${ModelName};
import ${baseServiceSupportFullName};
<#if objDoc?has_content>

View File

@ -1,8 +1,8 @@
package ${servicePkg}.service;
package ${servicePkg};
import ${modelPkg}.model.${ModelName};
import ${formCreatePkg}.form.create.FormCreate${ModelName};
import ${formUpdatePkg}.form.update.FormUpdate${ModelName};
import ${modelPkg}.${ModelName};
import ${formCreatePkg}.FormCreate${ModelName};
import ${formUpdatePkg}.FormUpdate${ModelName};
import ${baseServiceFullName};
<#if objDoc?has_content>

View File

@ -0,0 +1,33 @@
package com.pudonghot.yo.util;
import java.text.CharacterIterator;
import java.text.StringCharacterIterator;
/**
* @author Donghuang
* @date Aug 16, 2020 13:49:26
*/
public class FileSizeUtils {
/**
* human readable bytes
* @param bytes bytes
* @return human readable
*/
public static String humanReadable(long bytes) {
if (-1000 < bytes && bytes < 1000) {
return bytes + " B";
}
final CharacterIterator ci =
new StringCharacterIterator("kMGTPE");
while (bytes <= -999_950 || bytes >= 999_950) {
bytes /= 1000;
ci.next();
}
return String.format("%.1f %cB",
bytes / 1000.0, ci.current());
}
}

View File

@ -4,13 +4,13 @@ import $ from 'jquery';
export default BaseFormInput.extend({
didInsertElement() {
let me = this;
$(me.element).children('.date-picker').datepicker({
$(me.element).find('.date-picker').datepicker({
format: 'yyyy-mm-dd',
autoclose: true,
todayHighlight: true
})
.on('changeDate', function(ev) {
me.setVal($(me.element).children('input').val());
me.setVal($(me.element).find('input').val());
})
//show datepicker when clicking on the icon
.next().on(ace.click_event, function() {

View File

@ -14,7 +14,7 @@ export default BaseFormInput.extend({
},
didInsertElement() {
let me = this;
$(me.element).children('input').datetimepicker({
$(me.element).find('input').datetimepicker({
format: me.get('format'),
showClear: true,
autoclose: true,

View File

@ -28,7 +28,7 @@ export default BaseFormInput.extend({
let me = this;
me._super(...arguments);
['file', 'image'].includes(me.get('type')) &&
$(me.element).children('input[type=file]').ace_file_input({
$(me.element).find('input[type=file]').ace_file_input({
no_file: 'No File Choosed...',
btn_choose: 'Choose',
btn_change: 'Change',

View File

@ -43,6 +43,12 @@ export default (function() {
route: 'ivr-menu.list',
icon: 'fa-bullhorn',
text: 'IVR菜单管理'
},
{
perm: 'PERM_VIEW_SOUND_LIST',
route: 'sound.list',
icon: 'fa-file-sound-o',
text: '声音管理'
}
]
}, {

View File

@ -122,6 +122,12 @@ Router.map(function() {
this.route('create');
this.route('edit', {path: '/:id/edit'});
});
this.route('sound', function() {
this.route('list');
this.route('create');
this.route('edit', {path: '/:id/edit'});
});
});
export default Router;

View File

@ -0,0 +1,30 @@
import BaseRoute from '../base';
export default BaseRoute.extend({
perm: 'PERM_VIEW_SOUND_CREATE',
breadcrumbs: [{route: 'sound.list', text: '声音列表'}, {text: '创建声音'}],
model() {
return {
active: true
};
},
actions: {
fileChanged(files, oldFile) {
const me = this;
const newFile = files[0].name;
const propKey = 'controller.model.note';
const note = me.get(propKey);
if (!note || oldFile.match(new RegExp('^' + note + '\\.\\w+$'))) {
me.set(propKey, newFile.replace(/\.\w+$/, ''));
}
},
fileRemoved(files) {
const me = this;
const propKey = 'controller.model.note';
const note = me.get(propKey);
if (files[0].name.startsWith(note)) {
me.set(propKey, '');
}
},
}
});

View File

@ -0,0 +1,10 @@
import BaseEditRoute from '../base-edit';
export default BaseEditRoute.extend({
perm: 'PERM_VIEW_SOUND_EDIT',
afterModel(model) {
this.set('breadcrumbs',
[{route: 'sound.list', text: '声音列表'},
{text: '编辑声音[' + model.name + ']'}]);
}
});

View File

@ -0,0 +1,6 @@
import BaseListRoute from './../base-list';
export default BaseListRoute.extend({
perm: 'PERM_VIEW_SOUND_LIST',
breadcrumbs: [{text: '声音列表'}],
});

View File

@ -0,0 +1,10 @@
import Service from '../service';
export default Service.extend({
modelName: 'Sound',
createConstraints: {
file: {
presence: true,
}
}
});

View File

@ -7,8 +7,12 @@
label='动作'
options=(array
(hash value='menu-exec-app' text='menu-exec-app')
(hash value='menu-exec-api' text='menu-exec-api')
(hash value='menu-play-sound' text='menu-play-sound')
(hash value='menu-sub' text='menu-sub')
(hash value='menu-top' text='menu-top')
(hash value='menu-back' text='menu-back')
(hash value='menu-exit' text='menu-exit')
)
}}
{{form-input name='digits' label='按键'}}

View File

@ -6,8 +6,12 @@
label='动作'
options=(array
(hash value='menu-exec-app' text='menu-exec-app')
(hash value='menu-exec-api' text='menu-exec-api')
(hash value='menu-play-sound' text='menu-play-sound')
(hash value='menu-sub' text='menu-sub')
(hash value='menu-top' text='menu-top')
(hash value='menu-back' text='menu-back')
(hash value='menu-exit' text='menu-exit')
)
}}
{{form-input name='digits' label='按键'}}

View File

@ -0,0 +1,13 @@
{{#form-content}}
<hr />
{{form-input type='file'
before-file-change=(route-action 'fileChanged')
before-file-remove=(route-action 'fileRemoved')
name='file'
label='文件'}}
{{form-input name='note' label='备注'}}
<hr />
{{form-footer-buttons type='create'}}
{{/form-content}}
{{outlet}}

View File

@ -0,0 +1,12 @@
{{#form-content}}
{{form-input type='hidden' name='id'}}
{{form-input type='file' name='file' label='文件'}}
{{form-input-enabled}}
{{form-input name='note' label='备注'}}
<hr />
{{form-footer-buttons type='update'}}
{{/form-content}}
{{outlet}}

View File

@ -0,0 +1,81 @@
<div class="widget-box transparent" style="padding-top: 2px; border: 1px solid #ddd;">
{{#grid-header}}
{{#has-perm 'PERM_VIEW_SOUND_CREATE'}}
<li>
{{#link-to 'sound.create'}}
<i class="ace-icon fa fa-plus-circle bigger-110 green"></i>
新建声音
{{/link-to}}
</li>
{{/has-perm}}
{{/grid-header}}
<div class="widget-body">
<!-- #section:custom/scrollbar -->
<div class="widget-main no-padding">
<table class="table table-striped table-bordered table-hover dataTable">
<thead class="thin-border-bottom">
<tr>
<th>
路径
</th>
<th>
文件大小
</th>
<th>
<i class="ace-icon fa fa-sticky-note-o bigger-110"></i>
备注
</th>
<th>
<i class="ace-icon fa fa-exchange bigger-110 hidden-480"></i>
{{th-filter name='active'
text='状态'
options=(array (hash value=true text='启用')
(hash value=false text='禁用'))
}}
</th>
<th>
<i class="ace-icon fa fa-cogs bigger-110 hidden-480"></i>
管理
</th>
</tr>
</thead>
<tbody>
{{#each model.data as |it|}}
<tr>
<td>
<a href="{{model.basePath}}{{it.path}}" target="_blank" title="录音">
{{it.path}}
</a>
</td>
<td>
{{it.fileSizeHumanReadable}}
</td>
<td>
{{editable-cell model=it field='note'}}
</td>
<td>
{{status-cell model=it}}
</td>
<td>
<div class="btn-group">
{{#has-perm 'PERM_VIEW_SOUND_EDIT'}}
{{status-toggle-button model=it}}
{{edit-btn route-name='sound.edit' model-id=it.id perm='PERM_VIEW_SOUND_EDIT'}}
{{/has-perm}}
{{#has-perm 'PERM_VIEW_SOUND_DELETE'}}
{{#unless it.active}}
{{delete-button model=it}}
{{/unless}}
{{/has-perm}}
</div>
</td>
</tr>
{{/each}}
</tbody>
</table>
</div>
{{pagination-bar}}
</div>
</div>
{{outlet}}

View File

@ -0,0 +1,11 @@
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
module('Unit | Route | sound/create', function(hooks) {
setupTest(hooks);
test('it exists', function(assert) {
let route = this.owner.lookup('route:sound/create');
assert.ok(route);
});
});

View File

@ -0,0 +1,11 @@
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
module('Unit | Route | sound/edit', function(hooks) {
setupTest(hooks);
test('it exists', function(assert) {
let route = this.owner.lookup('route:sound/edit');
assert.ok(route);
});
});

View File

@ -0,0 +1,11 @@
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
module('Unit | Route | sound/list', function(hooks) {
setupTest(hooks);
test('it exists', function(assert) {
let route = this.owner.lookup('route:sound/list');
assert.ok(route);
});
});

View File

@ -0,0 +1,12 @@
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
module('Unit | Service | sound/service', function(hooks) {
setupTest(hooks);
// Replace this with your real tests.
test('it exists', function(assert) {
let service = this.owner.lookup('service:sound/service');
assert.ok(service);
});
});