update
This commit is contained in:
parent
adff46015a
commit
64d1dab732
@ -46,6 +46,11 @@
|
||||
<artifactId>commons-csv</artifactId>
|
||||
<version>1.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>joda-time</groupId>
|
||||
<artifactId>joda-time</artifactId>
|
||||
<version>2.9.9</version>
|
||||
</dependency>
|
||||
<!-- Test Dependencies -->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
|
@ -0,0 +1,25 @@
|
||||
package com.pudonghot.ambition.crm.controller;
|
||||
|
||||
import me.chyxion.tigon.webmvc.ResourceModel;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author Shaun Chyxion <br>
|
||||
* chyxion@163.com <br>
|
||||
* Mar 10, 2017 23:15:01
|
||||
*/
|
||||
@Controller
|
||||
public class DatabaseController {
|
||||
|
||||
@RequestMapping("/database/dump")
|
||||
public ResourceModel databaseDump() throws IOException {
|
||||
return new ResourceModel(
|
||||
IOUtils.toByteArray(DatabaseController.class.getResourceAsStream("/static/index.html")),
|
||||
MediaType.TEXT_HTML_VALUE, null);
|
||||
}
|
||||
}
|
@ -0,0 +1,98 @@
|
||||
package com.pudonghot.ambition.crm.controller;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import javax.validation.Valid;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import me.chyxion.tigon.mybatis.Search;
|
||||
import javax.validation.constraints.Max;
|
||||
import javax.validation.constraints.Min;
|
||||
import me.chyxion.tigon.model.ViewModel;
|
||||
import me.chyxion.tigon.model.ListResult;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import com.pudonghot.ambition.crm.model.User;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import com.pudonghot.ambition.crm.model.WeekGoal;
|
||||
import com.pudonghot.ambition.crm.util.AmDateUtil;
|
||||
import org.apache.shiro.authz.annotation.RequiresRoles;
|
||||
import com.pudonghot.ambition.crm.service.WeekGoalService;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import com.pudonghot.ambition.crm.form.update.WeekGoalFormForUpdate;
|
||||
|
||||
/**
|
||||
* @author Shaun Chyxion <br>
|
||||
* chyxion@163.com <br>
|
||||
* Mar 09, 2017 21:54:00
|
||||
*/
|
||||
@Slf4j
|
||||
@Controller
|
||||
@RequestMapping("/week-goal")
|
||||
public class WeekGoalController
|
||||
extends BaseQueryController<WeekGoal> {
|
||||
|
||||
private static final Map<String, String> CRITERION_COLS;
|
||||
static {
|
||||
CRITERION_COLS = new HashMap<>();
|
||||
CRITERION_COLS.put(WeekGoal.QUARTER, WeekGoal.QUARTER);
|
||||
}
|
||||
|
||||
@RequestMapping("/list")
|
||||
public ListResult<ViewModel<WeekGoal>> list(
|
||||
@Min(0)
|
||||
@RequestParam(value = "start", defaultValue = "0")
|
||||
final int start,
|
||||
@Min(1)
|
||||
@Max(512)
|
||||
@RequestParam(value = "limit", defaultValue = "64")
|
||||
final int limit,
|
||||
@RequestParam(value = "filters", required = false)
|
||||
final String filters,
|
||||
@RequestParam(value = "search", required = false)
|
||||
final String strSearch) {
|
||||
((WeekGoalService) queryService).initWeekGoal(getUserId());
|
||||
|
||||
return listViewModels(filters(
|
||||
search(start, limit, strSearch, null), filters));
|
||||
}
|
||||
|
||||
@RequiresRoles(User.ROLE_ADMIN)
|
||||
@RequestMapping(value = "/update", method = RequestMethod.POST)
|
||||
public ViewModel<WeekGoal> update(
|
||||
@Valid WeekGoalFormForUpdate form) {
|
||||
return ((WeekGoalService) queryService).update(form);
|
||||
}
|
||||
|
||||
private Search filters(final Search search, final String strFilters) {
|
||||
|
||||
if (StringUtils.isBlank(strFilters)) {
|
||||
log.debug("No filters given.");
|
||||
search.eq(WeekGoal.QUARTER, AmDateUtil.getQuarter(new Date()));
|
||||
return search;
|
||||
}
|
||||
|
||||
final JSONObject joFilters;
|
||||
try {
|
||||
joFilters = JSON.parseObject(decodeParam(strFilters));
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new IllegalStateException(
|
||||
"Invalid filters [" + strFilters + "]", e);
|
||||
}
|
||||
|
||||
final Integer[] quarters =
|
||||
joFilters.getObject(WeekGoal.QUARTER, Integer[].class);
|
||||
if (quarters != null && quarters.length > 0) {
|
||||
search.in(WeekGoal.QUARTER, quarters);
|
||||
}
|
||||
else {
|
||||
search.eq(WeekGoal.QUARTER, AmDateUtil.getQuarter(new Date()));
|
||||
}
|
||||
|
||||
return search;
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package com.pudonghot.ambition.crm.service;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* @author Shaun Chyxion <br>
|
||||
* chyxion@163.com <br>
|
||||
* Aug 08, 2017 21:54:55
|
||||
*/
|
||||
public interface DatabaseService {
|
||||
InputStream dump();
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package com.pudonghot.ambition.crm.service;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import me.chyxion.tigon.model.ViewModel;
|
||||
import me.chyxion.tigon.service.BaseCrudService;
|
||||
import com.pudonghot.ambition.crm.model.WeekGoal;
|
||||
import org.hibernate.validator.constraints.NotBlank;
|
||||
import com.pudonghot.ambition.crm.form.update.WeekGoalFormForUpdate;
|
||||
|
||||
/**
|
||||
* @version 0.0.1
|
||||
* @since 0.0.1
|
||||
* @author Shaun Chyxion <br>
|
||||
* chyxion@163.com <br>
|
||||
* May 4, 2016 1:18:42 PM
|
||||
*/
|
||||
public interface WeekGoalService
|
||||
extends BaseCrudService<String, WeekGoal> {
|
||||
|
||||
ViewModel<WeekGoal> update(@NotNull @Valid WeekGoalFormForUpdate form);
|
||||
|
||||
void initWeekGoal(@NotBlank String userId);
|
||||
}
|
||||
|
@ -0,0 +1,20 @@
|
||||
package com.pudonghot.ambition.crm.service.support;
|
||||
|
||||
import java.io.InputStream;
|
||||
import com.pudonghot.ambition.crm.service.DatabaseService;
|
||||
|
||||
/**
|
||||
* @author Shaun Chyxion <br>
|
||||
* chyxion@163.com <br>
|
||||
* Aug 08, 2017 21:55:52
|
||||
*/
|
||||
public class DatabaseServiceSupport implements DatabaseService {
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public InputStream dump() {
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,110 @@
|
||||
package com.pudonghot.ambition.crm.service.support;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import org.joda.time.*;
|
||||
import java.util.ArrayList;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.util.Assert;
|
||||
import me.chyxion.tigon.mybatis.Search;
|
||||
import me.chyxion.tigon.model.ViewModel;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.springframework.stereotype.Service;
|
||||
import com.pudonghot.ambition.crm.model.WeekGoal;
|
||||
import com.pudonghot.ambition.crm.util.AmDateUtil;
|
||||
import com.pudonghot.ambition.crm.mapper.WeekGoalMapper;
|
||||
import com.pudonghot.ambition.crm.service.WeekGoalService;
|
||||
import me.chyxion.tigon.service.support.BaseCrudServiceSupport;
|
||||
import com.pudonghot.ambition.crm.form.update.WeekGoalFormForUpdate;
|
||||
|
||||
/**
|
||||
* @version 0.0.1
|
||||
* @since 0.0.1
|
||||
* @author Shaun Chyxion <br>
|
||||
* chyxion@163.com <br>
|
||||
* Sep 22, 2015 10:45:41 AM
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class WeekGoalServiceSupport
|
||||
extends BaseCrudServiceSupport<String, WeekGoal, WeekGoalMapper>
|
||||
implements WeekGoalService {
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public ViewModel<WeekGoal> update(final WeekGoalFormForUpdate form) {
|
||||
final String id = form.getId();
|
||||
final WeekGoal weekGoal = find(id);
|
||||
Assert.state(weekGoal != null, "No week goal [" + id + "] found");
|
||||
return update(form.copy(weekGoal));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void initWeekGoal(final String userId) {
|
||||
if (count(new Search(WeekGoal.USER_ID, userId)
|
||||
.eq(WeekGoal.YEAR, DateTime.now().getYear())) == 0) {
|
||||
log.info("User [{}] week goal is not initialized, init.", userId);
|
||||
final Date now = new Date();
|
||||
final int thisYear = AmDateUtil.getYear(now);
|
||||
|
||||
for (final Pair<Date, Date> week : weeksOfYear()) {
|
||||
final WeekGoal weekGoal = new WeekGoal();
|
||||
weekGoal.setId(idSeq.get());
|
||||
weekGoal.setUserId(userId);
|
||||
weekGoal.setYear(thisYear);
|
||||
weekGoal.setGoal(0);
|
||||
weekGoal.setDone(0);
|
||||
weekGoal.setDateStart(week.getLeft());
|
||||
final Date dateEnd = week.getRight();
|
||||
weekGoal.setDateEnd(dateEnd);
|
||||
|
||||
// date end in next year is 4th quarter
|
||||
weekGoal.setQuarter(AmDateUtil.getYear(dateEnd) == thisYear ?
|
||||
AmDateUtil.getQuarter(dateEnd) : 4);
|
||||
|
||||
weekGoal.setEnabled(true);
|
||||
weekGoal.setCreatedBy(userId);
|
||||
weekGoal.setDateCreated(now);
|
||||
create(weekGoal);
|
||||
}
|
||||
}
|
||||
else {
|
||||
log.info("User [{}] week goal found, ignore init.", userId);
|
||||
}
|
||||
}
|
||||
|
||||
private List<Pair<Date, Date>> weeksOfYear() {
|
||||
|
||||
Period weekPeriod = new Period().withWeeks(1);
|
||||
int thisYear = DateTime.now().getYear();
|
||||
DateTime dateStart = new DateTime(thisYear, 1, 1, 0, 0, 0, 0 );
|
||||
|
||||
// move to first monday
|
||||
while (dateStart.getDayOfWeek() != DateTimeConstants.MONDAY) {
|
||||
dateStart = dateStart.plusDays(1);
|
||||
}
|
||||
|
||||
DateTime dateEnd = new DateTime(thisYear + 1, 1, 1, 0, 0, 0, 0);
|
||||
|
||||
// move to next sunday
|
||||
while (dateEnd.getDayOfWeek() != DateTimeConstants.SATURDAY) {
|
||||
dateEnd = dateEnd.plusDays(1);
|
||||
}
|
||||
|
||||
final List<Pair<Date, Date>> weeks = new ArrayList<>(54);
|
||||
|
||||
Interval interval = new Interval(dateStart, weekPeriod);
|
||||
DateTime intervalStart = null;
|
||||
while ((intervalStart = interval.getStart()).isBefore(dateEnd)) {
|
||||
weeks.add(Pair.of(intervalStart.toDate(),
|
||||
interval.getEnd().minusMillis(1).toDate()));
|
||||
interval = new Interval(intervalStart.plus(weekPeriod), weekPeriod);
|
||||
}
|
||||
return weeks;
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package com.pudonghot.ambition.crm.util;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Calendar;
|
||||
|
||||
/**
|
||||
* @author Donghuang <br>
|
||||
* donghuang@wacai.com <br>
|
||||
* Aug 13, 2017 11:06 PM
|
||||
*/
|
||||
public class AmDateUtil {
|
||||
|
||||
/**
|
||||
* get quarter of date
|
||||
* @param date date
|
||||
* @return quarter
|
||||
*/
|
||||
public static int getQuarter(Date date) {
|
||||
final Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTime(date);
|
||||
return calendar.get(Calendar.MONTH) / 3 + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* get year
|
||||
* @param date date
|
||||
* @return year
|
||||
*/
|
||||
public static int getYear(Date date) {
|
||||
final Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTime(date);
|
||||
return calendar.get(Calendar.YEAR);
|
||||
}
|
||||
}
|
@ -3,11 +3,11 @@ package com.pudonghot.ambition.crm;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.csv.CSVFormat;
|
||||
import org.apache.commons.csv.CSVParser;
|
||||
import org.apache.commons.csv.CSVPrinter;
|
||||
import org.apache.commons.csv.CSVRecord;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.*;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
@ -27,5 +27,18 @@ public class CSVTest {
|
||||
List<CSVRecord> records = parse.getRecords();
|
||||
CSVParser gbk = CSVParser.parse(CSVTest.class.getResource("/data/customers.csv"), Charset.forName("GBK"), CSVFormat.RFC4180);
|
||||
log.info("csv: [{}].", gbk);
|
||||
// p.print();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPrint() throws IOException {
|
||||
CSVFormat format = CSVFormat.DEFAULT;
|
||||
CSVParser parse = format.parse(new InputStreamReader(CSVTest.class.getResourceAsStream("/data/customers.csv")));
|
||||
List<CSVRecord> records = parse.getRecords();
|
||||
CSVParser gbk = CSVParser.parse(CSVTest.class.getResource("/data/customers.csv"), Charset.forName("GBK"), CSVFormat.RFC4180);
|
||||
log.info("csv: [{}].", gbk);
|
||||
|
||||
CSVPrinter p = new CSVPrinter(new FileWriter(new File("")), format);
|
||||
// p.print();
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,14 @@
|
||||
package com.pudonghot.ambition.crm;
|
||||
|
||||
import com.pudonghot.ambition.crm.util.AmDateUtil;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.DateTimeConstants;
|
||||
import org.joda.time.Interval;
|
||||
import org.joda.time.Period;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @version 0.0.1
|
||||
* @since 0.0.1
|
||||
@ -9,4 +18,44 @@ package com.pudonghot.ambition.crm;
|
||||
*/
|
||||
public class TestDriver {
|
||||
|
||||
@Test
|
||||
public void testWeeksOfYear() {
|
||||
Period weekPeriod = new Period().withWeeks(1);
|
||||
// int thisYear = DateTime.now().getYear();
|
||||
int thisYear = 2013;
|
||||
DateTime dateStart = new DateTime(thisYear, 1, 1, 0, 0, 0, 0 );
|
||||
|
||||
// move to first monday
|
||||
while (dateStart.getDayOfWeek() != DateTimeConstants.MONDAY) {
|
||||
dateStart = dateStart.plusDays(1);
|
||||
}
|
||||
|
||||
DateTime dateEnd = new DateTime(thisYear + 1, 1, 1, 0, 0, 0, 0);
|
||||
|
||||
// move to next sunday
|
||||
while (dateEnd.getDayOfWeek() != DateTimeConstants.SATURDAY) {
|
||||
dateEnd = dateEnd.plusDays(1);
|
||||
}
|
||||
|
||||
Interval interval = new Interval(dateStart, weekPeriod);
|
||||
|
||||
DateTime intervalStart = null;
|
||||
while ((intervalStart = interval.getStart()).isBefore(dateEnd)) {
|
||||
|
||||
System.out.println("week : " + intervalStart.getWeekOfWeekyear()
|
||||
+ " start: " + intervalStart.toDate()
|
||||
+ " ending: " + interval.getEnd().minusMillis(1).toDate());
|
||||
|
||||
interval = new Interval(intervalStart.plus(weekPeriod), weekPeriod);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Test
|
||||
public void testGetQuarter() {
|
||||
System.err.println(AmDateUtil.getQuarter(new Date()));
|
||||
System.err.println(AmDateUtil.getYear(new Date()));
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,45 @@
|
||||
package com.pudonghot.ambition.crm.service;
|
||||
|
||||
import java.io.File;
|
||||
import org.junit.Test;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.apache.commons.csv.CSVFormat;
|
||||
import org.apache.commons.csv.CSVPrinter;
|
||||
import com.pudonghot.ambition.crm.AmbitionCRM;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
/**
|
||||
* @author Donghuang <br>
|
||||
* donghuang@wacai.com <br>
|
||||
* Apr 24, 2017 11:33 PM
|
||||
*/
|
||||
@SpringBootTest
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(classes = AmbitionCRM.class)
|
||||
public class DatabaseDumpServiceTest {
|
||||
@Autowired
|
||||
private UserService userService;
|
||||
|
||||
@Test
|
||||
public void testReadCSV() throws Exception {
|
||||
|
||||
CSVFormat format = CSVFormat.DEFAULT;
|
||||
CSVPrinter p = new CSVPrinter(new FileWriter(new File("/Users/chyxion/Workspaces/dbdump.cvs")), format);
|
||||
userService.scan(user -> {
|
||||
try {
|
||||
p.printRecord(user);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
p.flush();
|
||||
p.close();
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package com.pudonghot.ambition.crm.mapper;
|
||||
|
||||
import me.chyxion.tigon.mybatis.BaseMapper;
|
||||
import com.pudonghot.ambition.crm.model.WeekGoal;
|
||||
|
||||
/**
|
||||
* @author Shaun Chyxion <br>
|
||||
* chyxion@163.com <br>
|
||||
* Aug 09, 2017 22:25:37
|
||||
*/
|
||||
public interface WeekGoalMapper extends BaseMapper<String, WeekGoal> {
|
||||
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
/**
|
||||
* @author Shaun Chyxion <br>
|
||||
* chyxion@163.com <br>
|
||||
* Aug 09, 2017 22:26:12
|
||||
*/
|
||||
-->
|
||||
<!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.WeekGoalMapper">
|
||||
|
||||
</mapper>
|
@ -0,0 +1,24 @@
|
||||
package com.pudonghot.ambition.crm.form.update;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import me.chyxion.tigon.form.FU2;
|
||||
import javax.validation.constraints.Min;
|
||||
|
||||
/**
|
||||
* @version 0.0.1
|
||||
* @since 0.0.1
|
||||
* @author Shaun Chyxion <br>
|
||||
* chyxion@163.com <br>
|
||||
* May 10, 2016 1:42:01 PM
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class WeekGoalFormForUpdate extends FU2<String, String> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Min(0)
|
||||
private int goal;
|
||||
@Min(0)
|
||||
private int done;
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
package com.pudonghot.ambition.crm.model;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import java.util.Date;
|
||||
import me.chyxion.tigon.model.M3;
|
||||
import me.chyxion.tigon.mybatis.Table;
|
||||
import me.chyxion.tigon.mybatis.NotUpdate;
|
||||
|
||||
/**
|
||||
* @author Shaun Chyxion <br>
|
||||
* chyxion@163.com <br>
|
||||
* Aug 09, 2017 22:24:40
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Table("crm_week_goal")
|
||||
public class WeekGoal extends M3<String, String> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
// Column Names
|
||||
public static final String USER_ID = "user_id";
|
||||
public static final String YEAR = "year";
|
||||
public static final String QUARTER = "quarter";
|
||||
public static final String DATE_START = "date_start";
|
||||
public static final String DATE_END = "date_end";
|
||||
public static final String GOAL = "goal";
|
||||
public static final String DONE = "done";
|
||||
|
||||
// Properties
|
||||
@NotUpdate
|
||||
private String userId;
|
||||
@NotUpdate
|
||||
private int year;
|
||||
@NotUpdate
|
||||
private int quarter;
|
||||
@NotUpdate
|
||||
private Date dateStart;
|
||||
@NotUpdate
|
||||
private Date dateEnd;
|
||||
private int goal;
|
||||
private int done;
|
||||
}
|
@ -2,16 +2,40 @@ import Ember from 'ember';
|
||||
import BaseComponentMixin from '../mixins/components/base-component';
|
||||
|
||||
export default Ember.Component.extend(BaseComponentMixin, {
|
||||
'col-width': 6,
|
||||
colWidth: Ember.computed.alias('col-width'),
|
||||
classNameBindings: ['hasError:has-error'],
|
||||
model: Ember.computed.alias('route.controller.model'),
|
||||
errors: Ember.computed.alias('route.controller.errors'),
|
||||
hasError: Ember.computed('errors', function() {
|
||||
return this.get('errors.' + this.get('name'));
|
||||
}),
|
||||
'error-msg': true,
|
||||
errorMsg: Ember.computed.alias('error-msg'),
|
||||
'label-class': 'col-xs-12 col-sm-3 col-md-3',
|
||||
labelClass: Ember.computed.alias('label-class'),
|
||||
'input-class': 'col-xs-12 col-sm-5 col-md-5',
|
||||
inputClass: Ember.computed.alias('input-class'),
|
||||
'data-scope': 'model',
|
||||
dataScope: Ember.computed.alias('data-scope'),
|
||||
didReceiveAttrs() {
|
||||
let me = this;
|
||||
me._super(...arguments);
|
||||
let dataScope = me.get('data-scope');
|
||||
if ('controller' === dataScope) {
|
||||
me.set('dataModel', me.get('route.controller'));
|
||||
}
|
||||
else if ('route' === dataScope) {
|
||||
me.set('dataModel', me.get('route'));
|
||||
}
|
||||
else {
|
||||
me.set('dataModel', me.get('model'));
|
||||
}
|
||||
},
|
||||
getVal() {
|
||||
return this.get('model.' + this.get('name'));
|
||||
return this.get('dataModel.' + this.get('name'));
|
||||
},
|
||||
setVal(val) {
|
||||
this.set('model.' + this.get('name'), val);
|
||||
this.set('dataModel.' + this.get('name'), val);
|
||||
}
|
||||
});
|
||||
|
@ -2,7 +2,10 @@ import Ember from 'ember';
|
||||
import BaseComponent from './base-component';
|
||||
|
||||
export default BaseComponent.extend({
|
||||
allowBlank: true,
|
||||
'allow-blank': true,
|
||||
allowBlank: Ember.computed.alias('allow-blank'),
|
||||
type: 'text',
|
||||
step: 1, // for number
|
||||
actions: {
|
||||
doEdit() {
|
||||
var me = this;
|
||||
@ -10,7 +13,7 @@ export default BaseComponent.extend({
|
||||
me.set('isEditing', true)
|
||||
Ember.run.later(() => {
|
||||
Ember.$('input[type="text"][name="' + me.get('model.id') + '"]').focus();
|
||||
}, 128);
|
||||
}, 320);
|
||||
},
|
||||
doUpdate() {
|
||||
let me = this;
|
||||
@ -20,9 +23,9 @@ export default BaseComponent.extend({
|
||||
}
|
||||
me.set('isUpdating', true);
|
||||
let newValue = me.getFieldValue();
|
||||
if (me.get('oldValue') !== newValue) {
|
||||
if (!me.get('allowBlank') && !newValue) {
|
||||
me.get('message').warn('属性不能为空');
|
||||
if (me.get('oldValue') != newValue) {
|
||||
if (!me.get('allow-blank') && !newValue) {
|
||||
me.get('message').warn('Property could not be blank');
|
||||
// reset field value
|
||||
me.resetValue();
|
||||
me.set('isUpdating', false);
|
||||
|
@ -1,74 +0,0 @@
|
||||
import Ember from 'ember';
|
||||
import BaseFormInput from './base-form-input';
|
||||
|
||||
export default BaseFormInput.extend({
|
||||
tagName: 'div',
|
||||
classNames: ['form-group'],
|
||||
classNameBindings: ['hasError:has-error'],
|
||||
colWidth: 6,
|
||||
'col-width': Ember.computed.alias('colWidth'),
|
||||
|
||||
configNames: ['allow-single-deselect',
|
||||
'disable-search',
|
||||
'disable-search-threshold',
|
||||
'enable-split-word-search',
|
||||
'inherit-select-classes',
|
||||
'max-selected-options',
|
||||
'no-results-text',
|
||||
'placeholder-text-multiple',
|
||||
'placeholder-text-single',
|
||||
'search-contains',
|
||||
'single-backstroke-delete',
|
||||
'width',
|
||||
'display-disabled-options',
|
||||
'display-selected-options',
|
||||
'include-group-label-in-selected',
|
||||
'max-shown-results',
|
||||
'case-sensitive-search',
|
||||
'hide-results-on-select',
|
||||
'rtl'
|
||||
],
|
||||
|
||||
// chosen options
|
||||
'allow-single-deselect': false,
|
||||
'disable-search': false,
|
||||
'disable-search-threshold': 0,
|
||||
'enable-split-word-search': true,
|
||||
'inherit-select-classes': false,
|
||||
'max-selected-options': Infinity,
|
||||
'no-results-text': 'No results match',
|
||||
'placeholder-text-multiple': 'Select Some Options',
|
||||
'placeholder-text-single': 'Select an Option',
|
||||
'search-contains': false,
|
||||
'single-backstroke-delete': true,
|
||||
'width': '100%',
|
||||
'display-disabled-options': true,
|
||||
'display-selected-options': true,
|
||||
'include-group-label-in-selected': false,
|
||||
'max-shown-results': undefined,
|
||||
'case-sensitive-search': false,
|
||||
'hide-results-on-select': true,
|
||||
'rtl': false,
|
||||
|
||||
didInsertElement() {
|
||||
let me = this;
|
||||
me._super(...arguments);
|
||||
|
||||
let config = {};
|
||||
me.get('configNames').forEach(n => config[n.replace(/\-/g, '_')] = me.get(n));
|
||||
|
||||
me.$('select').chosen(config).change(function(e, option) {
|
||||
let value = option.selected;
|
||||
if (value) {
|
||||
Ember.set(me.findOption(value), 'selected', 'selected');
|
||||
}
|
||||
else {
|
||||
Ember.set(me.findOption(option.deselected), 'selected', false);
|
||||
}
|
||||
});
|
||||
me.$('.search-field > input').width('100%');
|
||||
},
|
||||
findOption(value) {
|
||||
return this.get('options').find(option => {return option.value == value});
|
||||
}
|
||||
});
|
@ -4,5 +4,10 @@ import BaseFormInput from './base-form-input';
|
||||
export default BaseFormInput.extend({
|
||||
classNames: ['form-group'],
|
||||
classNameBindings: ['hasError:has-error'],
|
||||
colWidth: 6
|
||||
actions: {
|
||||
onOptionChanged(val) {
|
||||
let me = this;
|
||||
me.setVal(val);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
26
web/app/components/form-input-select2.js
Normal file
26
web/app/components/form-input-select2.js
Normal file
@ -0,0 +1,26 @@
|
||||
import Ember from 'ember';
|
||||
|
||||
import BaseFormInput from './base-form-input';
|
||||
|
||||
export default BaseFormInput.extend({
|
||||
classNames: ['form-group'],
|
||||
classNameBindings: ['hasError:has-error'],
|
||||
didInsertElement() {
|
||||
let me = this;
|
||||
me._super(...arguments);
|
||||
me.$('select.select2').select2({
|
||||
placeholder: me.get('placeholder') || me.get('label')
|
||||
}).on('change', function(e) {
|
||||
if (e.added) {
|
||||
Ember.set(me.findOption(e.added.id), 'selected', 'selected');
|
||||
}
|
||||
else if (e.removed) {
|
||||
Ember.set(me.findOption(e.removed.id), 'selected', false);
|
||||
}
|
||||
});
|
||||
},
|
||||
findOption(value) {
|
||||
return this.get('options').find(option => option.value == value);
|
||||
}
|
||||
});
|
||||
|
@ -11,7 +11,6 @@ export default BaseFormInput.extend({
|
||||
},
|
||||
didInsertElement() {
|
||||
let me = this;
|
||||
me._super(...arguments);
|
||||
me.$('input[type=text]').ace_spinner({
|
||||
value: me.getVal(),
|
||||
min: me.get('min'),
|
||||
|
@ -13,8 +13,8 @@ export default BaseFormInput.extend({
|
||||
didReceiveAttrs() {
|
||||
let me = this;
|
||||
let isFile = me.get('type') === 'file';
|
||||
!me.get('inputClass') &&
|
||||
me.set('inputClass', isFile ? 'col-xs-3' : 'col-xs-12 col-sm-5');
|
||||
!me.get('input-class') &&
|
||||
me.set('input-class', isFile ? 'col-xs-3' : 'col-xs-12 col-sm-5');
|
||||
let image = me.get('image');
|
||||
if (isFile && image) {
|
||||
me.set('imageUrl', me.get('model.' + image));
|
||||
|
27
web/app/components/input-spinner.js
Normal file
27
web/app/components/input-spinner.js
Normal file
@ -0,0 +1,27 @@
|
||||
import Ember from 'ember';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
step: 1,
|
||||
value: 0,
|
||||
classNames: ['ace-spinner', 'middle'],
|
||||
actions: {
|
||||
increase() {
|
||||
let me = this;
|
||||
let max = me.get('max');
|
||||
if (!Ember.isNone(max) && me.get('value') == max) {
|
||||
Ember.Logger.info('Spinner increase to max: ', max);
|
||||
return;
|
||||
}
|
||||
this.incrementProperty('value');
|
||||
},
|
||||
decrease() {
|
||||
let me = this;
|
||||
let min = me.get('min');
|
||||
if (!Ember.isNone(min) && me.get('value') == min) {
|
||||
Ember.Logger.info('Spinner decrease to min: ', min);
|
||||
return;
|
||||
}
|
||||
this.decrementProperty('value');
|
||||
}
|
||||
}
|
||||
});
|
@ -2,7 +2,7 @@ import Ember from 'ember';
|
||||
import BaseComponentMixin from '../mixins/components/base-component';
|
||||
|
||||
export default Ember.Component.extend(BaseComponentMixin, {
|
||||
classNames: ['widget-toolbar', 'no-border'],
|
||||
classNames: ['widget-toolbar', 'no-border', 'no-padding'],
|
||||
searchText: Ember.computed.oneWay('route.controller.search'),
|
||||
actions: {
|
||||
search() {
|
||||
|
@ -10,6 +10,7 @@ export default Ember.Component.extend(BaseComponentMixin, {
|
||||
asc: Ember.computed.equal('order', 'asc'),
|
||||
desc: Ember.computed.equal('order', 'desc'),
|
||||
// classNameBindings: ['asc:sorting_asc', 'desc:sorting_desc', 'sorting:sorting'],
|
||||
attributeBindings: ['style'],
|
||||
getDir() {
|
||||
let me = this;
|
||||
let name = me.get('name');
|
||||
|
@ -4,6 +4,8 @@ import BaseComponentMixin from '../mixins/components/base-component';
|
||||
export default Ember.Component.extend(BaseComponentMixin, {
|
||||
tagName: 'span',
|
||||
classNames: ['cursor-pointer'],
|
||||
'dialog-title': 'Data Filter',
|
||||
'full-width': false,
|
||||
didReceiveAttrs() {
|
||||
let me = this;
|
||||
let filters = me.getFilters()[me.get('name')];
|
||||
|
16
web/app/components/week-goal-completion-rate.js
Normal file
16
web/app/components/week-goal-completion-rate.js
Normal file
@ -0,0 +1,16 @@
|
||||
import Ember from 'ember';
|
||||
|
||||
const WeekGoalCompletionRateComponent = Ember.Component.extend({
|
||||
rate: Ember.computed('goal', 'goal.goal', 'goal.done', function() {
|
||||
let me = this;
|
||||
let goal = me.get('goal.goal');
|
||||
let done = me.get('goal.done');
|
||||
let result = ((done * 1.0 / goal * 1.0) * 100).toFixed(2);
|
||||
return result > 0 ? (result + '%').replace(/\.00%$/g, '%') : 0;
|
||||
})
|
||||
});
|
||||
WeekGoalCompletionRateComponent.reopenClass({
|
||||
positionalParams: ['goal'],
|
||||
});
|
||||
|
||||
export default WeekGoalCompletionRateComponent;
|
17
web/app/components/week-goal/completion-rate.js
Normal file
17
web/app/components/week-goal/completion-rate.js
Normal file
@ -0,0 +1,17 @@
|
||||
import Ember from 'ember';
|
||||
|
||||
const WeekGoalCompletionRateComponent = Ember.Component.extend({
|
||||
tagName: '',
|
||||
rate: Ember.computed('goal', 'goal.goal', 'goal.done', function() {
|
||||
let me = this;
|
||||
let goal = me.get('goal.goal');
|
||||
let done = me.get('goal.done');
|
||||
let result = ((done * 1.0 / goal * 1.0) * 100).toFixed(2);
|
||||
return result > 0 ? (result + '%').replace(/\.00%$/g, '%') : 0;
|
||||
})
|
||||
});
|
||||
WeekGoalCompletionRateComponent.reopenClass({
|
||||
positionalParams: ['goal'],
|
||||
});
|
||||
|
||||
export default WeekGoalCompletionRateComponent;
|
23
web/app/components/week-goal/total-completion-rate.js
Normal file
23
web/app/components/week-goal/total-completion-rate.js
Normal file
@ -0,0 +1,23 @@
|
||||
import Ember from 'ember';
|
||||
|
||||
const WeekGoalTotalCompletionRateComponent = Ember.Component.extend({
|
||||
tagName: '',
|
||||
totalGoal: Ember.computed('goals.@each.goal', function() {
|
||||
return this.get('goals').map(it => it.goal).reduce((pv, g) => pv + parseInt(g), 0);
|
||||
}),
|
||||
totalDone: Ember.computed('goals.@each.done', function() {
|
||||
return this.get('goals').map(it => it.done).reduce((pv, g) => pv + parseInt(g), 0);
|
||||
}),
|
||||
totalRate: Ember.computed('totalGoal', 'totalDone', function() {
|
||||
let me = this;
|
||||
let goal = me.get('totalGoal');
|
||||
let done = me.get('totalDone');
|
||||
let result = ((done * 1.0 / goal * 1.0) * 100).toFixed(2);
|
||||
return result > 0 ? (result + '%').replace(/\.00%$/g, '%') : 0;
|
||||
})
|
||||
});
|
||||
WeekGoalTotalCompletionRateComponent.reopenClass({
|
||||
positionalParams: ['goals'],
|
||||
});
|
||||
|
||||
export default WeekGoalTotalCompletionRateComponent;
|
13
web/app/components/week-goal/total-done.js
Normal file
13
web/app/components/week-goal/total-done.js
Normal file
@ -0,0 +1,13 @@
|
||||
import Ember from 'ember';
|
||||
|
||||
const WeekGoalTotalGoalComponent = Ember.Component.extend({
|
||||
tagName: '',
|
||||
totalDone: Ember.computed('goals.@each.done', function() {
|
||||
return this.get('goals').map(it => it.done).reduce((pv, g) => pv + parseInt(g), 0);
|
||||
})
|
||||
});
|
||||
WeekGoalTotalGoalComponent.reopenClass({
|
||||
positionalParams: ['goals'],
|
||||
});
|
||||
|
||||
export default WeekGoalTotalGoalComponent;
|
13
web/app/components/week-goal/total-goal.js
Normal file
13
web/app/components/week-goal/total-goal.js
Normal file
@ -0,0 +1,13 @@
|
||||
import Ember from 'ember';
|
||||
|
||||
const WeekGoalTotalGoalComponent = Ember.Component.extend({
|
||||
tagName: '',
|
||||
totalGoal: Ember.computed('goals.@each.goal', function() {
|
||||
return this.get('goals').map(it => it.goal).reduce((pv, g) => pv + parseInt(g), 0);
|
||||
})
|
||||
});
|
||||
WeekGoalTotalGoalComponent.reopenClass({
|
||||
positionalParams: ['goals'],
|
||||
});
|
||||
|
||||
export default WeekGoalTotalGoalComponent;
|
@ -49,6 +49,10 @@ Router.map(function() {
|
||||
this.route('create', {path: '/:customerId/create'});
|
||||
this.route('edit', {path: '/:id/edit'});
|
||||
});
|
||||
|
||||
this.route('week-goal', function() {
|
||||
this.route('list');
|
||||
});
|
||||
});
|
||||
|
||||
export default Router;
|
||||
|
20
web/app/routes/week-goal/list.js
Normal file
20
web/app/routes/week-goal/list.js
Normal file
@ -0,0 +1,20 @@
|
||||
import Ember from 'ember';
|
||||
import BaseListRoute from './../base-list';
|
||||
|
||||
export default BaseListRoute.extend({
|
||||
queryParams: {
|
||||
filters: {
|
||||
refreshModel: true
|
||||
}
|
||||
},
|
||||
breadcrumbs: [{text: 'Week Goal'}],
|
||||
setupController(controller) {
|
||||
let me = this;
|
||||
me._super(...arguments);
|
||||
controller.set('quarters', [
|
||||
{value: 1, text: '1', selected: true},
|
||||
{value: 2, text: '2', selected: true},
|
||||
{value: 3, text: '3', selected: true},
|
||||
{value: 4, text: '4', selected: true}]);
|
||||
}
|
||||
});
|
7
web/app/services/week-goal/service.js
Normal file
7
web/app/services/week-goal/service.js
Normal file
@ -0,0 +1,7 @@
|
||||
import Ember from 'ember';
|
||||
import BaseService from '../service';
|
||||
|
||||
export default BaseService.extend({
|
||||
modelName: 'WeekGoal',
|
||||
pageSize: 64
|
||||
});
|
@ -51,4 +51,26 @@
|
||||
max-height: 48px;
|
||||
overflow: auto;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.table > thead > tr > th {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
[data-ember-action] {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.table > thead > tr > th,
|
||||
.table > tbody > tr > th,
|
||||
.table > tfoot > tr > th
|
||||
/*
|
||||
,
|
||||
.table > thead > tr > td,
|
||||
.table > tbody > tr > td,
|
||||
.table > tfoot > tr > td
|
||||
*/
|
||||
{
|
||||
padding: 4px !important;
|
||||
font-size: 16px;
|
||||
}
|
@ -1,14 +1,27 @@
|
||||
{{#if isEditing}}
|
||||
{{input type="text"
|
||||
name=model.id
|
||||
placeholder=placeholder
|
||||
class="col-xs-12"
|
||||
value=(mut (get model field))
|
||||
focus-out='doUpdate'
|
||||
insert-newline='doUpdate'
|
||||
}}
|
||||
{{#if (eq type 'text')}}
|
||||
{{input type='text'
|
||||
name=model.id
|
||||
placeholder=placeholder
|
||||
class='col-xs-12'
|
||||
value=(mut (get model field))
|
||||
focus-out='doUpdate'
|
||||
insert-newline='doUpdate'
|
||||
}}
|
||||
{{else if (eq type 'number')}}
|
||||
{{input-spinner name=model.id
|
||||
max=max
|
||||
min=min
|
||||
step=step
|
||||
value=(mut (get model field))
|
||||
}}
|
||||
<button class="btn btn-sm btn-success" type="button" {{action 'doUpdate'}}>
|
||||
<i class="ace-icon fa fa-check bigger-110"></i>
|
||||
Submit
|
||||
</button>
|
||||
{{/if}}
|
||||
{{else}}
|
||||
<span class="col-xs-12" {{action 'doEdit'}} style="height: 2em;">
|
||||
<div class="col-xs-12 no-padding" {{action 'doEdit'}} style="height: 1em;">
|
||||
{{get model field}}
|
||||
</span>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
@ -1,15 +0,0 @@
|
||||
<label class="col-xs-12 col-sm-3 col-md-3 control-label no-padding-right"> {{label}} </label>
|
||||
<div class="col-xs-12 col-sm-5 no-padding-right">
|
||||
<div class="row col-xs-12 no-padding">
|
||||
<div class="col-xs-{{colWidth}} no-padding-right">
|
||||
<select multiple={{multiple}}
|
||||
data-placeholder={{if placeholder placeholder label}}
|
||||
class="form-control chosen-select">
|
||||
{{#each options as |option|}}
|
||||
<option value="{{option.value}}" selected={{option.selected}}>{{option.text}}</option>
|
||||
{{/each}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{form-input-errors-msg name=name}}
|
@ -1,11 +1,19 @@
|
||||
<label class="col-xs-12 col-sm-3 col-md-3 control-label no-padding-right"> {{label}} </label>
|
||||
<div class="col-xs-12 col-sm-5 no-padding-right">
|
||||
{{#if label}}
|
||||
<label for="{{if name name idField}}" class="{{get this 'label-class'}} control-label no-padding-right"> {{label}} </label>
|
||||
{{/if}}
|
||||
<div class="{{get this 'input-class'}}">
|
||||
<div class="row col-xs-12 no-padding">
|
||||
<div class="col-xs-{{colWidth}} no-padding-right">
|
||||
{{#x-select class='form-control' name=name value=(mut (get model name)) as |xs|}}
|
||||
<div class="col-xs-{{get this 'col-width'}} no-padding-right">
|
||||
{{#x-select class='form-control'
|
||||
name=name
|
||||
value=(mut (get dataModel name))
|
||||
action='onOptionChanged'
|
||||
as |xs|}}
|
||||
{{yield xs}}
|
||||
{{/x-select}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{form-input-errors-msg name=name}}
|
||||
{{#if (get this 'error-msg')}}
|
||||
{{form-input-errors-msg name=name}}
|
||||
{{/if}}
|
19
web/app/templates/components/form-input-select2.hbs
Normal file
19
web/app/templates/components/form-input-select2.hbs
Normal file
@ -0,0 +1,19 @@
|
||||
<label for="{{name}}" class="{{get this 'label-class'}} control-label no-padding-right"> {{label}} </label>
|
||||
<div class="{{get this 'input-class'}} no-padding-right">
|
||||
<div class="row col-xs-12 no-padding">
|
||||
<div class="col-xs-{{get this 'col-width'}} no-padding-right">
|
||||
<select name=name
|
||||
multiple={{multiple}}
|
||||
data-placeholder={{if placeholder placeholder label}}
|
||||
class="select2"
|
||||
style="width: 100%;">
|
||||
{{#each options as |option|}}
|
||||
<option value={{option.value}} selected={{option.selected}}>{{option.text}}</option>
|
||||
{{/each}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{#if (get this 'error-msg')}}
|
||||
{{form-input-errors-msg name=name}}
|
||||
{{/if}}
|
@ -1,4 +1,6 @@
|
||||
{{#if label}}
|
||||
<label class="col-xs-3 control-label no-padding-right"> {{label}} </label>
|
||||
{{/if}}
|
||||
<div class="col-xs-3">
|
||||
{{input class='col-xs-12'
|
||||
type='text'
|
||||
|
@ -1,31 +1,32 @@
|
||||
<label for="{{name}}" class="col-xs-12 col-sm-3 col-md-3 control-label no-padding-right"> {{label}} </label>
|
||||
<label for="{{if name name idField}}" class="{{get this 'label-class'}} control-label no-padding-right"> {{label}} </label>
|
||||
<div class="{{get this 'input-class'}}">
|
||||
|
||||
<div class="{{inputClass}}">
|
||||
{{#if hasBlock}}
|
||||
{{yield}}
|
||||
{{!else}}
|
||||
{{else if (eq 'file' type)}}
|
||||
{{else}}
|
||||
{{#if (eq 'file' type)}}
|
||||
{{input class='col-xs-12' type='file' name=name}}
|
||||
{{else if (eq 'textarea' type)}}
|
||||
{{textarea name=name
|
||||
class='col-xs-12 form-control textarea-resize-vertical'
|
||||
value=(mut (get model name))
|
||||
{{textarea class='col-xs-12'
|
||||
name=name
|
||||
value=(mut (get dataModel name))
|
||||
class='form-control'
|
||||
placeholder=(if placeholder placeholder label)}}
|
||||
{{else if (eq 'show' type)}}
|
||||
<h5 class="grey">{{get model name}}</h5>
|
||||
{{else}}
|
||||
{{input class='col-xs-12 width-100'
|
||||
type=type
|
||||
readonly=readonly
|
||||
name=name
|
||||
placeholder=(if placeholder placeholder label)
|
||||
value=(mut (get model name))}}
|
||||
value=(mut (get dataModel name))}}
|
||||
{{/if}}
|
||||
{{!/if}}
|
||||
{{/if}}
|
||||
</div>
|
||||
{{#if imageUrl}}
|
||||
<div class="col-xs-2 padding-top-3 no-padding-left" style="padding-top: 3px;">
|
||||
{{image-previews previews=imageUrl}}
|
||||
</div>
|
||||
{{/if}}
|
||||
{{form-input-errors-msg name=name}}
|
||||
{{#if (get this 'error-msg')}}
|
||||
{{form-input-errors-msg name=name}}
|
||||
{{/if}}
|
11
web/app/templates/components/input-spinner.hbs
Normal file
11
web/app/templates/components/input-spinner.hbs
Normal file
@ -0,0 +1,11 @@
|
||||
<div class="input-group">
|
||||
{{input type='number' class='spinbox-input form-control text-center' name=name value=value min=min max=max}}
|
||||
<div class="spinbox-buttons input-group-btn btn-group-vertical">
|
||||
<button type="button" class="btn spinbox-up btn-sm btn-info" {{action 'increase'}}>
|
||||
<i class="icon-only ace-icon fa fa-chevron-up"></i>
|
||||
</button>
|
||||
<button type="button" class="btn spinbox-down btn-sm btn-info" {{action 'decrease'}}>
|
||||
<i class="icon-only ace-icon fa fa-chevron-down"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
@ -45,6 +45,13 @@
|
||||
<span class="menu-text"> Customers </span>
|
||||
{{/link-to}}
|
||||
</li>
|
||||
<li>
|
||||
{{#link-to 'week-goal.list'}}
|
||||
<i class="menu-icon fa fa-calendar-check-o blue" aria-hidden="true"></i>
|
||||
<span class="menu-text"> Week Goal </span>
|
||||
{{/link-to}}
|
||||
</li>
|
||||
|
||||
{{#if ajax.user.admin}}
|
||||
<li>
|
||||
{{#link-to 'customer-status.list' 1}}
|
||||
|
@ -1,3 +1,5 @@
|
||||
<div class="main-content-inner">
|
||||
{{yield}}
|
||||
<div class="row">
|
||||
{{yield}}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -7,11 +7,4 @@
|
||||
focus-out='search'
|
||||
}}
|
||||
<i class="ace-icon fa fa-search nav-search-icon"></i>
|
||||
</span>
|
||||
{{!--
|
||||
<div class="inline" style="margin-top:0">
|
||||
<a class="btn btn-xs btn-info" style="margin-bottom: 3px;">
|
||||
<i class="ace-icon fa fa-search bigger-120"></i>
|
||||
</a>
|
||||
</div>
|
||||
--}}
|
||||
</span>
|
@ -1,6 +1,6 @@
|
||||
{{#if order}}
|
||||
<a {{action 'removeSort'}} style="cursor: pointer;">
|
||||
<i class="ace-icon fa fa-times red2"></i>
|
||||
<i class="ace-icon fa fa-times red2 bigger-110"></i>
|
||||
</a>
|
||||
{{/if}}
|
||||
|
||||
@ -14,10 +14,10 @@
|
||||
|
||||
<a {{action 'sort'}} class="pull-right" style="cursor: pointer;">
|
||||
{{#if asc}}
|
||||
<i class="ace-icon fa fa-sort-asc"></i>
|
||||
<i class="ace-icon fa fa-sort-asc bigger-110"></i>
|
||||
{{else if desc}}
|
||||
<i class="ace-icon fa fa-sort-desc"></i>
|
||||
<i class="ace-icon fa fa-sort-desc bigger-110"></i>
|
||||
{{else}}
|
||||
<i class="ace-icon fa fa-sort"></i>
|
||||
<i class="ace-icon fa fa-sort bigger-110"></i>
|
||||
{{/if}}
|
||||
</a>
|
||||
|
@ -1,12 +1,13 @@
|
||||
<span {{action 'onClick'}} data-rel="tooltip" title="Filter">
|
||||
<span class="{{if (get this 'full-width') 'col-xs-12 no-padding'}}" data-rel="tooltip" title="Filter" {{action 'onClick'}}>
|
||||
{{text}}
|
||||
</span>
|
||||
{{#if showModal}}
|
||||
{{#modal-dialog title='Data Filter' submit=(action 'onModalSubmit') on-close=(action 'onModalClose') transitionToParentRouteAfterClose=false}}
|
||||
{{#modal-dialog title=(get this 'dialog-title') submit=(action 'onModalSubmit') on-close=(action 'onModalClose') transitionToParentRouteAfterClose=false}}
|
||||
<div class="widget-body">
|
||||
<div class="widget-main">
|
||||
<form class="form-horizontal">
|
||||
{{form-input-chosen-select multiple=true col-width=12 label=(if label label text) options=options}}
|
||||
{{!form-input-chosen-select multiple=true col-width=12 label=(if label label text) options=options}}
|
||||
{{form-input-select2 multiple=true col-width=12 label=(if label label text) options=options}}
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -0,0 +1 @@
|
||||
{{rate}}
|
@ -0,0 +1 @@
|
||||
{{rate}}
|
@ -0,0 +1 @@
|
||||
{{totalRate}}
|
1
web/app/templates/components/week-goal/total-done.hbs
Normal file
1
web/app/templates/components/week-goal/total-done.hbs
Normal file
@ -0,0 +1 @@
|
||||
{{totalDone}}
|
1
web/app/templates/components/week-goal/total-goal.hbs
Normal file
1
web/app/templates/components/week-goal/total-goal.hbs
Normal file
@ -0,0 +1 @@
|
||||
{{totalGoal}}
|
@ -10,7 +10,7 @@
|
||||
|
||||
<div class="widget-body">
|
||||
<!-- #section:custom/scrollbar -->
|
||||
<div class="widget-main no-padding">
|
||||
<div class="widget-main no-padding table-responsive no-border">
|
||||
<table class="table table-striped table-bordered table-hover dataTable" style="border: 1px solid #ddd;">
|
||||
<thead class="thin-border-bottom">
|
||||
<tr>
|
||||
|
@ -35,8 +35,8 @@
|
||||
|
||||
<div class="widget-body">
|
||||
<!-- #section:custom/scrollbar -->
|
||||
<div class="widget-main no-padding">
|
||||
<table class="table table-striped table-bordered table-hover dataTable" style="border: 1px solid #ddd;">
|
||||
<div class="widget-main no-padding table-responsive no-border">
|
||||
<table class="table table-striped table-bordered table-hover" style="border: 1px solid #ddd;">
|
||||
<thead class="thin-border-bottom">
|
||||
<tr>
|
||||
{{#if tableOptions.showId}}
|
||||
@ -55,21 +55,21 @@
|
||||
{{sortable-th name='sumYtdSales' text='Sales'}}
|
||||
{{/if}}
|
||||
{{#if tableOptions.showCountryCode}}
|
||||
<th class="hidden-480">Country</th>
|
||||
<th>Country</th>
|
||||
{{/if}}
|
||||
{{#if tableOptions.showState}}
|
||||
<th class="hidden-480">State</th>
|
||||
<th>State</th>
|
||||
{{/if}}
|
||||
{{#if tableOptions.showCity}}
|
||||
<th class="hidden-480">City</th>
|
||||
<th>City</th>
|
||||
{{/if}}
|
||||
{{#if tableOptions.showMs}}
|
||||
{{#sortable-th name='ms' class='hidden-480'}}
|
||||
{{#sortable-th name='ms'}}
|
||||
{{th-filter name='ms' text='MS' label='MS Filter' options=model.msList}}
|
||||
{{/sortable-th}}
|
||||
{{/if}}
|
||||
{{#if tableOptions.showRegion}}
|
||||
{{#sortable-th name='region' text='Region' class='hidden-480'}}
|
||||
{{#sortable-th name='region' text='Region'}}
|
||||
{{th-filter name='region' text='Region' label='Region Filter' options=model.regionList}}
|
||||
{{/sortable-th}}
|
||||
{{/if}}
|
||||
@ -79,18 +79,18 @@
|
||||
{{/sortable-th}}
|
||||
{{/if}}
|
||||
{{#if tableOptions.showStatus}}
|
||||
<th class="hidden-480">
|
||||
<th>
|
||||
{{th-filter name='status' text='Status' label='Status Filter' options=model.statusList}}
|
||||
</th>
|
||||
{{/if}}
|
||||
{{#if tableOptions.showIssue1}}
|
||||
<th class="hidden-480">Comment 1</th>
|
||||
<th>Comment 1</th>
|
||||
{{/if}}
|
||||
{{#if tableOptions.showIssue2}}
|
||||
<th class="hidden-480">Comment 2</th>
|
||||
<th>Comment 2</th>
|
||||
{{/if}}
|
||||
{{#if tableOptions.showIssue3}}
|
||||
<th class="hidden-480">Comment 3</th>
|
||||
<th>Comment 3</th>
|
||||
{{/if}}
|
||||
<th>
|
||||
<i class="ace-icon fa fa-cogs bigger-110 hidden-480"></i>
|
||||
@ -121,11 +121,14 @@
|
||||
{{/if}}
|
||||
{{#if tableOptions.showYears}}
|
||||
<td>
|
||||
{{!--
|
||||
{{#if (eq it.years.length 1)}}
|
||||
{{it.years.firstObject}}
|
||||
{{else if (gt it.years.length 1)}}
|
||||
{{it.years.firstObject}}-{{it.years.lastObject}}
|
||||
{{/if}}
|
||||
--}}
|
||||
{{it.years.lastObject}}
|
||||
</td>
|
||||
{{/if}}
|
||||
{{#if tableOptions.showYtdSale}}
|
||||
@ -134,11 +137,11 @@
|
||||
{{#if it.sumYtdSales}}
|
||||
{{#if it.expand}}
|
||||
<a style="cursor: pointer;" {{action (route-action 'collapseYtdSales' it)}}>
|
||||
<i class="ui-icon ace-icon fa fa-minus center blue"></i>
|
||||
<i class="ui-icon ace-icon fa fa-minus center blue bigger-110"></i>
|
||||
</a>
|
||||
{{else}}
|
||||
<a style="cursor: pointer;" {{action (route-action 'expandYtdSales' it)}}>
|
||||
<i class="ui-icon ace-icon fa fa-plus center blue"></i>
|
||||
<i class="ui-icon ace-icon fa fa-plus center blue bigger-110"></i>
|
||||
</a>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
@ -162,12 +165,12 @@
|
||||
</td>
|
||||
{{/if}}
|
||||
{{#if tableOptions.showMs}}
|
||||
<td class="hidden-480">
|
||||
<td>
|
||||
{{it.ms}}
|
||||
</td>
|
||||
{{/if}}
|
||||
{{#if tableOptions.showRegion}}
|
||||
<td class="hidden-480">
|
||||
<td>
|
||||
{{it.region}}
|
||||
</td>
|
||||
{{/if}}
|
||||
|
@ -10,29 +10,29 @@
|
||||
|
||||
<div class="widget-body">
|
||||
<!-- #section:custom/scrollbar -->
|
||||
<div class="widget-main no-padding">
|
||||
<div class="widget-main no-padding table-responsive no-border">
|
||||
<table class="table table-striped table-bordered table-hover dataTable" style="border: 1px solid #ddd;">
|
||||
<thead class="thin-border-bottom">
|
||||
<tr>
|
||||
{{sortable-th name='employeeId' text='Employee ID'}}
|
||||
{{sortable-th name='account' text='Account' class="hidden-480"}}
|
||||
{{sortable-th name='employeeId' text='Emp ID' style='min-width: 105px;'}}
|
||||
{{sortable-th name='account' text='Acct'}}
|
||||
<th>
|
||||
Name
|
||||
</th>
|
||||
{{sortable-th name='enName' text='Name(EN)' class="hidden-480"}}
|
||||
{{sortable-th name='enName' text='Name(EN)' style='min-width: 130px;'}}
|
||||
<th>
|
||||
Admin
|
||||
</th>
|
||||
<th class="hidden-480">
|
||||
<i class="ace-icon fa fa-sticky-note-o bigger-110 hidden-480"></i>
|
||||
<th>
|
||||
<i class="ace-icon fa fa-sticky-note-o bigger-110"></i>
|
||||
Remark
|
||||
</th>
|
||||
<th class="hidden-480">
|
||||
<i class="ace-icon fa fa-exchange bigger-110 hidden-480"></i>
|
||||
<th>
|
||||
<i class="ace-icon fa fa-exchange bigger-110"></i>
|
||||
Status
|
||||
</th>
|
||||
<th>
|
||||
<i class="ace-icon fa fa-cogs bigger-110 hidden-480"></i>
|
||||
<i class="ace-icon fa fa-cogs bigger-110"></i>
|
||||
Settings
|
||||
</th>
|
||||
</tr>
|
||||
@ -44,22 +44,22 @@
|
||||
<td>
|
||||
{{it.employeeId}}
|
||||
</td>
|
||||
<td class="hidden-480">
|
||||
<td>
|
||||
{{it.account}}
|
||||
</td>
|
||||
<td>
|
||||
{{it.name}}
|
||||
</td>
|
||||
<td class="hidden-480">
|
||||
<td>
|
||||
{{it.enName}}
|
||||
</td>
|
||||
<td>
|
||||
{{status-cell model=it field='admin' enabledText='YES' disabledText='NO'}}
|
||||
</td>
|
||||
<td class="hidden-480">
|
||||
<td>
|
||||
{{editable-cell model=it field='note'}}
|
||||
</td>
|
||||
<td class="hidden-480">
|
||||
<td>
|
||||
{{status-cell model=it field='enabled' enabledText='ACTIVE' disabledText='BLOCKED'}}
|
||||
</td>
|
||||
<td>
|
||||
|
71
web/app/templates/week-goal/list.hbs
Normal file
71
web/app/templates/week-goal/list.hbs
Normal file
@ -0,0 +1,71 @@
|
||||
{{#main-content}}
|
||||
<div class="widget-box transparent">
|
||||
{{grid-header}}
|
||||
|
||||
<div class="widget-body">
|
||||
<!-- #section:custom/scrollbar -->
|
||||
<div class="widget-main no-padding table-responsive no-border">
|
||||
<table class="table table-striped table-bordered table-hover dataTable" style="border: 1px solid #ddd;">
|
||||
<thead class="thin-border-bottom">
|
||||
<tr>
|
||||
<th>
|
||||
{{th-filter full-width=true name='quarter' text='Week' label='Quarter' options=quarters}}
|
||||
</th>
|
||||
<th>
|
||||
Goal
|
||||
</th>
|
||||
<th>
|
||||
Done
|
||||
</th>
|
||||
<th>
|
||||
Rate
|
||||
</th>
|
||||
<th>
|
||||
<i class="ace-icon fa fa-sticky-note-o bigger-110"></i> Remark
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
{{#each model.data as |it|}}
|
||||
<tr>
|
||||
<td>
|
||||
{{date-cell value=it.dateStart format='M.D'}} - {{date-cell value=it.dateEnd format='M.D'}}
|
||||
</td>
|
||||
<td>
|
||||
{{editable-cell type='number' model=it field='goal' min=0}}
|
||||
</td>
|
||||
<td>
|
||||
{{editable-cell type='number' model=it field='done' min=0 max=it.goal}}
|
||||
</td>
|
||||
<td>
|
||||
{{week-goal/completion-rate it}}
|
||||
</td>
|
||||
<td>
|
||||
{{editable-cell model=it field='note'}}
|
||||
</td>
|
||||
</tr>
|
||||
{{/each}}
|
||||
<tr>
|
||||
<td>
|
||||
Total
|
||||
</td>
|
||||
<td>
|
||||
{{week-goal/total-goal model.data}}
|
||||
</td>
|
||||
<td>
|
||||
{{week-goal/total-done model.data}}
|
||||
</td>
|
||||
<td>
|
||||
{{week-goal/total-completion-rate model.data}}
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{{!pagination-bar}}
|
||||
</div>
|
||||
</div>
|
||||
{{/main-content}}
|
@ -18,9 +18,7 @@
|
||||
"jquery-colorbox": "^1.6.4",
|
||||
"fuelux": "^3.15.4",
|
||||
"jquery.hotkeys": "*",
|
||||
"bootstrap-wysiwyg": "*",
|
||||
"bootstrap-treeview": "^1.2.0",
|
||||
"chosen": "^1.7.0"
|
||||
"bootstrap-wysiwyg": "*"
|
||||
},
|
||||
"resolutions": {
|
||||
"ember": "release"
|
||||
|
@ -51,7 +51,6 @@ module.exports = function(defaults) {
|
||||
}
|
||||
}
|
||||
|
||||
let bd = app.bowerDirectory;
|
||||
importVendor(app, 'bower_components/bootstrap/dist/css/bootstrap.css');
|
||||
// importVendor(app, 'bower_components/bootstrap/dist/css/bootstrap-theme.css');
|
||||
importVendor(app, 'bower_components/bootstrap/dist/js/bootstrap.js');
|
||||
@ -82,14 +81,6 @@ module.exports = function(defaults) {
|
||||
destDir: '/assets/fonts'
|
||||
});
|
||||
|
||||
// jquery choosen
|
||||
importVendor(app, 'bower_components/chosen/chosen.jquery.js');
|
||||
importVendor(app, 'bower_components/chosen/chosen.css');
|
||||
let chosenAssets = new Funnel('bower_components/chosen', {
|
||||
include: ['*.png'],
|
||||
destDir: '/assets/css'
|
||||
});
|
||||
|
||||
// bootstrap color picker
|
||||
importVendor(app, 'bower_components/mjolnic-bootstrap-colorpicker/dist/css/bootstrap-colorpicker.min.css');
|
||||
importVendor(app, 'bower_components/mjolnic-bootstrap-colorpicker/dist/js/bootstrap-colorpicker.min.js');
|
||||
@ -98,6 +89,15 @@ module.exports = function(defaults) {
|
||||
destDir: '/assets/img'
|
||||
});
|
||||
|
||||
// Select2, must before ace
|
||||
importVendor(app, 'vendor/ace/js/select2.js');
|
||||
importVendor(app, 'vendor/ace/css/select2.css');
|
||||
|
||||
let select2Images = new Funnel('vendor/ace/css', {
|
||||
include: ['select2-spinner.gif', 'select2.png', 'select2x2.png'],
|
||||
destDir: '/assets/css'
|
||||
});
|
||||
|
||||
// ACE CSS
|
||||
importVendor(app, 'vendor/ace/css/ace.css');
|
||||
importVendor(app, 'vendor/ace/css/ace-fonts.css');
|
||||
@ -151,10 +151,10 @@ module.exports = function(defaults) {
|
||||
return app.toTree([bootstrapAssets,
|
||||
jqColorboxAssets,
|
||||
faAssets,
|
||||
chosenAssets,
|
||||
bcpAssets,
|
||||
aceFonts,
|
||||
aceImages,
|
||||
select2Images,
|
||||
publicJs
|
||||
]);
|
||||
};
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { moduleForComponent, test } from 'ember-qunit';
|
||||
import hbs from 'htmlbars-inline-precompile';
|
||||
|
||||
moduleForComponent('form-input-chosen-select', 'Integration | Component | form input chosen select', {
|
||||
moduleForComponent('form-input-select2', 'Integration | Component | form input select2', {
|
||||
integration: true
|
||||
});
|
||||
|
||||
@ -10,15 +10,15 @@ 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`{{form-input-chosen-select}}`);
|
||||
this.render(hbs`{{form-input-select2}}`);
|
||||
|
||||
assert.equal(this.$().text().trim(), '');
|
||||
|
||||
// Template block usage:
|
||||
this.render(hbs`
|
||||
{{#form-input-chosen-select}}
|
||||
{{#form-input-select2}}
|
||||
template block text
|
||||
{{/form-input-chosen-select}}
|
||||
{{/form-input-select2}}
|
||||
`);
|
||||
|
||||
assert.equal(this.$().text().trim(), 'template block text');
|
25
web/tests/integration/components/input-spinner-test.js
Normal file
25
web/tests/integration/components/input-spinner-test.js
Normal file
@ -0,0 +1,25 @@
|
||||
import { moduleForComponent, test } from 'ember-qunit';
|
||||
import hbs from 'htmlbars-inline-precompile';
|
||||
|
||||
moduleForComponent('input-spinner', 'Integration | Component | input spinner', {
|
||||
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`{{input-spinner}}`);
|
||||
|
||||
assert.equal(this.$().text().trim(), '');
|
||||
|
||||
// Template block usage:
|
||||
this.render(hbs`
|
||||
{{#input-spinner}}
|
||||
template block text
|
||||
{{/input-spinner}}
|
||||
`);
|
||||
|
||||
assert.equal(this.$().text().trim(), 'template block text');
|
||||
});
|
@ -0,0 +1,25 @@
|
||||
import { moduleForComponent, test } from 'ember-qunit';
|
||||
import hbs from 'htmlbars-inline-precompile';
|
||||
|
||||
moduleForComponent('week-goal-completion-rate', 'Integration | Component | week goal completion rate', {
|
||||
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`{{week-goal-completion-rate}}`);
|
||||
|
||||
assert.equal(this.$().text().trim(), '');
|
||||
|
||||
// Template block usage:
|
||||
this.render(hbs`
|
||||
{{#week-goal-completion-rate}}
|
||||
template block text
|
||||
{{/week-goal-completion-rate}}
|
||||
`);
|
||||
|
||||
assert.equal(this.$().text().trim(), 'template block text');
|
||||
});
|
@ -0,0 +1,25 @@
|
||||
import { moduleForComponent, test } from 'ember-qunit';
|
||||
import hbs from 'htmlbars-inline-precompile';
|
||||
|
||||
moduleForComponent('week-goal/completion-rate', 'Integration | Component | week goal/completion rate', {
|
||||
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`{{week-goal/completion-rate}}`);
|
||||
|
||||
assert.equal(this.$().text().trim(), '');
|
||||
|
||||
// Template block usage:
|
||||
this.render(hbs`
|
||||
{{#week-goal/completion-rate}}
|
||||
template block text
|
||||
{{/week-goal/completion-rate}}
|
||||
`);
|
||||
|
||||
assert.equal(this.$().text().trim(), 'template block text');
|
||||
});
|
@ -0,0 +1,25 @@
|
||||
import { moduleForComponent, test } from 'ember-qunit';
|
||||
import hbs from 'htmlbars-inline-precompile';
|
||||
|
||||
moduleForComponent('week-goal/total-completion-rate', 'Integration | Component | week goal/total completion rate', {
|
||||
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`{{week-goal/total-completion-rate}}`);
|
||||
|
||||
assert.equal(this.$().text().trim(), '');
|
||||
|
||||
// Template block usage:
|
||||
this.render(hbs`
|
||||
{{#week-goal/total-completion-rate}}
|
||||
template block text
|
||||
{{/week-goal/total-completion-rate}}
|
||||
`);
|
||||
|
||||
assert.equal(this.$().text().trim(), 'template block text');
|
||||
});
|
@ -0,0 +1,25 @@
|
||||
import { moduleForComponent, test } from 'ember-qunit';
|
||||
import hbs from 'htmlbars-inline-precompile';
|
||||
|
||||
moduleForComponent('week-goal/total-done', 'Integration | Component | week goal/total done', {
|
||||
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`{{week-goal/total-done}}`);
|
||||
|
||||
assert.equal(this.$().text().trim(), '');
|
||||
|
||||
// Template block usage:
|
||||
this.render(hbs`
|
||||
{{#week-goal/total-done}}
|
||||
template block text
|
||||
{{/week-goal/total-done}}
|
||||
`);
|
||||
|
||||
assert.equal(this.$().text().trim(), 'template block text');
|
||||
});
|
@ -0,0 +1,25 @@
|
||||
import { moduleForComponent, test } from 'ember-qunit';
|
||||
import hbs from 'htmlbars-inline-precompile';
|
||||
|
||||
moduleForComponent('week-goal/total-goal', 'Integration | Component | week goal/total goal', {
|
||||
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`{{week-goal/total-goal}}`);
|
||||
|
||||
assert.equal(this.$().text().trim(), '');
|
||||
|
||||
// Template block usage:
|
||||
this.render(hbs`
|
||||
{{#week-goal/total-goal}}
|
||||
template block text
|
||||
{{/week-goal/total-goal}}
|
||||
`);
|
||||
|
||||
assert.equal(this.$().text().trim(), 'template block text');
|
||||
});
|
11
web/tests/unit/routes/week-goal/list-test.js
Normal file
11
web/tests/unit/routes/week-goal/list-test.js
Normal file
@ -0,0 +1,11 @@
|
||||
import { moduleFor, test } from 'ember-qunit';
|
||||
|
||||
moduleFor('route:week-goal/list', 'Unit | Route | week goal/list', {
|
||||
// Specify the other units that are required for this test.
|
||||
// needs: ['controller:foo']
|
||||
});
|
||||
|
||||
test('it exists', function(assert) {
|
||||
let route = this.subject();
|
||||
assert.ok(route);
|
||||
});
|
12
web/tests/unit/services/week-goal/service-test.js
Normal file
12
web/tests/unit/services/week-goal/service-test.js
Normal file
@ -0,0 +1,12 @@
|
||||
import { moduleFor, test } from 'ember-qunit';
|
||||
|
||||
moduleFor('service:week-goal/service', 'Unit | Service | week goal/service', {
|
||||
// Specify the other units that are required for this test.
|
||||
// needs: ['service:foo']
|
||||
});
|
||||
|
||||
// Replace this with your real tests.
|
||||
test('it exists', function(assert) {
|
||||
let service = this.subject();
|
||||
assert.ok(service);
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user