@fto-consult/expo-ui 2.31.4 → 2.32.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/appConfig.txt +5 -0
- package/package.json +2 -2
- package/src/components/Datagrid/Common/Common.js +111 -13
- package/src/components/Form/Fields/Field.js +5 -3
- package/src/components/Form/Fields/sprintf.js +51 -19
- package/src/components/Form/Fields/sprintfSelectors.js +8 -105
- package/src/media/file-system/utils/write.js +33 -10
package/appConfig.txt
CHANGED
|
@@ -11,4 +11,9 @@
|
|
|
11
11
|
|
|
12
12
|
/***les fonctions d'aggregations du datagrid**/
|
|
13
13
|
datagridAggregatorFunctions : {objectOf({code:{string},label:{string},eval:{function}})|| arrayOf({code:{string},label:{string},eval:{function}})}
|
|
14
|
+
/**l'ensemble des selectors à appliquer au champs de type hashtag, permettant de faire des liens vers d'autres tables**/
|
|
15
|
+
sprintfSelectors : {
|
|
16
|
+
"&libele&" : selectLabel,
|
|
17
|
+
}
|
|
18
|
+
|
|
14
19
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fto-consult/expo-ui",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.32.0",
|
|
4
4
|
"description": "Bibliothèque de composants UI Expo,react-native",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"@emotion/native": "^11.10.0",
|
|
62
62
|
"@expo/html-elements": "^0.2.0",
|
|
63
63
|
"@expo/vector-icons": "^13.0.0",
|
|
64
|
-
"@fto-consult/common": "^1.25.
|
|
64
|
+
"@fto-consult/common": "^1.25.25",
|
|
65
65
|
"@gorhom/portal": "^1.0.14",
|
|
66
66
|
"@react-native-async-storage/async-storage": "~1.17.3",
|
|
67
67
|
"@react-native-community/datetimepicker": "6.5.2",
|
|
@@ -40,7 +40,8 @@ import {styles as tableStyles} from "$ecomponents/Table";
|
|
|
40
40
|
import {DialogProvider} from "$ecomponents/Form/FormData";
|
|
41
41
|
import Chart,{getMaxSupportedSeriesSize} from "$ecomponents/Chart";
|
|
42
42
|
import notify from "$cnotify";
|
|
43
|
-
import
|
|
43
|
+
import FileSystem from "$file-system";
|
|
44
|
+
import sprintf from "$cutils/sprintf";
|
|
44
45
|
|
|
45
46
|
export const donutChart = {
|
|
46
47
|
isChart : true,
|
|
@@ -244,6 +245,8 @@ export default class CommonDatagridComponent extends AppComponent {
|
|
|
244
245
|
displayTypes : {value : hasFoundDisplayTypes ? disTypes : Object.clone(displayTypes)},
|
|
245
246
|
dateFields : {value : {}},
|
|
246
247
|
sectionListColumnsSize : {value : {current:0}}, //la taille du nombre d'éléments de section dans les colonnes
|
|
248
|
+
chartRef : {value : {current:null}},
|
|
249
|
+
chartSeriesNamesColumnsMapping : {value : {}},//le mappage entre les index des series et les colonnes coorespondantes
|
|
247
250
|
})
|
|
248
251
|
const sessionAggregator = defaultStr(this.getSessionData("aggregatorFunction")).trim();
|
|
249
252
|
const aggregatorProps = defaultStr(this.props.aggregatorFunction).trim();
|
|
@@ -1404,7 +1407,7 @@ export default class CommonDatagridComponent extends AppComponent {
|
|
|
1404
1407
|
DialogProvider.open({
|
|
1405
1408
|
title : 'Configuration des graphes',
|
|
1406
1409
|
subtitle : false,
|
|
1407
|
-
data : this.
|
|
1410
|
+
data : this.getChartConfig(),
|
|
1408
1411
|
fields : {
|
|
1409
1412
|
x : {
|
|
1410
1413
|
text : 'Axe des x[horizontal]',
|
|
@@ -1434,6 +1437,14 @@ export default class CommonDatagridComponent extends AppComponent {
|
|
|
1434
1437
|
items : yItems,
|
|
1435
1438
|
multiple : true,
|
|
1436
1439
|
},
|
|
1440
|
+
dataLabels : {
|
|
1441
|
+
type : 'switch',
|
|
1442
|
+
label : "Affich les valeurs",
|
|
1443
|
+
checkedTooltip : "Les étiquettes de valeurs seront affichées sur le graphe",
|
|
1444
|
+
checkedValue : true,
|
|
1445
|
+
uncheckedValue : false,
|
|
1446
|
+
defaultValue : this.isDashboard()? true : false,
|
|
1447
|
+
},
|
|
1437
1448
|
stacked : stackSettings,
|
|
1438
1449
|
sparkline : {
|
|
1439
1450
|
type : 'switch',
|
|
@@ -1450,6 +1461,12 @@ export default class CommonDatagridComponent extends AppComponent {
|
|
|
1450
1461
|
titleColor: {
|
|
1451
1462
|
text : "Couleur de titre",
|
|
1452
1463
|
type :"color",
|
|
1464
|
+
format : "hashtag"
|
|
1465
|
+
},
|
|
1466
|
+
fileName : {
|
|
1467
|
+
text : "Nom fichier en téléchargement",
|
|
1468
|
+
format : "hashtag",
|
|
1469
|
+
tooltip : "Veuillez spécifier le nom du fichier du graphe qui sera utilisée lors du téléchargement"
|
|
1453
1470
|
},
|
|
1454
1471
|
},
|
|
1455
1472
|
actions : [
|
|
@@ -1472,7 +1489,7 @@ export default class CommonDatagridComponent extends AppComponent {
|
|
|
1472
1489
|
})
|
|
1473
1490
|
})
|
|
1474
1491
|
}
|
|
1475
|
-
|
|
1492
|
+
getChartConfig(){
|
|
1476
1493
|
return defaultObj(this.state.chartConfig);
|
|
1477
1494
|
}
|
|
1478
1495
|
getChartIsRendableArgs(){
|
|
@@ -1485,6 +1502,30 @@ export default class CommonDatagridComponent extends AppComponent {
|
|
|
1485
1502
|
isDashboard(){
|
|
1486
1503
|
return false;
|
|
1487
1504
|
}
|
|
1505
|
+
/*** télécharge le chart actif */
|
|
1506
|
+
downloadChart(){
|
|
1507
|
+
if(!this.chartRef.current || !this.chartRef.current.dataURI) return Promise.reject({message:'Référence du graphique non valide'});
|
|
1508
|
+
return this.chartRef.current.dataURI().then(({ imgURI, blob })=>{
|
|
1509
|
+
const config = this.getChartConfig();
|
|
1510
|
+
const fileName = sprintf(defaultStr(config.fileName,config.title,"graphe"));
|
|
1511
|
+
FileSystem.write({content:imgURI,fileName})
|
|
1512
|
+
});
|
|
1513
|
+
}
|
|
1514
|
+
///reoturne les options de menus à appliquer sur le char
|
|
1515
|
+
getChartMenus(){
|
|
1516
|
+
return [
|
|
1517
|
+
{
|
|
1518
|
+
text : "Options du graphe",
|
|
1519
|
+
textBold : true,
|
|
1520
|
+
divider:true,
|
|
1521
|
+
},
|
|
1522
|
+
{
|
|
1523
|
+
text :"Télécharger",
|
|
1524
|
+
icon : "download",
|
|
1525
|
+
onPress : this.downloadChart.bind(this),
|
|
1526
|
+
}
|
|
1527
|
+
]
|
|
1528
|
+
}
|
|
1488
1529
|
renderDisplayTypes(){
|
|
1489
1530
|
const m = [];
|
|
1490
1531
|
let activeType = null,hasFoundChart = false,hasFoundTable = false;
|
|
@@ -1539,6 +1580,11 @@ export default class CommonDatagridComponent extends AppComponent {
|
|
|
1539
1580
|
if(!isMobileOrTabletMedia()){
|
|
1540
1581
|
m.unshift({text:"Type d'affichage des données",divider:true,textBold:true});
|
|
1541
1582
|
}
|
|
1583
|
+
if(hasFoundChart){
|
|
1584
|
+
Object.map(this.getChartMenus(),(c,i)=>{
|
|
1585
|
+
m.push(c);
|
|
1586
|
+
})
|
|
1587
|
+
}
|
|
1542
1588
|
return <Menu
|
|
1543
1589
|
title = "Type d'affichage"
|
|
1544
1590
|
items = {m}
|
|
@@ -1594,7 +1640,7 @@ export default class CommonDatagridComponent extends AppComponent {
|
|
|
1594
1640
|
|
|
1595
1641
|
const code = aggregatorFunction.code;
|
|
1596
1642
|
const isDonut = chartType.isDonut || chartType.isRadial;
|
|
1597
|
-
const config = this.
|
|
1643
|
+
const config = this.getChartConfig();
|
|
1598
1644
|
//@see : https://apexcharts.com/docs/series/
|
|
1599
1645
|
///lorsqu'on affiche uniquement les totaux des sections, alors la visualition se fait sur uniquement sur la base des valeurs
|
|
1600
1646
|
///on parcoure uniquement les entêtes des sectionLis
|
|
@@ -1617,6 +1663,7 @@ export default class CommonDatagridComponent extends AppComponent {
|
|
|
1617
1663
|
seriesConfig = defaultSectionListHeadersSeries;
|
|
1618
1664
|
}
|
|
1619
1665
|
}
|
|
1666
|
+
const seriesNamesMapping = {};
|
|
1620
1667
|
/**** boucle sur chaque éléments trouvée dans le tableau des données sectionListData */
|
|
1621
1668
|
const loopForFooter = ({column,serieName,footers,header})=>{
|
|
1622
1669
|
if(!isObj(column) || !isObj(footers)) return null;
|
|
@@ -1635,12 +1682,13 @@ export default class CommonDatagridComponent extends AppComponent {
|
|
|
1635
1682
|
if(!isObj(this.sectionListHeaderFooters[header])) return null;
|
|
1636
1683
|
const footers = this.sectionListHeaderFooters[header];
|
|
1637
1684
|
if(isDonut){
|
|
1638
|
-
loopForFooter({footers,header,column:yAxisColumn})
|
|
1685
|
+
loopForFooter({footers,header,column:yAxisColumn,columnField:yAxisColumn.field})
|
|
1639
1686
|
} else {
|
|
1640
1687
|
seriesConfig.map((s)=>{
|
|
1641
1688
|
const serie = this.state.columns[s];
|
|
1642
1689
|
const serieName = defaultStr(serie.label,serie.text,s);
|
|
1643
|
-
|
|
1690
|
+
this.chartSeriesNamesColumnsMapping[serieName] = serie;
|
|
1691
|
+
loopForFooter({footers,serie,columnField:s,serieName,header,column:tableFooters[s]})
|
|
1644
1692
|
})
|
|
1645
1693
|
}
|
|
1646
1694
|
});
|
|
@@ -1679,7 +1727,7 @@ export default class CommonDatagridComponent extends AppComponent {
|
|
|
1679
1727
|
return null;
|
|
1680
1728
|
}
|
|
1681
1729
|
const isDonut = chartType.isDonut || chartType.isRadial;
|
|
1682
|
-
const config = this.
|
|
1730
|
+
const config = this.getChartConfig();
|
|
1683
1731
|
if(!this.state.columns[config.y]) return null;
|
|
1684
1732
|
const yAxisColumn = this.state.columns[config.y];
|
|
1685
1733
|
const type = defaultStr(yAxisColumn.jsType,yAxisColumn.type).toLowerCase();
|
|
@@ -1704,6 +1752,10 @@ export default class CommonDatagridComponent extends AppComponent {
|
|
|
1704
1752
|
const indexes = {};
|
|
1705
1753
|
let series = [],xaxis = {},customConfig = {},seriesNamesToColumns={};
|
|
1706
1754
|
let count = 0;
|
|
1755
|
+
//on réinitialise le mappage entre les index
|
|
1756
|
+
Object.map(this.chartSeriesNamesColumnsMapping,(_,k)=>{
|
|
1757
|
+
delete this.chartSeriesNamesColumnsMapping[k];
|
|
1758
|
+
});
|
|
1707
1759
|
if(!this.isSectionList()){
|
|
1708
1760
|
this.state.data.map((data,index)=>{
|
|
1709
1761
|
if(!isObj(data))return null;
|
|
@@ -1743,6 +1795,7 @@ export default class CommonDatagridComponent extends AppComponent {
|
|
|
1743
1795
|
type : chartType.type,
|
|
1744
1796
|
data,
|
|
1745
1797
|
})
|
|
1798
|
+
this.chartSeriesNamesColumnsMapping[name] = col;
|
|
1746
1799
|
})
|
|
1747
1800
|
} else {
|
|
1748
1801
|
const configs = this.getSectionListHeadersChartOptions({chartType,aggregatorFunction,xAxisColumn,yAxisColumn});
|
|
@@ -1765,8 +1818,25 @@ export default class CommonDatagridComponent extends AppComponent {
|
|
|
1765
1818
|
chartProps[settingKey] = defaultObj(chartProps[settingKey]);
|
|
1766
1819
|
chartProps[settingKey][key] = config[key];
|
|
1767
1820
|
});
|
|
1821
|
+
const dataLabelFormatter = typeof chartProps.dataLabels?.formatter =="function"? chartProps.dataLabels.formatter : undefined;
|
|
1768
1822
|
const chartOptions = {
|
|
1769
1823
|
...chartProps,
|
|
1824
|
+
dataLabels : extendObj(true,{enabled:!this.isDashboard()},chartProps.dataLabels,{
|
|
1825
|
+
formatter : (value, { seriesIndex, dataPointIndex, w })=> {
|
|
1826
|
+
const serie = w.config.series[seriesIndex];
|
|
1827
|
+
const serieName = serie.name;
|
|
1828
|
+
const column = isDonut ? defaultObj((this.state.columns[yAxisColumn.field],yAxisColumn)): defaultObj(this.chartSeriesNamesColumnsMapping[serieName]);
|
|
1829
|
+
const columnField = defaultStr(column.field, isDonut? config.y : undefined);
|
|
1830
|
+
if(dataLabelFormatter){
|
|
1831
|
+
return dataLabelFormatter({value,column,columnDef:column,columnField,serie,serieName,seriesIndex})
|
|
1832
|
+
}
|
|
1833
|
+
if(typeof value !=='number') return value;
|
|
1834
|
+
if(defaultStr(column.format).toLowerCase() ==='money'){
|
|
1835
|
+
return value.formatMoney();
|
|
1836
|
+
}
|
|
1837
|
+
return value.formatNumber();
|
|
1838
|
+
}
|
|
1839
|
+
}),
|
|
1770
1840
|
title :extendObj(true,{}, {
|
|
1771
1841
|
text: defaultStr(config.title,chartProps.title),
|
|
1772
1842
|
align: 'left',
|
|
@@ -1782,9 +1852,11 @@ export default class CommonDatagridComponent extends AppComponent {
|
|
|
1782
1852
|
},
|
|
1783
1853
|
},chartProps.title),
|
|
1784
1854
|
series,
|
|
1785
|
-
chart : extendObj(true,{},
|
|
1786
|
-
|
|
1787
|
-
|
|
1855
|
+
chart : extendObj(true,{},
|
|
1856
|
+
{toolbar : {show : false}},
|
|
1857
|
+
{height :this.isDashboard()?80:350},chartProps.chart,
|
|
1858
|
+
{type : chartType.type}
|
|
1859
|
+
)
|
|
1788
1860
|
}
|
|
1789
1861
|
const labelColor = theme.Colors.isValid(config.labelColor)? config.labelColor : theme.colors.text;
|
|
1790
1862
|
if(!isDonut){
|
|
@@ -1800,9 +1872,31 @@ export default class CommonDatagridComponent extends AppComponent {
|
|
|
1800
1872
|
const yLabels = chartOptions.yaxis.labels = defaultObj(chartOptions.yaxis.labels);
|
|
1801
1873
|
yLabels.style = defaultObj(yLabels.style)
|
|
1802
1874
|
yLabels.style.colors = (Array.isArray(yLabels.style.colors) && yLabels.style.colors.length || theme.Colors.isValid(yLabels.style.colors)) ? yLabels.style.colors : labelColor;
|
|
1875
|
+
const yLabelsSerieName = series?.length == 1 && series[0] && series[0].name ? series[0].name : undefined;
|
|
1876
|
+
const yLabelsColumn = yLabelsSerieName ? this.chartSeriesNamesColumnsMapping[yLabelsSerieName] : undefined;
|
|
1877
|
+
let yLabelFormat = null;
|
|
1878
|
+
if(!isDonut && !yLabelFormat){
|
|
1879
|
+
for(let i in series){
|
|
1880
|
+
const v = series[i];
|
|
1881
|
+
if(!isObj(v) || !isNonNullString(v.name) || !this.chartSeriesNamesColumnsMapping[v.name]) break;
|
|
1882
|
+
if(yLabelFormat && typeof this.chartSeriesNamesColumnsMapping[v.name]?.format !=yLabelFormat) {
|
|
1883
|
+
yLabelFormat = null;
|
|
1884
|
+
break;
|
|
1885
|
+
}
|
|
1886
|
+
if(!yLabelFormat){
|
|
1887
|
+
yLabelFormat = this.chartSeriesNamesColumnsMapping[v.name]?.format;
|
|
1888
|
+
}
|
|
1889
|
+
}
|
|
1890
|
+
}
|
|
1803
1891
|
yLabels.formatter = (value)=>{
|
|
1804
|
-
if(typeof value
|
|
1805
|
-
|
|
1892
|
+
if(typeof value !='number') return value;
|
|
1893
|
+
if(yLabelFormat =='money' || (isDonut && yAxisColumn.format =="money")){
|
|
1894
|
+
return value.formatMoney();
|
|
1895
|
+
}
|
|
1896
|
+
if(yLabelsColumn && yLabelsColumn.format =='money'){
|
|
1897
|
+
return value.formatMoney();
|
|
1898
|
+
}
|
|
1899
|
+
return value.formatNumber();
|
|
1806
1900
|
}
|
|
1807
1901
|
chartOptions.chart.id = this.chartIdPrefix+"-"+defaultStr(chartType.key,"no-key");
|
|
1808
1902
|
if(!chartType.isDonut){
|
|
@@ -1825,8 +1919,12 @@ export default class CommonDatagridComponent extends AppComponent {
|
|
|
1825
1919
|
chartOptions.legend = defaultObj(chartOptions.legend);
|
|
1826
1920
|
chartOptions.legend.show = false;
|
|
1827
1921
|
}
|
|
1922
|
+
if("dataLabels" in config){
|
|
1923
|
+
chartOptions.dataLabels.enabled = !!config.dataLabels;
|
|
1924
|
+
}
|
|
1828
1925
|
return <Chart
|
|
1829
1926
|
options = {chartOptions}
|
|
1927
|
+
ref = {this.chartRef}
|
|
1830
1928
|
key = {chartOptions.chart.id+"-"+this.state.displayType}
|
|
1831
1929
|
/>
|
|
1832
1930
|
}
|
|
@@ -2101,7 +2199,7 @@ export default class CommonDatagridComponent extends AppComponent {
|
|
|
2101
2199
|
mItem.right = (p)=>{
|
|
2102
2200
|
return <Icon name="material-settings" {...p} onPress={(e)=>{
|
|
2103
2201
|
//React.stopEventPropagation(e);
|
|
2104
|
-
this.configureSectionListColumn(mItem);
|
|
2202
|
+
this.configureSectionListColumn({...mItem,...defaultObj(sectionListColumns[field])});
|
|
2105
2203
|
//return false;
|
|
2106
2204
|
}}/>
|
|
2107
2205
|
}
|
|
@@ -505,9 +505,9 @@ export default class Field extends AppComponent {
|
|
|
505
505
|
}
|
|
506
506
|
sprintf(){
|
|
507
507
|
if(this.isDisabled() || this.isReadOnly()) return this;
|
|
508
|
-
sprintf({value:this.getValue(),
|
|
508
|
+
sprintf({context:this,value:this.getValue(),formatter:this.props.sprintfResultFormatter}).then((val)=>{
|
|
509
509
|
this.setValue(APP.sprintf(val),true);
|
|
510
|
-
}
|
|
510
|
+
});
|
|
511
511
|
}
|
|
512
512
|
/**** met le focus sur le prochain cham */
|
|
513
513
|
focusNextField (){
|
|
@@ -915,7 +915,7 @@ export default class Field extends AppComponent {
|
|
|
915
915
|
right = <Icon color={theme.colors.primary} {...props} tooltip = {tooltip} style={[styles.icon,props.style]} icon="information"/>;
|
|
916
916
|
}
|
|
917
917
|
if(canRenderHashtag && !rest.disabled && !rest.readOnly){
|
|
918
|
-
const nRight = <Icon {...props} icon={"format-header-pound"} style={[right||cRight?{marginLeft:-5}:null,props.style]} title={"Cliquer insérer un hashtag, ie faire référence à une données
|
|
918
|
+
const nRight = <Icon {...props} icon={"format-header-pound"} style={[right||cRight?{marginLeft:-5}:null,props.style]} title={"Cliquer insérer un hashtag, ie faire référence à une données externe"} onPress={this.sprintf.bind(this)}/>;
|
|
919
919
|
right = right ? <>{right}{nRight}</> : nRight;
|
|
920
920
|
}
|
|
921
921
|
return (cRight)? <>{cRight}{right}</> : right;
|
|
@@ -988,6 +988,8 @@ Field.propTypes = {
|
|
|
988
988
|
PropTypes.node,
|
|
989
989
|
PropTypes.func,
|
|
990
990
|
]),
|
|
991
|
+
/**** la fonction utilisée pour le formattage des valeurs de type sprintf */
|
|
992
|
+
sprintfResultFormatter : PropTypes.func,
|
|
991
993
|
jsType : PropTypes.string,
|
|
992
994
|
usePlaceholderWhenEmpty : PropTypes.bool,//si la valeur du placeholder sera utilée, lorsque la valeur du champ de type formatable est nulle ou égale à la valeur vide
|
|
993
995
|
responsive : PropTypes.bool,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import selectors from "./sprintfSelectors";
|
|
2
|
-
import {isNonNullString,defaultFunc} from "$utils";
|
|
2
|
+
import {isNonNullString,defaultFunc,isObj,isPromise} from "$utils";
|
|
3
3
|
|
|
4
|
-
export default ({value,val,cb,success})=>{
|
|
4
|
+
export default ({value,val,formatter,cb,success})=>{
|
|
5
5
|
val = defaultStr(value,val)
|
|
6
6
|
if(!isNonNullString(val)){
|
|
7
7
|
return null;
|
|
@@ -16,27 +16,59 @@ export default ({value,val,cb,success})=>{
|
|
|
16
16
|
keys.push(i.toUpperCase())
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
|
-
|
|
19
|
+
const results = {};
|
|
20
20
|
let length = keys.length;
|
|
21
21
|
let index = length;
|
|
22
22
|
let key = undefined
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
let
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
23
|
+
const sKeys = {};
|
|
24
|
+
return new Promise((resolve)=>{
|
|
25
|
+
const next = ()=>{
|
|
26
|
+
index -=1;
|
|
27
|
+
if(index < 0){
|
|
28
|
+
for(let i in results){
|
|
29
|
+
let indexName = i.toLowerCase();
|
|
30
|
+
let selector = selectors[indexName];
|
|
31
|
+
if(!selector){
|
|
32
|
+
indexName = i.toUpperCase();
|
|
33
|
+
selector = selectors[indexName];
|
|
34
|
+
}
|
|
35
|
+
const replace = results[i];
|
|
36
|
+
if(typeof formatter =='function'){
|
|
37
|
+
val = formatter({selectors,selector,value:val,replace,result:results[i],results,indexName,selectorIndex:indexName,selectorName:indexName})
|
|
38
|
+
}
|
|
39
|
+
if(typeof val =='string' && typeof replace =='string'){
|
|
40
|
+
val = val.replaceAll(i,replace);
|
|
41
|
+
}
|
|
32
42
|
}
|
|
33
|
-
val = val
|
|
43
|
+
val = defaultStr(val);
|
|
44
|
+
cb(val);
|
|
45
|
+
resolve(val);
|
|
46
|
+
} else {
|
|
47
|
+
key = keys[index];
|
|
48
|
+
if(!isNonNullString(key)) {return next();}
|
|
49
|
+
let indexName = i.toLowerCase();
|
|
50
|
+
let selector = selectors[indexName];
|
|
51
|
+
if(!selector){
|
|
52
|
+
indexName = i.toUpperCase();
|
|
53
|
+
selector = selectors[indexName];
|
|
54
|
+
}
|
|
55
|
+
sKeys[i] = indexName;
|
|
56
|
+
const select = isObj(selector)? selector.select : selector;
|
|
57
|
+
if(typeof cb =='function'){
|
|
58
|
+
const v = select({...rest,selector,selectors,indexName,selectorIndex:indexName,selectorName:indexName,results,index:key,keys,key,value:val});
|
|
59
|
+
if(isPromise(v)){
|
|
60
|
+
return v.then((r)=>{
|
|
61
|
+
if(typeof r ==='string'){
|
|
62
|
+
results[key] = r;
|
|
63
|
+
}
|
|
64
|
+
}).finally(next);
|
|
65
|
+
} else if(typeof v =='string' || typeof v =='number'){
|
|
66
|
+
results[key] = v.toString();
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
next();
|
|
34
70
|
}
|
|
35
|
-
cb(val);
|
|
36
|
-
} else {
|
|
37
|
-
key = keys[index];
|
|
38
|
-
if(!isNonNullString(key)) {return next();}
|
|
39
71
|
}
|
|
40
|
-
|
|
41
|
-
|
|
72
|
+
next();
|
|
73
|
+
})
|
|
42
74
|
}
|
|
@@ -1,116 +1,19 @@
|
|
|
1
1
|
import Date from "$lib/date";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
dbName : 'struct_data',
|
|
6
|
-
itemValue : ({item})=>defaultStr(item.label,item.code)
|
|
7
|
-
}
|
|
2
|
+
import {defaultObj} from "$utils";
|
|
3
|
+
import appConfig from "$capp/config";
|
|
4
|
+
const sprintfSelectors = defaultObj(appConfig.get("sprintfSelectors"));
|
|
8
5
|
export default {
|
|
9
|
-
|
|
10
|
-
"&vente&" : {
|
|
11
|
-
title : 'Sélectionner une vente',
|
|
12
|
-
table : 'sales',
|
|
13
|
-
},
|
|
14
|
-
"&achat&" : {
|
|
15
|
-
title : 'Sélectionner un achat',
|
|
16
|
-
table : 'purchases',
|
|
17
|
-
},
|
|
18
|
-
"&stock&" : {
|
|
19
|
-
title : 'Sélectionner stock',
|
|
20
|
-
table : 'stocks',
|
|
21
|
-
},
|
|
22
|
-
"&transfert&" : {
|
|
23
|
-
title : 'Sélectionner mouvement de transfert',
|
|
24
|
-
table : 'stocks_transfers',
|
|
25
|
-
},
|
|
26
|
-
"®lement&" : {
|
|
27
|
-
title : 'Sélectionner un règlement',
|
|
28
|
-
table : 'payments',
|
|
29
|
-
},
|
|
30
|
-
"&tiers&" : {
|
|
31
|
-
title : 'Sélectionner un tier',
|
|
32
|
-
table : 'third_parties',
|
|
33
|
-
dbName : 'third_parties',
|
|
34
|
-
},
|
|
35
|
-
"&projet&" : {
|
|
36
|
-
title : 'Sélectionner un projet',
|
|
37
|
-
table : 'projects',
|
|
38
|
-
dbName : 'projects',
|
|
39
|
-
},
|
|
40
|
-
"&tache&" : {
|
|
41
|
-
title : 'Sélectionner une tâche',
|
|
42
|
-
table : 'tasks',
|
|
43
|
-
dbName : 'projects',
|
|
44
|
-
},
|
|
45
|
-
"&commercial&" : {
|
|
46
|
-
title : 'Sélectionner commercial',
|
|
47
|
-
table : 'users',
|
|
48
|
-
dbName : 'users',
|
|
49
|
-
fetchDataOpts:{
|
|
50
|
-
selector : {$and:[{isSeller:1}]}
|
|
51
|
-
}
|
|
52
|
-
},
|
|
53
|
-
"&client&" : {
|
|
54
|
-
title : 'Sélectionner client',
|
|
55
|
-
table : 'third_parties',
|
|
56
|
-
dbName : 'third_parties',
|
|
57
|
-
fetchDataOpts:{
|
|
58
|
-
selector : {$and:[{type:{$in:["customer"]}}]}
|
|
59
|
-
}
|
|
60
|
-
},
|
|
61
|
-
"&fournisseur&" : {
|
|
62
|
-
title : 'Sélectionner Fournisseur',
|
|
63
|
-
table : 'third_parties',
|
|
64
|
-
dbName : 'third_parties',
|
|
65
|
-
fetchDataOpts:{
|
|
66
|
-
selector : {$and:[{type:{$in:["provider"]}}]}
|
|
67
|
-
}
|
|
68
|
-
},
|
|
69
|
-
"&utilisateur&" : {
|
|
70
|
-
title : 'Sélectionner un utilisateur',
|
|
71
|
-
table : 'users',
|
|
72
|
-
dbName : 'users',
|
|
73
|
-
},
|
|
74
|
-
"&caisse&" : {
|
|
75
|
-
title : 'Sélectionner une caisse',
|
|
76
|
-
table : 'checkouts',
|
|
77
|
-
dbName : 'common',
|
|
78
|
-
},
|
|
79
|
-
"&produit&" : {
|
|
80
|
-
title : 'Sélectionner un produit/article',
|
|
81
|
-
table : 'products',
|
|
82
|
-
dbName : 'products',
|
|
83
|
-
},
|
|
84
|
-
"&categorie&" : {
|
|
85
|
-
title : 'Sélectionner une catégorie de produit',
|
|
86
|
-
table : 'products_categories',
|
|
87
|
-
dbName : 'products',
|
|
88
|
-
},
|
|
89
|
-
"&taxe&" : {
|
|
90
|
-
title : 'Sélectionner une taxe',
|
|
91
|
-
table : 'taxes',
|
|
92
|
-
dbName : 'common',
|
|
93
|
-
},
|
|
94
|
-
"&depot&" : {
|
|
95
|
-
title : 'Sélectionner un dépôt',
|
|
96
|
-
table : 'warehouses',
|
|
97
|
-
dbName : 'common',
|
|
98
|
-
},
|
|
99
|
-
"&contact&" : {
|
|
100
|
-
title : 'Sélectionner un contact',
|
|
101
|
-
table : 'contacts',
|
|
102
|
-
dbName : 'common',
|
|
103
|
-
},
|
|
6
|
+
...sprintfSelectors,
|
|
104
7
|
"&sdate&" : {
|
|
105
8
|
title : 'Sélectionner une date',
|
|
106
9
|
type : 'field',
|
|
107
10
|
field : {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
11
|
+
type : 'date',
|
|
12
|
+
text : 'Sélectionner une date',
|
|
13
|
+
format : Date.defaultDateFormat
|
|
111
14
|
},
|
|
112
15
|
desc : "remplace le motif par la date qui sera sélectionnée par l'utilisateur au format jj/mm/aaaa",
|
|
113
|
-
|
|
16
|
+
},
|
|
114
17
|
"&date&" : "remplace le motif par la date actuelle au format : jj/mm/aaaa",
|
|
115
18
|
"&heure&" : "remplace le motif par l'heure actuelle au format hh:mm:ss",
|
|
116
19
|
"&dateheure&" : "remplace le motif par la date et l'heure actuelle au format : jj/mm/aaaa hh:mm:ss",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Copyright 2022 @fto-consult/Boris Fouomene. All rights reserved.
|
|
2
2
|
// Use of this source code is governed by a BSD-style
|
|
3
3
|
// license that can be found in the LICENSE file.
|
|
4
|
-
import {defaultStr,base64toBlob,isNonNullString,getFileName,getFileExtension,defaultNumber,defaultBool,dataURLToBase64,isBlob,isBase64,isDataURL} from "$utils";
|
|
4
|
+
import {defaultStr,base64toBlob,dataURLToBlob,getTypeFromDataURL,isNonNullString,getFileName,getFileExtension,defaultNumber,defaultBool,dataURLToBase64,isBlob,isBase64,isDataURL} from "$utils";
|
|
5
5
|
const FileSaver = require('file-saver');
|
|
6
6
|
const mime = require('mime-types')
|
|
7
7
|
const XLSX = require("xlsx");
|
|
@@ -29,6 +29,13 @@ import Preloader from "$preloader";
|
|
|
29
29
|
reject({status:false,msg:'Nom de fichier invalide'});
|
|
30
30
|
return;
|
|
31
31
|
}
|
|
32
|
+
if(isDataURL(content)){
|
|
33
|
+
const type = getTypeFromDataURL(content);
|
|
34
|
+
content = dataURLToBlob(content);
|
|
35
|
+
if(isNonNullString(type)){
|
|
36
|
+
contentType = type;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
32
39
|
content = isBlob(content)? content : new Blob([content], { type: content?.type||contentType})
|
|
33
40
|
try {
|
|
34
41
|
FileSaver.saveAs(content, fileName);
|
|
@@ -55,10 +62,6 @@ function s2ab(s) {
|
|
|
55
62
|
* .xls : application/vnd.ms-excel
|
|
56
63
|
*/
|
|
57
64
|
export const writeExcel = ({workbook,content,contentType,fileName,...rest})=>{
|
|
58
|
-
if(!isNonNullString(contentType) || !contentType.contains("application/vnd.")){
|
|
59
|
-
//contentType = "application/vnd.ms-excel";
|
|
60
|
-
contentType : "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
|
61
|
-
}
|
|
62
65
|
let ext = defaultStr(getFileExtension(fileName,true),"xlsx");
|
|
63
66
|
fileName = sanitizeFileName(getFileName(fileName,true))+"."+ext;
|
|
64
67
|
if(!isNonNullString(fileName)){
|
|
@@ -70,11 +73,31 @@ export const writeExcel = ({workbook,content,contentType,fileName,...rest})=>{
|
|
|
70
73
|
if(isBlob(content)){
|
|
71
74
|
return write({...rest,content,fileName,contentType})
|
|
72
75
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
76
|
+
return new Promise((resolve,reject)=>{
|
|
77
|
+
Preloader.open("génération du fichier excel "+fileName);
|
|
78
|
+
try {
|
|
79
|
+
XLSX.writeFile(workbook, fileName);
|
|
80
|
+
setTimeout(()=>{
|
|
81
|
+
Preloader.close();
|
|
82
|
+
resolve({fileName});
|
|
83
|
+
},1000);
|
|
84
|
+
} catch(e){
|
|
85
|
+
reject(e);
|
|
86
|
+
}
|
|
87
|
+
})
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/***
|
|
91
|
+
* @see https://ourtechroom.com/tech/mime-type-for-excel/ for excel mimesTypes
|
|
92
|
+
* .xls : application/vnd.ms-excel
|
|
93
|
+
*/
|
|
94
|
+
export const writeImage = ({content,fileName,...rest})=>{
|
|
95
|
+
let ext = defaultStr(getFileExtension(fileName,true),"png");
|
|
96
|
+
fileName = sanitizeFileName(getFileName(fileName,true))+"."+ext;
|
|
97
|
+
if(!isNonNullString(fileName)){
|
|
98
|
+
return Promise.reject({status:false,message:'Nom de fichier invalide pour le contenu excel à créer'});
|
|
99
|
+
}
|
|
100
|
+
|
|
78
101
|
}
|
|
79
102
|
|
|
80
103
|
|