Merge pull request #6279 from hsm-lv/feat-formula

feat:增加判断日期范围的表达式BETWEENRANGE&&优化STARTOF和ENDOF
This commit is contained in:
hsm-lv 2023-02-28 14:40:43 +08:00 committed by GitHub
commit e5b9f24dfc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 291 additions and 15 deletions

View File

@ -508,6 +508,11 @@ test('evalute:array:func', () => {
expect(evaluate('${GET(obj1, "p2")}', data)).toBe('age');
expect(evaluate('${GET(obj1, "p4.1.p42")}', data)).toBe('amis');
expect(evaluate('${GET(obj1, "p4[1].p42")}', data)).toBe('amis');
expect(evaluate('${ENCODEJSON(obj1)}', data)).toBe(JSON.stringify(data.obj1));
expect(
evaluate('${DECODEJSON("{\\"name\\":\\"amis\\"}")}', data)
).toMatchObject(JSON.parse('{"name":"amis"}'));
});
test('evalute:ISTYPE', () => {

View File

@ -272,6 +272,80 @@ test('formula:date', () => {
moment('2023-02-27').isoWeekday()
);
expect(evalFormual('WEEK("2023-03-05")')).toBe(moment('2023-03-05').week());
expect(
evalFormual(
'BETWEENRANGE("2023-03-08", ["2023-03-01", "2024-04-07"], "year")'
)
).toBe(
moment('2023-03-08').isBetween('2023-03-01', '2024-04-07', 'year', '[]')
);
expect(
evalFormual(
'BETWEENRANGE("2022-03-08", ["2023-03-01", "2024-04-07"], "year")'
)
).toBe(
moment('2022-03-08').isBetween('2023-03-01', '2024-04-07', 'year', '[]')
);
expect(
evalFormual(
'BETWEENRANGE("2023-03-08", ["2023-03-01", "2023-04-07"], "month")'
)
).toBe(
moment('2023-03-08').isBetween('2023-03-01', '2023-04-07', 'month', '[]')
);
expect(
evalFormual(
'BETWEENRANGE("2023-05-08", ["2023-03-01", "2023-04-07", "month"])'
)
).toBe(
moment('2023-05-08').isBetween('2023-03-01', '2023-04-07', 'month', '[]')
);
expect(
evalFormual('BETWEENRANGE("2023-03-06", ["2023-03-01", "2023-05-07"])')
).toBe(
moment('2023-03-06').isBetween('2023-03-01', '2023-05-07', 'day', '[]')
);
expect(
evalFormual('BETWEENRANGE("2023-05-08", ["2023-03-01", "2023-05-07"])')
).toBe(
moment('2023-05-08').isBetween('2023-03-01', '2023-05-07', 'day', '[]')
);
expect(
evalFormual(
'BETWEENRANGE("2023-05-07", ["2023-03-01", "2023-05-07"], "day", "()")'
)
).toBe(
moment('2023-05-07').isBetween('2023-03-01', '2023-05-07', 'day', '()')
);
expect(
evalFormual(
'CONCATENATE(STARTOF("2023-02-28", "day"), "," ,ENDOF("2023-02-28", "day"))'
)
).toBe(
`${moment('2023-02-28').startOf('day').toDate()},${moment('2023-02-28')
.endOf('day')
.toDate()}`
);
expect(
evalFormual(
'CONCATENATE(STARTOF("2023-02-28", "day", "YYYY-MM-DD HH:mm:ss"), ",", ENDOF("2023-02-28", "day", "YYYY-MM-DD HH:mm:ss"))'
)
).toBe(
`${moment('2023-02-28')
.startOf('day')
.format('YYYY-MM-DD HH:mm:ss')},${moment('2023-02-28')
.endOf('day')
.format('YYYY-MM-DD HH:mm:ss')}`
);
expect(
evalFormual(
'CONCATENATE(STARTOF("2023-02-28", "day", "X"), "," ,ENDOF("2023-02-28", "day", "X"))'
)
).toBe(
`${moment('2023-02-28').startOf('day').format('X')},${moment('2023-02-28')
.endOf('day')
.format('X')}`
);
});
test('formula:last', () => {

View File

@ -617,7 +617,7 @@
用法:`WEEKDAY(date)`
* `date:any` 日期
* `type:number` 星期定义类型 1表示0至6代表星期一到星期日2表示1至7代表星期一到星期天
* `type:number` 星期定义类型默认为11表示0至6代表星期一到星期日2表示1至7代表星期一到星期日
返回:`number` 星期几的数字标识
@ -632,6 +632,7 @@ WEEKDAY('2023-02-27') 得到 1
用法:`WEEK(date)`
* `date:any` 日期
* `isISO:boolean` 是否ISO星期
返回:`number` 星期几的数字标识
@ -687,6 +688,7 @@ DATERANGESPLIT('1676563200, 1676735999', 'end' , 'YYYY.MM.DD hh:mm:ss') 得到 '
* `date:date` 日期对象
* `unit:string` 比如可以传入 'day'、'month'、'year' 或者 `week` 等等
* `format:string` 日期格式,可选
返回:`date` 新的日期对象
@ -698,6 +700,7 @@ DATERANGESPLIT('1676563200, 1676735999', 'end' , 'YYYY.MM.DD hh:mm:ss') 得到 '
* `date:date` 日期对象
* `unit:string` 比如可以传入 'day'、'month'、'year' 或者 `week` 等等
* `format:string` 日期格式,可选
返回:`date` 新的日期对象
@ -862,6 +865,21 @@ DATEMODIFY(A, -2, 'month')
判断两个日期,是否第一个日期在第二个日期的后面
### BETWEENRANGE
用法:`BETWEENRANGE(date, [start, end])`
* `date:any` 第一个日期
* `daterange:Array<any>` 日期范围
* `unit:string` 单位,默认是 'day' 即之比较到天
* `inclusivity:string` 包容性规则,默认为'[]'。[ 表示包含、( 表示排除,如果使用包容性参数,则必须传入两个指示符,如'()'表示左右范围都排除
返回:`boolean` 判断结果
判断日期是否在指定范围内
示例BETWEENRANGE('2021/12/6', ['2021/12/5','2021/12/7'])
### ISSAMEORBEFORE
用法:`ISSAMEORBEFORE(a, b)`
@ -1058,6 +1076,20 @@ CONCAT(['a', 'b', 'c'], ['1'], ['3']) 得到 ['a', 'b', 'c', '1', '3']
UNIQ([{a: '1'}, {b: '2'}, {a: '1'}] 'id')
### ENCODEJSON
用法:`ENCODEJSON({name: 'amis'})`
* `obj:object` 数组
返回:`string` 结果
将JS对象转换成JSON字符串
示例:
ENCODEJSON({name: 'amis'}) 得到 '{"name":"amis"}'
## 其他
### GET
@ -1086,7 +1118,23 @@ GET({arr: [{name: 'amis', age: 18}]}, 'arr.1.name', 'not-found') 得到 'not-fou
* `判断对象:string` null
返回:`boolean` 结果结果
返回:`boolean` 结果
判断是否为类型支持string, number, array, date, plain-object。
## 编码
### DECODEJSON
用法:`DECODEJSON('{\"name\": "amis"}')`
* `str:string` 字符串
返回:`object` 结果
解析JSON编码数据返回JS对象
示例:
DECODEJSON('{\"name\": "amis"}') 得到 {name: 'amis'}

View File

@ -1042,7 +1042,7 @@ export const doc: {
{
type: "number",
name: "type",
description: "星期定义类型 1表示0至6代表星期一到星期日2表示1至7代表星期一到星期天"
description: "星期定义类型默认为11表示0至6代表星期一到星期日2表示1至7代表星期一到星期日"
}
],
returns: {
@ -1060,6 +1060,11 @@ export const doc: {
type: "any",
name: "date",
description: "日期"
},
{
type: "boolean",
name: "isISO",
description: "是否ISO星期"
}
],
returns: {
@ -1136,6 +1141,11 @@ export const doc: {
type: "string",
name: "unit",
description: "比如可以传入 'day'、'month'、'year' 或者 `week` 等等"
},
{
type: "string",
name: "format",
description: "日期格式,可选"
}
],
returns: {
@ -1158,6 +1168,11 @@ export const doc: {
type: "string",
name: "unit",
description: "比如可以传入 'day'、'month'、'year' 或者 `week` 等等"
},
{
type: "string",
name: "format",
description: "日期格式,可选"
}
],
returns: {
@ -1459,6 +1474,38 @@ export const doc: {
},
namespace: "日期函数"
},
{
name: "BETWEENRANGE",
description: "判断日期是否在指定范围内\n\n示例BETWEENRANGE('2021/12/6', ['2021/12/5','2021/12/7'])",
example: "BETWEENRANGE(date, [start, end])",
params: [
{
type: "any",
name: "date",
description: "第一个日期"
},
{
type: "Array<any>",
name: "daterange",
description: "日期范围"
},
{
type: "string",
name: "unit",
description: "单位,默认是 'day' 即之比较到天"
},
{
type: "string",
name: "inclusivity",
description: "包容性规则,默认为'[]'。[ 表示包含、( 表示排除,如果使用包容性参数,则必须传入两个指示符,如'()'表示左右范围都排除"
}
],
returns: {
type: "boolean",
description: "判断结果"
},
namespace: "日期函数"
},
{
name: "ISSAMEORBEFORE",
description: "判断两个日期,是否第一个日期在第二个日期的前面或者相等",
@ -1789,6 +1836,40 @@ export const doc: {
},
namespace: "数组"
},
{
name: "ENCODEJSON",
description: "将JS对象转换成JSON字符串\n\n示例\n\nENCODEJSON({name: 'amis'}) 得到 '{\"name\":\"amis\"}'",
example: "ENCODEJSON({name: 'amis'})",
params: [
{
type: "object",
name: "obj",
description: "数组"
}
],
returns: {
type: "string",
description: "结果"
},
namespace: "数组"
},
{
name: "DECODEJSON",
description: "解析JSON编码数据返回JS对象\n\n示例\n\nDECODEJSON('{\\\"name\\\": \"amis\"}') 得到 {name: 'amis'}",
example: "DECODEJSON('{\\\"name\\\": \"amis\"}')",
params: [
{
type: "string",
name: "str",
description: "字符串"
}
],
returns: {
type: "object",
description: "结果"
},
namespace: "编码"
},
{
name: "ISTYPE",
description: "判断是否为类型支持string, number, array, date, plain-object。",
@ -1802,7 +1883,7 @@ export const doc: {
],
returns: {
type: "boolean",
description: "结果结果"
description: "结果"
},
namespace: "其他"
}

View File

@ -1529,11 +1529,13 @@ export class Evaluator {
* @example WEEK(date)
* @namespace
* @param {any} date
* @param {boolean} isISO ISO星期
*
* @returns {number}
*/
fnWEEK(date: Date | string | number) {
return moment(this.normalizeDate(date)).week();
fnWEEK(date: Date | string | number, isISO = false) {
const md = moment(this.normalizeDate(date));
return isISO ? md.isoWeek() : md.week();
}
/**
@ -1618,12 +1620,12 @@ export class Evaluator {
* @example STARTOF(date[unit = "day"])
* @param {date} date
* @param {string} unit 'day''month''year' `week`
* @param {string} format
* @returns {date}
*/
fnSTARTOF(date: Date, unit?: any) {
return moment(this.normalizeDate(date))
.startOf(unit || 'day')
.toDate();
fnSTARTOF(date: Date, unit?: any, format?: string) {
const md = moment(this.normalizeDate(date)).startOf(unit || 'day');
return format ? md.format(format) : md.toDate();
}
/**
@ -1632,12 +1634,12 @@ export class Evaluator {
* @example ENDOF(date[unit = "day"])
* @param {date} date
* @param {string} unit 'day''month''year' `week`
* @param {string} format
* @returns {date}
*/
fnENDOF(date: Date, unit?: any) {
return moment(this.normalizeDate(date))
.endOf(unit || 'day')
.toDate();
fnENDOF(date: Date, unit?: any, format?: string) {
const md = moment(this.normalizeDate(date)).endOf(unit || 'day');
return format ? md.format(format) : md.toDate();
}
normalizeDate(raw: any): Date {
@ -1662,6 +1664,12 @@ export class Evaluator {
return raw;
}
normalizeDateRange(raw: string | Date[]): Date[] {
return (Array.isArray(raw) ? raw : raw.split(',')).map((item: any) =>
this.normalizeDate(String(item).trim())
);
}
/**
*
* @namespace
@ -1859,6 +1867,34 @@ export class Evaluator {
return moment(a).isAfter(moment(b), unit);
}
/**
*
*
* BETWEENRANGE('2021/12/6', ['2021/12/5','2021/12/7'])
*
* @param {any} date
* @param {any[]} daterange
* @param {string} unit 'day'
* @param {string} inclusivity '[]'[ ( 使'()'
* @namespace
* @example BETWEENRANGE(date, [start, end])
* @returns {boolean}
*/
fnBETWEENRANGE(
date: Date,
daterange: Date[],
unit: any = 'day',
inclusivity: '[]' | '()' | '(]' | '[)' = '[]'
) {
const range = this.normalizeDateRange(daterange);
return moment(this.normalizeDate(date)).isBetween(
range[0],
range[1],
unit,
inclusivity
);
}
/**
*
*
@ -2162,13 +2198,45 @@ export class Evaluator {
return field ? uniqBy(arr, field) : uniqWith(arr, isEqual);
}
/**
* JS对象转换成JSON字符串
*
*
*
* ENCODEJSON({name: 'amis'}) '{"name":"amis"}'
*
* @param {object} obj
* @namespace
* @example ENCODEJSON({name: 'amis'})
* @returns {string}
*/
fnENCODEJSON(obj: object): string {
return JSON.stringify(obj);
}
/**
* JSON编码数据JS对象
*
*
*
* DECODEJSON('{\"name\": "amis"}') {name: 'amis'}
*
* @param {string} str
* @namespace
* @example DECODEJSON('{\"name\": "amis"}')
* @returns {object}
*/
fnDECODEJSON(str: string): object {
return JSON.parse(str);
}
/**
* string, number, array, date, plain-object
*
* @param {string}
* @namespace
* @example ISTYPE([{a: '1'}, {b: '2'}, {a: '1'}], 'array')
* @returns {boolean}
* @returns {boolean}
*/
fnISTYPE(
target: any,