add export bage

This commit is contained in:
Donghuang 2022-06-23 17:29:32 +08:00
parent b3a3cf5ec8
commit 126575f0bf
60 changed files with 566 additions and 323 deletions

View File

@ -53,7 +53,7 @@ public class ExportTaskServiceSupport
@Override
public void doExport(final String employeeKey) {
val now = Long.valueOf(System.currentTimeMillis());
Assert.state(now.equals(LOCK_MAP.putIfAbsent(employeeKey, now)),
Assert.state(LOCK_MAP.putIfAbsent(employeeKey, now) == null,
"There is a running export task, please try again later!");
threadPoolTaskExecutor.execute(() ->{

View File

@ -2,6 +2,12 @@ server:
port: 8088
spring:
jackson:
default-property-inclusion: NON_NULL
time-zone: GMT+8
serialization:
write-dates-as-timestamps: true
fail-on-empty-beans: false
servlet:
multipart:
max-file-size: 512MB
@ -22,6 +28,9 @@ file:
base-dir: /Users/donghuang/Documents/Workspaces/ambition-crm/files/
base-path: http://127.0.0.1:1217/lm-f/
export:
location: d:/data/export
tigon:
shiro:
session:

View File

@ -2,6 +2,12 @@ server:
port: 8088
spring:
jackson:
default-property-inclusion: NON_NULL
time-zone: GMT+8
serialization:
write-dates-as-timestamps: true
fail-on-empty-beans: false
servlet:
multipart:
max-file-size: 512MB
@ -15,13 +21,16 @@ datasource:
username: root
database:
backup-dir: /Users/chyxion/Workspaces/ambition-crm/database_backups
backup-dir: d:/data/database_backups
restore-shell: /data/program/mysql-backup/bin/mysql_restore.sh
file:
base-dir: /Users/donghuang/Documents/Workspaces/ambition-crm/files/
base-path: http://127.0.0.1:1217/lm-f/
export:
location: d:/data/export
tigon:
shiro:
session:

@ -1 +1 @@
Subproject commit 56a42f79cac7f8369bacf51e323242c0ae202e55
Subproject commit 1c57bdaf5ab05684239ea1a1e50d33730095d464

View File

@ -33,7 +33,7 @@ public interface CustomerMapper extends BaseMapper<String, Customer> {
* @return customers
*/
List<Customer> listForShow(
@NotNull @Param("s") Search search,
@NotNull @Param(PARAM_SEARCH_KEY) Search search,
@Param("account") String account);
/**
@ -67,7 +67,7 @@ public interface CustomerMapper extends BaseMapper<String, Customer> {
* @return count of customers
*/
int countForShow(
@NotNull @Param("s") Search search,
@NotNull @Param(PARAM_SEARCH_KEY) Search search,
@Param("account") String account);
List<Map<String, String>> listMs();

View File

@ -234,24 +234,24 @@
<sql id="showFilter">
<!-- Application not null -->
<if test="s.getAttr('APPLICATION_NOT_NULL') != null">
<if test="__search__.getAttr('APPLICATION_NOT_NULL') != null">
join (select distinct customer_id
from crm_customer_application) app_not_null
on customer.id = app_not_null.customer_id
</if>
<if test="s.getAttr('APPLICATIONS') != null">
<if test="__search__.getAttr('APPLICATIONS') != null">
join (select distinct customer_id
from crm_customer_application
where application_id in
<foreach item="appId" collection="s.getAttr('APPLICATIONS')" open="(" close=")" separator=",">
<foreach item="appId" collection="__search__.getAttr('APPLICATIONS')" open="(" close=")" separator=",">
#{appId}
</foreach>
) app
on customer.id = app.customer_id
</if>
<if test="s.getAttr('YTD_SALE') != null">
<if test="__search__.getAttr('YTD_SALE') != null">
left join (select customer_id, max(year) year
from crm_customer_year_to_date_sale
where enabled = 1

View File

@ -18,12 +18,12 @@ public interface ImportRecordMapper extends BaseMapper<String, ImportRecord> {
* @param search search
* @return import records
*/
List<ImportRecord> listForShow(@Param("s") Search search);
List<ImportRecord> listForShow(@Param(PARAM_SEARCH_KEY) Search search);
/**
* count for show
* @param search search
* @return count of import records
*/
int countForShow(@Param("s") Search search);
int countForShow(@Param(PARAM_SEARCH_KEY) Search search);
}

View File

@ -20,14 +20,14 @@ public interface WeekGoalMapper extends BaseMapper<String, WeekGoal> {
* @param search search
* @return week goals
*/
List<WeekGoal> listJoinUser(@Param("s") Search search);
List<WeekGoal> listJoinUser(@Param(PARAM_SEARCH_KEY) Search search);
/**
* count join user
* @param search search
* @return count of week goals
*/
int countJoinUser(@Param("s") Search search);
int countJoinUser(@Param(PARAM_SEARCH_KEY) Search search);
/**
* @return list user

View File

@ -37,6 +37,11 @@
<artifactId>tigon-web</artifactId>
<scope>${tigon.webmvc.scope}</scope>
</dependency>
<dependency>
<groupId>me.chyxion.tigon</groupId>
<artifactId>tigon-mybatis</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>

View File

@ -3,8 +3,12 @@ package me.chyxion.tigon.model;
import lombok.Getter;
import lombok.Setter;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
import me.chyxion.tigon.mybatis.NotUpdate;
import org.apache.commons.lang3.StringUtils;
import lombok.experimental.FieldNameConstants;
import me.chyxion.tigon.mybatis.util.EntityUtils;
/**
* @version 0.0.1
@ -43,4 +47,16 @@ public class M1<Id> extends M0<Id> {
super.beforeUpdate();
dateUpdated = new Date();
}
public List<String> cols() {
return EntityUtils.cols(getClass());
}
public List<String> cols(final String table) {
if (StringUtils.isBlank(table)) {
return cols();
}
return cols().stream().map(it -> table + "." + it).collect(Collectors.toList());
}
}

0
server/launch.sh → server/start.sh Executable file → Normal file
View File

View File

@ -1,14 +1,12 @@
import Ember from 'ember';
import Application from '@ember/application';
import Resolver from './resolver';
import loadInitializers from 'ember-load-initializers';
import config from './config/environment';
import $ from 'jquery';
let App;
// Ember.MODEL_FACTORY_INJECTIONS = true;
App = Ember.Application.extend({
const App = Application.extend({
modulePrefix: config.modulePrefix,
podModulePrefix: config.podModulePrefix,
Resolver

View File

@ -0,0 +1,8 @@
import Component from '@ember/component';
export default Component.extend({
tagName: 'a',
classNames: ['cursor-pointer'],
attributeBindings: ['title', 'href', 'target'],
'data-rel': 'tooltip'
});

View File

@ -1,4 +0,0 @@
import Ember from 'ember';
import BaseComponentMixin from '../mixins/components/base-component';
export default Ember.Component.extend(BaseComponentMixin, {});

View File

@ -1,23 +1,24 @@
import Ember from 'ember';
import BaseComponentMixin from '../mixins/components/base-component';
import { computed } from '@ember/object';
import { alias } from '@ember/object/computed';
import BasicComponent from './basic-component';
export default Ember.Component.extend(BaseComponentMixin, {
export default BasicComponent.extend({
'col-width': 6,
colWidth: Ember.computed.alias('col-width'),
colWidth: 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() {
model: alias('route.controller.model'),
errors: alias('route.controller.errors'),
hasError: computed('errors', function() {
return this.get('errors.' + this.get('name'));
}),
'error-msg': true,
errorMsg: Ember.computed.alias('error-msg'),
errorMsg: alias('error-msg'),
'label-class': 'col-xs-12 col-sm-3 col-md-3',
labelClass: Ember.computed.alias('label-class'),
labelClass: alias('label-class'),
'input-class': 'col-xs-12 col-sm-5 col-md-5',
inputClass: Ember.computed.alias('input-class'),
inputClass: alias('input-class'),
'data-scope': 'model',
dataScope: Ember.computed.alias('data-scope'),
dataScope: alias('data-scope'),
didReceiveAttrs() {
let me = this;
me._super(...arguments);

View File

@ -9,8 +9,8 @@ export default Component.extend({
routeName: alias('router.currentRouteName'),
'trim-index': true,
route: computed('routeName', function() {
let me = this;
let routeName = me.get('routeName');
const me = this;
const routeName = me.get('routeName');
return me.getRoute(me.get('trim-index') ?
routeName.replace(/\.index$/, '') : routeName);
}),

View File

@ -1,9 +1,8 @@
import Ember from 'ember';
import BaseComponentMixin from '../mixins/components/base-component';
import { computed } from '@ember/object';
import BasicComponent from './basic-component';
export default Ember.Component.extend(BaseComponentMixin, {
// breadcrumbs: Ember.computed.alias('route.breadcrumbs'),
breadcrumbs: Ember.computed('route', function() {
export default BasicComponent.extend({
breadcrumbs: computed('route', function() {
let me = this;
let breadcrumbs = this.get('route.breadcrumbs');
if (!breadcrumbs) {

View File

@ -1,7 +1,8 @@
import Ember from 'ember';
import { alias } from '@ember/object/computed';
export default Ember.Component.extend({
tagName: 'span',
value: Ember.computed.alias('model'),
value: alias('model'),
format: 'YYYY-MM-DD H:mm:ss'
});

View File

@ -1,16 +1,15 @@
import Ember from 'ember';
import BaseComponent from './base-component';
import { alias } from '@ember/object/computed';
import BaseComponent from './basic-component';
export default BaseComponent.extend({
tagName: 'a',
attributeBindings: ['title'],
'data-rel': 'tooltip',
enabled: Ember.computed.alias('model.enabled'),
enabled: alias('model.enabled'),
title: 'Delete',
'icon-size-class': 'bigger-120',
didReceiveAttrs() {
let me = this;
const me = this;
me._super(...arguments);
if (me.get('icon-only')) {
me.set('icon-size-class', 'bigger-130');
@ -24,7 +23,7 @@ export default BaseComponent.extend({
}
},
click() {
let me = this;
const me = this;
me.dialog.confirm('Are you sure to delete?', () => {
me.get('service').del(me.get('model.id')).then(() => {
me.get('route.controller.model.data').removeObject(me.get('model'));

View File

@ -1,10 +1,11 @@
import Ember from 'ember';
import BaseComponent from './base-component';
import { alias } from '@ember/object/computed';
import { later } from '@ember/runloop';
import BaseComponent from './basic-component';
import $ from 'jquery';
export default BaseComponent.extend({
'allow-blank': true,
allowBlank: Ember.computed.alias('allow-blank'),
allowBlank: alias('allow-blank'),
type: 'text',
step: 1, // for number
'confirm-update': true,
@ -14,12 +15,12 @@ export default BaseComponent.extend({
const me = this;
me.set('oldValue', me.getFieldValue());
me.set('isEditing', true)
Ember.run.later(() => {
later(() => {
$('input[type="text"][name="' + me.get('model.id') + '"]', me.element).focus();
}, 320);
},
doUpdate() {
let me = this;
const me = this;
if (me.get('isUpdating')) {
console.info('Cell Is Updating, Ignore.');
return;
@ -60,7 +61,7 @@ export default BaseComponent.extend({
return this.get('model.' + this.get('field'));
},
resetValue() {
let me = this;
const me = this;
me.set('model.' + me.get('field'), me.get('oldValue'));
},
execUpdate() {

View File

@ -1,11 +1,10 @@
import Ember from 'ember';
import Component from '@ember/component';
import { computed } from '@ember/object';
import { alias } from '@ember/object/computed';
import $ from 'jquery'
export default Component.extend({
file: {},
value: computed.alias('file.file'),
value: alias('file.file'),
'no-file': 'Choose file',
'btn-choose': 'Choose file',
didReceiveAttrs() {

View File

@ -1,6 +1,8 @@
import Ember from 'ember';
import BaseComponent from './base-component';
import { computed } from '@ember/object';
import BaseComponent from './basic-component';
import { alias } from '@ember/object/computed';
import { isArray } from '@ember/array';
import { setProperties } from '@ember/object';
import { isNone } from '@ember/utils';
import { inject as service } from '@ember/service';
import $ from 'jquery'
@ -9,12 +11,12 @@ export default BaseComponent.extend({
type: 'create',
form: true,
state: service('state'),
successMsg: computed.alias('success-message'),
postUrl: computed.alias('post-url'),
backRouteName: computed.alias('back-route'),
backRouteParams: computed.alias('back-route-params'),
hideGoback: computed.alias('no-goback'),
hideSubmit: computed.alias('no-submit'),
successMsg: alias('success-message'),
postUrl: alias('post-url'),
backRouteName: alias('back-route'),
backRouteParams: alias('back-route-params'),
hideGoback: alias('no-goback'),
hideSubmit: alias('no-submit'),
'back-to-list': false,
backToList() {
const me = this;
@ -29,20 +31,20 @@ export default BaseComponent.extend({
transitionToRoute(name, params, queryParams) {
const me = this;
let args = [name];
if (!Ember.isNone(params)) {
if (Ember.isArray(params)) {
if (!isNone(params)) {
if (isArray(params)) {
args = args.concat(params);
}
else if (params !== false) {
args.push(params);
}
}
Ember.isNone(queryParams) || args.push({queryParams: queryParams});
isNone(queryParams) || args.push({queryParams: queryParams});
me.get('router').transitionTo(...args);
},
actions: {
goback() {
let me = this;
const me = this;
let routeName = me.get('backRouteName');
if (routeName) {
me.transitionToRoute(routeName,
@ -57,13 +59,13 @@ export default BaseComponent.extend({
}
},
save() {
let me = this;
const me = this;
if (!me.validate()) {
me.dialog.confirm('Are you sure to submit?', () => {
me.postData().then((m) => {
console.info('Post Model Result: ', m);
// write back
Ember.setProperties(me.getModel(), m);
setProperties(me.getModel(), m);
me.alertMessage();
me.send('goback');
});
@ -75,7 +77,7 @@ export default BaseComponent.extend({
return this.get('type') === 'create';
},
validate() {
let me = this;
const me = this;
let vr = me.get('service').validate(
me.getModel(), me.get('type') + 'Constraints');
me.set('route.controller.errors', vr || {});

View File

@ -1,12 +1,13 @@
import Ember from 'ember';
import { computed } from '@ember/object';
import { match } from '@ember/object/computed';
import BaseFormInput from './base-form-input';
export default BaseFormInput.extend({
classNames: ['form-group'],
classNameBindings: ['hasError:has-error'],
hasError: Ember.computed('route.controller.errors', function() {
hasError: computed('route.controller.errors', function() {
return this.get('errors.' + this.get('idField'));
}),
btnIcon: 'fa-server',
isFaBtnIcon: Ember.computed.match('btnIcon', /^fa-/)
isFaBtnIcon: match('btnIcon', /^fa-/)
});

View File

@ -1,10 +1,10 @@
import Component from '@ember/component';
import { computed } from '@ember/object';
import { alias } from '@ember/object/computed';
import $ from 'jquery'
export default Component.extend({
image: {},
value: computed.alias('image.file'),
value: alias('image.file'),
didReceiveAttrs() {
const me = this;
me._super(...arguments);

View File

@ -1,4 +1,4 @@
import Ember from 'ember';
import { once } from '@ember/runloop';
import Component from '@ember/component';
import { computed } from '@ember/object';
import $ from 'jquery'
@ -50,7 +50,7 @@ export default Component.extend({
}
});
Ember.run.once(() => {
once(() => {
// add a custom loading icon
$('#cboxLoadingGraphic').html('<i class="ace-icon fa fa-spinner orange fa-spin"></i>');
});

View File

@ -1,9 +1,9 @@
import Ember from 'ember';
import BaseComponentMixin from '../mixins/components/base-component';
import { alias } from '@ember/object/computed';
import BasicComponent from './basic-component';
export default Ember.Component.extend(BaseComponentMixin, {
export default BasicComponent.extend({
tagName: 'label',
selectedId: Ember.computed.alias('route.controller.selectedId'),
selectedModel: Ember.computed.alias('route.controller.selectedModel'),
selectedId: alias('route.controller.selectedId'),
selectedModel: alias('route.controller.selectedModel'),
classNames: ['pos-rel']
});

View File

@ -1,13 +1,17 @@
import Component from '@ember/component';
import { inject as service } from '@ember/service';
import $ from 'jquery'
export default Component.extend({
elementId: 'main-container',
classNames: ['main-container'],
exportTaskService: service('export-task/service'),
sidebarCollapsed: false,
didInsertElement() {
let me = this;
const me = this;
me._super(...arguments);
me.get('exportTaskService').startup();
// $('body').removeClass().addClass('login-layout blur-login');
(function($) {
basics();
@ -298,8 +302,6 @@ export default Component.extend({
})
}
//in small devices display navbar dropdowns like modal boxes
function smallDeviceDropdowns() {
if(ace.vars['old_ie']) return;

View File

@ -1,8 +1,7 @@
import Component from '@ember/component'
import BaseComponentMixin from '../mixins/components/base-component';
import BasicComponent from './basic-component';
import $ from 'jquery'
export default Component.extend(BaseComponentMixin, {
export default BasicComponent.extend({
classNames: ['modal', 'fade'],
'init-modal': true,
'close-to-parent': true,

View File

@ -8,8 +8,8 @@ export default Ember.LinkComponent.extend(BaseComponentMixin, {
title: '操作详情',
activeClass: '',
willRender() {
let me = this;
let params = me.get('params');
const me = this;
const params = me.get('params');
params.unshift(me.get('service.modelName'));
params.unshift('op-detail');
params.unshift('操作详情');

View File

@ -1,21 +1,21 @@
import Ember from 'ember';
import BaseComponent from './base-component';
import BaseComponent from './basic-component';
import { computed } from '@ember/object';
import { alias } from '@ember/object/computed';
export default BaseComponent.extend({
classNames: ['widget-toolbox', 'clearfix'],
total: Ember.computed.alias('route.controller.model.total'),
total: alias('route.controller.model.total'),
prevPage: computed('currPage', function() {
return this.get('currPage') - 1 || 1;
}),
nextPage: computed('currPage', function() {
let me = this;
let page = me.get('currPage');
const me = this;
const page = me.get('currPage');
return page + 1 <= me.get('totalPage') ? page + 1 : page;
}),
currPage: computed('params.page', function() {
let me = this;
let currPage = parseInt(me.get('params.page'));
const me = this;
const currPage = parseInt(me.get('params.page'));
console.info('Get current page [' + currPage + ']');
return currPage;
}),
@ -23,7 +23,7 @@ export default BaseComponent.extend({
const me = this;
const totalPage = me.get('totalPage');
const currPage = me.get('currPage');
let pages = [];
const pages = [];
if (currPage > 4) {
pages.push({page: 1, text: 1});
@ -59,7 +59,7 @@ export default BaseComponent.extend({
allPages: computed('total', function() {
const me = this;
const totalPage = me.get('totalPage');
let pages = [];
const pages = [];
let i = 0;
while (++i <= totalPage) {
@ -68,15 +68,15 @@ export default BaseComponent.extend({
return pages;
}),
totalPage: computed('total', function() {
let me = this;
let pageSize = me.get('service.pageSize') || 32;
const me = this;
const pageSize = me.get('service.pageSize') || 32;
return parseInt((me.get('total') + pageSize - 1) / pageSize);
}),
actions: {
gotoPage(page) {
let me = this;
let router = me.get('router');
let params = me.get('params');
const me = this;
const router = me.get('router');
const params = me.get('params');
console.info('Go to page [' + page + '], params: ', params);
router.transitionTo(me.get('routeName'), page, {queryParams: params});
}

View File

@ -1,5 +1,4 @@
import Ember from 'ember';
import BaseComponent from './base-component';
import BaseComponent from './basic-component';
export default BaseComponent.extend({
tagName: 'a',

View File

@ -1,12 +1,12 @@
import Ember from 'ember';
import BaseComponentMixin from '../mixins/components/base-component';
import { oneWay } from '@ember/object/computed';
import BasicComponent from './basic-component';
export default Ember.Component.extend(BaseComponentMixin, {
export default BasicComponent.extend({
classNames: ['widget-toolbar', 'no-border', 'no-padding'],
searchText: Ember.computed.oneWay('route.controller.search'),
searchText: oneWay('route.controller.search'),
actions: {
search() {
let me = this;
const me = this;
me.set('route.controller.search', me.get('searchText'));
}
}

View File

@ -1,43 +1,43 @@
import Ember from 'ember';
import BaseComponentMixin from '../mixins/components/base-component';
import { computed } from '@ember/object';
import BasicComponent from './basic-component';
export default Ember.Component.extend(BaseComponentMixin, {
export default BasicComponent.extend({
tagName: 'th',
order: Ember.computed('route.controller.orders', function() {
order: computed('route.controller.orders', function() {
return this.getDir();
}),
sorting: Ember.computed.none('order'),
asc: Ember.computed.equal('order', 'asc'),
desc: Ember.computed.equal('order', 'desc'),
sorting: computed.none('order'),
asc: computed.equal('order', 'asc'),
desc: computed.equal('order', 'desc'),
// classNameBindings: ['asc:sorting_asc', 'desc:sorting_desc', 'sorting:sorting'],
attributeBindings: ['style'],
getDir() {
let me = this;
let name = me.get('name');
let orders = me.getOrders();
const me = this;
const name = me.get('name');
const orders = me.getOrders();
if (orders && orders.length) {
let order = orders.find(order => order.hasOwnProperty(name));
const order = orders.find(order => order.hasOwnProperty(name));
if (order) {
return order[name];
}
}
},
getOrders() {
let me = this;
let strOrders = me.get('route.controller.orders');
const me = this;
const strOrders = me.get('route.controller.orders');
if (strOrders) {
return JSON.parse(strOrders);
}
},
actions: {
sort() {
let me = this;
const me = this;
let orders = me.getOrders() || [];
let name = me.get('name');
const name = me.get('name');
if (orders.length) {
orders = orders.filter(order => !order.hasOwnProperty(name));
}
let order = {};
const order = {};
order[name] =
me.get('order') === 'asc' ?
'desc' : 'asc';
@ -46,10 +46,10 @@ export default Ember.Component.extend(BaseComponentMixin, {
me.set('route.controller.orders', JSON.stringify(orders));
},
removeSort() {
let me = this;
let orders = me.getOrders();
const me = this;
const orders = me.getOrders();
if (orders) {
let name = me.get('name');
const name = me.get('name');
me.set('route.controller.orders',
JSON.stringify(orders.filter(order => !order.hasOwnProperty(name))));
}

View File

@ -1,23 +1,25 @@
import Ember from 'ember';
import Component from '@ember/component';
import { addObserver } from '@ember/object/observers';
import { computed } from '@ember/object';
export default Ember.Component.extend({
export default Component.extend({
tagName: 'span',
classNames: ['label', 'label-sm'],
classNameBindings: ['enabled:label-success:label-warning'],
field: 'enabled',
name: Ember.computed.alias('field'),
name: computed.alias('field'),
didReceiveAttrs() {
let me = this;
const me = this;
me._super(...arguments);
me.set('enabled', me.get(me.getFieldPath()));
Ember.addObserver(me, me.getFieldPath(), function() {
addObserver(me, me.getFieldPath(), function() {
me.set('enabled', me.get(me.getFieldPath()));
});
},
enabledText: '启用',
disabledText: '禁用',
getFieldPath() {
let me = this;
const me = this;
return 'model.' + (me.get('field') || 'enabled');
},
});

View File

@ -1,5 +1,6 @@
import Ember from 'ember';
import BaseComponent from './base-component';
import { computed } from '@ember/object';
import { alias } from '@ember/object/computed';
import BaseComponent from './basic-component';
export default BaseComponent.extend({
tagName: 'a',
@ -10,13 +11,13 @@ export default BaseComponent.extend({
disabledText: 'Disable',
enabledOp: 'enable',
disabledOp: 'disable',
enabled: Ember.computed.alias('model.enabled'),
title: Ember.computed('enabled', function() {
enabled: alias('model.enabled'),
title: computed('enabled', function() {
let me = this;
return this.get('enabled') ? me.get('disabledText') : me.get('enabledText');
}),
'data-original-title': Ember.computed.alias('title'),
op: Ember.computed('enabled', function() {
'data-original-title': alias('title'),
op: computed('enabled', function() {
let me = this;
return this.get('enabled') ?
me.get('disabledOp') || me.get('disabledText')

View File

@ -1,4 +1,4 @@
import BaseComponent from './base-component';
import BaseComponent from './basic-component';
import { alias } from '@ember/object/computed';
import { inject as service } from '@ember/service';

View File

@ -1,19 +1,23 @@
import Ember from 'ember';
import Mixin from '@ember/object/mixin';
import { inject as service } from '@ember/service';
import { alias } from '@ember/object/computed';
import { computed } from '@ember/object';
import { getOwner } from '@ember/application';
export default Ember.Mixin.create({
toolService: Ember.inject.service('tool-service'),
routeName: Ember.computed.alias('router.currentRouteName'),
export default Mixin.create({
toolService: service('tool-service'),
routeName: alias('router.currentRouteName'),
'trim-index': true,
route: Ember.computed('routeName', function() {
route: computed('routeName', function() {
let me = this;
let routeName = me.get('routeName');
return me.getRoute(me.get('trim-index') ?
routeName.replace(/\.index$/, '') : routeName);
}),
service: Ember.computed('routeName', function() {
service: computed('routeName', function() {
return this.getService();
}),
params: Ember.computed('router.location.lastSetURL', function() {
params: computed('router.location.lastSetURL', function() {
let me = this;
let routeName = me.get('routeName');
return me.getRouteParams(me.get('trim-index') ?
@ -23,14 +27,14 @@ export default Ember.Mixin.create({
return this.get('route').paramsFor(routeName);
},
getRoute(routeName) {
return Ember.getOwner(this).lookup(
return getOwner(this).lookup(
'route:' + (routeName || this.get('routeName')));
},
getParentRouteName(routeName) {
return routeName.replace(/\.[^\.]+$/, '');
},
getService(name) {
let me = this;
const me = this;
return name ? me.get('toolService').getServiceByRouteName(name) :
me.getRoute().get('service') ||
me.get('toolService').getServiceByRouteName(me.get('routeName'));

View File

@ -1,86 +0,0 @@
import Ember from 'ember';
import $ from 'jquery'
export default Ember.Mixin.create({
store: Ember.inject.service(),
message: Ember.inject.service(),
pageSize: 32,
constraints: {},
createConstraints: null,
updateConstraints: null,
find(params) {
console.debug('Find Model: ', params);
return this._getStore().find(this.get('modelName'), params);
},
list(start, limit, params) {
console.debug('List Models Start: ', start, ', Limit: ', limit, ", Search: ", params);
return this._getStore().list(this.get('modelName'), start, limit, params);
},
listPage(page, params) {
page > 0 || (page = 1);
let me = this;
let pageSize = me.get('pageSize');
return me.list((page - 1) * pageSize, pageSize, params);
},
create(model) {
console.debug('Create Model: ', model);
return this._getStore().create(this.get('modelName'), model);
},
update(model, defaultPromise) {
console.debug('Update Model: ', model);
let me = this;
let p = me._getStore().update(me.get('modelName'), model);
if (defaultPromise) {
p.then((m) => {
console.debug('After Update: ', m);
!(model instanceof FormData) &&
Object.keys(m).forEach((prop) => {
Ember.set(model, prop, m[prop]);
});
me.get('message').alert('Updated successfully');
})
}
return p;
},
del(params) {
console.debug('Update Model: ', params);
return this._getStore().del(this.get('modelName'), params);
},
ajaxGet(path, params) {
return this._getStore().modelAjaxGet(this.get('modelName'), path, params);
},
ajaxPost(path, params) {
return this._getStore().modelAjaxPost(this.get('modelName'), path, params);
},
validate(model, constraints) {
let me = this;
console.debug('Validate Model: ', model);
if (constraints) {
if ($.type(constraints) === 'string') {
constraints = me.get(constraints);
}
else if ($.type(constraints) !== 'object') {
validation = me.get('constraints');
}
}
else {
constraints = me.get('constraints');
}
return validate(model, constraints || me.get('constraints'));
},
createValidate(model) {
console.debug('Create Validate Model: ', model);
let me = this;
let constraints = me.get('createConstraints') || me.get('constraints') || null;
return constraints && validate(model, constraints);
},
updateValidate(model) {
console.debug('Update Validate Model: ', model);
let me = this;
let constraints = me.get('updateConstraints') || me.get('constraints') || null;
return constraints && validate(model, constraints);
},
_getStore() {
return this.get('store');
}
});

View File

@ -80,6 +80,10 @@ Router.map(function() {
this.route('create');
this.route('edit', {path: '/:id/edit'});
});
this.route('export-task', function() {
this.route('list', {path: '/list/:page'});
});
});
export default Router;

View File

@ -12,18 +12,19 @@ export default Route.extend({
}
},
beforeModel: function(transition) {
console.info('Before Application Model.', transition);
console.info('Before application model.', transition);
this.transitionIntercept(transition);
},
activate() {
console.info('Application Activate.');
const me = this;
console.info('Application activate.');
$('body').addClass('no-skin');
try{ace.settings.check('navbar', 'fixed');}catch(e){console.log(e)}
try{ace.settings.check('main-container', 'fixed');}catch(e){console.log(e)}
},
actions: {
loading(transition, originRoute) {
console.info('Application Loading...');
console.info('Application loading...');
// var appCtrl = this.controllerFor('application');
this.router.one('didTransition', function() {
// appCtrl.set('loading', false);

View File

@ -1,4 +1,6 @@
import Ember from 'ember';
import EmberObject from '@ember/object';
import { observer, set } from '@ember/object';
import BaseListRoute from './../base-list';
const cols = ['showId',
@ -20,7 +22,7 @@ const cols = ['showId',
];
const config = {
showAll: false,
showAllChanged: Ember.observer('showAll', function() {
showAllChanged: observer('showAll', function() {
let me = this;
if (!me.get('lock')) {
let val = me.get('showAll');
@ -29,7 +31,7 @@ const config = {
});
}
}),
colChanged: Ember.observer(...cols.concat(function() {
colChanged: observer(...cols.concat(function() {
let me = this;
me.set('lock', true);
me.set('showAll', cols.map(col => {
@ -60,7 +62,7 @@ config.countOfShowing = cols.filter(col => {
return config[col];
}).length + 1;
const TableOptions = Ember.Object.extend(config);
const TableOptions = EmberObject.extend(config);
export default BaseListRoute.extend({
queryParams: {
@ -87,10 +89,16 @@ export default BaseListRoute.extend({
},
actions: {
expandYtdSales(row) {
Ember.set(row, 'expand', true);
set(row, 'expand', true);
},
collapseYtdSales(row) {
Ember.set(row, 'expand', false);
set(row, 'expand', false);
},
asyncExport() {
const me = this;
me.get('service').ajaxPost('async-export').then(msg => {
me.get('message').alert('Export task created.');
});
}
}
});

View File

@ -0,0 +1,5 @@
import BaseListRoute from './../base-list';
export default BaseListRoute.extend({
breadcrumbs: [{text: 'Export Tasks'}]
});

View File

@ -1,4 +1,3 @@
import Ember from 'ember';
import BaseListRoute from './../base-list';
export default BaseListRoute.extend({

View File

@ -1,4 +1,3 @@
import Ember from 'ember';
import BaseListRoute from './../base-list';
export default BaseListRoute.extend({

View File

@ -0,0 +1,15 @@
import BaseService from '../service';
import $ from 'jquery';
export default BaseService.extend({
modelName: 'ExportTask',
startup: function() {
const me = this;
$.on('WEBSOCKET', function(e, data) {
console.log('Export task: On websocket message trigger.', e, data);
if (data.type == 'EXPORT_TASK_UPDATED') {
me.set('countUndownloaded', data ? data.countUndownloaded : null);
}
});
}
});

View File

@ -1,7 +1,6 @@
import Ember from 'ember';
import BaseServiceMixin from '../../mixins/services/base-service';
import BaseService from '../service';
export default Ember.Service.extend(BaseServiceMixin, {
export default BaseService.extend({
modelName: 'ImportRecord',
pageSize: 128
});

View File

@ -1,11 +1,20 @@
import Ember from 'ember';
import Service from '@ember/service';
import $ from 'jquery'
export default Ember.Service.extend({
export default Service.extend({
alert(msg) {
this._show_alert_(msg);
toastr.success(msg);
},
info(msg) {
toastr.info(msg);
},
warn(msg) {
toastr.warning(msg);
},
alert2(msg) {
this._show_alert_(msg);
},
warn2(msg) {
this._show_alert_(msg, '#F6F0F0');
},
_show_alert_(msg, bg) {

View File

@ -1,4 +1,88 @@
import Ember from 'ember';
import BaseServiceMixin from '../mixins/services/base-service';
import Service from '@ember/service';
import { set } from '@ember/object';
import { typeOf } from '@ember/utils';
import { inject as service } from '@ember/service';
export default Ember.Service.extend(BaseServiceMixin, {});
export default Service.extend({
store: service(),
message: service(),
pageSize: 32,
constraints: {},
createConstraints: null,
updateConstraints: null,
find(params) {
console.debug('Find model: ', params);
return this._getStore().find(this.get('modelName'), params);
},
list(start, limit, params) {
console.debug('List models start: ', start, ', limit: ', limit, ", search: ", params);
return this._getStore().list(this.get('modelName'), start, limit, params);
},
listPage(page, params) {
page > 0 || (page = 1);
let me = this;
let pageSize = me.get('pageSize');
return me.list((page - 1) * pageSize, pageSize, params);
},
create(model) {
console.debug('Create model: ', model);
return this._getStore().create(this.get('modelName'), model);
},
update(model, defaultPromise) {
console.debug('Update model: ', model);
let me = this;
let p = me._getStore().update(me.get('modelName'), model);
if (defaultPromise) {
p.then((m) => {
console.debug('After update: ', m);
!(model instanceof FormData) &&
Object.keys(m).forEach((prop) => {
set(model, prop, m[prop]);
});
me.get('message').alert('Updated successfully');
})
}
return p;
},
del(params) {
console.debug('Update Model: ', params);
return this._getStore().del(this.get('modelName'), params);
},
ajaxGet(path, params) {
return this._getStore().modelAjaxGet(this.get('modelName'), path, params);
},
ajaxPost(path, params) {
return this._getStore().modelAjaxPost(this.get('modelName'), path, params);
},
validate(model, constraints) {
let me = this;
console.debug('Validate model: ', model);
if (constraints) {
if (typeOf(constraints) === 'string') {
constraints = me.get(constraints);
}
else if (typeOf(constraints) !== 'object') {
validation = me.get('constraints');
}
}
else {
constraints = me.get('constraints');
}
return validate(model, constraints || me.get('constraints'));
},
createValidate(model) {
console.debug('Create validate model: ', model);
let me = this;
let constraints = me.get('createConstraints') || me.get('constraints') || null;
return constraints && validate(model, constraints);
},
updateValidate(model) {
console.debug('Update validate model: ', model);
let me = this;
let constraints = me.get('updateConstraints') || me.get('constraints') || null;
return constraints && validate(model, constraints);
},
_getStore() {
return this.get('store');
}
});

View File

@ -1,7 +1,13 @@
import Ember from 'ember';
import Service from '@ember/service';
import $ from 'jquery'
import { Promise } from 'rsvp';
import { dasherize } from '@ember/string';
import { run } from '@ember/runloop';
import { typeOf } from '@ember/utils';
export default Ember.Service.extend({
export default Service.extend({
list(modelName, start, limit, params) {
var p = {
start: start,
@ -44,14 +50,14 @@ export default Ember.Service.extend({
},
_ajax_request(method, url, params) {
let me = this;
return new Ember.RSVP.Promise((resolve, reject) => {
let paramsType = $.type(params);
return new Promise((resolve, reject) => {
const paramsType = typeOf(params);
me.ajax[method ? method : 'doGet'](url,
paramsType === 'string' ||
paramsType === 'number' ?
{id: params} : params,
(data) => {
Ember.run(null, resolve, data);
run(null, resolve, data);
}, (msg, r) => {
reject(msg);
me.dialog.error(msg || 'Ajax request erorr caused');
@ -60,7 +66,7 @@ export default Ember.Service.extend({
},
_pathForType(modelName, path) {
return (/^[a-zA-Z_][a-zA-Z0-9_]+$/.test(modelName) ?
Ember.String.dasherize(modelName) : modelName) +
dasherize(modelName) : modelName) +
(/^\//.test(path) ? path : '/' + path);
}
});

View File

@ -1,12 +1,13 @@
import Ember from 'ember';
import Service from '@ember/service';
import { getOwner } from '@ember/application';
import BaseService from './service';
import Ajax from './ajax';
import Store from './store';
export default Ember.Service.extend({
export default Service.extend({
getServiceByRouteName: function(routeName) {
let me = this;
let container = Ember.getOwner(me);
let container = getOwner(me);
let service = container.lookup('service:' + routeName);
console.debug(`No Route Service [${routeName}] Found, Try To Find Model Service`);
let indexTrimmedRouteName = null;

View File

@ -1,4 +1,3 @@
import Ember from 'ember';
import BaseService from '../service';
export default BaseService.extend({

View File

@ -42,7 +42,7 @@ export default Service.extend({
console.info('Websocket connected: ', frame);
me.set('subscription', client.subscribe('/topic/' + user.id, function(msg) {
console.info('On websocket message: ', msg);
$.trigger('WEBSOCKET', JSON.parse(msg.body));
$.trigger('WEBSOCKET', [JSON.parse(msg.body)]);
}));
me.set('connected', true);
};
@ -62,6 +62,10 @@ export default Service.extend({
me.set('connected', false);
};
client.onWebSocketClose = function(event) {
console.log('On websocket close.', event);
};
client.activate();
me.set('client', client);
},

View File

@ -108,3 +108,20 @@ input[type="number"] {
background-color: inherit;
border: 0;
}
.export-task-badge {
position: absolute;
top: 4px;
left: 24px;
width: 14px;
height: 14px;
font-size: 10px;
border-radius: 50%;
color: #fff;
background-color: rgba(255, 0, 0, 0.8);
// rgba(0, 0, 0, 0.7);
display: flex;
justify-content: center;
align-items: center;
}

View File

@ -0,0 +1 @@
{{yield}}

View File

@ -98,6 +98,13 @@
<span class="menu-text"> Database Backup </span>
</LinkTo>
</li>
<li>
<LinkTo @route="export-task.list" @model=1>
<i class="menu-icon fa fa-tasks {{if this.exportTaskService.countUndownloaded 'green' 'blue'}}"></i>
<span class="export-task-badge">21</span>
<span class="menu-text"> Export Task {{#if this.exportTaskService.countUndownloaded}}<span class="badge badge-danger">{{this.exportTaskService.countUndownloaded}}</span>{{/if}}</span>
</LinkTo>
</li>
{{/if}}
</ul><!-- /.nav-list -->
@ -153,7 +160,7 @@
<div class="footer-content">
<span class="bigger-120">
<span class="blue bolder">LEMO</span>
CHINA &copy; 2017
CHINA &copy; 2017 - 2022
</span>
{{!--&nbsp; &nbsp;

View File

@ -23,10 +23,10 @@
{{/link-to}}
</li>
<li>
<a href="/customer/export" target="_blank">
{{#a-btn click=(route-action 'asyncExport') title='Export Customers'}}
<i class="ace-icon fa fa-download bigger-110"></i>
Export Customers
</a>
{{/a-btn}}
</li>
{{/if}}
<li>

View File

@ -0,0 +1,71 @@
{{#main-content}}
<div class="widget-box transparent">
{{grid-header search-box=false}}
<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>
{{sortable-th name='dateCreated' text='Date Created' style='min-width: 105px;'}}
<th>
<i class="ace-icon fa fa-exchange bigger-110"></i>
Status
</th>
<th>
File Downloaded
</th>
<th style="min-width: 106px;">
<i class="ace-icon fa fa-cogs bigger-110"></i>
Actions
</th>
</tr>
</thead>
<tbody>
{{#each model.list as |it|}}
<tr>
<td>
{{moment-format it.dateCreated 'M/D/YYYY H:mm:ss'}}
</td>
<td>
{{it.status}}
</td>
<td>
{{status-cell model=it field='downloaded' enabledText='DOWNLOADED' disabledText='NOT DOWNLOAD'}}
</td>
<td>
<div class="hidden-sm hidden-xs btn-group">
{{#link-to 'user.edit' it.id class='btn btn-xs btn-info' data-rel='tooltip' title='Download'}}
<i class="ace-icon fa fa-pencil bigger-120"></i>
Download
{{/link-to}}
</div>
<div class="hidden-md hidden-lg">
<div class="inline pos-rel">
<button class="btn btn-minier btn-primary dropdown-toggle" data-toggle="dropdown" data-position="auto">
<i class="ace-icon fa fa-cog icon-only bigger-110"></i>
</button>
<ul class="dropdown-menu dropdown-only-icon dropdown-yellow dropdown-menu-right dropdown-caret dropdown-close">
<li>
{{#link-to 'user.edit' it.id class='tooltip-info' data-rel='tooltip' title='Download'}}
<span class="blue">
<i class="ace-icon fa fa-pencil-square-o bigger-120"></i>
Download
</span>
{{/link-to}}
</li>
</ul>
</div>
</div>
</td>
</tr>
{{/each}}
</tbody>
</table>
</div>
{{pagination-bar}}
</div>
</div>
{{/main-content}}

View File

@ -0,0 +1,26 @@
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render } from '@ember/test-helpers';
import { hbs } from 'ember-cli-htmlbars';
module('Integration | Component | a-btn', function(hooks) {
setupRenderingTest(hooks);
test('it renders', async function(assert) {
// Set any properties with this.set('myProperty', 'value');
// Handle any actions with this.set('myAction', function(val) { ... });
await render(hbs`<ABtn />`);
assert.dom(this.element).hasText('');
// Template block usage:
await render(hbs`
<ABtn>
template block text
</ABtn>
`);
assert.dom(this.element).hasText('template block text');
});
});

View File

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

View File

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