Merge branch 'release'

This commit is contained in:
Xu Chang 2023-03-15 10:42:41 +08:00
commit 3d539b93db
49 changed files with 1603 additions and 1090 deletions

View File

@ -1123,7 +1123,8 @@ function constructFilter(statements, entity) {
case 'Int': case 'Int':
case 'Uint': case 'Uint':
case 'Float': case 'Float':
case 'Double': { case 'Double':
case 'Price': {
type2 = factory.createTypeReferenceNode(factory.createIdentifier('Q_NumberValue')); type2 = factory.createTypeReferenceNode(factory.createIdentifier('Q_NumberValue'));
break; break;
} }
@ -1276,7 +1277,8 @@ function constructProjection(statements, entity) {
case 'File': case 'File':
case 'SingleGeo': case 'SingleGeo':
case 'Geo': case 'Geo':
case 'Object': { case 'Object':
case 'Price': {
properties.push([name_4, false]); properties.push([name_4, false]);
break; break;
} }
@ -1639,7 +1641,8 @@ function constructSorter(statements, entity) {
case 'Boolean': case 'Boolean':
case 'Datetime': case 'Datetime':
case 'Image': case 'Image':
case 'File': { case 'File':
case 'Price': {
type2 = factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword); type2 = factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword);
break; break;
} }
@ -2658,6 +2661,7 @@ var initialStatements = function () { return [
factory.createImportSpecifier(false, undefined, factory.createIdentifier('Text')), factory.createImportSpecifier(false, undefined, factory.createIdentifier('Text')),
factory.createImportSpecifier(false, undefined, factory.createIdentifier('Datetime')), factory.createImportSpecifier(false, undefined, factory.createIdentifier('Datetime')),
factory.createImportSpecifier(false, undefined, factory.createIdentifier('File')), factory.createImportSpecifier(false, undefined, factory.createIdentifier('File')),
factory.createImportSpecifier(false, undefined, factory.createIdentifier('Price')),
factory.createImportSpecifier(false, undefined, factory.createIdentifier('Image')), factory.createImportSpecifier(false, undefined, factory.createIdentifier('Image')),
factory.createImportSpecifier(false, undefined, factory.createIdentifier('PrimaryKey')), factory.createImportSpecifier(false, undefined, factory.createIdentifier('PrimaryKey')),
factory.createImportSpecifier(false, undefined, factory.createIdentifier('ForeignKey')), factory.createImportSpecifier(false, undefined, factory.createIdentifier('ForeignKey')),
@ -2934,15 +2938,13 @@ function constructAttributes(entity) {
], true))); ], true)));
break; break;
} }
case 'Float': { case 'Double':
attrAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("type"), factory.createStringLiteral("float")), factory.createPropertyAssignment(factory.createIdentifier("params"), factory.createObjectLiteralExpression([ case 'Float':
factory.createPropertyAssignment(factory.createIdentifier("precision"), factory.createNumericLiteral(typeArguments[0].literal.text)), case 'Decimal': {
factory.createPropertyAssignment(factory.createIdentifier("scale"), factory.createNumericLiteral(typeArguments[1].literal.text)) if (['Double', 'Float'].includes(text)) {
], true))); console.warn("".concat(entity, "\u5BF9\u8C61\u4E2D\u8FD8\u6709").concat(text, "\u7C7B\u578B\u5B9A\u4E49\uFF0C\u73B0\u5728\u7EDF\u4E00\u7528Decimal\u8FDB\u884C\u5B58\u50A8"));
break;
} }
case 'Double': { attrAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("type"), factory.createStringLiteral("decimal")), factory.createPropertyAssignment(factory.createIdentifier("params"), factory.createObjectLiteralExpression([
attrAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("type"), factory.createStringLiteral("double")), factory.createPropertyAssignment(factory.createIdentifier("params"), factory.createObjectLiteralExpression([
factory.createPropertyAssignment(factory.createIdentifier("precision"), factory.createNumericLiteral(typeArguments[0].literal.text)), factory.createPropertyAssignment(factory.createIdentifier("precision"), factory.createNumericLiteral(typeArguments[0].literal.text)),
factory.createPropertyAssignment(factory.createIdentifier("scale"), factory.createNumericLiteral(typeArguments[1].literal.text)) factory.createPropertyAssignment(factory.createIdentifier("scale"), factory.createNumericLiteral(typeArguments[1].literal.text))
], true))); ], true)));
@ -2952,6 +2954,10 @@ function constructAttributes(entity) {
attrAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("type"), factory.createStringLiteral("boolean"))); attrAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("type"), factory.createStringLiteral("boolean")));
break; break;
} }
case 'Price': {
attrAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("type"), factory.createStringLiteral("money")));
break;
}
case 'Datetime': { case 'Datetime': {
attrAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("type"), factory.createStringLiteral("datetime"))); attrAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("type"), factory.createStringLiteral("datetime")));
break; break;

View File

@ -21,6 +21,7 @@ var indexes = [
]; ];
var locale = { var locale = {
zh_CN: { zh_CN: {
name: '更新',
attr: { attr: {
targetEntity: '目标对象', targetEntity: '目标对象',
entity: '关联对象', entity: '关联对象',

View File

@ -6,6 +6,7 @@ var config = {
}; };
var locale = { var locale = {
zh_CN: { zh_CN: {
name: '更新对象连接',
attr: { attr: {
modi: '更新', modi: '更新',
entity: '关联对象', entity: '关联对象',

View File

@ -6,6 +6,7 @@ var configuration = {
}; };
var locale = { var locale = {
zh_CN: { zh_CN: {
name: '操作',
attr: { attr: {
action: '动作', action: '动作',
data: '数据', data: '数据',

View File

@ -6,6 +6,7 @@ var config = {
}; };
var locale = { var locale = {
zh_CN: { zh_CN: {
name: '操作对象连接',
attr: { attr: {
oper: '操作', oper: '操作',
entity: '关联对象', entity: '关联对象',

View File

@ -8,6 +8,7 @@ var UserActionDef = {
}; };
var locale = { var locale = {
zh_CN: { zh_CN: {
name: '用户',
attr: { attr: {
name: '姓名', name: '姓名',
nickname: '昵称', nickname: '昵称',

View File

@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
; ;
var locale = { var locale = {
zh_CN: { zh_CN: {
name: '用户授权',
attr: { attr: {
relation: '关系', relation: '关系',
entity: '关联对象', entity: '关联对象',

View File

@ -64,93 +64,91 @@ var AsyncContext = /** @class */ (function () {
}; };
AsyncContext.prototype.commit = function () { AsyncContext.prototype.commit = function () {
return tslib_1.__awaiter(this, void 0, void 0, function () { return tslib_1.__awaiter(this, void 0, void 0, function () {
var _a, _b, e, e_1_1; var commitEvents, commitEvents_1, commitEvents_1_1, e, e_1_1;
var e_1, _c; var e_1, _a;
return tslib_1.__generator(this, function (_d) { return tslib_1.__generator(this, function (_b) {
switch (_d.label) { switch (_b.label) {
case 0: case 0:
if (!this.uuid) return [3 /*break*/, 10]; if (!this.uuid) return [3 /*break*/, 9];
return [4 /*yield*/, this.rowStore.commit(this.uuid)]; return [4 /*yield*/, this.rowStore.commit(this.uuid)];
case 1: case 1:
_d.sent(); _b.sent();
this.uuid = undefined; this.uuid = undefined;
_d.label = 2; commitEvents = this.events.commit;
this.resetEvents();
_b.label = 2;
case 2: case 2:
_d.trys.push([2, 7, 8, 9]); _b.trys.push([2, 7, 8, 9]);
_a = tslib_1.__values(this.events.commit), _b = _a.next(); commitEvents_1 = tslib_1.__values(commitEvents), commitEvents_1_1 = commitEvents_1.next();
_d.label = 3; _b.label = 3;
case 3: case 3:
if (!!_b.done) return [3 /*break*/, 6]; if (!!commitEvents_1_1.done) return [3 /*break*/, 6];
e = _b.value; e = commitEvents_1_1.value;
return [4 /*yield*/, e()]; return [4 /*yield*/, e()];
case 4: case 4:
_d.sent(); _b.sent();
_d.label = 5; _b.label = 5;
case 5: case 5:
_b = _a.next(); commitEvents_1_1 = commitEvents_1.next();
return [3 /*break*/, 3]; return [3 /*break*/, 3];
case 6: return [3 /*break*/, 9]; case 6: return [3 /*break*/, 9];
case 7: case 7:
e_1_1 = _d.sent(); e_1_1 = _b.sent();
e_1 = { error: e_1_1 }; e_1 = { error: e_1_1 };
return [3 /*break*/, 9]; return [3 /*break*/, 9];
case 8: case 8:
try { try {
if (_b && !_b.done && (_c = _a.return)) _c.call(_a); if (commitEvents_1_1 && !commitEvents_1_1.done && (_a = commitEvents_1.return)) _a.call(commitEvents_1);
} }
finally { if (e_1) throw e_1.error; } finally { if (e_1) throw e_1.error; }
return [7 /*endfinally*/]; return [7 /*endfinally*/];
case 9: case 9: return [2 /*return*/];
this.resetEvents();
_d.label = 10;
case 10: return [2 /*return*/];
} }
}); });
}); });
}; };
AsyncContext.prototype.rollback = function () { AsyncContext.prototype.rollback = function () {
return tslib_1.__awaiter(this, void 0, void 0, function () { return tslib_1.__awaiter(this, void 0, void 0, function () {
var _a, _b, e, e_2_1; var rollbackEvents, rollbackEvents_1, rollbackEvents_1_1, e, e_2_1;
var e_2, _c; var e_2, _a;
return tslib_1.__generator(this, function (_d) { return tslib_1.__generator(this, function (_b) {
switch (_d.label) { switch (_b.label) {
case 0: case 0:
if (!this.uuid) return [3 /*break*/, 10]; if (!this.uuid) return [3 /*break*/, 9];
return [4 /*yield*/, this.rowStore.rollback(this.uuid)]; return [4 /*yield*/, this.rowStore.rollback(this.uuid)];
case 1: case 1:
_d.sent(); _b.sent();
// console.log('rollback', this.uuid); // console.log('rollback', this.uuid);
this.uuid = undefined; this.uuid = undefined;
_d.label = 2; rollbackEvents = this.events.rollback;
this.resetEvents();
_b.label = 2;
case 2: case 2:
_d.trys.push([2, 7, 8, 9]); _b.trys.push([2, 7, 8, 9]);
_a = tslib_1.__values(this.events.rollback), _b = _a.next(); rollbackEvents_1 = tslib_1.__values(rollbackEvents), rollbackEvents_1_1 = rollbackEvents_1.next();
_d.label = 3; _b.label = 3;
case 3: case 3:
if (!!_b.done) return [3 /*break*/, 6]; if (!!rollbackEvents_1_1.done) return [3 /*break*/, 6];
e = _b.value; e = rollbackEvents_1_1.value;
return [4 /*yield*/, e()]; return [4 /*yield*/, e()];
case 4: case 4:
_d.sent(); _b.sent();
_d.label = 5; _b.label = 5;
case 5: case 5:
_b = _a.next(); rollbackEvents_1_1 = rollbackEvents_1.next();
return [3 /*break*/, 3]; return [3 /*break*/, 3];
case 6: return [3 /*break*/, 9]; case 6: return [3 /*break*/, 9];
case 7: case 7:
e_2_1 = _d.sent(); e_2_1 = _b.sent();
e_2 = { error: e_2_1 }; e_2 = { error: e_2_1 };
return [3 /*break*/, 9]; return [3 /*break*/, 9];
case 8: case 8:
try { try {
if (_b && !_b.done && (_c = _a.return)) _c.call(_a); if (rollbackEvents_1_1 && !rollbackEvents_1_1.done && (_a = rollbackEvents_1.return)) _a.call(rollbackEvents_1);
} }
finally { if (e_2) throw e_2.error; } finally { if (e_2) throw e_2.error; }
return [7 /*endfinally*/]; return [7 /*endfinally*/];
case 9: case 9: return [2 /*return*/];
this.resetEvents();
_d.label = 10;
case 10: return [2 /*return*/];
} }
}); });
}); });

View File

@ -339,12 +339,18 @@ function translateCascadeRelationFilterMaker(schema, lch, entity2, pathPrefix) {
}; };
var filterMaker = paths.length ? translateFilterMakerIter(entity2, 0) : translateRelationFilter(entity2); var filterMaker = paths.length ? translateFilterMakerIter(entity2, 0) : translateRelationFilter(entity2);
if (!paths.length) { if (!paths.length) {
// 不可能是create
return function (oper, userId) { return filterMaker(userId); }; return function (oper, userId) { return filterMaker(userId); };
} }
/** /**
* 针对第一层做一下特别优化比如对象A指向对象B多对一如果A的cascadePath是 'B' * 针对第一层做一下特别优化比如对象A指向对象B多对一如果A的cascadePath是 'B'
* 当create A时会带有Bid此时生成该B对象上的相关表达式查询返回可以避免必须将此判定在对象创建之后再做 * 当create A时会带有Bid此时生成该B对象上的相关表达式查询返回可以避免必须将此判定在对象创建之后再做
* 另一使用场景是在查询A时如果带有Bid在对象跳一对多子对象场景下很常见可以提前判定这个查询对某些用户一定返回空集 * 另一使用场景是在查询A时如果带有Bid在对象跳一对多子对象场景下很常见可以提前判定这个查询对某些用户一定返回空集
*
* 20230306:
* 在前台的权限判断中会将list上的filter当成内在的限制对create动作进行判断此时有一种可能是filter并不能直接判断出外键但会限制外键的查询范围
* 例如在jichuang项目中就存在park/list上平台的用户去访问时其查询条件是{ system: { platformId: 1 }}而用户的关系落在system.platform.platformProvider上
* 此时如直接通过data上的外键判断就会失败需要通过对filter上相应的语义解构进行进一步的判断
*/ */
var _a = tslib_1.__read(paths, 1), attr = _a[0]; var _a = tslib_1.__read(paths, 1), attr = _a[0];
var relation = (0, relation_1.judgeRelation)(schema, entity2, attr); var relation = (0, relation_1.judgeRelation)(schema, entity2, attr);
@ -352,14 +358,76 @@ function translateCascadeRelationFilterMaker(schema, lch, entity2, pathPrefix) {
var filterMaker2 = paths.length > 1 var filterMaker2 = paths.length > 1
? (relation === 2 ? translateFilterMakerIter(attr, 1) : translateFilterMakerIter(relation, 1)) ? (relation === 2 ? translateFilterMakerIter(attr, 1) : translateFilterMakerIter(relation, 1))
: (relation === 2 ? translateRelationFilter(attr) : translateRelationFilter(relation)); : (relation === 2 ? translateRelationFilter(attr) : translateRelationFilter(relation));
var translateCreateFilterMaker = function (entity, filter, userId) {
var counters = [];
if (filter) {
if (relation === 2) {
if (filter.entity === entity && filter.entityId) {
// 这里对entityId的限定的数据只要和userId有一条relation就不能否定可能会有创建动作外键在最终create时data上一定会有判定
counters.push({
$entity: attr,
$filter: (0, filter_1.addFilterSegment)(filterMaker2(userId), { id: filter.entityId }),
});
}
if (filter[attr]) {
counters.push({
$entity: attr,
$filter: (0, filter_1.addFilterSegment)(filterMaker2(userId), filter[attr]),
});
}
}
else {
(0, assert_1.default)(typeof relation === 'string');
if (filter["".concat(attr, "Id")]) {
var filterMaker3 = paths.length > 1 ? translateFilterMakerIter(relation, 1) : translateRelationFilter(relation);
// 这里对attrId的限定的数据只要和userId有一条relation就不能否定可能会有创建动作外键在最终create时data上一定会有判定
counters.push({
$entity: relation,
$filter: (0, filter_1.addFilterSegment)(filterMaker3(userId), { id: filter["".concat(attr, "Id")] }),
});
}
if (filter[attr]) {
counters.push({
$entity: relation,
$filter: (0, filter_1.addFilterSegment)(filterMaker2(userId), filter[attr]),
});
}
}
if (filter.$and) {
var countersAnd = filter.$and.map(function (ele) { return translateCreateFilterMaker(entity, ele, userId); });
// and 只要有一个满足就行
var ca2 = countersAnd.filter(function (ele) { return !(ele instanceof Exception_1.OakUserUnpermittedException); });
counters.push.apply(counters, tslib_1.__spreadArray([], tslib_1.__read(ca2), false));
}
if (filter.$or) {
var countersOr = filter.$and.map(function (ele) { return translateCreateFilterMaker(entity, ele, userId); });
// or也只要有一个满足就行不能否定
var co2 = countersOr.filter(function (ele) { return !(ele instanceof Exception_1.OakUserUnpermittedException); });
counters.push.apply(counters, tslib_1.__spreadArray([], tslib_1.__read(co2), false));
}
}
if (counters.length === 0) {
// 一个counter都找不出来说明当前路径上不满足
return new Exception_1.OakUserUnpermittedException();
}
else if (counters.length === 1) {
return counters[0];
}
// 是or关系只要其中有一个满足就可以通过
return {
$$or: counters,
};
};
return function (operation, userId) { return function (operation, userId) {
var action = operation.action; var action = operation.action;
if (action === 'create') { if (action === 'create') {
var data = operation.data; var data = operation.data;
if (data) {
// 有data的情形根据data判定
var getForeignKeyId_1 = function (d) { var getForeignKeyId_1 = function (d) {
if (relation === 2) { if (relation === 2) {
if (d.entity === attr && typeof d.entityId === 'string') { if (d.entity === attr && typeof d.entityId === 'string') {
return d.entitId; return d.entityId;
} }
throw new Exception_1.OakUserUnpermittedException(); throw new Exception_1.OakUserUnpermittedException();
} }
@ -401,6 +469,19 @@ function translateCascadeRelationFilterMaker(schema, lch, entity2, pathPrefix) {
$filter: (0, filter_1.addFilterSegment)(filterMaker2(userId), { id: fkId }), $filter: (0, filter_1.addFilterSegment)(filterMaker2(userId), { id: fkId }),
}; };
} }
else {
// todo
var filter_4 = operation.filter;
if (filter_4) {
var counter = translateCreateFilterMaker(entity2, filter_4, userId);
if (counter instanceof Exception_1.OakUserUnpermittedException) {
throw counter;
}
return counter;
}
throw new Exception_1.OakUserUnpermittedException();
}
}
var filter = operation.filter; var filter = operation.filter;
if (relation === 2 && (filter === null || filter === void 0 ? void 0 : filter.entity) === attr && (filter === null || filter === void 0 ? void 0 : filter.entityId)) { if (relation === 2 && (filter === null || filter === void 0 ? void 0 : filter.entity) === attr && (filter === null || filter === void 0 ? void 0 : filter.entityId)) {
if (typeof filter.entityId === 'string') { if (typeof filter.entityId === 'string') {
@ -450,8 +531,77 @@ function translateActionAuthFilterMaker(schema, relationItem, entity, pathPrefix
var filterMaker = translateCascadeRelationFilterMaker(schema, relationItem, entity, pathPrefix); var filterMaker = translateCascadeRelationFilterMaker(schema, relationItem, entity, pathPrefix);
return filterMaker; return filterMaker;
} }
function execCreateCounter(context, counter) {
if (counter === null || counter === void 0 ? void 0 : counter.$$and) {
// 每个counter都要满足才能过
var counters = counter === null || counter === void 0 ? void 0 : counter.$$and;
(0, assert_1.default)(counters.length > 0);
var counterResults = counters.map(function (ele) { return execCreateCounter(context, ele); });
if (counterResults[0] instanceof Promise) {
return Promise.all(counterResults)
.then(function (cr2) {
var unpermitted = cr2.find(function (ele) { return ele instanceof Exception_1.OakUserUnpermittedException; });
if (unpermitted) {
return unpermitted;
}
return undefined;
});
}
else {
var unpermitted = counterResults.find(function (ele) { return ele instanceof Exception_1.OakUserUnpermittedException; });
if (unpermitted) {
return unpermitted;
}
else {
return undefined;
}
}
}
else if (counter === null || counter === void 0 ? void 0 : counter.$$or) {
// 只要有一个counter能过就算过
var counters = counter === null || counter === void 0 ? void 0 : counter.$$or;
(0, assert_1.default)(counters.length > 0);
var counterResults = counters.map(function (ele) { return execCreateCounter(context, ele); });
if (counterResults[0] instanceof Promise) {
return Promise.all(counterResults)
.then(function (cr2) {
var permittedIdx = cr2.indexOf(undefined);
if (permittedIdx !== -1) {
return undefined;
}
return new Exception_1.OakUserUnpermittedException();
});
}
else {
var permittedIndex = counterResults.indexOf(undefined);
if (permittedIndex !== -1) {
return undefined;
}
else {
return new Exception_1.OakUserUnpermittedException();
}
}
}
else if (counter === null || counter === void 0 ? void 0 : counter.$entity) {
var _a = counter, $entity = _a.$entity, $filter = _a.$filter, _b = _a.$count, $count_1 = _b === void 0 ? 1 : _b;
var count = context.count($entity, {
filter: $filter,
}, { dontCollect: true });
if (count instanceof Promise) {
return count.then(function (c2) {
if (c2 >= $count_1) {
return undefined;
}
return new Exception_1.OakUserUnpermittedException();
});
}
else {
return count >= $count_1 ? undefined : new Exception_1.OakUserUnpermittedException();
}
}
}
function makePotentialFilter(operation, context, filterMaker) { function makePotentialFilter(operation, context, filterMaker) {
var e_1, _a; var e_1, _a, e_2, _b;
var userId = context.getCurrentUserId(); var userId = context.getCurrentUserId();
(0, assert_1.default)(userId); (0, assert_1.default)(userId);
var filters = filterMaker instanceof Array ? filterMaker.map(function (ele) { var filters = filterMaker instanceof Array ? filterMaker.map(function (ele) {
@ -470,38 +620,27 @@ function makePotentialFilter(operation, context, filterMaker) {
*/ */
var filtersOr = []; var filtersOr = [];
var isAsyncOr = false; var isAsyncOr = false;
var _loop_1 = function (f) { try {
var e_2, _b; for (var filters_1 = tslib_1.__values(filters), filters_1_1 = filters_1.next(); !filters_1_1.done; filters_1_1 = filters_1.next()) {
var f = filters_1_1.value;
if (f instanceof Array) { if (f instanceof Array) {
var isAsyncAnd = true; var isAsyncAnd = false;
(0, assert_1.default)(f.length > 0);
var filtersAnd = []; var filtersAnd = [];
var _loop_2 = function (ff) { try {
if (ff === null || ff === void 0 ? void 0 : ff.$entity) { for (var f_1 = (e_2 = void 0, tslib_1.__values(f)), f_1_1 = f_1.next(); !f_1_1.done; f_1_1 = f_1.next()) {
var _e = ff, $entity = _e.$entity, $filter = _e.$filter, _f = _e.$count, $count_1 = _f === void 0 ? 1 : _f; var ff = f_1_1.value;
var count = context.count($entity, { if ((ff === null || ff === void 0 ? void 0 : ff.$$and) || (ff === null || ff === void 0 ? void 0 : ff.$$or) || (ff === null || ff === void 0 ? void 0 : ff.$entity)) {
filter: $filter, // 每个counter都要满足才能过
}, {}); var result = execCreateCounter(context, ff);
if (count instanceof Promise) { if (result instanceof Promise) {
isAsyncAnd = true; isAsyncAnd = true;
filtersAnd.push(count.then(function (c2) {
if (c2 >= $count_1) {
return undefined;
}
return new Exception_1.OakUserUnpermittedException();
}));
}
else {
filtersAnd.push(count >= $count_1 ? undefined : new Exception_1.OakUserUnpermittedException());
} }
filtersAnd.push(result);
} }
else if (ff) { else if (ff) {
filtersAnd.push(ff); filtersAnd.push(ff);
} }
};
try {
for (var f_1 = (e_2 = void 0, tslib_1.__values(f)), f_1_1 = f_1.next(); !f_1_1.done; f_1_1 = f_1.next()) {
var ff = f_1_1.value;
_loop_2(ff);
} }
} }
catch (e_2_1) { e_2 = { error: e_2_1 }; } catch (e_2_1) { e_2 = { error: e_2_1 }; }
@ -545,28 +684,17 @@ function makePotentialFilter(operation, context, filterMaker) {
} }
} }
else { else {
if (f === null || f === void 0 ? void 0 : f.$entity) { if ((f === null || f === void 0 ? void 0 : f.$$and) || (f === null || f === void 0 ? void 0 : f.$$or) || (f === null || f === void 0 ? void 0 : f.$entity)) {
var _c = f, $entity = _c.$entity, $filter = _c.$filter, _d = _c.$count, $count_2 = _d === void 0 ? 1 : _d; var counterResults = execCreateCounter(context, f);
var count = context.count($entity, { if (counterResults instanceof Promise) {
filter: $filter,
}, {});
if (count instanceof Promise) {
isAsyncOr = true; isAsyncOr = true;
filtersOr.push(count.then(function (c2) { return c2 >= $count_2 ? undefined : new Exception_1.OakUserUnpermittedException(); }));
}
else {
filtersOr.push(count >= $count_2 ? undefined : new Exception_1.OakUserUnpermittedException());
} }
filtersOr.push(counterResults);
} }
else if (f) { else if (f) {
filtersOr.push(f); filtersOr.push(f);
} }
} }
};
try {
for (var filters_1 = tslib_1.__values(filters), filters_1_1 = filters_1.next(); !filters_1_1.done; filters_1_1 = filters_1.next()) {
var f = filters_1_1.value;
_loop_1(f);
} }
} }
catch (e_1_1) { e_1 = { error: e_1_1 }; } catch (e_1_1) { e_1 = { error: e_1_1 }; }
@ -603,18 +731,30 @@ function makePotentialFilter(operation, context, filterMaker) {
*/ */
function createAuthCheckers(schema, authDict) { function createAuthCheckers(schema, authDict) {
var checkers = []; var checkers = [];
var _loop_3 = function (entity) { var _loop_1 = function (entity) {
var _a; var _a;
if (authDict[entity]) { if (authDict[entity]) {
var _b = authDict[entity], relationAuth = _b.relationAuth, actionAuth = _b.actionAuth; var _b = authDict[entity], relationAuth = _b.relationAuth, actionAuth = _b.actionAuth;
if (relationAuth) { if (relationAuth) {
var raFilterMakerDict_1 = {}; var raFilterMakerDict_1 = {};
var userEntityName = "user".concat((0, string_1.firstLetterUpperCase)(entity)); var userEntityName = "user".concat((0, string_1.firstLetterUpperCase)(entity));
var allAuthItem = [];
for (var r in relationAuth) { for (var r in relationAuth) {
var authItem = relationAuth[r];
Object.assign(raFilterMakerDict_1, (_a = {}, Object.assign(raFilterMakerDict_1, (_a = {},
_a[r] = translateActionAuthFilterMaker(schema, relationAuth[r], userEntityName, entity), _a[r] = translateActionAuthFilterMaker(schema, authItem, userEntityName, entity),
_a)); _a));
if (authItem instanceof Array) {
allAuthItem.push.apply(allAuthItem, tslib_1.__spreadArray([], tslib_1.__read(authItem), false));
} }
else {
allAuthItem.push(authItem);
}
}
// 如果不指定relation则使用所有的authItem的or组合
Object.assign(raFilterMakerDict_1, {
'@@all': translateActionAuthFilterMaker(schema, allAuthItem, userEntityName, entity),
});
var entityIdAttr_1 = "".concat(entity, "Id"); var entityIdAttr_1 = "".concat(entity, "Id");
checkers.push({ checkers.push({
entity: userEntityName, entity: userEntityName,
@ -624,8 +764,12 @@ function createAuthCheckers(schema, authDict) {
var data = operation.data; var data = operation.data;
(0, assert_1.default)(!(data instanceof Array)); (0, assert_1.default)(!(data instanceof Array));
var _a = data, relation = _a.relation, _b = entityIdAttr_1, entityId = _a[_b]; var _a = data, relation = _a.relation, _b = entityIdAttr_1, entityId = _a[_b];
if (!relation) {
// 不指定relation测试是否有创建权限
return makePotentialFilter(operation, context, raFilterMakerDict_1['@@all']);
}
if (!raFilterMakerDict_1[relation]) { if (!raFilterMakerDict_1[relation]) {
return; throw new Exception_1.OakUserUnpermittedException();
} }
var filter = makePotentialFilter(operation, context, raFilterMakerDict_1[relation]); var filter = makePotentialFilter(operation, context, raFilterMakerDict_1[relation]);
return filter; return filter;
@ -694,7 +838,7 @@ function createAuthCheckers(schema, authDict) {
// todo 等实现的时候再写 // todo 等实现的时候再写
} }
if (actionAuth) { if (actionAuth) {
var _loop_4 = function (a) { var _loop_2 = function (a) {
var filterMaker = translateActionAuthFilterMaker(schema, actionAuth[a], entity); var filterMaker = translateActionAuthFilterMaker(schema, actionAuth[a], entity);
checkers.push({ checkers.push({
entity: entity, entity: entity,
@ -709,13 +853,13 @@ function createAuthCheckers(schema, authDict) {
}); });
}; };
for (var a in actionAuth) { for (var a in actionAuth) {
_loop_4(a); _loop_2(a);
} }
} }
} }
}; };
for (var entity in schema) { for (var entity in schema) {
_loop_3(entity); _loop_1(entity);
} }
return checkers; return checkers;
} }
@ -784,7 +928,7 @@ function createRemoveCheckers(schema, authDict) {
} }
// 当删除一时,要确认多上面没有指向一的数据 // 当删除一时,要确认多上面没有指向一的数据
var entities = (0, lodash_1.union)(Object.keys(OneToManyMatrix), Object.keys(OneToManyOnEntityMatrix)); var entities = (0, lodash_1.union)(Object.keys(OneToManyMatrix), Object.keys(OneToManyOnEntityMatrix));
var _loop_5 = function (entity) { var _loop_3 = function (entity) {
checkers.push({ checkers.push({
entity: entity, entity: entity,
action: 'remove', action: 'remove',
@ -793,7 +937,7 @@ function createRemoveCheckers(schema, authDict) {
var e_6, _a, e_7, _b; var e_6, _a, e_7, _b;
var promises = []; var promises = [];
if (OneToManyMatrix[entity]) { if (OneToManyMatrix[entity]) {
var _loop_7 = function (otm) { var _loop_5 = function (otm) {
var _g, _h; var _g, _h;
var _j = tslib_1.__read(otm, 2), e = _j[0], attr = _j[1]; var _j = tslib_1.__read(otm, 2), e = _j[0], attr = _j[1];
var proj = (_g = { var proj = (_g = {
@ -832,7 +976,7 @@ function createRemoveCheckers(schema, authDict) {
try { try {
for (var _c = (e_6 = void 0, tslib_1.__values(OneToManyMatrix[entity])), _d = _c.next(); !_d.done; _d = _c.next()) { for (var _c = (e_6 = void 0, tslib_1.__values(OneToManyMatrix[entity])), _d = _c.next(); !_d.done; _d = _c.next()) {
var otm = _d.value; var otm = _d.value;
_loop_7(otm); _loop_5(otm);
} }
} }
catch (e_6_1) { e_6 = { error: e_6_1 }; } catch (e_6_1) { e_6 = { error: e_6_1 }; }
@ -844,7 +988,7 @@ function createRemoveCheckers(schema, authDict) {
} }
} }
if (OneToManyOnEntityMatrix[entity]) { if (OneToManyOnEntityMatrix[entity]) {
var _loop_8 = function (otm) { var _loop_6 = function (otm) {
var _l, _m, _o; var _l, _m, _o;
var proj = { var proj = {
id: 1, id: 1,
@ -890,7 +1034,7 @@ function createRemoveCheckers(schema, authDict) {
try { try {
for (var _e = (e_7 = void 0, tslib_1.__values(OneToManyOnEntityMatrix[entity])), _f = _e.next(); !_f.done; _f = _e.next()) { for (var _e = (e_7 = void 0, tslib_1.__values(OneToManyOnEntityMatrix[entity])), _f = _e.next(); !_f.done; _f = _e.next()) {
var otm = _f.value; var otm = _f.value;
_loop_8(otm); _loop_6(otm);
} }
} }
catch (e_7_1) { e_7 = { error: e_7_1 }; } catch (e_7_1) { e_7 = { error: e_7_1 }; }
@ -910,7 +1054,7 @@ function createRemoveCheckers(schema, authDict) {
try { try {
for (var entities_1 = tslib_1.__values(entities), entities_1_1 = entities_1.next(); !entities_1_1.done; entities_1_1 = entities_1.next()) { for (var entities_1 = tslib_1.__values(entities), entities_1_1 = entities_1.next(); !entities_1_1.done; entities_1_1 = entities_1.next()) {
var entity = entities_1_1.value; var entity = entities_1_1.value;
_loop_5(entity); _loop_3(entity);
} }
} }
catch (e_4_1) { e_4 = { error: e_4_1 }; } catch (e_4_1) { e_4 = { error: e_4_1 }; }
@ -920,13 +1064,13 @@ function createRemoveCheckers(schema, authDict) {
} }
finally { if (e_4) throw e_4.error; } finally { if (e_4) throw e_4.error; }
} }
var _loop_6 = function (entity) { var _loop_4 = function (entity) {
var e_8, _b; var e_8, _b;
var cascadeRemove = authDict[entity].cascadeRemove; var cascadeRemove = authDict[entity].cascadeRemove;
if (cascadeRemove) { if (cascadeRemove) {
var entitiesOnEntityAttr = []; var entitiesOnEntityAttr = [];
var hasAllEntity = false; var hasAllEntity = false;
var _loop_9 = function (attr) { var _loop_7 = function (attr) {
if (attr === '@entity') { if (attr === '@entity') {
hasAllEntity = true; hasAllEntity = true;
return "continue"; return "continue";
@ -1001,13 +1145,13 @@ function createRemoveCheckers(schema, authDict) {
} }
}; };
for (var attr in cascadeRemove) { for (var attr in cascadeRemove) {
_loop_9(attr); _loop_7(attr);
} }
if (hasAllEntity) { if (hasAllEntity) {
var attributes = schema[entity].attributes; var attributes = schema[entity].attributes;
var ref = attributes.entity.ref; var ref = attributes.entity.ref;
var restEntities = (0, lodash_1.difference)(ref, entitiesOnEntityAttr); var restEntities = (0, lodash_1.difference)(ref, entitiesOnEntityAttr);
var _loop_10 = function (e) { var _loop_8 = function (e) {
checkers.push({ checkers.push({
entity: e, entity: e,
action: 'remove', action: 'remove',
@ -1043,7 +1187,7 @@ function createRemoveCheckers(schema, authDict) {
try { try {
for (var restEntities_1 = (e_8 = void 0, tslib_1.__values(restEntities)), restEntities_1_1 = restEntities_1.next(); !restEntities_1_1.done; restEntities_1_1 = restEntities_1.next()) { for (var restEntities_1 = (e_8 = void 0, tslib_1.__values(restEntities)), restEntities_1_1 = restEntities_1.next(); !restEntities_1_1.done; restEntities_1_1 = restEntities_1.next()) {
var e = restEntities_1_1.value; var e = restEntities_1_1.value;
_loop_10(e); _loop_8(e);
} }
} }
catch (e_8_1) { e_8 = { error: e_8_1 }; } catch (e_8_1) { e_8 = { error: e_8_1 }; }
@ -1058,7 +1202,7 @@ function createRemoveCheckers(schema, authDict) {
}; };
// 注入声明的cascade删除时的外键处理动作 // 注入声明的cascade删除时的外键处理动作
for (var entity in authDict) { for (var entity in authDict) {
_loop_6(entity); _loop_4(entity);
} }
return checkers; return checkers;
} }

View File

@ -8,11 +8,14 @@ export declare type Text = string;
export declare type Image = string; export declare type Image = string;
export declare type File = string; export declare type File = string;
export declare type Datetime = number | Date; export declare type Datetime = number | Date;
export declare type Day = number | Date;
export declare type Time = number | Date;
export declare type Boolean = boolean; export declare type Boolean = boolean;
export declare type Price = number;
export declare type PrimaryKey = string; export declare type PrimaryKey = string;
export declare type ForeignKey<E extends string> = string; export declare type ForeignKey<E extends string> = string;
export declare type Sequence = string; export declare type Sequence = string;
export { Geo, SingleGeo } from './Geo'; export { Geo, SingleGeo } from './Geo';
export declare type DataTypes = number | string | Datetime | Geo | Object | SingleGeo; export declare type DataTypes = number | string | Datetime | Day | Time | Geo | Object | SingleGeo;
export declare const types: string[]; export declare const types: string[];
export declare const unIndexedTypes: string[]; export declare const unIndexedTypes: string[];

View File

@ -1,5 +1,6 @@
"use strict"; "use strict";
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.unIndexedTypes = exports.types = void 0; exports.unIndexedTypes = exports.types = void 0;
exports.types = ['Int', 'Uint', 'Double', 'Float', 'String', 'Text', 'Datetime', 'Boolean', 'Image', 'File', 'Geo', 'SingleGeo']; exports.types = ['Int', 'Uint', 'Double', 'Float', 'String', 'Text', 'Datetime', 'Day', 'Time',
'Boolean', 'Image', 'File', 'Geo', 'SingleGeo', 'Price'];
exports.unIndexedTypes = ['Text', 'Image', 'File', 'Object']; exports.unIndexedTypes = ['Text', 'Image', 'File', 'Object'];

View File

@ -13,6 +13,7 @@ declare type LocaleOfValue<V extends Record<string, string>> = {
}; };
export declare type LocaleDef<Sc extends Record<string, any>, Ac extends string, R extends string, V extends Record<string, string>> = { export declare type LocaleDef<Sc extends Record<string, any>, Ac extends string, R extends string, V extends Record<string, string>> = {
[L in Language]?: { [L in Language]?: {
name: string;
attr: LocaleOfSchema<Sc> & { attr: LocaleOfSchema<Sc> & {
[A in keyof V]: string; [A in keyof V]: string;
}; };

11
lib/types/Style.d.ts vendored Normal file
View File

@ -0,0 +1,11 @@
import { EntityDict } from './Entity';
import { EntityDict as BaseEntityDict } from '../base-app-domain';
declare type ThemeColor = 'default' | 'success' | 'warning' | 'error';
export declare type ColorDict<ED extends BaseEntityDict & EntityDict> = {
[T in keyof ED]?: {
[A in keyof ED[T]['OpSchema']]?: {
[E in ED[T]['OpSchema'][A]]?: ThemeColor | `#${string}`;
};
};
};
export {};

2
lib/types/Style.js Normal file
View File

@ -0,0 +1,2 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });

View File

@ -1,5 +1,6 @@
import { RecurrenceRule, RecurrenceSpecDateRange, RecurrenceSpecObjLit } from 'node-schedule';
import { EntityDict } from './Entity'; import { EntityDict } from './Entity';
import { AsyncContext } from "../store/AsyncRowStore"; import { AsyncContext } from '../store/AsyncRowStore';
declare type RoutineFn<ED extends EntityDict, Cxt extends AsyncContext<ED>> = (context: Cxt) => Promise<string>; declare type RoutineFn<ED extends EntityDict, Cxt extends AsyncContext<ED>> = (context: Cxt) => Promise<string>;
export declare type Routine<ED extends EntityDict, Cxt extends AsyncContext<ED>> = { export declare type Routine<ED extends EntityDict, Cxt extends AsyncContext<ED>> = {
name: string; name: string;
@ -7,7 +8,7 @@ export declare type Routine<ED extends EntityDict, Cxt extends AsyncContext<ED>>
}; };
export declare type Timer<ED extends EntityDict, Cxt extends AsyncContext<ED>> = { export declare type Timer<ED extends EntityDict, Cxt extends AsyncContext<ED>> = {
name: string; name: string;
cron: string; cron: RecurrenceRule | RecurrenceSpecDateRange | RecurrenceSpecObjLit | Date | string | number;
fn: RoutineFn<ED, Cxt>; fn: RoutineFn<ED, Cxt>;
}; };
export {}; export {};

View File

@ -19,3 +19,4 @@ export * from './Connector';
export * from './Timer'; export * from './Timer';
export * from './Port'; export * from './Port';
export * from './Endpoint'; export * from './Endpoint';
export * from './Style';

View File

@ -22,3 +22,4 @@ tslib_1.__exportStar(require("./Connector"), exports);
tslib_1.__exportStar(require("./Timer"), exports); tslib_1.__exportStar(require("./Timer"), exports);
tslib_1.__exportStar(require("./Port"), exports); tslib_1.__exportStar(require("./Port"), exports);
tslib_1.__exportStar(require("./Endpoint"), exports); tslib_1.__exportStar(require("./Endpoint"), exports);
tslib_1.__exportStar(require("./Style"), exports);

View File

@ -29,4 +29,6 @@ export interface DataTypeParams {
precision?: number; precision?: number;
scale?: number; scale?: number;
signed?: boolean; signed?: boolean;
max?: number;
min?: number;
} }

View File

@ -10,7 +10,7 @@ function makeContentTypeAndBody(data) {
if (process.env.OAK_PLATFORM !== 'wechatMp') { if (process.env.OAK_PLATFORM !== 'wechatMp') {
if (data instanceof FormData) { if (data instanceof FormData) {
return { return {
contentType: 'multipart/form-data', // contentType: 'multipart/form-data',
body: data, body: data,
}; };
} }
@ -39,11 +39,12 @@ var SimpleConnector = /** @class */ (function (_super) {
_a = makeContentTypeAndBody(params), contentType = _a.contentType, body = _a.body; _a = makeContentTypeAndBody(params), contentType = _a.contentType, body = _a.body;
return [4 /*yield*/, global.fetch(this.serverUrl, { return [4 /*yield*/, global.fetch(this.serverUrl, {
method: 'POST', method: 'POST',
headers: { headers: Object.assign({
'Content-Type': contentType,
'oak-cxt': cxtStr, 'oak-cxt': cxtStr,
'oak-aspect': name, 'oak-aspect': name,
}, }, contentType && {
'Content-Type': contentType,
}),
body: body, body: body,
})]; })];
case 1: case 1:
@ -106,7 +107,7 @@ var SimpleConnector = /** @class */ (function (_super) {
}); });
}; };
SimpleConnector.prototype.serializeResult = function (result, context, headers, body) { SimpleConnector.prototype.serializeResult = function (result, context, headers, body) {
if (result instanceof stream_1.Stream) { if (result instanceof stream_1.Stream || result instanceof Buffer) {
return { return {
body: result, body: result,
}; };

1
lib/utils/cron.d.ts vendored
View File

@ -1 +0,0 @@
export declare function schedule(cron: string, fn: (date: Date) => any): void;

View File

@ -1,18 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.schedule = void 0;
var tslib_1 = require("tslib");
var cronjs_matcher_1 = require("@datasert/cronjs-matcher");
var dayjs_1 = tslib_1.__importDefault(require("dayjs"));
function schedule(cron, fn) {
var futureMatches = (0, cronjs_matcher_1.getFutureMatches)(cron, {
matchCount: 1,
});
var date = (0, dayjs_1.default)(futureMatches[0]);
var interval = date.diff((0, dayjs_1.default)(), 'ms');
setTimeout(function () {
fn(new Date());
schedule(cron, fn);
}, interval);
}
exports.schedule = schedule;

5
lib/utils/mask.d.ts vendored Normal file
View File

@ -0,0 +1,5 @@
declare const maskIdCard: (idCardNumber: string) => string;
declare const maskMobile: (mobile: string) => string;
declare const maskName: (name: string) => string;
declare const maskStar: (str: string, front: number, end: number, star: string) => string;
export { maskIdCard, maskMobile, maskName, maskStar, };

35
lib/utils/mask.js Normal file
View File

@ -0,0 +1,35 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.maskStar = exports.maskName = exports.maskMobile = exports.maskIdCard = void 0;
var maskIdCard = function (idCardNumber) {
if (!idCardNumber instanceof String) {
throw new Error("身份证号码必须是String类型");
}
var begin = idCardNumber.slice(0, 4);
var end = idCardNumber.slice(idCardNumber.length - 4, 4);
for (var i = 0; i < idCardNumber.length - 8; i++) {
begin = begin.concat("*");
}
return begin.concat(end);
};
exports.maskIdCard = maskIdCard;
var maskMobile = function (mobile) {
var begin = mobile.slice(0, 3);
var end = mobile.slice(7, 11);
return begin.concat("****").concat(end);
};
exports.maskMobile = maskMobile;
var maskName = function (name) {
return name.slice(0, name.length - 1).concat("*");
};
exports.maskName = maskName;
var maskStar = function (str, frontLen, endLen, star) {
if (star === void 0) { star = '*'; }
var len = str.length - frontLen - endLen;
var xing = '';
for (var i = 0; i < len; i++) {
xing += star;
}
return str.substring(0, frontLen) + xing + str.substring(str.length - endLen);
};
exports.maskStar = maskStar;

5
lib/utils/money.d.ts vendored Normal file
View File

@ -0,0 +1,5 @@
declare const ToCent: (float: number) => number;
declare const ToYuan: (int: number) => number;
declare const StringToCent: (value: string, allowNegative?: true) => number | undefined;
declare const CentToString: (value: number) => string | undefined;
export { ToCent, ToYuan, StringToCent, CentToString, };

24
lib/utils/money.js Normal file
View File

@ -0,0 +1,24 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CentToString = exports.StringToCent = exports.ToYuan = exports.ToCent = void 0;
var ToCent = function (float) {
return Math.round(float * 100);
};
exports.ToCent = ToCent;
var ToYuan = function (int) {
return Math.round(int) / 100;
};
exports.ToYuan = ToYuan;
var StringToCent = function (value, allowNegative) {
var numValue = parseInt(value, 10);
if (typeof numValue === 'number' && (numValue >= 0 || allowNegative)) {
return ToCent(numValue);
}
};
exports.StringToCent = StringToCent;
var CentToString = function (value) {
if (typeof value === 'number') {
return "".concat(ToYuan(value));
}
};
exports.CentToString = CentToString;

View File

@ -16,6 +16,7 @@ export declare const isNickname: ValidatorFunction;
export declare const isSizedCaptcha: ValidatorFunction; export declare const isSizedCaptcha: ValidatorFunction;
export declare const isDigital: ValidatorFunction; export declare const isDigital: ValidatorFunction;
export declare const isPhone: ValidatorFunction; export declare const isPhone: ValidatorFunction;
export declare const isTel: ValidatorFunction;
export declare const isNumber: ValidatorFunction; export declare const isNumber: ValidatorFunction;
export declare const isMoney: ValidatorMoneyFunction; export declare const isMoney: ValidatorMoneyFunction;
export declare const isVehicleNumber: ValidatorFunction; export declare const isVehicleNumber: ValidatorFunction;

View File

@ -3,7 +3,7 @@
*/ */
'use strict'; 'use strict';
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.checkAttributesScope = exports.checkAttributesNotNull = exports.isVehicleNumber = exports.isMoney = exports.isNumber = exports.isPhone = exports.isDigital = exports.isSizedCaptcha = exports.isNickname = exports.isUrl = exports.isSoldierNumber = exports.isBirthNumber = exports.isTwCardNumber = exports.isAmCardNumber = exports.isHkCardNumber = exports.isPassportNumber = exports.isIdCardNumber = exports.isCaptcha = exports.isPassword = exports.isMobile = void 0; exports.checkAttributesScope = exports.checkAttributesNotNull = exports.isVehicleNumber = exports.isMoney = exports.isNumber = exports.isTel = exports.isPhone = exports.isDigital = exports.isSizedCaptcha = exports.isNickname = exports.isUrl = exports.isSoldierNumber = exports.isBirthNumber = exports.isTwCardNumber = exports.isAmCardNumber = exports.isHkCardNumber = exports.isPassportNumber = exports.isIdCardNumber = exports.isCaptcha = exports.isPassword = exports.isMobile = void 0;
var types_1 = require("../types"); var types_1 = require("../types");
var isMobile = function (text) { var isMobile = function (text) {
return ((text) && (typeof text === "string") && ((/^1[3|4|5|6|7|8|9]\d{9}$/.test(text)))); return ((text) && (typeof text === "string") && ((/^1[3|4|5|6|7|8|9]\d{9}$/.test(text))));
@ -79,14 +79,19 @@ var isPhone = function (phone) {
return /^(\(\d{3,4}\)|\d{3,4}-)?\d{7,8}$/.test(phone); return /^(\(\d{3,4}\)|\d{3,4}-)?\d{7,8}$/.test(phone);
}; };
exports.isPhone = isPhone; exports.isPhone = isPhone;
var isTel = function (text) {
// 1、133xxxx4545 2、0571-630xx239 3、400-123-1400
var reg = /^(((\d{3,4}-)?[0-9]{7,8})|(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}|((400)-(\d{3})-(\d{4})(.)(\d{1,4})|(400)-(\d{3})-(\d{4}$)|(400)(\d{3})(\d{4}$)|(400)-(\d{4})-(\d{3}$)))$/.test(text);
return reg;
};
exports.isTel = isTel;
var isNumber = function (str) { var isNumber = function (str) {
return /^[0-9]*$/.test(str); return /^[0-9]*$/.test(str);
}; };
exports.isNumber = isNumber; exports.isNumber = isNumber;
var isMoney = function (str, zero) { var isMoney = function (str, zero) {
// zero为true包含零 // 金额,最多可以有两位小数 zero为true包含零
if (zero) { if (zero) {
// 金额,最多可以有两位小数
return /(^[1-9]([0-9]+)?(\.[0-9]{1,2})?$)|(^(0){1}$)|(^[0-9]\.[0-9]([0-9])?$)/.test(str); return /(^[1-9]([0-9]+)?(\.[0-9]{1,2})?$)|(^(0){1}$)|(^[0-9]\.[0-9]([0-9])?$)/.test(str);
} }
return /(^[1-9](\d+)?(\.\d{1,2})?$)|(^\d\.\d{1,2}$)/.test(str); return /(^[1-9](\d+)?(\.\d{1,2})?$)|(^\d\.\d{1,2}$)/.test(str);

View File

@ -1,6 +1,6 @@
{ {
"name": "oak-domain", "name": "oak-domain",
"version": "2.6.3", "version": "2.6.4",
"author": { "author": {
"name": "XuChang" "name": "XuChang"
}, },
@ -27,6 +27,7 @@
"@types/luxon": "^2.0.9", "@types/luxon": "^2.0.9",
"@types/mocha": "^8.2.0", "@types/mocha": "^8.2.0",
"@types/node": "^14.14.25", "@types/node": "^14.14.25",
"@types/node-schedule": "^2.1.0",
"@types/react": "^17.0.2", "@types/react": "^17.0.2",
"@types/uuid": "^8.3.0", "@types/uuid": "^8.3.0",
"@types/wechat-miniprogram": "^3.4.1", "@types/wechat-miniprogram": "^3.4.1",
@ -40,9 +41,9 @@
"typescript": "^4.7.4" "typescript": "^4.7.4"
}, },
"dependencies": { "dependencies": {
"@datasert/cronjs-matcher": "^1.2.0",
"dayjs": "^1.11.5", "dayjs": "^1.11.5",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"node-schedule": "^2.1.1",
"uuid": "^9.0.0" "uuid": "^9.0.0"
} }
} }

View File

@ -1642,7 +1642,8 @@ function constructFilter(statements: Array<ts.Statement>, entity: string) {
case 'Int': case 'Int':
case 'Uint': case 'Uint':
case 'Float': case 'Float':
case 'Double': { case 'Double':
case 'Price': {
type2 = factory.createTypeReferenceNode( type2 = factory.createTypeReferenceNode(
factory.createIdentifier('Q_NumberValue'), factory.createIdentifier('Q_NumberValue'),
); );
@ -1897,7 +1898,8 @@ function constructProjection(statements: Array<ts.Statement>, entity: string) {
case 'File': case 'File':
case 'SingleGeo': case 'SingleGeo':
case 'Geo': case 'Geo':
case 'Object': { case 'Object':
case 'Price': {
properties.push( properties.push(
[name, false] [name, false]
) )
@ -2410,7 +2412,8 @@ function constructSorter(statements: Array<ts.Statement>, entity: string) {
case 'Boolean': case 'Boolean':
case 'Datetime': case 'Datetime':
case 'Image': case 'Image':
case 'File': { case 'File':
case 'Price': {
type2 = factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword); type2 = factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword);
break; break;
} }
@ -4417,6 +4420,11 @@ const initialStatements = () => [
undefined, undefined,
factory.createIdentifier('File') factory.createIdentifier('File')
), ),
factory.createImportSpecifier(
false,
undefined,
factory.createIdentifier('Price')
),
factory.createImportSpecifier( factory.createImportSpecifier(
false, false,
undefined, undefined,
@ -5332,40 +5340,16 @@ function constructAttributes(entity: string): ts.PropertyAssignment[] {
); );
break; break;
} }
case 'Float': { case 'Double':
attrAssignments.push( case 'Float':
factory.createPropertyAssignment( case 'Decimal': {
factory.createIdentifier("type"), if (['Double', 'Float'].includes(text)) {
factory.createStringLiteral("float") console.warn(`${entity}对象中还有${text}类型定义现在统一用Decimal进行存储`);
),
factory.createPropertyAssignment(
factory.createIdentifier("params"),
factory.createObjectLiteralExpression(
[
factory.createPropertyAssignment(
factory.createIdentifier("precision"),
factory.createNumericLiteral(
(<ts.NumericLiteral>(<ts.LiteralTypeNode>typeArguments![0]).literal).text
)
),
factory.createPropertyAssignment(
factory.createIdentifier("scale"),
factory.createNumericLiteral(
(<ts.NumericLiteral>(<ts.LiteralTypeNode>typeArguments![1]).literal).text
)
)
],
true
)
)
);
break;
} }
case 'Double': {
attrAssignments.push( attrAssignments.push(
factory.createPropertyAssignment( factory.createPropertyAssignment(
factory.createIdentifier("type"), factory.createIdentifier("type"),
factory.createStringLiteral("double") factory.createStringLiteral("decimal")
), ),
factory.createPropertyAssignment( factory.createPropertyAssignment(
factory.createIdentifier("params"), factory.createIdentifier("params"),
@ -5399,6 +5383,15 @@ function constructAttributes(entity: string): ts.PropertyAssignment[] {
); );
break; break;
} }
case 'Price': {
attrAssignments.push(
factory.createPropertyAssignment(
factory.createIdentifier("type"),
factory.createStringLiteral("money")
),
);
break;
}
case 'Datetime': { case 'Datetime': {
attrAssignments.push( attrAssignments.push(
factory.createPropertyAssignment( factory.createPropertyAssignment(

View File

@ -43,6 +43,7 @@ const locale: LocaleDef<Schema, Action, '', {
iState: IState, iState: IState,
}> = { }> = {
zh_CN: { zh_CN: {
name: '更新',
attr: { attr: {
targetEntity: '目标对象', targetEntity: '目标对象',
entity: '关联对象', entity: '关联对象',

View File

@ -15,6 +15,7 @@ const config: Configuration = {
const locale: LocaleDef<Schema, '', '', {}> = { const locale: LocaleDef<Schema, '', '', {}> = {
zh_CN: { zh_CN: {
name: '更新对象连接',
attr: { attr: {
modi: '更新', modi: '更新',
entity: '关联对象', entity: '关联对象',

View File

@ -17,6 +17,7 @@ const configuration: Configuration = {
const locale: LocaleDef<Schema, '', '', {}> = { const locale: LocaleDef<Schema, '', '', {}> = {
zh_CN: { zh_CN: {
name: '操作',
attr: { attr: {
action: '动作', action: '动作',
data: '数据', data: '数据',

View File

@ -15,6 +15,7 @@ const config: Configuration = {
const locale: LocaleDef<Schema, '', '', {}> = { const locale: LocaleDef<Schema, '', '', {}> = {
zh_CN: { zh_CN: {
name: '操作对象连接',
attr: { attr: {
oper: '操作', oper: '操作',
entity: '关联对象', entity: '关联对象',

View File

@ -25,6 +25,7 @@ const locale: LocaleDef<Schema, Action, '', {
userState: UserState; userState: UserState;
}> = { }> = {
zh_CN: { zh_CN: {
name: '用户',
attr: { attr: {
name: '姓名', name: '姓名',
nickname: '昵称', nickname: '昵称',

View File

@ -15,6 +15,7 @@ const locale: LocaleDef<
{} {}
> = { > = {
zh_CN: { zh_CN: {
name: '用户授权',
attr: { attr: {
relation: '关系', relation: '关系',
entity: '关联对象', entity: '关联对象',

View File

@ -70,21 +70,23 @@ export abstract class AsyncContext<ED extends EntityDict> implements Context {
if (this.uuid) { if (this.uuid) {
await this.rowStore.commit(this.uuid!); await this.rowStore.commit(this.uuid!);
this.uuid = undefined; this.uuid = undefined;
for(const e of this.events.commit) { const { commit: commitEvents } = this.events;
this.resetEvents();
for (const e of commitEvents) {
await e(); await e();
} }
this.resetEvents();
} }
} }
async rollback(): Promise<void> { async rollback(): Promise<void> {
if(this.uuid) { if (this.uuid) {
await this.rowStore.rollback(this.uuid!); await this.rowStore.rollback(this.uuid!);
// console.log('rollback', this.uuid); // console.log('rollback', this.uuid);
this.uuid = undefined; this.uuid = undefined;
for(const e of this.events.rollback) { const { rollback: rollbackEvents } = this.events;
this.resetEvents();
for (const e of rollbackEvents) {
await e(); await e();
} }
this.resetEvents();
} }
} }
@ -95,21 +97,21 @@ export abstract class AsyncContext<ED extends EntityDict> implements Context {
) { ) {
return this.rowStore.operate(entity, operation, this, option); return this.rowStore.operate(entity, operation, this, option);
} }
select<T extends keyof ED, OP extends SelectOption> ( select<T extends keyof ED, OP extends SelectOption>(
entity: T, entity: T,
selection: ED[T]['Selection'], selection: ED[T]['Selection'],
option: OP option: OP
) { ) {
return this.rowStore.select(entity, selection, this, option); return this.rowStore.select(entity, selection, this, option);
} }
aggregate<T extends keyof ED, OP extends SelectOption> ( aggregate<T extends keyof ED, OP extends SelectOption>(
entity: T, entity: T,
aggregation: ED[T]['Aggregation'], aggregation: ED[T]['Aggregation'],
option: OP option: OP
) { ) {
return this.rowStore.aggregate(entity, aggregation, this, option); return this.rowStore.aggregate(entity, aggregation, this, option);
} }
count<T extends keyof ED, OP extends SelectOption> ( count<T extends keyof ED, OP extends SelectOption>(
entity: T, entity: T,
selection: Pick<ED[T]['Selection'], 'filter' | 'count'>, selection: Pick<ED[T]['Selection'], 'filter' | 'count'>,
option: OP option: OP
@ -154,21 +156,21 @@ export interface AsyncRowStore<ED extends EntityDict, Cxt extends Context> exten
option: OP option: OP
): Promise<OperationResult<ED>>; ): Promise<OperationResult<ED>>;
select<T extends keyof ED, OP extends SelectOption> ( select<T extends keyof ED, OP extends SelectOption>(
entity: T, entity: T,
selection: ED[T]['Selection'], selection: ED[T]['Selection'],
context: Cxt, context: Cxt,
option: OP option: OP
): Promise<Partial<ED[T]['Schema']>[]>; ): Promise<Partial<ED[T]['Schema']>[]>;
aggregate<T extends keyof ED, OP extends SelectOption> ( aggregate<T extends keyof ED, OP extends SelectOption>(
entity: T, entity: T,
aggregation: ED[T]['Aggregation'], aggregation: ED[T]['Aggregation'],
context: Cxt, context: Cxt,
option: OP option: OP
): Promise<AggregationResult<ED[T]['Schema']>>; ): Promise<AggregationResult<ED[T]['Schema']>>;
count<T extends keyof ED, OP extends SelectOption> ( count<T extends keyof ED, OP extends SelectOption>(
entity: T, entity: T,
selection: Pick<ED[T]['Selection'], 'filter' | 'count'>, selection: Pick<ED[T]['Selection'], 'filter' | 'count'>,
context: Cxt, context: Cxt,

View File

@ -841,7 +841,7 @@ export abstract class CascadeStore<ED extends EntityDict & BaseEntityDict> exten
data: opData, data: opData,
beforeFns, beforeFns,
afterFns, afterFns,
}; };
} }
// 对插入的数据没有初始值的属性置null // 对插入的数据没有初始值的属性置null
@ -870,7 +870,7 @@ export abstract class CascadeStore<ED extends EntityDict & BaseEntityDict> exten
else { else {
processSingle(data as ED[T]['CreateSingle']['data']); processSingle(data as ED[T]['CreateSingle']['data']);
} }
} }
// 对更新的数据去掉所有的undefined属性 // 对更新的数据去掉所有的undefined属性
protected preProcessDataUpdated(data: Record<string, any>) { protected preProcessDataUpdated(data: Record<string, any>) {
@ -880,12 +880,12 @@ export abstract class CascadeStore<ED extends EntityDict & BaseEntityDict> exten
undefinedKeys.forEach( undefinedKeys.forEach(
ele => unset(data, ele) ele => unset(data, ele)
); );
} }
judgeRelation(entity: keyof ED, attr: string) { judgeRelation(entity: keyof ED, attr: string) {
return judgeRelation(this.storageSchema, entity, attr); return judgeRelation(this.storageSchema, entity, attr);
} }
/** /**
* update过程无关的例程放在这里later动作的处理oper的记录以及对record的收集等 * update过程无关的例程放在这里later动作的处理oper的记录以及对record的收集等
@ -898,7 +898,7 @@ judgeRelation(entity: keyof ED, attr: string) {
operation: ED[T]['CreateSingle'] | ED[T]['Update'] | ED[T]['Remove'], operation: ED[T]['CreateSingle'] | ED[T]['Update'] | ED[T]['Remove'],
context: Cxt, context: Cxt,
option: OP option: OP
) { ) {
const { data, action, id: operId, filter } = operation; const { data, action, id: operId, filter } = operation;
const now = Date.now(); const now = Date.now();
@ -1268,13 +1268,13 @@ judgeRelation(entity: keyof ED, attr: string) {
} }
} }
} }
} }
private doUpdateSingleRow<T extends keyof ED, OP extends OperateOption, Cxt extends SyncContext<ED>>(entity: T, private doUpdateSingleRow<T extends keyof ED, OP extends OperateOption, Cxt extends SyncContext<ED>>(entity: T,
operation: ED[T]['Operation'], operation: ED[T]['Operation'],
context: Cxt, context: Cxt,
option: OP option: OP
) { ) {
const { data, action, id: operId, filter } = operation; const { data, action, id: operId, filter } = operation;
const now = Date.now(); const now = Date.now();
@ -1337,21 +1337,21 @@ judgeRelation(entity: keyof ED, attr: string) {
return this.updateAbjointRow(entity, operation, context, option); return this.updateAbjointRow(entity, operation, context, option);
} }
} }
} }
protected cascadeUpdate<T extends keyof ED, Cxt extends SyncContext<ED>, OP extends OperateOption>( protected cascadeUpdate<T extends keyof ED, Cxt extends SyncContext<ED>, OP extends OperateOption>(
entity: T, entity: T,
operation: ED[T]['Operation'], operation: ED[T]['Operation'],
context: Cxt, context: Cxt,
option: OP): OperationResult < ED > { option: OP): OperationResult<ED> {
reinforceOperation(this.getSchema(), entity, operation); reinforceOperation(this.getSchema(), entity, operation);
const { action, data, filter, id } = operation; const { action, data, filter, id } = operation;
let opData: any; let opData: any;
const wholeBeforeFns: Array<() => any> =[]; const wholeBeforeFns: Array<() => any> = [];
const wholeAfterFns: Array<() => any> = []; const wholeAfterFns: Array<() => any> = [];
const result: OperationResult<ED> = {}; const result: OperationResult<ED> = {};
if (['create', 'create-l'].includes(action) && data instanceof Array) { if (['create', 'create-l'].includes(action) && data instanceof Array) {
opData = []; opData = [];
for (const d of data) { for (const d of data) {
const { data: od, beforeFns, afterFns } = this.destructCascadeUpdate( const { data: od, beforeFns, afterFns } = this.destructCascadeUpdate(
@ -1366,8 +1366,8 @@ if (['create', 'create-l'].includes(action) && data instanceof Array) {
wholeBeforeFns.push(...beforeFns); wholeBeforeFns.push(...beforeFns);
wholeAfterFns.push(...afterFns); wholeAfterFns.push(...afterFns);
} }
} }
else { else {
const { data: od, beforeFns, afterFns } = this.destructCascadeUpdate( const { data: od, beforeFns, afterFns } = this.destructCascadeUpdate(
entity, entity,
action, action,
@ -1380,21 +1380,21 @@ else {
opData = od; opData = od;
wholeBeforeFns.push(...beforeFns); wholeBeforeFns.push(...beforeFns);
wholeAfterFns.push(...afterFns); wholeAfterFns.push(...afterFns);
} }
const operation2: ED[T]['CreateSingle'] | ED[T]['Update'] | ED[T]['Remove'] = const operation2: ED[T]['CreateSingle'] | ED[T]['Update'] | ED[T]['Remove'] =
Object.assign({}, operation as ED[T]['CreateSingle'] | ED[T]['Update'] | ED[T]['Remove'], { Object.assign({}, operation as ED[T]['CreateSingle'] | ED[T]['Update'] | ED[T]['Remove'], {
data: opData as ED[T]['OpSchema'], data: opData as ED[T]['OpSchema'],
}); });
for (const before of wholeBeforeFns) { for (const before of wholeBeforeFns) {
before(); before();
} }
const count = this.doUpdateSingleRow(entity, operation2, context, option); const count = this.doUpdateSingleRow(entity, operation2, context, option);
for (const after of wholeAfterFns) { for (const after of wholeAfterFns) {
after(); after();
} }
return result; return result;
} }
/** /**
@ -1408,15 +1408,15 @@ return result;
entity: T, entity: T,
operation: ED[T]['Operation'], operation: ED[T]['Operation'],
context: Cxt, context: Cxt,
option: OP): Promise < OperationResult < ED >> { option: OP): Promise<OperationResult<ED>> {
reinforceOperation(this.getSchema(), entity, operation); reinforceOperation(this.getSchema(), entity, operation);
const { action, data, filter, id } = operation; const { action, data, filter, id } = operation;
let opData: any; let opData: any;
const wholeBeforeFns: Array<() => Promise<any>> =[]; const wholeBeforeFns: Array<() => Promise<any>> = [];
const wholeAfterFns: Array<() => Promise<any>> = []; const wholeAfterFns: Array<() => Promise<any>> = [];
const result: OperationResult<ED> = {}; const result: OperationResult<ED> = {};
if (['create', 'create-l'].includes(action) && data instanceof Array) { if (['create', 'create-l'].includes(action) && data instanceof Array) {
opData = []; opData = [];
for (const d of data) { for (const d of data) {
const { data: od, beforeFns, afterFns } = this.destructCascadeUpdate( const { data: od, beforeFns, afterFns } = this.destructCascadeUpdate(
@ -1431,8 +1431,8 @@ if (['create', 'create-l'].includes(action) && data instanceof Array) {
wholeBeforeFns.push(...beforeFns); wholeBeforeFns.push(...beforeFns);
wholeAfterFns.push(...afterFns); wholeAfterFns.push(...afterFns);
} }
} }
else { else {
const { data: od, beforeFns, afterFns } = this.destructCascadeUpdate( const { data: od, beforeFns, afterFns } = this.destructCascadeUpdate(
entity, entity,
action, action,
@ -1445,33 +1445,33 @@ else {
opData = od; opData = od;
wholeBeforeFns.push(...beforeFns); wholeBeforeFns.push(...beforeFns);
wholeAfterFns.push(...afterFns); wholeAfterFns.push(...afterFns);
} }
const operation2: ED[T]['CreateSingle'] | ED[T]['Update'] | ED[T]['Remove'] = const operation2: ED[T]['CreateSingle'] | ED[T]['Update'] | ED[T]['Remove'] =
Object.assign({}, operation as ED[T]['CreateSingle'] | ED[T]['Update'] | ED[T]['Remove'], { Object.assign({}, operation as ED[T]['CreateSingle'] | ED[T]['Update'] | ED[T]['Remove'], {
data: opData as ED[T]['OpSchema'], data: opData as ED[T]['OpSchema'],
}); });
for (const before of wholeBeforeFns) { for (const before of wholeBeforeFns) {
await before(); await before();
} }
const count = await this.doUpdateSingleRowAsync(entity, operation2, context, option); const count = await this.doUpdateSingleRowAsync(entity, operation2, context, option);
this.mergeOperationResult(result, { this.mergeOperationResult(result, {
[entity]: { [entity]: {
[operation2.action]: count, [operation2.action]: count,
} }
} as OperationResult<ED>); } as OperationResult<ED>);
for (const after of wholeAfterFns) { for (const after of wholeAfterFns) {
await after(); await after();
} }
return result; return result;
} }
protected cascadeSelect<T extends keyof ED, OP extends SelectOption, Cxt extends SyncContext<ED>>( protected cascadeSelect<T extends keyof ED, OP extends SelectOption, Cxt extends SyncContext<ED>>(
entity: T, entity: T,
selection: ED[T]['Selection'], selection: ED[T]['Selection'],
context: Cxt, context: Cxt,
option: OP): Partial < ED[T]['Schema'] > [] { option: OP): Partial<ED[T]['Schema']>[] {
reinforceSelection(this.getSchema(), entity, selection); reinforceSelection(this.getSchema(), entity, selection);
const { data, filter, indexFrom, count, sorter } = selection; const { data, filter, indexFrom, count, sorter } = selection;
const { projection, cascadeSelectionFns } = this.destructCascadeSelect( const { projection, cascadeSelectionFns } = this.destructCascadeSelect(
@ -1519,7 +1519,7 @@ return result;
} }
return rows; return rows;
} }
/** /**
* result * result
@ -1528,7 +1528,7 @@ return result;
* @param rows * @param rows
* @param context * @param context
*/ */
private addToResultSelections<T extends keyof ED, Cxt extends AsyncContext<ED>>(entity: T, rows: Partial < ED[T]['Schema'] > [], context: Cxt) { private addToResultSelections<T extends keyof ED, Cxt extends AsyncContext<ED>>(entity: T, rows: Partial<ED[T]['Schema']>[], context: Cxt) {
if (this.supportManyToOneJoin()) { if (this.supportManyToOneJoin()) {
const attrsToPick: string[] = []; const attrsToPick: string[] = [];
for (const attr in rows[0]) { for (const attr in rows[0]) {
@ -1555,9 +1555,9 @@ return result;
else { else {
this.addSingleRowToResultSelections(entity, rows, context); this.addSingleRowToResultSelections(entity, rows, context);
} }
} }
private addSingleRowToResultSelections<T extends keyof ED, Cxt extends AsyncContext<ED>>(entity: T, rows: Partial < ED[T]['OpSchema'] > [], context: Cxt) { private addSingleRowToResultSelections<T extends keyof ED, Cxt extends AsyncContext<ED>>(entity: T, rows: Partial<ED[T]['OpSchema']>[], context: Cxt) {
const { opRecords } = context; const { opRecords } = context;
let lastOperation = opRecords[opRecords.length - 1]; let lastOperation = opRecords[opRecords.length - 1];
@ -1605,13 +1605,13 @@ return result;
Object.assign(lastOperation.d, { Object.assign(lastOperation.d, {
[entity]: entityBranch, [entity]: entityBranch,
}); });
} }
protected async cascadeSelectAsync<T extends keyof ED, OP extends SelectOption, Cxt extends AsyncContext<ED>>( protected async cascadeSelectAsync<T extends keyof ED, OP extends SelectOption, Cxt extends AsyncContext<ED>>(
entity: T, entity: T,
selection: ED[T]['Selection'], selection: ED[T]['Selection'],
context: Cxt, context: Cxt,
option: OP): Promise < Partial < ED[T]['Schema'] > [] > { option: OP): Promise<Partial<ED[T]['Schema']>[]> {
reinforceSelection(this.getSchema(), entity, selection); reinforceSelection(this.getSchema(), entity, selection);
const { data, filter, indexFrom, count, sorter } = selection; const { data, filter, indexFrom, count, sorter } = selection;
const { projection, cascadeSelectionFns } = this.destructCascadeSelect( const { projection, cascadeSelectionFns } = this.destructCascadeSelect(
@ -1631,11 +1631,11 @@ return result;
}, context, option); }, context, option);
if(!option.dontCollect) { if (!option.dontCollect) {
this.addToResultSelections(entity, rows, context); this.addToResultSelections(entity, rows, context);
} }
if (cascadeSelectionFns.length > 0) { if (cascadeSelectionFns.length > 0) {
const ruException: Array<{ const ruException: Array<{
entity: keyof ED, entity: keyof ED,
selection: ED[keyof ED]['Selection'] selection: ED[keyof ED]['Selection']
@ -1662,8 +1662,8 @@ if (cascadeSelectionFns.length > 0) {
if (ruException.length > 0) { if (ruException.length > 0) {
throw new OakRowUnexistedException(ruException); throw new OakRowUnexistedException(ruException);
} }
} }
return rows; return rows;
} }
} }

View File

@ -220,12 +220,22 @@ export function translateCheckerInSyncContext<
} }
} }
type FilterMakeFn<ED extends EntityDict & BaseEntityDict> = (operation: ED[keyof ED]['Operation'] | ED[keyof ED]['Selection'], userId: string) => ED[keyof ED]['Selection']['filter'] | { type CreateRelationSingleCounter<ED extends EntityDict & BaseEntityDict> = {
$entity: keyof ED; $entity: keyof ED;
$filter?: ED[keyof ED]['Selection']['filter']; $filter?: ED[keyof ED]['Selection']['filter'];
$count?: number; $count?: number;
}; };
type CreateRelationMultipleCounter<ED extends EntityDict & BaseEntityDict> = {
[K in '$$and' | '$$or']?: (CreateRelationSingleCounter<ED> | CreateRelationMultipleCounter<ED>)[];
}
type CreateRelationCounter<ED extends EntityDict & BaseEntityDict> = CreateRelationSingleCounter<ED> | CreateRelationMultipleCounter<ED>;
type FilterMakeFn<ED extends EntityDict & BaseEntityDict> =
(operation: ED[keyof ED]['Operation'] | ED[keyof ED]['Selection'], userId: string) => ED[keyof ED]['Selection']['filter'] | CreateRelationCounter<ED>;
function translateCascadeRelationFilterMaker<ED extends EntityDict & BaseEntityDict>( function translateCascadeRelationFilterMaker<ED extends EntityDict & BaseEntityDict>(
schema: StorageSchema<ED>, schema: StorageSchema<ED>,
lch: CascadeRelationItem, lch: CascadeRelationItem,
@ -315,12 +325,18 @@ function translateCascadeRelationFilterMaker<ED extends EntityDict & BaseEntityD
const filterMaker = paths.length ? translateFilterMakerIter(entity2, 0) : translateRelationFilter(entity2); const filterMaker = paths.length ? translateFilterMakerIter(entity2, 0) : translateRelationFilter(entity2);
if (!paths.length) { if (!paths.length) {
// 不可能是create
return (oper, userId) => filterMaker(userId); return (oper, userId) => filterMaker(userId);
} }
/** /**
* A指向对象BA的cascadePath是 'B' * A指向对象BA的cascadePath是 'B'
* create A时BidB对象上的相关表达式查询返回 * create A时BidB对象上的相关表达式查询返回
* 使A时Bid * 使A时Bid
*
* 20230306:
* list上的filter当成内在的限制对create动作进行判断filter并不能直接判断出外键
* jichuang项目中park/list上访{ system: { platformId: 1 }}system.platform.platformProvider上
* data上的外键判断就会失败filter上相应的语义解构
*/ */
const [attr] = paths; const [attr] = paths;
const relation = judgeRelation(schema, entity2, attr); const relation = judgeRelation(schema, entity2, attr);
@ -328,14 +344,92 @@ function translateCascadeRelationFilterMaker<ED extends EntityDict & BaseEntityD
const filterMaker2 = paths.length > 1 const filterMaker2 = paths.length > 1
? (relation === 2 ? translateFilterMakerIter(attr, 1) : translateFilterMakerIter(relation, 1)) ? (relation === 2 ? translateFilterMakerIter(attr, 1) : translateFilterMakerIter(relation, 1))
: (relation === 2 ? translateRelationFilter(attr) : translateRelationFilter(relation)); : (relation === 2 ? translateRelationFilter(attr) : translateRelationFilter(relation));
const translateCreateFilterMaker = (
entity: keyof ED,
filter: ED[keyof ED]['Selection']['filter'],
userId: string
): CreateRelationCounter<ED> | OakUserUnpermittedException<ED> => {
const counters: CreateRelationCounter<ED>[] = [];
if (filter) {
if (relation === 2) {
if (filter.entity === entity && filter.entityId) {
// 这里对entityId的限定的数据只要和userId有一条relation就不能否定可能会有创建动作外键在最终create时data上一定会有判定
counters.push({
$entity: attr,
$filter: addFilterSegment(filterMaker2(userId), { id: filter.entityId }),
});
}
if (filter[attr]) {
counters.push({
$entity: attr,
$filter: addFilterSegment(filterMaker2(userId), filter[attr]),
});
}
}
else {
assert(typeof relation === 'string');
if (filter[`${attr}Id`]) {
const filterMaker3 = paths.length > 1 ? translateFilterMakerIter(relation, 1) : translateRelationFilter(relation);
// 这里对attrId的限定的数据只要和userId有一条relation就不能否定可能会有创建动作外键在最终create时data上一定会有判定
counters.push({
$entity: relation,
$filter: addFilterSegment(filterMaker3(userId), { id: filter[`${attr}Id`] }),
});
}
if (filter[attr]) {
counters.push({
$entity: relation,
$filter: addFilterSegment(filterMaker2(userId), filter[attr]),
});
}
}
if (filter.$and) {
const countersAnd = filter.$and.map(
(ele: ED[keyof ED]['Selection']['filter']) => translateCreateFilterMaker(entity, ele, userId)
) as ReturnType<typeof translateCreateFilterMaker>[];
// and 只要有一个满足就行
const ca2 = countersAnd.filter(
ele => !(ele instanceof OakUserUnpermittedException)
) as CreateRelationCounter<ED>[];
counters.push(...ca2);
}
if (filter.$or) {
const countersOr = filter.$and.map(
(ele: ED[keyof ED]['Selection']['filter']) => translateCreateFilterMaker(entity, ele, userId)
) as ReturnType<typeof translateCreateFilterMaker>[];
// or也只要有一个满足就行不能否定
const co2 = countersOr.filter(
ele => !(ele instanceof OakUserUnpermittedException)
) as CreateRelationCounter<ED>[];
counters.push(...co2);
}
}
if (counters.length === 0) {
// 一个counter都找不出来说明当前路径上不满足
return new OakUserUnpermittedException();
}
else if (counters.length === 1) {
return counters[0];
}
// 是or关系只要其中有一个满足就可以通过
return {
$$or: counters,
};
};
return (operation, userId) => { return (operation, userId) => {
const { action } = operation as ED[keyof ED]['Operation']; const { action } = operation as ED[keyof ED]['Operation'];
if (action === 'create') { if (action === 'create') {
const { data } = operation as ED[keyof ED]['Create']; const { data } = operation as ED[keyof ED]['Create'];
if (data) {
// 有data的情形根据data判定
const getForeignKeyId = (d: ED[keyof ED]['CreateSingle']['data']) => { const getForeignKeyId = (d: ED[keyof ED]['CreateSingle']['data']) => {
if (relation === 2) { if (relation === 2) {
if (d.entity === attr && typeof d.entityId === 'string') { if (d.entity === attr && typeof d.entityId === 'string') {
return d.entitId as string; return d.entityId as string;
} }
throw new OakUserUnpermittedException(); throw new OakUserUnpermittedException();
} }
@ -377,6 +471,19 @@ function translateCascadeRelationFilterMaker<ED extends EntityDict & BaseEntityD
$filter: addFilterSegment(filterMaker2(userId), { id: fkId }), $filter: addFilterSegment(filterMaker2(userId), { id: fkId }),
}; };
} }
else {
// todo
const { filter } = operation as ED[keyof ED]['Selection'];
if (filter) {
const counter = translateCreateFilterMaker(entity2, filter, userId);
if (counter instanceof OakUserUnpermittedException) {
throw counter;
}
return counter;
}
throw new OakUserUnpermittedException();
}
}
const { filter } = operation; const { filter } = operation;
if (relation === 2 && filter?.entity === attr && filter?.entityId) { if (relation === 2 && filter?.entity === attr && filter?.entityId) {
if (typeof filter.entityId === 'string') { if (typeof filter.entityId === 'string') {
@ -437,7 +544,94 @@ function translateActionAuthFilterMaker<ED extends EntityDict & BaseEntityDict>(
return filterMaker; return filterMaker;
} }
function makePotentialFilter<ED extends EntityDict & BaseEntityDict, Cxt extends AsyncContext<ED> | SyncContext<ED>> ( function execCreateCounter<ED extends EntityDict & BaseEntityDict, Cxt extends AsyncContext<ED> | SyncContext<ED>>(
context: Cxt,
counter: CreateRelationCounter<ED>,
): SyncOrAsync<undefined | OakUserUnpermittedException<ED>> {
if ((<CreateRelationMultipleCounter<ED>>counter)?.$$and) {
// 每个counter都要满足才能过
const counters = (<CreateRelationMultipleCounter<ED>>counter)?.$$and!;
assert(counters.length > 0);
const counterResults = counters.map(
ele => execCreateCounter(context, ele)
);
if (counterResults[0] instanceof Promise) {
return Promise.all(counterResults)
.then(
(cr2) => {
const unpermitted = cr2.find(
(ele) => ele instanceof OakUserUnpermittedException
);
if (unpermitted) {
return unpermitted;
}
return undefined;
}
);
}
else {
const unpermitted = counterResults.find(
(ele) => ele instanceof OakUserUnpermittedException
);
if (unpermitted) {
return unpermitted;
}
else {
return undefined;
}
}
}
else if ((<CreateRelationMultipleCounter<ED>>counter)?.$$or) {
// 只要有一个counter能过就算过
const counters = (<CreateRelationMultipleCounter<ED>>counter)?.$$or!;
assert(counters.length > 0);
const counterResults = counters.map(
ele => execCreateCounter(context, ele)
);
if (counterResults[0] instanceof Promise) {
return Promise.all(counterResults)
.then(
(cr2) => {
const permittedIdx = cr2.indexOf(undefined);
if (permittedIdx !== -1) {
return undefined;
}
return new OakUserUnpermittedException();
}
);
}
else {
const permittedIndex = counterResults.indexOf(undefined);
if (permittedIndex !== -1) {
return undefined;
}
else {
return new OakUserUnpermittedException();
}
}
}
else if ((<CreateRelationSingleCounter<ED>>counter)?.$entity) {
const { $entity, $filter, $count = 1 } = counter as CreateRelationSingleCounter<ED>;
const count = context.count($entity, {
filter: $filter,
}, { dontCollect: true });
if (count instanceof Promise) {
return count.then(
(c2) => {
if (c2 >= $count) {
return undefined;
}
return new OakUserUnpermittedException();
}
);
}
else {
return count >= $count ? undefined : new OakUserUnpermittedException();
}
}
}
function makePotentialFilter<ED extends EntityDict & BaseEntityDict, Cxt extends AsyncContext<ED> | SyncContext<ED>>(
operation: ED[keyof ED]['Operation'] | ED[keyof ED]['Selection'], operation: ED[keyof ED]['Operation'] | ED[keyof ED]['Selection'],
context: Cxt, context: Cxt,
filterMaker: FilterMakeFn<ED> | (FilterMakeFn<ED> | FilterMakeFn<ED>[])[]): SyncOrAsync<ED[keyof ED]['Selection']['filter']> { filterMaker: FilterMakeFn<ED> | (FilterMakeFn<ED> | FilterMakeFn<ED>[])[]): SyncOrAsync<ED[keyof ED]['Selection']['filter']> {
@ -466,30 +660,17 @@ function makePotentialFilter<ED extends EntityDict & BaseEntityDict, Cxt extends
let isAsyncOr = false; let isAsyncOr = false;
for (const f of filters) { for (const f of filters) {
if (f instanceof Array) { if (f instanceof Array) {
let isAsyncAnd = true; let isAsyncAnd = false;
assert(f.length > 0);
const filtersAnd: (SyncOrAsync<ED[keyof ED]['Selection']['filter'] | OakUserUnpermittedException<ED>>)[] = []; const filtersAnd: (SyncOrAsync<ED[keyof ED]['Selection']['filter'] | OakUserUnpermittedException<ED>>)[] = [];
for (const ff of f) { for (const ff of f) {
if (ff?.$entity) { if ((<CreateRelationMultipleCounter<ED>>ff)?.$$and || (<CreateRelationMultipleCounter<ED>>ff)?.$$or || (<CreateRelationSingleCounter<ED>>ff)?.$entity) {
const { $entity, $filter, $count = 1 } = ff!; // 每个counter都要满足才能过
const count = context.count($entity, { const result = execCreateCounter<ED, Cxt>(context, ff as CreateRelationMultipleCounter<ED>);
filter: $filter, if (result instanceof Promise) {
}, {});
if (count instanceof Promise) {
isAsyncAnd = true; isAsyncAnd = true;
filtersAnd.push(
count.then(
(c2) => {
if (c2 >= $count) {
return undefined;
}
return new OakUserUnpermittedException();
}
)
);
}
else {
filtersAnd.push(count >= $count ? undefined : new OakUserUnpermittedException());
} }
filtersAnd.push(result);
} }
else if (ff) { else if (ff) {
filtersAnd.push(ff as ED[keyof ED]['Selection']['filter']); filtersAnd.push(ff as ED[keyof ED]['Selection']['filter']);
@ -520,22 +701,12 @@ function makePotentialFilter<ED extends EntityDict & BaseEntityDict, Cxt extends
} }
} }
else { else {
if (f?.$entity) { if ((<CreateRelationMultipleCounter<ED>>f)?.$$and || (<CreateRelationMultipleCounter<ED>>f)?.$$or || (<CreateRelationSingleCounter<ED>>f)?.$entity) {
const { $entity, $filter, $count = 1 } = f!; const counterResults = execCreateCounter<ED, Cxt>(context, f as CreateRelationCounter<ED>);
const count = context.count($entity, { if (counterResults instanceof Promise) {
filter: $filter,
}, {});
if (count instanceof Promise) {
isAsyncOr = true; isAsyncOr = true;
filtersOr.push(
count.then(
(c2) => c2 >= $count ? undefined : new OakUserUnpermittedException()
)
);
}
else {
filtersOr.push(count >= $count ? undefined : new OakUserUnpermittedException());
} }
filtersOr.push(counterResults);
} }
else if (f) { else if (f) {
filtersOr.push(f as ED[keyof ED]['Selection']['filter']); filtersOr.push(f as ED[keyof ED]['Selection']['filter']);
@ -584,11 +755,26 @@ export function createAuthCheckers<ED extends EntityDict & BaseEntityDict, Cxt e
if (relationAuth) { if (relationAuth) {
const raFilterMakerDict = {} as Record<string, FilterMakeFn<ED> | (FilterMakeFn<ED> | FilterMakeFn<ED>[])[]>; const raFilterMakerDict = {} as Record<string, FilterMakeFn<ED> | (FilterMakeFn<ED> | FilterMakeFn<ED>[])[]>;
const userEntityName = `user${firstLetterUpperCase(entity)}`; const userEntityName = `user${firstLetterUpperCase(entity)}`;
const allAuthItem: (CascadeRelationItem | CascadeRelationItem[])[] = [];
for (const r in relationAuth) { for (const r in relationAuth) {
const authItem = relationAuth[r as NonNullable<ED[keyof ED]['Relation']>]!;
Object.assign(raFilterMakerDict, { Object.assign(raFilterMakerDict, {
[r]: translateActionAuthFilterMaker(schema, relationAuth[r as NonNullable<ED[keyof ED]['Relation']>]!, userEntityName, entity), [r]: translateActionAuthFilterMaker(schema, authItem, userEntityName, entity),
}); });
if (authItem instanceof Array) {
allAuthItem.push(...authItem);
} }
else {
allAuthItem.push(authItem);
}
}
// 如果不指定relation则使用所有的authItem的or组合
Object.assign(raFilterMakerDict, {
'@@all': translateActionAuthFilterMaker(schema, allAuthItem, userEntityName, entity),
});
const entityIdAttr = `${entity}Id`; const entityIdAttr = `${entity}Id`;
checkers.push({ checkers.push({
entity: userEntityName as keyof ED, entity: userEntityName as keyof ED,
@ -598,8 +784,12 @@ export function createAuthCheckers<ED extends EntityDict & BaseEntityDict, Cxt e
const { data } = operation as ED[keyof ED]['Create']; const { data } = operation as ED[keyof ED]['Create'];
assert(!(data instanceof Array)); assert(!(data instanceof Array));
const { relation, [entityIdAttr]: entityId } = data; const { relation, [entityIdAttr]: entityId } = data;
if (!relation) {
// 不指定relation测试是否有创建权限
return makePotentialFilter(operation, context, raFilterMakerDict['@@all']);
}
if (!raFilterMakerDict[relation]) { if (!raFilterMakerDict[relation]) {
return; throw new OakUserUnpermittedException();
} }
const filter = makePotentialFilter(operation, context, raFilterMakerDict[relation]); const filter = makePotentialFilter(operation, context, raFilterMakerDict[relation]);

View File

@ -9,13 +9,17 @@ export type Text = string;
export type Image = string; export type Image = string;
export type File = string; export type File = string;
export type Datetime = number | Date; export type Datetime = number | Date;
export type Day = number | Date;
export type Time = number | Date;
export type Boolean = boolean; export type Boolean = boolean;
export type Price = number;
export type PrimaryKey = string; export type PrimaryKey = string;
export type ForeignKey<E extends string> = string; export type ForeignKey<E extends string> = string;
export type Sequence = string; // 自增长序列为了让人阅读方便为了支持分布式这里用string底层实现可自定义 export type Sequence = string; // 自增长序列为了让人阅读方便为了支持分布式这里用string底层实现可自定义
export { Geo, SingleGeo } from './Geo'; export { Geo, SingleGeo } from './Geo';
export type DataTypes = number | string | Datetime | Geo | Object | SingleGeo; export type DataTypes = number | string | Datetime | Day | Time | Geo | Object | SingleGeo;
export const types = ['Int', 'Uint', 'Double', 'Float', 'String', 'Text', 'Datetime', 'Boolean', 'Image', 'File', 'Geo', 'SingleGeo']; export const types = ['Int', 'Uint', 'Double', 'Float', 'String', 'Text', 'Datetime', 'Day', 'Time',
'Boolean', 'Image', 'File', 'Geo', 'SingleGeo', 'Price'];
export const unIndexedTypes = ['Text', 'Image', 'File', 'Object']; export const unIndexedTypes = ['Text', 'Image', 'File', 'Object'];

View File

@ -18,6 +18,7 @@ type LocaleOfValue<V extends Record<string, string>> = {
export type LocaleDef<Sc extends Record<string, any>, Ac extends string, R extends string, V extends Record<string, string>> = { export type LocaleDef<Sc extends Record<string, any>, Ac extends string, R extends string, V extends Record<string, string>> = {
[L in Language]?: { [L in Language]?: {
name: string;
attr: LocaleOfSchema<Sc> & { attr: LocaleOfSchema<Sc> & {
[A in keyof V]: string; // 目前写在V里面的应该只有枚举变量和state [A in keyof V]: string; // 目前写在V里面的应该只有枚举变量和state
}; };

12
src/types/Style.ts Normal file
View File

@ -0,0 +1,12 @@
import { EntityDict } from './Entity';
import { EntityDict as BaseEntityDict } from '../base-app-domain';
type ThemeColor = 'default' | 'success' | 'warning' | 'error';
export type ColorDict<ED extends BaseEntityDict & EntityDict> = {
[T in keyof ED]?: {
[A in keyof ED[T]['OpSchema']]?: {
[E in ED[T]['OpSchema'][A]]?: ThemeColor | `#${string}`;
};
};
};

View File

@ -1,7 +1,10 @@
import { RecurrenceRule, RecurrenceSpecDateRange, RecurrenceSpecObjLit } from 'node-schedule';
import { EntityDict } from './Entity'; import { EntityDict } from './Entity';
import { AsyncContext } from "../store/AsyncRowStore"; import { AsyncContext } from '../store/AsyncRowStore';
type RoutineFn<ED extends EntityDict, Cxt extends AsyncContext<ED>> = (context: Cxt) => Promise<string>; type RoutineFn<ED extends EntityDict, Cxt extends AsyncContext<ED>> = (
context: Cxt
) => Promise<string>;
export type Routine<ED extends EntityDict, Cxt extends AsyncContext<ED>> = { export type Routine<ED extends EntityDict, Cxt extends AsyncContext<ED>> = {
name: string; name: string;
@ -10,6 +13,6 @@ export type Routine<ED extends EntityDict, Cxt extends AsyncContext<ED>> = {
export type Timer<ED extends EntityDict, Cxt extends AsyncContext<ED>> = { export type Timer<ED extends EntityDict, Cxt extends AsyncContext<ED>> = {
name: string; name: string;
cron: string; cron: RecurrenceRule | RecurrenceSpecDateRange | RecurrenceSpecObjLit | Date | string | number;
fn: RoutineFn<ED, Cxt>; fn: RoutineFn<ED, Cxt>;
}; };

View File

@ -19,3 +19,4 @@ export * from './Connector';
export * from './Timer'; export * from './Timer';
export * from './Port'; export * from './Port';
export * from './Endpoint'; export * from './Endpoint';
export * from './Style';

View File

@ -218,4 +218,6 @@ export interface DataTypeParams {
precision?: number; precision?: number;
scale?: number; scale?: number;
signed?: boolean; signed?: boolean;
max?: number;
min?: number;
}; };

View File

@ -10,7 +10,7 @@ function makeContentTypeAndBody(data: any) {
if (process.env.OAK_PLATFORM !== 'wechatMp') { if (process.env.OAK_PLATFORM !== 'wechatMp') {
if (data instanceof FormData) { if (data instanceof FormData) {
return { return {
contentType: 'multipart/form-data', // contentType: 'multipart/form-data',
body: data, body: data,
}; };
} }
@ -41,11 +41,15 @@ export class SimpleConnector<ED extends EntityDict, BackCxt extends AsyncContext
const { contentType, body } = makeContentTypeAndBody(params); const { contentType, body } = makeContentTypeAndBody(params);
const response = await global.fetch(this.serverUrl, { const response = await global.fetch(this.serverUrl, {
method: 'POST', method: 'POST',
headers: { headers: Object.assign(
'Content-Type': contentType, {
'oak-cxt': cxtStr, 'oak-cxt': cxtStr,
'oak-aspect': name as string, 'oak-aspect': name as string,
}, },
contentType && {
'Content-Type': contentType as string,
}
) as RequestInit['headers'],
body, body,
}); });
if (response.status > 299) { if (response.status > 299) {
@ -101,7 +105,7 @@ export class SimpleConnector<ED extends EntityDict, BackCxt extends AsyncContext
} }
serializeResult(result: any, context: BackCxt, headers: IncomingHttpHeaders, body: any): { body: any; headers?: Record<string, any> | undefined; } { serializeResult(result: any, context: BackCxt, headers: IncomingHttpHeaders, body: any): { body: any; headers?: Record<string, any> | undefined; } {
if (result instanceof Stream) { if (result instanceof Stream || result instanceof Buffer) {
return { return {
body: result, body: result,
}; };

View File

@ -1,17 +0,0 @@
import { getFutureMatches } from '@datasert/cronjs-matcher';
import DayJs from 'dayjs';
export function schedule(cron: string, fn: (date: Date) => any) {
const futureMatches = getFutureMatches(cron, {
matchCount: 1,
});
const date = DayJs(futureMatches[0]);
const interval = date.diff(DayJs(), 'ms');
setTimeout(
() => {
fn(new Date());
schedule(cron, fn);
},
interval
);
}

40
src/utils/mask.ts Normal file
View File

@ -0,0 +1,40 @@
const maskIdCard: (idCardNumber: string) => string = (idCardNumber) => {
if(!idCardNumber as any instanceof String) {
throw new Error("身份证号码必须是String类型");
}
let begin = idCardNumber.slice(0, 4);
let end = idCardNumber.slice(idCardNumber.length - 4, 4);
for(let i = 0; i < idCardNumber.length - 8; i ++) {
begin = begin.concat("*");
}
return begin.concat(end);
}
const maskMobile: (mobile: string) => string = (mobile) => {
let begin = mobile.slice(0, 3);
let end = mobile.slice(7, 11);
return begin.concat("****").concat(end);
}
const maskName: (name: string) => string = (name) => {
return name.slice(0, name.length - 1).concat("*");
}
const maskStar: (str: string, front: number, end: number, star: string) => string = (str, frontLen, endLen, star = '*') => {
const len = str.length - frontLen - endLen;
let xing = '';
for (let i = 0; i < len; i++) {
xing += star;
}
return str.substring(0, frontLen) + xing + str.substring(str.length - endLen);
}
export {
maskIdCard,
maskMobile,
maskName,
maskStar,
}

27
src/utils/money.ts Normal file
View File

@ -0,0 +1,27 @@
const ToCent: (float: number) => number = (float) => {
return Math.round(float * 100);
}
const ToYuan: (int: number) => number = ( int) => {
return Math.round(int) / 100;
}
const StringToCent: (value: string, allowNegative?: true) => number | undefined = (value, allowNegative) => {
const numValue = parseInt(value, 10);
if (typeof numValue === 'number' && (numValue >= 0 || allowNegative)) {
return ToCent(numValue);
}
}
const CentToString: (value: number) => string | undefined = (value) => {
if (typeof value === 'number') {
return `${ToYuan(value)}`;
}
}
export {
ToCent,
ToYuan,
StringToCent,
CentToString,
}

View File

@ -83,16 +83,26 @@ export const isPhone: ValidatorFunction = (phone) => {
return /^(\(\d{3,4}\)|\d{3,4}-)?\d{7,8}$/.test(phone); return /^(\(\d{3,4}\)|\d{3,4}-)?\d{7,8}$/.test(phone);
}; };
export const isTel: ValidatorFunction = (text) => {
// 1、133xxxx4545 2、0571-630xx239 3、400-123-1400
const reg =
/^(((\d{3,4}-)?[0-9]{7,8})|(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}|((400)-(\d{3})-(\d{4})(.)(\d{1,4})|(400)-(\d{3})-(\d{4}$)|(400)(\d{3})(\d{4}$)|(400)-(\d{4})-(\d{3}$)))$/.test(
text
);
return reg;
};
export const isNumber: ValidatorFunction = (str) => { export const isNumber: ValidatorFunction = (str) => {
return /^[0-9]*$/.test(str); return /^[0-9]*$/.test(str);
} }
export const isMoney: ValidatorMoneyFunction = (str, zero) => { export const isMoney: ValidatorMoneyFunction = (str, zero) => {
// zero为true包含零 // 金额,最多可以有两位小数 zero为true包含零
if (zero) { if (zero) {
// 金额,最多可以有两位小数 return /(^[1-9]([0-9]+)?(\.[0-9]{1,2})?$)|(^(0){1}$)|(^[0-9]\.[0-9]([0-9])?$)/.test(
return /(^[1-9]([0-9]+)?(\.[0-9]{1,2})?$)|(^(0){1}$)|(^[0-9]\.[0-9]([0-9])?$)/.test(str); str
);
} }
return /(^[1-9](\d+)?(\.\d{1,2})?$)|(^\d\.\d{1,2}$)/.test(str); return /(^[1-9](\d+)?(\.\d{1,2})?$)|(^\d\.\d{1,2}$)/.test(str);
} }