From 947ded7784b6012349701d9a8661e4359d3b644c Mon Sep 17 00:00:00 2001 From: lvxiaojiao Date: Tue, 28 Feb 2023 14:11:04 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E5=A2=9E=E5=8A=A0=E5=88=A4=E6=96=AD?= =?UTF-8?q?=E6=97=A5=E6=9C=9F=E8=8C=83=E5=9B=B4=E7=9A=84=E8=A1=A8=E8=BE=BE?= =?UTF-8?q?=E5=BC=8FBETWEENRANGE&&=E4=BC=98=E5=8C=96STARTOF=E5=92=8CENDOF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../amis-formula/__tests__/evalute.test.ts | 5 ++ .../amis-formula/__tests__/fomula.test.ts | 74 +++++++++++++++ packages/amis-formula/src/doc.md | 52 ++++++++++- packages/amis-formula/src/doc.ts | 85 +++++++++++++++++- packages/amis-formula/src/evalutor.ts | 90 ++++++++++++++++--- 5 files changed, 291 insertions(+), 15 deletions(-) diff --git a/packages/amis-formula/__tests__/evalute.test.ts b/packages/amis-formula/__tests__/evalute.test.ts index ce59fb678..88d0fe685 100644 --- a/packages/amis-formula/__tests__/evalute.test.ts +++ b/packages/amis-formula/__tests__/evalute.test.ts @@ -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', () => { diff --git a/packages/amis-formula/__tests__/fomula.test.ts b/packages/amis-formula/__tests__/fomula.test.ts index b9af6e584..26d586e4c 100644 --- a/packages/amis-formula/__tests__/fomula.test.ts +++ b/packages/amis-formula/__tests__/fomula.test.ts @@ -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', () => { diff --git a/packages/amis-formula/src/doc.md b/packages/amis-formula/src/doc.md index 73d1a209b..6b2146de2 100644 --- a/packages/amis-formula/src/doc.md +++ b/packages/amis-formula/src/doc.md @@ -617,7 +617,7 @@ 用法:`WEEKDAY(date)` * `date:any` 日期 - * `type:number` 星期定义类型 1表示0至6代表星期一到星期日,2表示1至7代表星期一到星期天 + * `type:number` 星期定义类型,默认为1,1表示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` 日期范围 + * `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'} + diff --git a/packages/amis-formula/src/doc.ts b/packages/amis-formula/src/doc.ts index edb9574af..7255b3008 100644 --- a/packages/amis-formula/src/doc.ts +++ b/packages/amis-formula/src/doc.ts @@ -1042,7 +1042,7 @@ export const doc: { { type: "number", name: "type", - description: "星期定义类型 1表示0至6代表星期一到星期日,2表示1至7代表星期一到星期天" + description: "星期定义类型,默认为1,1表示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", + 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: "其他" } diff --git a/packages/amis-formula/src/evalutor.ts b/packages/amis-formula/src/evalutor.ts index 5b5df47c9..08abec01a 100644 --- a/packages/amis-formula/src/evalutor.ts +++ b/packages/amis-formula/src/evalutor.ts @@ -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,