明树Git Lab

Commit 48325772 authored by sky_3509's avatar sky_3509

MysqlSearchProcessor.ts

parents
node_modules
dist
.vscode
\ No newline at end of file
{
"root": true,
"parser": "@typescript-eslint/parser",
"plugins": ["@typescript-eslint"],
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended"
],
"rules": {
"no-unused-vars": "off",
"prefer-const": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-unused-vars": "off",
"@typescript-eslint/no-empty-interface": "off",
"@typescript-eslint/no-empty-function": "off",
"no-console": 2 // 如果有console,会抛出错误
}
}
dist
DS_Store
.DS_Store
tsconfig.tsbuildinfo
node_modules/*
# Official framework image. Look for the different tagged releases at:
# https://hub.docker.com/r/library/node/tags/
# Pick zero or more services to be used on all builds.
# Only needed when using a docker container to run your tests in.
# Check out: http://docs.gitlab.com/ce/ci/docker/using_docker_images.html#what-is-a-service
# This folder is cached between builds
# http://docs.gitlab.com/ce/ci/yaml/README.html#cache
# 自动化测试,创建一个node docker 容器
test_automation:
image: harbor.bridata.com/library/node:12.01
stage: deploy
cache:
paths:
- node_modules/
script:
- npm install --registry https://registry.npmmirror.com
- npm run citest
when: always
environment:
name: dev
only:
- dev
tags:
- bridata-auto-testing
\ No newline at end of file
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Debug Typescript",
"skipFiles": [
"<node_internals>/**"
],
"program": "${workspaceFolder}/dist/bin.js",
"runtimeArgs": ["-r", "ts-node/register", "-r", "tsconfig-paths/register"],
"console": "integratedTerminal",
"outFiles": [
"${workspaceFolder}/**/*.js"
]
}
]
}
\ No newline at end of file
# 新TS项目创建步骤
1. 创建项目
2. 拷贝TS_BASIS下全部文件到文件夹,并正确运行。
3. 修改mw.ts, gvar.ts, routes下相关文件。
4. controllers, managers, models, services 注意使用base文件夹下的类继承,不要重复定义方法。
5. 如要修改核心内容,到TS_BASIS项目修改,然后运行node bcopy同步代码。
6. 使用import export模式。
7. controller和manager的参数动用一个params的对象,统一格式。
# 代码替换规则
1. 本地manager都从keyItem, compItem, appItem, IdItem四类继承。
1.1 class ResourceManager extends CompItemManager<ResourceDef>
1.2 可参考resource,file项目
2. cloudEnv获取参数修改位置,从remoteEnv获取
2.1 获取core redis的链接getRemoteRedisClient("core");
2.2 获取配置getRemoteConfigByKey("core");
3. 不再使用modBuildService之类的service文件创建manager,创建manager的函数直接放到manager文件定义中。
4. 固定schema的动态表单创建,custom(flowInst, stepInst),log三个项目用到。
4.1 可参考log项目, CustomLogManager文件
4.2 let customLogManager = await getCustomLogManagerInst(dbinfo);
5. 路由上的请求直接转发(无复杂逻辑),可使用remoteController。
6. 动态请求外部的数据,可继承KeyItemRemote, CompItemRemote, AppItemRemote三个Manager,或者直接继承。
6.1 let resourceRemoteManager = new CompItemRemoteManager<ResourceDef>({user: user, remoteKey: "resource", modelName: "Resource"});
6.2 let resource = await resourceRemoteManager.mGetByCompKey(compKey, field._resourceKey);
6.3 请求任意接口可使用customCall方法.
# redis哨兵模式
const ioredis = new Redis({
sentinels: [
{ host: '47.93.215.95', port: 26379 },
{ host: '39.106.26.127', port: 26379 },
{ host: '47.94.239.108', port: 26379 },
],
name: "mymaster",
password: "Bridata2017",
});
ioredis.set("foo", "bar");
db.core_innerapp.updateOne({compKey: "shenhezhuan", _key: "renliziyuan"}, {$push: { "managers": "0858cb3eb33b7bf93bab1cdbe781d32e" } } )
# 数据库连接
内网
tscore 配置数据库
mongo -u 'bridata' -p 'bridata2023' 172.17.60.101:27017 --authenticationDatabase "admin"
tscustom 默认的custom数据库
mongo -u 'bridata' -p 'bridata2023' 172.17.60.95:27520 --authenticationDatabase "admin"
明树数据库应用数据库
mongo -u 'bridata' -p 'bridata2023' 172.17.60.95:27017 --authenticationDatabase "admin"
江西,国家信息中心数据库
mongo -u 'bridata' -p 'bridata2023' 172.17.166.85:27017 --authenticationDatabase "admin"
V3数据库
mongo -u 'bridata' -p 'bridata2023' 172.17.60.96:27017 --authenticationDatabase "admin"
外网
tscore 配置数据库
mongo -u 'bridata' -p 'bridata2023' 39.105.56.246:27017 --authenticationDatabase "admin"
tscustom 默认的custom数据库
mongo -u 'bridata' -p 'bridata2023' 101.201.77.220:27520 --authenticationDatabase "admin"
明树数据库应用数据库
mongo -u 'bridata' -p 'bridata2023' 101.201.77.220:27017 --authenticationDatabase "admin"
江西,国家信息中心数据库
mongo -u 'bridata' -p 'bridata2023' 47.94.97.216:27017 --authenticationDatabase "admin"
V3数据库
mongo -u 'bridata' -p 'bridata2023' 39.97.211.251:27017 --authenticationDatabase "admin"
db.cust_appmessage.remove({});
db.cust_commonphrases.remove({});
db.cust_flowinst.remove({});
db.cust_flownotify.remove({});
db.cust_flowtask.remove({});
db.cust_label.remove({});
db.cust_stepinst.remove({});
let fs = require('fs')
let projects = [
"../ts_file",
"../ts_resource",
"../ts_proxy",
"../ts_comp",
"../ts_core",
"../ts_ticker",
"../ts_share",
"../ts_log",
"../ts_job",
"../ts_sender",
"../ts_mod",
"../ts_admin",
"../ts_calculator",
"../ts_dstore",
"../ts_custom",
"../ts_cgpt",
]
let deleteFiles = [
// "src/api/managers/base/remote/ModDataRemoteManager.ts"
]
let files = [
".vscode/launch.json",
".eslintignore",
".eslintrc",
"src/app.ts",
"src/bin.ts",
"src/api/controllers/base/ManagerController.ts",
"src/api/controllers/base/CompItemController.ts",
"src/api/controllers/base/AppItemController.ts",
"src/api/controllers/base/KeyItemController.ts",
"src/api/controllers/base/RemoteController.ts",
"src/api/def/base/adminTypes.ts",
"src/api/def/base/basisTypes.ts",
"src/api/def/base/commonTypes.ts",
"src/api/def/base/compTypes.ts",
"src/api/def/base/coreTypes.ts",
"src/api/def/base/customTypes.ts",
"src/api/def/base/defUtil.ts",
"src/api/def/base/dstoreTypes.ts",
"src/api/def/base/fileTypes.ts",
"src/api/def/base/jobTypes.ts",
"src/api/def/base/logTypes.ts",
"src/api/def/base/modTypes.ts",
"src/api/def/base/proxyTypes.ts",
"src/api/def/base/resourceTypes.ts",
"src/api/def/base/senderTypes.ts",
"src/api/def/base/shareTypes.ts",
"src/api/def/base/tickerTypes.ts",
"src/api/def/base/cgptTypes.ts",
"src/api/def/base/enums.ts",
"src/api/lib/mongo/index.ts",
"src/api/lib/mongo/plugins.ts",
"src/api/lib/cloudEnv.ts",
"src/api/lib/events.ts",
"src/api/lib/jwtlib.ts",
"src/api/lib/redis.ts",
"src/api/lib/remoteEnv.ts",
"src/api/lib/tools.ts",
"src/api/lib/cms.ts",
"src/api/util/api_util.ts",
"src/api/managers/base/BaseManager.ts",
"src/api/managers/base/CommonManager.ts",
"src/api/managers/base/IdItemManager.ts",
"src/api/managers/base/OrderManager.ts",
"src/api/managers/base/KeyItemManager.ts",
"src/api/managers/base/AppItemManager.ts",
"src/api/managers/base/CompItemManager.ts",
"src/api/managers/base/remote/RemoteCaller.ts",
"src/api/managers/base/remote/BaseRemoteManager.ts",
"src/api/managers/base/remote/CompItemRemoteManager.ts",
"src/api/managers/base/remote/AppItemRemoteManager.ts",
"src/api/managers/base/remote/IdItemRemoteManager.ts",
"src/api/managers/base/remote/KeyItemRemoteManager.ts",
"src/api/managers/base/remote/DynamicModRemoteManager.ts",
"src/api/models/base/CommonModel.ts",
"src/api/services/base/controllerService.ts",
"src/api/services/base/basePopService.ts",
"src/api/services/base/connectionService.ts",
"src/tests/setup.ts"
]
for( let project of projects ) {
// fs.mkdirSync(project + "/src/api/managers/base/remote")
for( let filepath of deleteFiles ){
let destFile = project + "/" + filepath;
if(fs.existsSync(destFile)){
fs.unlinkSync(destFile);
}
}
for( let filepath of files ){
let srcFile = "./" + filepath;
let destFile = project + "/" + filepath;
fs.copyFileSync(srcFile, destFile);
}
}
{
"dbConfig":
{
"user": "bridata",
"password": "Mingshu20170706",
"host": "172.17.60.96",
"port": 27000,
"dbName": "ts_basis_test"
},
"redisConfig":
{
"host": "172.17.60.96",
"port": 6380,
"password": "Mingshu20170706",
"db": 11
},
"remoteRedisConfig": {
"host": "172.17.60.96",
"port": 6380,
"password": "Mingshu20170706",
"db": 11
},
"server":
{
"PORT": 5201
},
"log4jsConfig": {
"categories": {
"default": {
"level": "error"
}
}
}
}
\ No newline at end of file
{
"server":
{
"PORT": 6306
},
"dbConfig":
{
"poolSize": 10
},
"pagination":
{
"pagesize": 10
},
"DEBUG_PARAM":
{
"meta":
{
"debug": 2734096276,
"api_key": "bridata",
"api_secret": "Bridata@2017"
}
},
"cacheSecs": 0,
"serviceKey": "hBasis",
"log4jsConfig": {
"appenders": {
"console": {
"type": "console"
},
"file": {
"type": "file",
"filename": "out.log"
}
},
"categories": {
"default": {
"appenders": [
"console"
],
"level": "info"
}
},
"replaceConsole": false
}
}
{
"dbConfig":
{
"host": "127.0.0.1",
"port": 27017,
"dbName": "ts_basis"
},
"redisConfig":
{
"host": "127.0.0.1",
"port": 6379
},
"remoteRedisConfig": {
"host": "127.0.0.1",
"port": 6379,
"db": 15
},
"server":
{
"PORT": 7901
}
}
\ No newline at end of file
{
"dbConfig":
{
"host": "127.0.0.1",
"port": 27017,
"dbName": "ts_basis_test"
},
"redisConfig":
{
"host": "127.0.0.1",
"port": 6379,
"db": 11
},
"remoteRedisConfig": {
"host": "127.0.0.1",
"port": 6379,
"db": 11
},
"server":
{
"PORT": 5201
},
"log4jsConfig": {
"categories": {
"default": {
"level": "error"
}
}
}
}
\ No newline at end of file
{
"model": "BaseExample",
"list": [
{
"_id": "5d5224e4f6268da7337cbd01",
"name": "明树数据",
"description": "北京明树数据科技有限公司",
"amount": "3000",
"itemType": "Mod"
},
{
"_id": "5d5224e4f6268da7337cbd02",
"name": "明树数据-南京分公司",
"description": "北京明树数据科技有限公司-南京分公司",
"amount": "1000",
"itemType": "Dashboard"
},
{
"_id": "5d5224e4f6268da7337cbd03",
"name": "明树数据-武汉分公司",
"description": "北京明树数据科技有限公司-武汉分公司",
"amount": "1200",
"itemType": "Dashboard"
}
]
}
{
"model": "Resource",
"remoteKey": "resource",
"modelType": "compItem",
"list": [
{
"name": "运作方式",
"_key": "optype",
"compKey": "test",
"resData": [
{
"_key": "bot",
"name": "BOT",
"color": "color-1",
"children": [],
"description": ""
},
{
"_key": "tot",
"name": "TOT",
"color": "color-2",
"children": [],
"description": ""
},
{
"_key": "boo",
"name": "BOO",
"color": "color-3",
"children": [],
"description": ""
}
]
}
]
}
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"name": "ts_basis",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "NODE_ENV=development node dist/bin.js",
"staging": "NODE_ENV=staging node ./dist/bin.js",
"cloud": "NODE_ENV=cloud node ./dist/bin.js",
"dev": "nodemon -e ts --watch src .env --exec \"tsc --incremental && node dist/bin.js\"",
"test": "NODE_ENV=test node ./node_modules/mocha/bin/mocha --require ts-node/register src/tests/setup.ts src/tests/**/*.test.ts",
"citest": "NODE_ENV=citest node ./node_modules/mocha/bin/mocha --require ts-node/register src/tests/setup.ts src/tests/**/*.test.ts",
"lint": "eslint . --ext .ts",
"build": "tsc -p ."
},
"repository": {
"type": "git",
"url": "http://gitlab.bridata.com:8090/root/ts_basis.git"
},
"author": "",
"license": "ISC",
"dependencies": {
"ali-oss": "^6.15.2",
"async-redis": "^1.1.7",
"axios": "^0.21.1",
"bson-objectid": "^1.3.1",
"bull": "^4.10.2",
"config": "^3.1.0",
"cookie-parser": "^1.4.6",
"debug": "~2.6.9",
"esprima": "^4.0.1",
"express": "^4.18.1",
"html-docx-js": "^0.3.1",
"http-errors": "~1.6.2",
"ioredis": "^5.3.1",
"irr-npv": "^1.0.1",
"jsonwebtoken": "^8.5.1",
"lodash": "^4.17.21",
"log4js": "^6.7.1",
"mammoth": "^1.4.14",
"md5": "^2.2.1",
"mocha": "^9.2.2",
"moment": "^2.29.4",
"mongoose": "^5.9.2",
"mongoose-autopopulate": "^0.9.1",
"multer": "^1.4.4",
"mysql2": "^2.1.0",
"passport": "^0.4.1",
"sequelize": "^6.3.4",
"socket.io": "^4.5.4",
"svg-captcha": "^1.4.0",
"xlsx": "^0.16.9"
},
"devDependencies": {
"@types/ali-oss": "^6.16.6",
"@types/async-redis": "^1.1.3",
"@types/config": "^3.3.0",
"@types/cookie-parser": "^1.4.3",
"@types/express": "^4.17.13",
"@types/html-docx-js": "^0.3.1",
"@types/http-errors": "^2.0.1",
"@types/jsonwebtoken": "^8.5.9",
"@types/lodash": "^4.14.189",
"@types/md5": "^2.3.2",
"@types/mocha": "^10.0.1",
"@types/multer": "^1.4.7",
"@types/node": "^18.7.16",
"@types/passport": "^1.0.11",
"@typescript-eslint/eslint-plugin": "^5.44.0",
"@typescript-eslint/parser": "^5.44.0",
"eslint": "^8.28.0",
"nodemon": "^2.0.19",
"ts-node": "^10.9.1",
"tsconfig-paths": "^4.1.1",
"typescript": "^4.8.3"
}
}
pwd
for project in "ts_file" "ts_resource" "ts_proxy" "ts_comp" "ts_core" "ts_ticker" "ts_share" "ts_log" "ts_job" "ts_sender" "ts_mod" "ts_admin" "ts_calculator" "ts_dstore" "ts_custom" "ts_cgpt"
do
cd ../${project}
rm -rf node_modules
npm install --registry https://registry.npm.taobao.org
rm -rf dist
npm run build
echo "======================= ${project} finished."
done
cd ../ts_basis
pwd
for project in "ts_file" "ts_resource" "ts_proxy" "ts_comp" "ts_core" "ts_ticker" "ts_share" "ts_log" "ts_job" "ts_sender" "ts_mod" "ts_admin" "ts_calculator" "ts_dstore" "ts_custom" "ts_cgpt"
do
cd ../${project}
git checkout staging
git pull
git checkout cloud
git pull
git merge staging
git push
git checkout dev
git status
echo "======================= ${project} finished."
done
cd ../ts_basis
pwd
for project in "ts_file" "ts_resource" "ts_proxy" "ts_comp" "ts_core" "ts_ticker" "ts_share" "ts_log" "ts_job" "ts_sender" "ts_mod" "ts_admin" "ts_calculator" "ts_dstore" "ts_custom" "ts_cgpt"
do
cd ../${project}
git checkout dev
git pull
git checkout staging
git pull
git merge dev
git push
git checkout dev
git status
echo "======================= ${project} finished."
done
cd ../ts_basis
pwd
for project in "ts_file" "ts_resource" "ts_proxy" "ts_comp" "ts_core" "ts_ticker" "ts_share" "ts_log" "ts_job" "ts_sender" "ts_mod" "ts_admin" "ts_calculator" "ts_dstore" "ts_custom" "ts_cgpt"
do
cd ../${project}
git checkout dev
git pull
git checkout tmp
git pull
git merge dev
git push
git checkout dev
git status
echo "======================= ${project} finished."
done
cd ../ts_basis
pwd
for project in "ts_file" "ts_resource" "ts_proxy" "ts_comp" "ts_core" "ts_ticker" "ts_share" "ts_log" "ts_job" "ts_sender" "ts_mod" "ts_admin" "ts_calculator" "ts_dstore" "ts_custom" "ts_cgpt"
do
cd ../${project}
git checkout dev
git pull
done
cd ../ts_basis
git checkout dev
git pull
pwd
for project in "ts_file" "ts_resource" "ts_proxy" "ts_comp" "ts_core" "ts_ticker" "ts_share" "ts_log" "ts_job" "ts_sender" "ts_mod" "ts_admin" "ts_calculator" "ts_dstore" "ts_custom" "ts_cgpt"
do
cd ../${project}
git checkout dev
git pull
git add src
git add .gitignore
git add .vscode
git add ./tsconfig.json
git add ./.eslintignore
git add ./.eslintrc
git add package.json
git commit -m "feat: sync from basis"
git push
git status
echo "======================= ${project} finished."
done
cd ../ts_basis
for project in "ts_file" "ts_resource" "ts_proxy" "ts_comp" "ts_core" "ts_ticker" "ts_share" "ts_log" "ts_job" "ts_sender" "ts_mod" "ts_admin" "ts_calculator" "ts_dstore" "ts_custom" "ts_cgpt"
do
cd ../${project}
git checkout dev
rm -rf src
git checkout .
echo "======================= ${project} finished."
done
\ No newline at end of file
for project in "ts_file" "ts_resource" "ts_proxy" "ts_comp" "ts_core" "ts_ticker" "ts_share" "ts_log" "ts_job" "ts_sender" "ts_mod" "ts_admin" "ts_calculator" "ts_dstore" "ts_custom" "ts_cgpt"
do
cd ../${project}
git status
echo "======================= ${project} finished."
done
\ No newline at end of file
import ManagerControllerSchema from './base/ManagerController'
import { BaseExampleDef } from '../def/base/basisTypes';
import { BaseExampleManagerInst } from '../../api/managers/BaseExampleManager'
class BaseExampleControllerSchema extends ManagerControllerSchema<BaseExampleDef> {
constructor(params: any = {}) {
super(BaseExampleManagerInst, params);
}
}
export default BaseExampleControllerSchema;
\ No newline at end of file
////////////////////////////////////////////////////////
//
// 重要 !!!!!!!!!!!!!!!!!!!!
//
// 核心模块代码, 请到ts_basis项目中修改提交
//
////////////////////////////////////////////////////////
import ManagerControllerSchema from './ManagerController'
import { AppItemDef } from '../../def/base/commonTypes';
import controllerService from '../../services/base/controllerService';
import { Request, Response } from 'express'
import AppItemManager from '../../managers/base/AppItemManager';
class AppItemControllerSchema<T extends AppItemDef> extends ManagerControllerSchema<T> {
compKey: string;
appKey: string;
manager: AppItemManager<T>;
constructor(manager: AppItemManager<T>, params: any) {
super(manager, params);
this.compKey = params.compKey;
this.appKey = params.appKey;
this.manager = manager;
}
async index(req: Request, res: Response): Promise<{ total: number; list: (T)[] }> {
throw new Error("index not supported, use appIndex!")
}
async all(req: Request, res: Response): Promise<{ total: number; list: (T)[] }> {
throw new Error("all not supported, use appAll!")
}
async show(req: Request, res: Response): Promise<T | null> {
throw new Error("show not supported, use appShow!")
}
async create(req: Request, res: Response): Promise<T> {
throw new Error("create not supported, use appCreate!")
}
async update(req: Request, res: Response): Promise<T> {
throw new Error("update not supported, use appUpdate!")
}
async delete(req: Request, res: Response): Promise<T> {
throw new Error("delete not supported, use appDelete!")
}
async searchDelete(req: Request, res: Response): Promise<{ list: (T)[] }> {
throw new Error("searchDelete not supported, use appSearchDelete!")
}
/// ///////////////
// 应用相关接口
/// ///////////////
async appIndex(req: Request, res: Response): Promise<{ total: number; list: (T)[] }> {
controllerService.injectSearch(req, "compKey", this.compKey);
controllerService.injectSearch(req, "appKey", this.appKey);
return await super.index(req, res);
}
async appAll(req: Request, res: Response): Promise<{ total: number; list: (T)[] }> {
controllerService.injectSearch(req, "compKey", this.compKey);
controllerService.injectSearch(req, "appKey", this.appKey);
return await super.all(req, res);
}
async appSearchDelete(req: Request, res: Response): Promise<{ list: (T)[] }> {
controllerService.injectSearch(req, "compKey", this.compKey);
controllerService.injectSearch(req, "appKey", this.appKey);
return await super.searchDelete(req, res);
}
async appDelete(req: Request, res: Response): Promise<T | null> {
const params = {
compKey: this.compKey,
appKey: this.appKey,
_key: req.body._key,
menuType: this.manager.modelName,
};
return this.manager.mDelete(params);
}
async appShow(req: Request, res: Response): Promise<T | null> {
controllerService.injectParam(req, "compKey", this.compKey);
controllerService.injectParam(req, "appKey", this.appKey);
return await super.show(req, res)
}
async appCreate(req: Request, res: Response): Promise<T> {
delete req.body.search;
controllerService.injectParam(req, "compKey", this.compKey);
controllerService.injectParam(req, "appKey", this.appKey);
controllerService.verifyKey(req.body._key);
let eObj = await this.manager.mFindOne(this.manager.getUniqueSearch(req.body));
if (eObj) {
throw new Error("主键_key冲突");
}
return await super.create(req, res);
}
async appUpdate(req: Request, res: Response): Promise<T> {
if (req.body.appKey && req.body.appKey != this.appKey) {
throw new Error("App id wrong!");
}
controllerService.injectParam(req, "compKey", this.compKey);
controllerService.injectParam(req, "appKey", this.appKey);
return await super.update(req, res);
}
async getByKey(req: Request, res: Response): Promise<T | null> {
// let populate = req.body.populate || [];
let obj = await this.manager.mGetByAppKey(this.compKey, this.appKey, req.body._key);
if (!obj) {
throw new Error("Obj not found by key!");
}
return obj;
}
}
export default AppItemControllerSchema;
\ No newline at end of file
////////////////////////////////////////////////////////
//
// 重要 !!!!!!!!!!!!!!!!!!!!
//
// 核心模块代码, 请到ts_basis项目中修改提交
//
////////////////////////////////////////////////////////
import ManagerControllerSchema from './ManagerController'
import { CompItemDef } from '../../def/base/commonTypes';
import CompItemManager from '../../managers/base/CompItemManager';
import controllerService from '../../services/base/controllerService';
import { Request, Response } from 'express'
class CompItemControllerSchema<T extends CompItemDef> extends ManagerControllerSchema<T> {
compKey: string;
manager: CompItemManager<T>;
constructor(manager: CompItemManager<T>, params: any) {
super(manager, params);
this.compKey = params.compKey
this.manager = manager
}
async index(req: Request, res: Response): Promise<{ total: number; list: (T)[] }> {
throw new Error("index not supported, use compIndex!")
}
async all(req: Request, res: Response): Promise<{ total: number; list: (T)[] }> {
throw new Error("all not supported, use compAll!")
}
async show(req: Request, res: Response): Promise<T | null> {
throw new Error("show not supported, use compShow!")
}
async create(req: Request, res: Response): Promise<T> {
throw new Error("create not supported, use compCreate!")
}
async update(req: Request, res: Response): Promise<T> {
throw new Error("update not supported, use compUpdate!")
}
async delete(req: Request, res: Response): Promise<T> {
throw new Error("delete not supported, use compDelete!")
}
async searchDelete(req: Request, res: Response): Promise<{ list: (T)[] }> {
throw new Error("searchDelete not supported, use compSearchDelete!")
}
async compIndex(req: Request, res: Response): Promise<{ total: number; list: (T)[] }> {
controllerService.injectSearch(req, "compKey", this.compKey);
return await super.index(req, res);
}
async compAll(req: Request, res: Response): Promise<{ total: number; list: (T)[] }> {
controllerService.injectSearch(req, "compKey", this.compKey);
return await super.all(req, res);
}
async compShow(req: Request, res: Response): Promise<T | null> {
controllerService.injectParam(req, "compKey", this.compKey);
return await super.show(req, res);
}
async compSearchDelete(req: Request, res: Response): Promise<{ list: (T)[] }> {
controllerService.injectSearch(req, "compKey", this.compKey);
return await super.searchDelete(req, res);
}
async compCreate(req: Request, res: Response): Promise<T> {
controllerService.injectParam(req, "compKey", this.compKey);
controllerService.verifyKey(req.body._key);
let eObj = await this.manager.mFindOne(this.manager.getUniqueSearch(req.body));
if (eObj) {
throw new Error("主键_key冲突");
}
return await super.create(req, res);
}
async compUpdate(req: Request, res: Response): Promise<T> {
controllerService.injectParam(req, "compKey", this.compKey);
return await super.update(req, res);
}
async compDelete(req: Request, res: Response): Promise<T | null> {
let search = {
_key: req.body._key,
compKey: this.compKey
};
let ret = await this.getManager().mDelete(search);
return ret;
}
}
export default CompItemControllerSchema;
\ No newline at end of file
////////////////////////////////////////////////////////
//
// 重要 !!!!!!!!!!!!!!!!!!!!
//
// 核心模块代码, 请到ts_basis项目中修改提交
//
////////////////////////////////////////////////////////
import ManagerControllerSchema from './ManagerController'
import { KeyItemDef } from '../../def/base/commonTypes';
import KeyItemManager from '../../managers/base/KeyItemManager';
import controllerService from '../../services/base/controllerService';
import { Request, Response } from 'express'
class KeyItemControllerSchema<T extends KeyItemDef> extends ManagerControllerSchema<T> {
manager: KeyItemManager<T>;
constructor(manager: KeyItemManager<T>, params: any) {
super(manager, params);
this.manager = manager
}
async create(req: Request, res: Response): Promise<T> {
controllerService.verifyKey(req.body._key);
let eObj = await this.manager.mFindOne(this.manager.getUniqueSearch(req.body));
if (eObj) {
throw new Error("主键_key冲突");
}
return await super.create(req, res);
}
}
export default KeyItemControllerSchema;
\ No newline at end of file
////////////////////////////////////////////////////////
//
// 重要 !!!!!!!!!!!!!!!!!!!!
//
// 核心模块代码, 请到ts_basis项目中修改提交
//
////////////////////////////////////////////////////////
import { Request, Response } from 'express'
import { BaseDef } from '../../def/base/commonTypes';
import { AbstractManager } from '../../managers/base/CommonManager';
class ManagerControllerSchema<T extends BaseDef>{
manager: AbstractManager<T>;
allPageSize: number;
constructor(manager: AbstractManager<T>, params: any = {}) {
this.manager = manager;
this.allPageSize = params.allPageSize || 5000
}
getManager() {
return this.manager;
}
async all(req: Request, res: Response): Promise<{ total: number; list: (T)[] }> {
let limit = req.body.limit != null ? req.body.limit : this.allPageSize;
if( req.body.skip != null ) {
req.body.pagination = {
page: -1,
pagesize: limit,
start: req.body.skip
};
}
else {
req.body.pagination = {
page: 1,
pagesize: limit
};
}
let result = await this.getManager().mIndex(req.body);
return result
}
async create(req: Request, res: Response): Promise<T> {
let obj = await this.getManager().mCreate(req.body);
return obj;
}
async delete(req: Request, res: Response): Promise<T | null> {
let obj = await this.getManager().mDelete(req.body);
return obj;
}
async searchDelete(req: Request, res: Response): Promise<{ list: (T)[] }> {
let result: T[] = [];
if (req.body.__deleteAll__) {
result = await this.getManager().mDeleteMany({}, [], true);
}
else if (req.body.search) {
result = await this.getManager().mDeleteMany(req.body.search, req.body.fields, req.body.returnEmpty);
}
return {
list: result
}
}
async searchUpdate(req: Request, res: Response): Promise<{ list: (T)[] }> {
let result: T[] = [];
if (req.body.search) {
result = await this.getManager().mUpdateMany(req.body.search, req.body.updateParams, req.body.fields, req.body.returnEmpty);
}
return {
list: result
}
}
async softDelete(req: Request, res: Response): Promise<T> {
let obj = await this.getManager().mSoftDelete(req.body);
return obj;
}
async softSearchDelete(req: Request, res: Response): Promise<{ list: (T)[] }> {
let result: T[] = [];
if (req.body.__deleteAll__) {
result = await this.getManager().mSoftDeleteMany({}, [], true);
}
else if (req.body.search) {
result = await this.getManager().mSoftDeleteMany(req.body.search, req.body.fields, req.body.returnEmpty);
}
return {
list: result
};
}
async update(req: Request, res: Response): Promise<T> {
let obj = await this.getManager().mUpdate(req.body);
return obj;
}
async index(req: Request, res: Response): Promise<{ total: number; list: (T)[] }> {
let result = await this.getManager().mIndex(req.body);
return result;
}
async show(req: Request, res: Response): Promise<T | null> {
let objParam: any = req.body;
if (req.method == "GET") {
objParam = {
_id: req.params["_id"]
}
}
let obj = await this.getManager().mGet(objParam);
return obj;
}
async count(req: Request, res: Response): Promise<{ total: number }> {
let total = await this.getManager().mCount(req.body.search, req.body.countLimit);
return {
total
};
}
async types(req: Request, res: Response): Promise<any> {
let result = await this.getManager().mTypes();
return result;
}
async insertMany(req: Request, res: Response): Promise<{ list: T[] }> {
let resultList = await this.getManager().mInsertMany(req.body.list);
return {
list: resultList
}
}
async findOne(req: Request, res: Response): Promise<T | null> {
let result = this.getManager().mFindOne(req.body.search)
return result
}
async aggregate(req: Request, res: Response): Promise<{ list: any[] }> {
let list = await this.getManager().mAggregate(req.body.list, req.body.option);
return {
list
}
}
}
export default ManagerControllerSchema;
////////////////////////////////////////////////////////
//
// 重要 !!!!!!!!!!!!!!!!!!!!
//
// 核心模块代码, 请到ts_basis项目中修改提交
//
////////////////////////////////////////////////////////
import RemoteCaller from '../../managers/base/remote/RemoteCaller'
import { RemoteParam } from '../../managers/base/CommonManager';
class RemoteControllerSchema {
user: any;
remoteCaller: RemoteCaller;
constructor(params: RemoteParam) {
this.remoteCaller = new RemoteCaller(params);
}
// path为相对路径
async getRemoteData(path: string, params: any, headers = {}) {
let data = await this.remoteCaller.requestRemoteData(path, params, headers)
return data
}
}
export default RemoteControllerSchema;
\ No newline at end of file
import { BaseDef, CascaderDef, KeyItemDef } from "./commonTypes";
import mongoose from "mongoose";
export interface CategoryDef extends CascaderDef, BaseDef {
_key: string;
order: number;
is_show: string;
description: string;
children: Array<CategoryDef>;
}
export interface ArticleDef extends BaseDef {
_key: string;
order: number;
icon: string;
name: string;
description: string;
isHot: string;
isHide: string;
category: mongoose.Types.ObjectId | CascaderDef;
attachments: string;
content: string;
category__t_n: string;
}
export interface FeedBackDef extends KeyItemDef {
compKey: string;
content: string;
appKey: string;
userKey: string;
whatCanUp: string;
followData: string;
score: string;
willShare: string;
feedType: "comp" | "custom";
}
export interface ReleaseDef extends BaseDef {
ios_version: string; // "Ios版本号";
android_version: string; // "Android版本号"
force_update: boolean; // "是否强制更新"
ios_online: boolean; // "Ios是否上线"
android_online: boolean; //
xiaomi_online: boolean; //
huawei_online: boolean; //
ios_online_date: Date; //
android_online_date: Date; // "线上更新时间"
xiaomi_online_date: Date; //
huawei_online_date: Date; //
// ios_ipa: string; // Ios包
// android_apk: string; // Android包
androidUrl: string;
}
////////////////////////////////////////////////////////
//
// 重要 !!!!!!!!!!!!!!!!!!!!
//
// 核心模块代码, 请到ts_basis项目中修改提交
//
////////////////////////////////////////////////////////
import { BaseDef } from "./commonTypes";
export interface BaseExampleDef extends BaseDef {
name: string;
description: string;
amount: number;
itemType: "Mod" | "Dashboard" | "Report" | "InnerApp" | "Tabulation" | "EmbedPage" | "InnerChart" | "InnerTable" | "AppRole" | "Trigger" | "FlowDef";
}
////////////////////////////////////////////////////////
//
// 重要 !!!!!!!!!!!!!!!!!!!!
//
// 核心模块代码, 请到ts_basis项目中修改提交
//
////////////////////////////////////////////////////////
import { OrderDef } from "./commonTypes";
export interface ConversationDef extends OrderDef {
compKey: string,
appKey: string,
userKey: string,
messageIds: string[],
messages?: MessageDef[],
question?: string,
answer?: string,
title?: string,
}
export interface MessageDef extends OrderDef {
conversationId: string,
question?: string,
answer?: string,
}
\ No newline at end of file
////////////////////////////////////////////////////////
//
// 重要 !!!!!!!!!!!!!!!!!!!!
//
// 核心模块代码, 请到ts_basis项目中修改提交
//
////////////////////////////////////////////////////////
import mongoose from "mongoose"
import { UserDef } from "./compTypes"
export interface BaseDef {
_id: mongoose.Types.ObjectId | string | number;
visible: boolean;
createdAt: Date;
updatedAt: Date;
__old__?: any; // 老对象
}
export interface OrderDef extends BaseDef {
order: number;
}
export interface KeyItemDef extends OrderDef {
_key: string;
}
export interface NameDef extends OrderDef {
name: string;
description: string;
createType: "self" | "download";
}
export interface CompItemDef extends NameDef {
compKey: string;
_key: string;
itemGroupKey: string;
}
export interface AppItemDef extends NameDef {
compKey: string;
appKey: string;
_key: string;
itemGroupKey: string;
}
export interface CompItemGroupDef extends CompItemDef {
menuType: "Resource" | "Entity" | "Archive";
outerCompKey: string;
}
export type MenuType = "Mod" | "Dashboard" | "FlowDef" | "Report" | "Resource" | "Tabulation" | "EmbedPage" | "Trigger" | "DataFactory" | "TabulationCreate";
export type AnchorType = "Top" | "Bottom" | "Left" | "Right" | "TopLeft" | "TopRight" | "BottomLeft" | "BottomRight";
export interface AppItemGroupDef extends AppItemDef {
menuType: MenuType
}
export interface CascaderDef {
name: string; // 名字
code: string; // 编码
level: number; // 层级
full_name: string; // 全名
is_leaf: boolean; // 是否是最低层
}
export interface DbInfo {
dbName: string;
host?: string;
port?: number | string;
user?: string;
password?: string;
readPreference?: any;
coreCluster?: {
host: string;
port: string;
}[];
cache?: {
[key: string]: any
};
coreClusterRSName?: string;
dbId: string;
}
export interface CustomRemoteConfigDef {
localSetting?: string,
frontHost: string,
frontAppHost?: string,
host: string,
db: DbInfo
}
type CustomRequest = AppendToObject<Request, 'user', UserDef>;
////////////////////////////////////////////////////////
//
// 重要 !!!!!!!!!!!!!!!!!!!!
//
// 核心模块代码, 请到ts_basis项目中修改提交
//
////////////////////////////////////////////////////////
import { BaseDef, CompItemDef, KeyItemDef } from './commonTypes'
import mongoose from "mongoose"
import { CascaderDef } from './commonTypes';
import { AttachmentBaseDef } from './fileTypes';
export interface UserDef extends KeyItemDef {
mobile: string;
realname: string;
username: string;
email: string;
job: string;
birthday: Date;
password: string;
salt: string;
avatarurl: string;
gender: "male" | "female";
user_type: "BR1" | "ADV" | "CUS" | "TMP" | "SHA";
system_type: "inner" | "outer";
companyOut: {
[propName: string]: any;
};
sic_uid: string;
user_status: "invalid" | "valid";
usbKey: string;
mobileEnc: string;
companies: {
compKey: string;
isDefault: boolean;
isValid: boolean;
compRole: "ADM" | "HIG" | "USR";
}[];
departments: {
compKey: string;
deptKey: string;
isDefault: boolean;
deptGrade: string;
}[];
compKey: string;
user_card:string;
oldId: string;
industry: string[];
}
interface DDWXConfig {
// 常规配置
corpid: string, // 公司组织 id
appkey: string, // 钉钉 appkey;企业微信 AgentId
appsecret: string, // appsecret
// 消息回调配置
callback_token: string, // 回调加密 aes_key
encoding_ase_key: string, // 签名 token
// 系统标记
isDocking: boolean, // 是否开启同步
isCheckUrl: boolean, // 消息回调是否已开启
}
export interface CompanyDef extends KeyItemDef {
company_type: "free" | "standard" | "professional" | "ultimate";
maxUsers: number;
name: string;
description: string;
defaultApp: mongoose.Types.ObjectId;
logoUrl: string;
fixPhone: string;
fax: string;
email: string;
address: string;
zipCode: string;
licenseNumber: string;
loginName: string;
loginBg: string;
allowAddDepartment: boolean;
ddInfo: DDWXConfig;
wxInfo: DDWXConfig;
app_secretes: {
foreignCompKey: string //
userKey: string
app_secrete: string
apps: string[]
}[]
}
export interface DepartmentDef extends CompItemDef, CascaderDef {
creditCode: string;
oldCode: string;
region: string[];
ord: number;
deptClass: string;
// 是否在用户端通讯录显示
contactShow: boolean;
oid: string;
}
export interface DepartmentGradeDef extends CompItemDef {
}
interface ArchiveMenu {
name: string;
icon: string;
children: ArchiveMenu[];
}
export interface ArchiveDef extends CompItemDef {
articleMenus: ArchiveMenu[];
}
export interface ArticleDef extends CompItemDef {
name: string;
icon: string;
isHot: "0" | "1";
isHid: "0" | "1";
attachments: AttachmentBaseDef[];
content: string;
}
export interface LoginLogDef extends CompItemDef {
userKey: string;
loginType: number;
browser: string;
os: string;
engine: string;
mobile: string;
loginStatus: string;
failReason: string;
ip: string;
}
export interface InviteMessageDef extends CompItemDef {
is_valid: "0" | "1";
operate_time: Date;
invite_status: "waiting" | "completed" | "rejected";
userKey: string;
inviteUserKey: string;
mobile: string;
}
type platform = 'dd' | 'wx';
export interface OuterUserDef extends BaseDef {
platform: platform,
user_id: string,
user_name: string,
mobile: string,
email: string,
avatar: string,
dept_ids: string[],
compKey: string,
user: {
_key: string,
name: string,
mobile: string,
mobileMatch: boolean
} | null
}
export interface OuterDepartmentDef extends BaseDef {
platform: platform,
dept_id: string,
dept_name: string,
parent_id: string,
order: string,
compKey: string,
department: {
_key: string,
name: string,
} | null
}
export interface CompanyMessageDef extends CompItemDef {
title: string,
content: string,
showStatus: string
}
export interface WxappmessageDef extends BaseDef {
userKeys: string[],
docCreator: string,
realUserKeys: any,
invaliduser?: string[],
unlicenseduser?: string[],
compKey: string,
appKey: string,
touser?: string,
toparty?: string,
msgtype: "text" | "textcard" | "markdown",
agentid: number,
text?: { context: string },
textcard?: {
title: string,
description: string,
url: string,
btntxt: string
},
markdown?: {
content: string
},
safe?: number,
enable_id_trans?: number,
enable_duplicate_check?: number,
duplicate_check_interval?: number
}
export interface SystemNotifyDef extends KeyItemDef {
msgType: "update" | "upload" | "function";
sendWay: string[];
sendTime: Date;
sendStatus: "0" | "1";
editor: string;
title: string;
abstract: string;
content: string;
}
export interface CompanyNotifyDef extends KeyItemDef {
compKey: string,
notifyKey: string;
viewUser: string;
}
\ No newline at end of file
////////////////////////////////////////////////////////
//
// 重要 !!!!!!!!!!!!!!!!!!!!
//
// 核心模块代码, 请到ts_basis项目中修改提交
//
////////////////////////////////////////////////////////
// InnerApp 继承 CompItemDef, 其他的都继承AppItemDef
import { AppItemDef, CompItemDef, CascaderDef, OrderDef, MenuType } from "./commonTypes"
import mongoose from "mongoose"
import { EntityFieldDef } from "./modTypes"
import { ResData } from "./resourceTypes";
import { AnchorType } from "./commonTypes";
export interface ModRule {
modKey: string;
fieldRules: PermissionDef[];
screenRules: {
hasAccess: boolean;
buttonRules: {
canShow: boolean;
canCreate: boolean;
canUpdate: boolean;
canDelete: boolean;
canImport: boolean;
canExport: boolean;
canShare: boolean;
canBatchUpdate: boolean;
};
screenKey: string;
}[];
}
// --> AppRole.js
export interface AppRoleDef extends AppItemDef {
menuOpenKeys: string[];
flowOpenKeys: string[];
users: {
user: string
role_manager: boolean
}[];
departments: string[];
grades: string[];
userTypes: string[];
accessControl: boolean;
canSetCore: boolean;
modRules: ModRule[];
fakeRole: boolean;
}
// --> ConfigLog.js
export interface ConfigLogDef extends OrderDef {
compKey: string;
appKey: string;
configStr: string;
modKey: string;
modType: "Mod" | "Dashboard" | "Report" | "InnerApp" | "Tabulation" | "EmbedPage" | "InnerChart" | "InnerTable" | "AppRole" | "Trigger" | "FlowDef";
// 配置加密
cipherStr: string;
user: string;
operateType: "create" | "update" | "delete";
}
// --> Dashboard.js
export interface DashboardDef extends AppItemDef {
form: FieldBaseDef[];
// 主题
theme: "default" | "profoundBlue" | "simplicityWhite";
// 保存的图表
board?: DashboardDataDef[];
mobileBoard?: DashboardDataDef[];
formData: {
[propName: string]: any;
};
source: "custom" | "core" | "";
own_scope: "personal" | "office" | "department" | "area" | "";
// 个人的组织架构
owner_org_struct?: {
areaKey: string; // 区域 所属地区 武汉市
departmentKey: string; // 部门单位 所属部门 发展改革委员会
officeKey: string;// 所属科室 地政局
};
owner: string;
// 信息中心自动为owner生成的标志
source_label: "auto" | "";
}
// --> DataFactory.js
export interface DataFactoryDef extends AppItemDef {
chart_def: {
steps: {
_key: string;
position: {
top: number;
left: number;
},
name: string;
icon: string;
stepType: "start" | "unwind" | "input" | "connect" | "group" | "calculate" | "output";
inputSettings: {
entityKey: string;
// screen: string;
fields: string[];
},
unwindSettings: {
unwindField: string;
},
connectSettings: {
connectType: "innerJoin" | "leftJoin";
name: string;
joinFields: {
leftField: string;
rightField: string;
}[]
},
groupSettings: {
keys: {
_key: string;
fieldName: string;
}[],
aims: {
_key: string;
aimName: string;
operator: string;
}[],
dateFormat: string;
},
calculateSettings: {
items: {
fieldName: string;
fieldKey: string;
resourceKey: string;
fieldType: string;
_calculate: {
_variables: {
_var: string;
_fields: string[];
}[],
_formula: string;
}
}[]
},
outputSettings: {
exportFields: {
fieldField: string;
fieldPicked: boolean;
fieldName: string;
}[]
}
}[];
relations: {
source: string;
target: string;
endAnchor: string;
startAnchor: string;
}[];
}
}
// --> EmbedPage.js
export interface EmbedPageDef extends AppItemDef {
// 外部链接
url: string;
params: string;
type: "outer" | "inner";
}
// --> FileArchive.js
export interface FileArchiveDef extends AppItemDef, CascaderDef {
}
export interface FlowChartDef {
steps: StepDef[];
relations: RelationDef[];
}
// --> FlowDef.js
export interface FlowDefDef extends AppItemDef {
// 主表单关联
modKey: string;
screenKey: string;
flow_operation: "create" | "update";
start_type: "user_start" | "event_start";
listFields: string[];
flow_style: "default" | "form";
chart_def: FlowChartDef,
actionUpdateFlag: boolean;
conditionUpdateFlag: boolean;
}
// --> InnerApp.js
export interface InnerAppDef extends CompItemDef {
creator: string;
originId: string;
templateKey: string;
dbAppVersion: string;
dbAppKey: string;
iconType: "icon-1" | "icon-2" | "icon-3" | "icon-4" | "icon-5";
colorType: "color-1" | "color-2" | "color-3" | "color-4" | "color-5";
managers: string[],
appStatus: "valid" | "deleted" | null | "";
menuMode: "horizontal" | "vertical";
layout: "creative" | "tradition" | "";
logoUrl: string;
globalEdit: boolean;
menus: MenuDef[];
mobileMenus: MenuDef[];
// 前端分支: dev
// 描述: 支持功能添加到一级菜单
menuItems: SubMenuDef[],
// dashboard主页
homeDashboardKey: string;
// 是否显示主页
displayHome: boolean;
displayAppName: boolean;
hideMenu: boolean;
loginRedirectType: string;
}
// --> InnerChart.js
export interface InnerChartDef extends InnerDataDef {
sourceType: string;
customFunction: string;
statistical: string;
chartType: 'bar' | 'line' | 'pie' | 'scatter' | 'heatmap' | 'country' | 'bar__line' | 'bar__yx' | 'line__area' | 'funnel' | 'pie_ratio' | 'pivotTable' | 'radar' | 'gauge' | "gaodeChart" | "olScatter" | "olLine" | "graph" | "footmark";
// 散点图展示类型
coordinateSystem: 'cartesian2d' | 'geo' | 'geoCountry';
coordinateSystemRegion: string[];
autoSetFitView: boolean;
tableField: string;
showLimit: number;
pivotTableType: string; //透视表类型切换
aggregateFill: boolean;
keys: {
_key: string;
_alias: string;
dateFormat: string;
regionFormat: 'province' | 'city' | 'county' | null;
regionCode: string;
fieldName: string;
level: number;
// 映射字段
mappingField: string;
// 地区统计方式
curLevel: 'all' | 'cur';
width: number;
sort: 1 | -1 | 0;
// 透视表该key加入总计
showCount: boolean;
// 仅对resource生效,填充资源
fullResource: boolean;
}[],
aims: {
codeBlock: string;
operator: 'sum' | 'avg' | 'min' | 'max' | 'calculate';
separator: boolean;
calculate: {
_variables: {
_var: string;
_fields: string[];
}[],
_formula: string;
},
fieldName: string;
_key: string;
distinctFields: string;
yAxisIndex: number;
sort: 1 | -1 | 0;
// 数字框 单位
unit: string;
round: number;
ratio: number;
symbol: string;
icon: string;
// 预警
// owarning: {
// type: Array,
// default: [],
// },
warning: {
start: number;
end: number;
logic: "range" | "rangein";
}[],
sortNum: number;
width: number;
}[],
calculateAxis: {
_type: 'ratio' | 'sort';
_key: string;
fieldName: string;
sortNum: number;
sort: 'asc' | 'desc';
aim: {
fieldName: string;
sourceKey: string;
},
key: {
fieldName: string;
sourceKey: string;
},
width: number;
}[],
option: string;
mobileOption: string;
// 数据缺失名称
emptyText: string;
hideNullData: boolean;
fillAndSort: boolean;
needCount: boolean;
displayData: boolean;
displayType: "list" | "detail";
dataFields: string[];
// number 类型
numberType: 'normal' | 'icon';
arrangeType: 'crosswise' | 'lengthways';
relyCode: boolean;
modKey: string;
screenKey: string;
buttonRules: {
canShow: false,
canUpdate: false
},
shpUrl: string;
topSearchList: [{
_key: string,
_name: string,
_span: number
}],
innerSearch: {
fieldName: string;
fieldKey: string;
fieldType: string;
_dateType: string;
_resourceKey: string;
}[],
innerSearchData: {
[propName: string]: any;
}
funcType: string
hideFuncData: boolean
yoyYear: string
momDuration: string[]
}
// --> InnerTable.js
export interface InnerTableDef extends InnerDataDef {
sourceType: string;
customFunction: string;
statistical: string;
chartType: 'bar' | 'line' | 'pie' | 'scatter' | 'heatmap' | 'country' | 'bar__line' | 'bar__yx' | 'line__area' | 'funnel' | 'pie_ratio' | 'pivotTable' | 'radar' | 'gauge' | "gaodeChart" | "olScatter" | "olLine";
// 散点图展示类型
coordinateSystem: 'cartesian2d' | 'geo' | 'geoCountry';
coordinateSystemRegion: string[];
autoSetFitView: boolean;
tableField: string;
showLimit: number;
pivotTableType: string; //透视表类型切换
keys: {
_key: string;
_alias: string;
dateFormat: string;
regionFormat: 'province' | 'city' | 'county' | null;
regionCode: string;
fieldName: string;
level: number;
// 映射字段
mappingField: string;
// 地区统计方式
curLevel: 'all' | 'cur';
width: number;
sort: 1 | -1 | 0;
// 透视表该key加入总计
showCount: boolean;
// 仅对resource生效,填充资源
fullResource: boolean;
}[];
aims: {
codeBlock: string;
operator: 'sum' | 'avg' | 'min' | 'max' | 'calculate';
separator: boolean;
calculate: {
_variables: {
_var: string;
_fields: string[];
}[],
_formula: string;
},
fieldName: string;
_key: string;
distinctFields: string;
yAxisIndex: number;
sort: 1 | -1 | 0;
// 数字框 单位
unit: string;
round: number;
ratio: number;
symbol: string;
icon: string;
// 预警
// owarning: {
// type: Array,
// default: [],
// },
warning: {
start: number;
end: number;
logic: "range" | "rangein";
}[],
sortNum: number;
width: number;
}[],
calculateAxis: {
_type: 'ratio' | 'sort';
_key: string;
fieldName: string;
sortNum: number;
sort: 'asc' | 'desc';
aim: {
fieldName: string;
sourceKey: string;
},
key: {
fieldName: string;
sourceKey: string;
},
width: number;
}[],
option: string;
mobileOption: string;
// 数据缺失名称
emptyText: string;
hideNullData: boolean;
fillAndSort: boolean;
needCount: boolean;
displayData: boolean;
dataFields: string[],
// number 类型
numberType: 'normal' | 'icon';
arrangeType: 'crosswise' | 'lengthways';
relyCode: boolean;
// 下钻
modKey: string;
screenKey: string;
buttonRules: {
canShow: false;
canUpdate: false;
},
shpUrl: string;
innerSearch: {
fieldName: string;
fieldKey: string;
fieldType: string;
_dateType: string;
_resourceKey: string;
}[],
innerSearchData: {
[propName: string]: any;
}
}
export interface ScreenDef {
order: number;
screenType: "all" | "normal";
_key: string;
advSearch: AdvSearchDef,
// 创建视图数据时,默认的参数
createFormEntries: {
fieldKey: string;
fieldValue: any[]; // MongooseSchema.Types.Mixed 一定是数组
fieldOperator: "notnull" | "isnull" | "replenish";
}[],
form: ScreenFieldAuthDef[],
tableFields: string[];
indexHints: {
fieldKey: string;
hintOrder: number;
}[],
defaultSearchFields: string[];
topSearchList: {
_key: string;
_name: string;
_span: number;
}[],
defaultSearchWidth: number;
defaultSearchShowRowNum: number;
hasAccess: boolean;
buttonRules: {
canShow: boolean;
canCreate: boolean;
canUpdate: boolean;
canDelete: boolean;
canImport: boolean;
canExport: boolean;
canShare: boolean;
canBatchUpdate: boolean;
// canStartInputFlow: boolean;
// canStartSelectFlow: boolean;
},
name: string;
description: string;
// // 固定前几列
// fixedColumnNumber: number;
// 默认排序字段, ["project_name", "-bid_date"]
sortField: string[];
tableType: 'table' | 'card' | 'panel' | 'crossTable' | 'singleData';
mTableType: 'table' | 'card';
tableSettings: {
maxBtnNum: number;
displaySearch: boolean;
};
cardSettings: {
imageField: string,
titleField: string,
displaySearch: boolean;
};
panelSettings: {
groupField: string,
titleField: string,
displaySearch: boolean;
};
crossTableSettings: {
displaySearch: boolean;
};
singleDataSettings: {
//
};
mTableSettings: {
showColNum: number;
};
mCardSettings: {
showColNum: number;
};
editType: 'normal' | 'standOut';
customGroups: {
_key: string;
order: number;
dashboardKey: string;
name: string;
}[];
}
// --> Mod.js
export interface ModDef extends AppItemDef {
form: FieldBaseDef[]
bindFlow: boolean;
entityAction: "entityPull" | "entityPush";
entityKey: string;
sourceType: "self" | "outer";
bindTask: boolean;
// 保存的form 表单
screens: ScreenDef[],
groups: {
_key: string;
// _name: string;
name: string;
}[],
calOrderMap: {
[propName: string]: any;
}, // string -> int
calChildGraph: {
[propName: string]: any;
}, // string -> []string
flatIdxMap: {
[propName: string]: any;
}, // string -> (string -> int)
fieldIdxMap: {
[propName: string]: any;
}, // string -> int
calOrderSet: string[][][];
version: string;
actionUpdateFlag: boolean;
entityType?: string;
isStoreType?: boolean;
}
// --> Report.js
export interface ReportDef extends AppItemDef {
// 关联仪表盘
dashboardKey: string;
// 报告模板
template: string;
// boards: [{
// _key: String,
// dashboardKey: String,
// itemType: String,
// aimId: String
// }],
form: FieldBaseDef[];
}
// --> ShortCut.js
export interface ShortCutDef extends AppItemDef {
// author: ObjectId,
menuKey: string;
menuType: "Mod" | "Dashboard" | "Tabulation" | "EmbedPage" | "FlowDef" | "TabulationCreate";
user: string;
}
// --> Tabulation.js
export interface TabulationDef extends AppItemDef {
modKey: string;
screenKey: string;
sourceType: string;
// 汇总字段集合
summaryFieldList: {
_key: string;
_name: string;
_numberFormat: "normal" | "percent" | "";
_unit: string;
_ratio: number;
_separator: boolean;
_round: "normal" | "decimal" | "round" | "";
_digit: "1" | "2" | "3" | "4" | "";
_summaryType: "sum" | "average" | "max" | "min" | "no" | "";
}[],
// 主表单关联
tableType: 'table' | 'card' | 'panel' | 'crossTable' | 'singleData';
tableTypes: string[];
tableSettings: {
maxBtnNum: number;
displayFields: string[];
displaySearch: boolean;
},
cardSettings: {
imageField: string;
titleField: string;
displayFields: string[];
displaySearch: boolean;
},
panelSettings: {
groupField: string;
titleField: string;
displayFields: string[],
displaySearch: boolean;
},
crossTableSettings: {
displayFields: string[];
displaySearch: boolean;
},
singleDataSettings: {
displayFields: string[];
},
editType: 'normal' | 'standOut';
buttonSettings: {
boxButtons: {
_type: 'inputFlow' | 'canCustomCreate';
name: string;
customIcon: string;
flowDefKey: string;
}[],
batchButtons: {
_type: 'canCustomBatchUpdate' | 'canCustomBatchDelete' | 'canCustomBatchExport' | 'canCustomBatchImport' | 'canCustomSimpleBatchUpdate' | 'canCustomBatchFunction' | 'canCustomEmebedPage';
name: string;
customIcon: string;
customBatchFunction: string;
canCustomEmebedPage: string;
subType: 'auto' | 'input';
formEntries: {
fieldKey: string;
fieldType: string;
fieldValue: any[]; // MongooseSchema.Types.Mixed 一定是数组
fieldOperator: "notnull" | "isnull" | "replenish";
}[]
}[],
dataButtons: {
_type: 'selectFlow' | 'customEmbedpage' | 'refInputflow' | 'referenceBy' | 'canCustomShow' | 'canCustomUpdate' | 'canCustomDelete' | 'canCustomSimpleShow' | 'canCustomSimpleUpdate';
name: string;
customIcon: string;
relyCondition: AdvSearchDef,
// 修改数据流程的
flowDefKey: string;
showOnUpdate: boolean; // 在编辑页显示
disappearOnList: boolean; // 不在列表页显示
// 嵌入页的
subType: 'route' | 'modal' | 'outImage';
embedpageUrl: string;
// 关联表的
fieldKey: string;
refFlowDefKey: string;
// 编辑的
useRules: boolean;
// 部分查看 部分编辑的
simpleFieldKeys: any[],
}[],
},
useCreateMenu: boolean;
createMenuName: string;
createSuccessTip: string;
modName: string;
screenName: string;
}
// --> Trigger.js
export interface TriggerDef extends AppItemDef {
// 触发类型
triggerType: "timeField" | "fieldChange" | "cycleTime";
modKey: string;
// 是否有效
isTriggerValid: boolean;
// 事件触发的类型
triggerEvent: "createOrUpdate" | "create" | "update" | null;
fieldKey: string;
isOffset: boolean;
// 当前时间判断前后
timeCheck: "before" | "after" | null;
timeUnit: "minute" | "hour" | "day" | null;
timeOffset: number;
triggerTime: Date;
isCycle: boolean;
cycleUnit: "year" | "month" | "day" | "quarter";
cycleLength: number;
// cycleMonth: Number,
// cycleDay: Number,
// cycleTime: {
// type: String,
// enum: ["current", "system"],
// types: [
// { "current": "当前时间" },
// { "system": "系统固定时间" },
// ]
// },
changeLogic: "and" | "or";
isChange: boolean;
changeFields: string[];
hasUpdate: boolean;
flowDefKey: string;
advSearch: AdvSearchDef;
}
// ------------>------------>------------>------------>------------>------------>------------>
// ------------>------------>------------>
export interface PermissionDef {
fieldEditable: boolean;
fieldPicked: boolean;
fieldKey: string;
fieldSubRules: PermissionDef[];
}
export interface ScreenFieldAuthDef extends PermissionDef {
fieldWidth: number;
}
// ------------>------------>------------>
export interface DashboardDataDef {
// Base
_key: string;
itemType: string;
relyType: "show" | "hide";
x: number;
y: number;
w: number;
h: number;
title: string;
name: string;
textContent: string;
moveTab: string[];
// TextData
textTemplate: string;
customFunction: string;
advSearch: AdvSearchDef,
textAlign: "left" | "center";
// PictureData
pictureType: "image" | "tag";
tagIcon: string;
tagKind: string;
imageUrl: string;
linkUrl: string;
backgroundSize: string;
backgroundPositionY: string;
backgroundPositionX: string;
// MenuData
menuList: {
_key: string;
name: string;
_type: string;
}[];
menuProperty: "right" | "down";
// FormData
formType: string;
step: number;
// formSetting: formSetting; // todo
formJustify: string;
// GanttData
dimension: string
// EmbedPageData
url: string;
embedPageType: string;
params: string;
// tabsData
subBoard: {
_key: string;
name: string;
data: DashboardDataDef[]
}[]
}
// ------------>------------>------------>
/// /////////////////////////////////////
// 管理态表单控件选项
/// /////////////////////////////////////
// ------------>------------>------------>
export interface StepDef {
/// /////////////////////////////////////////////
// 共用属性
/// /////////////////////////////////////////////
_id: string;
_key: string;
name: string;
order_single: number;
order_group: number;
order_show: boolean;
percentage: number;
step_type: "user_start" | "event_start" | "user_task" | "end_event";
screenKey: string;
update_owner: boolean;
owner_field: string;
////////////////////
// 结束
////////////////////
task_class: "submit" | "verify" | "notify" | "subflow" | null | "";
// 开始条件
start_condition: "and" | "or" | "";
// 用户操作条件
operate_condition: "and" | "or" | "";
push_condition: "and" | "or" | "";
push_name: string;
reject_name: string;
/////////////////////////////////////////////////
// 子流程 sub_flow
/////////////////////////////////////////////////
sub_flow: string;
/////////////////////////////////////////////////
// 系统任务 system_task
/////////////////////////////////////////////////
start_actions: SystemActionDef[];
pause_actions: SystemActionDef[]; // 暂停时事件
stop_actions: SystemActionDef[]; // 终止时事件
reset_actions: SystemActionDef[]; // 重启时事件
no_push_step_msg: string;
// 允许审批人转签
allow_change_other: boolean;
change_other_name: string;
// 允许审批人加签
allow_add_other: boolean;
add_other_name: string;
// 允许暂停
allow_pause: boolean;
pause_name: string;
reset_name: string;
// 允许停止
allow_stop: boolean;
stop_name: string;
// 允许关联用户字段
allow_related_user: boolean;
form: PermissionDef[],
// 操作用户角色 start
roles: mongoose.Types.ObjectId[];
roleKeys: string[];
user_type: string;
dept_type: {
full_name: string,
level: string,
role: string,
}[],
users: string[],
user_field: string;
custom_function: {
function_name: string;
function_title: string;
},
push_user_field: string;
position: {
top: number;
left: number;
},
node_remark: string;
}
export interface SystemActionDef {
system_action: "update" | "updateTime" | "dbCreateOrUpdate" | "sendEmail" | "sendSms" | "customFunction";
action_data: {
timeFields: string[];
subject: string;
html: string;
custom_function: string;
name: string;
formEntries: {
fieldKey: string;
fieldValue: any[]; // MongooseSchema.Types.Mixed 一定是数组
fieldOperator: "notnull" | "isnull" | "replenish";
}[]
}
}
export interface RelationDef {
_key: string;
source: string;
target: string;
description: string;
startAnchor: AnchorType;
endAnchor: AnchorType;
relation_type: "push" | "push_revert" | "revert";
match_left: boolean;
actions: SystemActionDef[];
advSearch: AdvSearchDef;
node_remark: string;
}
// ------------>------------>------------>
export interface SubMenuDef {
name: string;
order?: number;
color?: string;
icon?: string;
mobileHide: boolean;
menuKey: string;
menuType: MenuType;
}
// ------------>------------>------------>
export interface MenuDef {
name: string;
order: number;
icon: string;
isSpecial: boolean;
menuItems: SubMenuDef[],
children: MenuDef[]
}
// ------------>------------>------------>
export interface InnerDataDef extends AppItemDef {
modKey: string;
sourceType: string;
screenKey: string;
entityKey: string;
cacheSeconds: number;
search: {
[propName: string]: any;
},
itemType: string,
advSearch: AdvSearchDef,
// 引用当前图表的列表
refererKeys: string[];
}
// ------------>------------>------------>
export interface AdvSearchDef {
fieldKey?: string;
fieldType?: string;
fieldValue?: any[]; // MongooseSchema.Types.Mixed 一定是数组
fieldParams?: string[];
fieldOperator?: "eq" | "ne" | "regex" | "textnot" | "startsWith" | "endsWith" | "isnull" | "notnull" | "range" | "notrange" | "rangein" | "rangenin" | "rangeLeftin" | "rangeLeftnin" | "rangeRightin" | "rangeRightnin" | "in" | "nin" | "nosize" | "size" | "belong" | "nbelong" | "subSearch" | "code" | "" | "all" | "flatSearch" | "subTableSearch" | "noList" | "list";
logic: "and" | "or" | "field" | "text" | "native";
parameterType?: string,// 仪表盘用
customFuncName?: string,
conditions?: AdvSearchDef[],
fieldSearch?: AdvSearchDef,
nativeSearch?: {
[propName: string]: any;
},
textSearch?: string,
formData?: {
[propName: string]: any;
},
_dateType?: string,
formItem?: EntityFieldDef
}
type fieldTypeEnum = 'text' | 'textarea' | 'number' | 'idcard' | 'email' | 'phone' | 'switch' | 'date' | 'select' | 'cascader' | 'cascaders' | 'checkbox' | 'file' | 'region' | 'regions' | 'editor' | 'reference' | 'referenceBy' | 'flatTable' | 'cascaderTable' | 'package' | 'labels' | 'users' | 'departments' | 'coordinates' | 'serialNumber' | 'tag';
export interface FieldBaseDef {
// Base
_type: fieldTypeEnum;
// 该控件数据库保存名称
_key: string;
// 该控件前端显示名称
_name: string;
_description: string;
_comment: string;
_tagKey: string,
// 宽度 24、12
_span: number;
_align: "left" | "center" | "right" | "";
// 是否独占一行
_br: boolean;
_wrap: boolean;
// 默认值
_line: boolean;
_noLabel: boolean;
_default: any[]; // MongooseSchema.Types.Mixed 一定是数组
_required: boolean;
_group: string;
_clearable: boolean;
_isExport: boolean;
_regStr: string;
_regMessage: string;
// tagSchema
_tagKind: string;
_tagIcon: string;
// resourceBase
_resourceKey: string;
_data?: ResData[];
// optionBase
_optionKind: "dropdown" | "flat" | "";
_useColor: boolean;
_color: boolean;
// commonSchema、calculateSchema
_enterType: "input" | "calculate" | "calculateInput" | "copyData" | "";
_calculate: {
_variables: {
_var: string;
_fields: string[]
}[],
_formula: string
},
_displayType: "show" | "hide" | "advRely" | "";
_advRely: AdvSearchDef,
// 复制数据表 需要字段
_copyRef: string;
_copyScreen: string;
_copyField: string;
_copyShowFields: string[],
_width: number;
_padding: number;
// switchSchema
_openText: string;
_closeText: string;
// textSchema
_verifyRegular: string;
_textType: "default" | "url";
// phoneSchema
_phoneType: "mobilePhone" | "fixPhone" | "";
// labelsSchema
_multiple: boolean;
_labelType: "entity" | "user";
_onlySelect: boolean;
_originLabels: {
_key: string;
name: string;
}[];
// textareaSchema
_maxlength: number; // 最大输入长度
// numberSchema
// 单位
_unit: string;
_numberFormat: "normal" | "percent" | "";
_max: number;
_min: number;
_round: "normal" | "decimal" | "round" | "";
_digit: "1" | "2" | "3" | "4" | "";
_showProgress: boolean;
_separator: boolean;
_summaryType: "sum" | "average" | "max" | "min" | "no";
// saveRulesSchemaMap
_saveRuleLogic: "and" | "or" | "";
_saveRuleConfigs: {
_operator: "gt" | "lt" | "et" | "gtAet" | "ltAet";
_fieldKey: string;
_ruleTip: string;
}[]
// dateSchema
_dateType: "date" | "month" | "year" | "datetime" | "time" | "";
_autoGetTime: boolean;
// selectSchema
_openTip: boolean;
_tipName: string;
_tipKind: "fixed" | "dynamic" | "";
_tipContent: string;
_tipUrl: string;
// commonCascaderSchema
_showMode: "default" | "custom" | "mdoal";
_filterable: boolean;
_changeOnSelect: boolean;
_cascaderLevel: string;
_cascaderFilterVals: any[];
_joinSymbol: String;
// referenceBase
// 关联表 数据库表名 针对 table ref 使用
_ref: string;
_screen: string;
_refFields: string[];
_showScreen: string;
_entityKey: string;
// referenceSchema
_exhibitionType: "table" | "form" | "";
_searchCodeBlock: any[];
// referenceBySchema
_filterField: string;
_toBRelationField: string;
_sortField: any[];
_filterString: string;
_filterReplaceKeys: string;
// 八局需求
_listScreen: string;
// fileSchema
_fileType: "file" | "image" | "";
_listShowMode: "default" | "thumbnail";
// usersSchema
_searchString: string; // 检索字符串
// departmentsSchema
_showParent: boolean; //是否显示上级
// checkboxSchema
_maxTagCount: number;
// coordinatesSchema
_showType: "marker" | "multipleMarker" | "polyline" | "polygon" | "rectangle" | "circle" | "";
_autoLocation: boolean;
_mapType: "2D" | "3D";
_zoom: number;
_center: string;
// tableBase
_defaultTableString: string;
_subForm: FieldBaseDef[]; // todo 不知道咋写
// flatTableSchema
_flatTableIdentify: string;
_useIndex: boolean;
_useSummary: boolean;
_disabledBtns: boolean;
_disabledOldDataRow: boolean;
// _default: { // todo 跟 Base 里的 _default 一样,但是类型不同
// "list": [],
// "rowDefault": {}
// },
_flatTableLayout: "line" | "vertical" | "";
// cascaderTableSchema
_treeForm: treeFormDef[];
isCreateField?: any;
}
export interface treeFormDef {
_key: string;
_name: string;
_type: "textarea" | "";
_width: number;
_treeSubForm: {
_key: string;
_name: string;
_type: string;
_operator: "sum" | "avg" | "max" | "min" | "";
_calField: string;
}[];
// level: number;
}
\ No newline at end of file
////////////////////////////////////////////////////////
//
// 重要 !!!!!!!!!!!!!!!!!!!!
//
// 核心模块代码, 请到ts_basis项目中修改提交
//
////////////////////////////////////////////////////////
import { BaseDef } from "./commonTypes";
import { StepDef, RelationDef } from "./coreTypes";
import { FieldBaseDef } from "./coreTypes";
import { AttachmentBaseDef } from "./fileTypes";
import { AnchorType } from "./commonTypes";
import mongoose from "mongoose"
export type StepOperateType = "waiting" | "completed" | "rejected" | "reverted" | "other_completed" | "other_rejected" | "changed" | "add_task" | "pause" | "stoped";
export interface AppMessageDef extends BaseDef {
// 根据key判断task类型
taskKey: string;
// 保存变化较少的基础信息 start
dataName: string;
stepName: string;
// 保存变化较少的基础信息 end
userKey: string;
appKey: string;
view_status: "0" | "1";
is_valid: "0" | "1";
messageType: "FlowTask" | "FlowNotify" | "TabNotify";
}
export interface CommonPhrasesDef extends BaseDef {
userKey: string;
title: string;
opinion: string;
status: "0" | "1";
_type: "verify" | "reject";
}
export interface FlowInstDef extends BaseDef {
flow_stage: "started" | "completed" | "stoped" | "pause";
finishTime: Date;
stageSave: boolean;
flow_style: "default" | "form";
flow_operation: "create" | "update";
flowDefKey: string;
chart_name: string;
appKey: string;
// 所属人
owner: string;
// 所属人
creator: string;
modKey: string;
form: FieldBaseDef[];
dataId: mongoose.Types.ObjectId;
// 数据对象
dataObj: {
[propName: string]: any;
},
oldDataObj: {
[propName: string]: any;
},
taskData: {
[propName: string]: any;
},
dataName: string;
// 流程可见用户
usersAll: string[];
percentage: number;
// 所属步骤, 表示这个流程是一个子流程
ownerStep: mongoose.Types.ObjectId;
// 流程当前步骤
stepsNow: {
step: mongoose.Types.ObjectId;
users: string[];
usersAll: string[];
}[],
changeLog: [{
user: string;
action: "create" | "update";
updatedAt: Date;
changed: {
fieldKey: string;
oldDesc: string;
newDesc: string;
}[]
}],
pauseDate: Date[];
resetDate: Date[];
}
export interface FlowNotifyDef extends BaseDef, TaskNotifyDef {
}
export interface FlowTaskDef extends BaseDef, TaskNotifyDef {
// 转签或加签的流程审批,parent指向转签或加签的那个人
parentTask: mongoose.Types.ObjectId;
flowInstStage: string;
actionUpdateFlag: boolean;
}
export interface LabelDef extends BaseDef {
_key: string;
name: string;
compKey: string;
entityKey: string;
deptKey: string;
deptKeys: any[];
creator: string;
labelType: "user" | "entity";
labelStatus: "enable" | "disable";
}
export interface ReportInstDef extends BaseDef {
name: string;
reportKey: string;
formData: {
[propName: string]: any;
},
attachment: AttachmentBaseDef
}
export interface RelationInstDef {
_key: string;
relation_status: "0" | "1";
relation_type: "push" | "revert";
active_count: number;
priority: number;
target: mongoose.Types.ObjectId;
startAnchor: AnchorType;
endAnchor: AnchorType;
relation_def: RelationDef,
}
export interface StepInstDef extends BaseDef {
step_def: StepDef,
stepOrder: number;
step_status: "waiting" | "started" | "completed" | "rejected" | "reverted" | "pause" | "stoped";
appKey: string;
flow_inst: mongoose.Types.ObjectId;
modKey: string;
dataId: mongoose.Types.ObjectId;
stepData: {
[propName: string]: any;
},
active_count: number;
// 只用来做计算
beforeRelations: {
source: mongoose.Types.ObjectId;
relation_type: "push" | "revert";
}[];
relations: RelationInstDef[],
start_date: Date;
end_date: Date;
actionUpdateFlag: boolean
}
export interface TabNotifyDef extends BaseDef {
userKey: string;
appKey: string;
_key: string;
stepName: string;
modKey: string;
tabulationKey: string;
dataId: string;
operate_time: Date;
view_status: "0" | "1";
// 有些步骤可能已失效
is_valid: "0" | "1";
}
export interface TriggerLogDef extends BaseDef {
// 工作表及数据信息
appKey: string;
triggerKey: string;
triggerTime: Date;
// 用户操作
status: "fail" | "success";
log: string;
data: {
[propName: string]: any;
}
}
export interface TaskNotifyDef {
_key: string;
modKey: string;
dataId: mongoose.Types.ObjectId;
// 保存变化较少的基础信息 start
dataName: string;
flowOwner: string;
// 保存变化较少的基础信息 end
step_def: StepDef,
stepDefKey: string;
userKey: string;
prevUserKey: string;
appKey: string;
flow_inst: mongoose.Types.ObjectId;
step_active: number;
step_inst: mongoose.Types.ObjectId;
operate_time: Date;
view_status: "0" | "1";
// 有些步骤可能已失效
is_valid: "0" | "1";
step_operate: StepOperateType;
taskData: {
[propName: string]: any;
},
step_opinion: string;
}
type Merge<T> = {
[P in keyof T]: T[P]
}
/**
* 实现一种向接口添加新字段的类型
*/
type AppendToObject<T, U extends string, V> = Merge<
{ [P in keyof T]: T[P] } & { [P in U]: V }
>
\ No newline at end of file
////////////////////////////////////////////////////////
//
// 重要 !!!!!!!!!!!!!!!!!!!!
//
// 核心模块代码, 请到ts_basis项目中修改提交
//
////////////////////////////////////////////////////////
import { BaseDef, KeyItemDef, NameDef } from "./commonTypes";
import { AdvSearchDef, PermissionDef } from "./coreTypes";
import { EntityFieldDef } from "./modTypes";
import { ResData } from "./resourceTypes";
// --> TimeRiver.js
export interface DbEntityDef extends KeyItemDef, NameDef {
// 大部分都是outer数据,其他预留给其他公司下载应用用。
entityType: "normal" | "inner" | "dataFactory";
sourceType: "self" | "outer";
outerSourceKey: "custom" | "ppp";
ownerCompany: string;
dbAppKey: string;
ownerEntity: string;
form: EntityFieldDef[];
groups: GroupItemDef[];
}
export interface DbPackageDef extends KeyItemDef, NameDef {
// 控制哪些公司有权限
companies: {
_key: string;
}[];
// 拥有者公司
ownerCompany: string;
dbAppKey: string;
defaultExpireDays: number;
entityRules: {
dbEntityKey: string;
fieldRules: PermissionDef[];
advSearch: AdvSearchDef;
}[];
}
export interface DbResourceDef extends KeyItemDef, NameDef {
ownerCompany: string;
resType: "dropdown" | "tree";
dbAppKey: string;
resData: ResData[];
maxLevel: number;
sourceType: "self" | "outer"
}
export interface DbAppDef extends KeyItemDef, NameDef {
ownerCompany: string;
name: string;
description: string;
dbPackageKey: string;
appType: "normal" | "data";
appScene: "invest" | "project" | "oa" | "accounting" | "sales" | "manufacturing" | "purchase" | "store" | ""
dataScene: "industry" | "public" | "finance" | "research" | "society" | ""
version: string;
appItems: any;
active: "0" | "1";
is_exists: boolean;
introduction: string;
owner: string;
validity: number;
dbEntitys: string[];
dbResources: string[];
downloadNum: number;
visibleCompKeys: string[];
maxQuery: number;
integral: number;
extendDuration: number;
durationIntegral: number;
appImages: any[];
updateFrequency: string;
dataVolume: string;
}
export interface DbPurchaseDef extends BaseDef {
ownerCompany: string;
purchaseCompany: string;
purchaseDate: Date;
expireDate: Date;
dbPackageKey: string;
dbAppKey: string;
appType: "normal" | "data";
purchaseUser: string;
delayStartDate: Date;
amount: number;
delayUser: string;
is_active: boolean;
remarks: string;
maxQuery: number;
handleType: string;
}
export interface GroupItemDef {
_key: string;
name: string;
children: GroupItemDef[];
}
export interface DbAppItemDef extends KeyItemDef, NameDef {
dbAppKey: string;
coreKey: string;
schemaType: "Mod" | "DashBoard" | "InnerChart" | "InnerTable" | "Tabulation" | "FlowDef" | "AppRole" | "EmbedPage";
config: any;
}
export interface DbAppRecordDef extends KeyItemDef {
dbAppKey: string;
owner: string;
version: string;
}
export interface DbRequestDef extends BaseDef {
contact: string;
detail: string;
compKey: string;
compName: string;
industry: "government" | "construction" | "retail" | "manufacture" | "internet" | "rent" | "architecture" | "education" | "realestate" | "traffic" | "farmer" | "catering" | "culture" | "public" | "mining" | "energy" | "medical" | "other" | ""
}
export interface QueryRecordDef extends BaseDef {
compKey: string;
useCompKey: string;
dbAppKey: string;
entityKey: string;
serviceTime: Date;
count: number;
queryType: "index" | "all" | "groupData"
}
export interface IntegralDef extends KeyItemDef {
compKey: string;
sourceCompKey: string;
dealIntegral: number;
residueIntegral: number;
changeType: "init" | "share" | "deal" | "delay";
dbAppKey: string;
is_active: boolean;
}
export interface VisitRecordDef extends BaseDef {
visitCompany: string;
dbAppKey: string;
visitTime: Date;
visitUser: string;
content: string;
}
"use strict";
////////////////////////////////////////////////////////
//
// 重要 !!!!!!!!!!!!!!!!!!!!
//
// 核心模块代码, 请到ts_basis项目中修改提交
//
////////////////////////////////////////////////////////
/**
* Hypertext Transfer Protocol (HTTP) response status codes.
*/
export enum HttpStatusCode {
/**
* The server has received the request headers and the client should proceed to send the request body
* (in the case of a request for which a body needs to be sent; for example, a POST request).
* Sending a large request body to a server after a request has been rejected for inappropriate headers would be inefficient.
* To have a server check the request's headers, a client must send Expect: 100-continue as a header in its initial request
* and receive a 100 Continue status code in response before sending the body. The response 417 Expectation Failed indicates the request should not be continued.
*/
CONTINUE = 100,
/**
* The requester has asked the server to switch protocols and the server has agreed to do so.
*/
SWITCHING_PROTOCOLS = 101,
/**
* A WebDAV request may contain many sub-requests involving file operations, requiring a long time to complete the request.
* This code indicates that the server has received and is processing the request, but no response is available yet.
* This prevents the client from timing out and assuming the request was lost.
*/
PROCESSING = 102,
/**
* Standard response for successful HTTP requests.
* The actual response will depend on the request method used.
* In a GET request, the response will contain an entity corresponding to the requested resource.
* In a POST request, the response will contain an entity describing or containing the result of the action.
*/
OK = 200,
/**
* The request has been fulfilled, resulting in the creation of a new resource.
*/
CREATED = 201,
/**
* The request has been accepted for processing, but the processing has not been completed.
* The request might or might not be eventually acted upon, and may be disallowed when processing occurs.
*/
ACCEPTED = 202,
/**
* SINCE HTTP/1.1
* The server is a transforming proxy that received a 200 OK from its origin,
* but is returning a modified version of the origin's response.
*/
NON_AUTHORITATIVE_INFORMATION = 203,
/**
* The server successfully processed the request and is not returning any content.
*/
NO_CONTENT = 204,
/**
* The server successfully processed the request, but is not returning any content.
* Unlike a 204 response, this response requires that the requester reset the document view.
*/
RESET_CONTENT = 205,
/**
* The server is delivering only part of the resource (byte serving) due to a range header sent by the client.
* The range header is used by HTTP clients to enable resuming of interrupted downloads,
* or split a download into multiple simultaneous streams.
*/
PARTIAL_CONTENT = 206,
/**
* The message body that follows is an XML message and can contain a number of separate response codes,
* depending on how many sub-requests were made.
*/
MULTI_STATUS = 207,
/**
* The members of a DAV binding have already been enumerated in a preceding part of the (multistatus) response,
* and are not being included again.
*/
ALREADY_REPORTED = 208,
/**
* The server has fulfilled a request for the resource,
* and the response is a representation of the result of one or more instance-manipulations applied to the current instance.
*/
IM_USED = 226,
/**
* Indicates multiple options for the resource from which the client may choose (via agent-driven content negotiation).
* For example, this code could be used to present multiple video format options,
* to list files with different filename extensions, or to suggest word-sense disambiguation.
*/
MULTIPLE_CHOICES = 300,
/**
* This and all future requests should be directed to the given URI.
*/
MOVED_PERMANENTLY = 301,
/**
* This is an example of industry practice contradicting the standard.
* The HTTP/1.0 specification (RFC 1945) required the client to perform a temporary redirect
* (the original describing phrase was "Moved Temporarily"), but popular browsers implemented 302
* with the functionality of a 303 See Other. Therefore, HTTP/1.1 added status codes 303 and 307
* to distinguish between the two behaviours. However, some Web applications and frameworks
* use the 302 status code as if it were the 303.
*/
FOUND = 302,
/**
* SINCE HTTP/1.1
* The response to the request can be found under another URI using a GET method.
* When received in response to a POST (or PUT/DELETE), the client should presume that
* the server has received the data and should issue a redirect with a separate GET message.
*/
SEE_OTHER = 303,
/**
* Indicates that the resource has not been modified since the version specified by the request headers If-Modified-Since or If-None-Match.
* In such case, there is no need to retransmit the resource since the client still has a previously-downloaded copy.
*/
NOT_MODIFIED = 304,
/**
* SINCE HTTP/1.1
* The requested resource is available only through a proxy, the address for which is provided in the response.
* Many HTTP clients (such as Mozilla and Internet Explorer) do not correctly handle responses with this status code, primarily for security reasons.
*/
USE_PROXY = 305,
/**
* No longer used. Originally meant "Subsequent requests should use the specified proxy."
*/
SWITCH_PROXY = 306,
/**
* SINCE HTTP/1.1
* In this case, the request should be repeated with another URI; however, future requests should still use the original URI.
* In contrast to how 302 was historically implemented, the request method is not allowed to be changed when reissuing the original request.
* For example, a POST request should be repeated using another POST request.
*/
TEMPORARY_REDIRECT = 307,
/**
* The request and all future requests should be repeated using another URI.
* 307 and 308 parallel the behaviors of 302 and 301, but do not allow the HTTP method to change.
* So, for example, submitting a form to a permanently redirected resource may continue smoothly.
*/
PERMANENT_REDIRECT = 308,
/**
* The server cannot or will not process the request due to an apparent client error
* (e.g., malformed request syntax, too large size, invalid request message framing, or deceptive request routing).
*/
BAD_REQUEST = 400,
/**
* Similar to 403 Forbidden, but specifically for use when authentication is required and has failed or has not yet
* been provided. The response must include a WWW-Authenticate header field containing a challenge applicable to the
* requested resource. See Basic access authentication and Digest access authentication. 401 semantically means
* "unauthenticated",i.e. the user does not have the necessary credentials.
*/
UNAUTHORIZED = 401,
/**
* Reserved for future use. The original intention was that this code might be used as part of some form of digital
* cash or micro payment scheme, but that has not happened, and this code is not usually used.
* Google Developers API uses this status if a particular developer has exceeded the daily limit on requests.
*/
PAYMENT_REQUIRED = 402,
/**
* The request was valid, but the server is refusing action.
* The user might not have the necessary permissions for a resource.
*/
FORBIDDEN = 403,
/**
* The requested resource could not be found but may be available in the future.
* Subsequent requests by the client are permissible.
*/
NOT_FOUND = 404,
/**
* A request method is not supported for the requested resource;
* for example, a GET request on a form that requires data to be presented via POST, or a PUT request on a read-only resource.
*/
METHOD_NOT_ALLOWED = 405,
/**
* The requested resource is capable of generating only content not acceptable according to the Accept headers sent in the request.
*/
NOT_ACCEPTABLE = 406,
/**
* The client must first authenticate itself with the proxy.
*/
PROXY_AUTHENTICATION_REQUIRED = 407,
/**
* The server timed out waiting for the request.
* According to HTTP specifications:
* "The client did not produce a request within the time that the server was prepared to wait. The client MAY repeat the request without modifications at any later time."
*/
REQUEST_TIMEOUT = 408,
/**
* Indicates that the request could not be processed because of conflict in the request,
* such as an edit conflict between multiple simultaneous updates.
*/
CONFLICT = 409,
/**
* Indicates that the resource requested is no longer available and will not be available again.
* This should be used when a resource has been intentionally removed and the resource should be purged.
* Upon receiving a 410 status code, the client should not request the resource in the future.
* Clients such as search engines should remove the resource from their indices.
* Most use cases do not require clients and search engines to purge the resource, and a "404 Not Found" may be used instead.
*/
GONE = 410,
/**
* The request did not specify the length of its content, which is required by the requested resource.
*/
LENGTH_REQUIRED = 411,
/**
* The server does not meet one of the preconditions that the requester put on the request.
*/
PRECONDITION_FAILED = 412,
/**
* The request is larger than the server is willing or able to process. Previously called "Request Entity Too Large".
*/
PAYLOAD_TOO_LARGE = 413,
/**
* The URI provided was too long for the server to process. Often the result of too much data being encoded as a query-string of a GET request,
* in which case it should be converted to a POST request.
* Called "Request-URI Too Long" previously.
*/
URI_TOO_LONG = 414,
/**
* The request entity has a media type which the server or resource does not support.
* For example, the client uploads an image as image/svg+xml, but the server requires that images use a different format.
*/
UNSUPPORTED_MEDIA_TYPE = 415,
/**
* The client has asked for a portion of the file (byte serving), but the server cannot supply that portion.
* For example, if the client asked for a part of the file that lies beyond the end of the file.
* Called "Requested Range Not Satisfiable" previously.
*/
RANGE_NOT_SATISFIABLE = 416,
/**
* The server cannot meet the requirements of the Expect request-header field.
*/
EXPECTATION_FAILED = 417,
/**
* This code was defined in 1998 as one of the traditional IETF April Fools' jokes, in RFC 2324, Hyper Text Coffee Pot Control Protocol,
* and is not expected to be implemented by actual HTTP servers. The RFC specifies this code should be returned by
* teapots requested to brew coffee. This HTTP status is used as an Easter egg in some websites, including Google.com.
*/
I_AM_A_TEAPOT = 418,
/**
* The request was directed at a server that is not able to produce a response (for example because a connection reuse).
*/
MISDIRECTED_REQUEST = 421,
/**
* The request was well-formed but was unable to be followed due to semantic errors.
*/
UNPROCESSABLE_ENTITY = 422,
/**
* The resource that is being accessed is locked.
*/
LOCKED = 423,
/**
* The request failed due to failure of a previous request (e.g., a PROPPATCH).
*/
FAILED_DEPENDENCY = 424,
/**
* The client should switch to a different protocol such as TLS/1.0, given in the Upgrade header field.
*/
UPGRADE_REQUIRED = 426,
/**
* The origin server requires the request to be conditional.
* Intended to prevent "the 'lost update' problem, where a client
* GETs a resource's state, modifies it, and PUTs it back to the server,
* when meanwhile a third party has modified the state on the server, leading to a conflict."
*/
PRECONDITION_REQUIRED = 428,
/**
* The user has sent too many requests in a given amount of time. Intended for use with rate-limiting schemes.
*/
TOO_MANY_REQUESTS = 429,
/**
* The server is unwilling to process the request because either an individual header field,
* or all the header fields collectively, are too large.
*/
REQUEST_HEADER_FIELDS_TOO_LARGE = 431,
/**
* A server operator has received a legal demand to deny access to a resource or to a set of resources
* that includes the requested resource. The code 451 was chosen as a reference to the novel Fahrenheit 451.
*/
UNAVAILABLE_FOR_LEGAL_REASONS = 451,
/**
* A generic error message, given when an unexpected condition was encountered and no more specific message is suitable.
*/
INTERNAL_SERVER_ERROR = 500,
/**
* The server either does not recognize the request method, or it lacks the ability to fulfill the request.
* Usually this implies future availability (e.g., a new feature of a web-service API).
*/
NOT_IMPLEMENTED = 501,
/**
* The server was acting as a gateway or proxy and received an invalid response from the upstream server.
*/
BAD_GATEWAY = 502,
/**
* The server is currently unavailable (because it is overloaded or down for maintenance).
* Generally, this is a temporary state.
*/
SERVICE_UNAVAILABLE = 503,
/**
* The server was acting as a gateway or proxy and did not receive a timely response from the upstream server.
*/
GATEWAY_TIMEOUT = 504,
/**
* The server does not support the HTTP protocol version used in the request
*/
HTTP_VERSION_NOT_SUPPORTED = 505,
/**
* Transparent content negotiation for the request results in a circular reference.
*/
VARIANT_ALSO_NEGOTIATES = 506,
/**
* The server is unable to store the representation needed to complete the request.
*/
INSUFFICIENT_STORAGE = 507,
/**
* The server detected an infinite loop while processing the request.
*/
LOOP_DETECTED = 508,
/**
* Further extensions to the request are required for the server to fulfill it.
*/
NOT_EXTENDED = 510,
/**
* The client needs to authenticate to gain network access.
* Intended for use by intercepting proxies used to control access to the network (e.g., "captive portals" used
* to require agreement to Terms of Service before granting full Internet access via a Wi-Fi hotspot).
*/
NETWORK_AUTHENTICATION_REQUIRED = 511
}
////////////////////////////////////////////////////////
//
// 重要 !!!!!!!!!!!!!!!!!!!!
//
// 核心模块代码, 请到ts_basis项目中修改提交
//
////////////////////////////////////////////////////////
import { BaseDef } from './commonTypes'
export interface AttachmentBaseDef extends BaseDef {
name: string;
mimetype: string;
path: string;
size: number;
url: string;
downloadUrl: string;
bucket: string;
}
export interface AttachmentDef extends AttachmentBaseDef {
imgWidth: number;
imgHeight: number;
groupKey: string;
archiveKey: string;
fileType: string;
userKey: string;
storageStatus: string;
}
////////////////////////////////////////////////////////
//
// 重要 !!!!!!!!!!!!!!!!!!!!
//
// 核心模块代码, 请到ts_basis项目中修改提交
//
////////////////////////////////////////////////////////
import { BaseDef } from "./commonTypes";
export interface ExcelData{
rows: any[];
fileName: string;
"!merges"?: any[];
}
export interface ImportExcelJobDef extends BaseDef {
_id: string,
compKey: string,
appKey?: string,
modKey?: string,
entityKey: string,
screenKey?: string,
total: number,
suc: number,
fai: number,
status: "check" | "import" | "over" | "check-fai" | "fai",
faiMsg?: string
}
////////////////////////////////////////////////////////
//
// 重要 !!!!!!!!!!!!!!!!!!!!
//
// 核心模块代码, 请到ts_basis项目中修改提交
//
////////////////////////////////////////////////////////
import { BaseDef } from "./commonTypes";
import mongoose from "mongoose"
export interface CustomLogDef extends BaseDef {
// 工作表及数据信息
appKey: string;
modKey: string;
oid: mongoose.Types.ObjectId;
// 用户信息
user: string;
// 用户操作
action: "create" | "update" | "delete";
data: string;
changed: {
fieldKey: string;
oldDesc: string;
newDesc: string;
}[];
deleted: boolean;
dataName: string;
}
\ No newline at end of file
////////////////////////////////////////////////////////
//
// 重要 !!!!!!!!!!!!!!!!!!!!
//
// 核心模块代码, 请到ts_basis项目中修改提交
//
////////////////////////////////////////////////////////
import { BaseDef, CompItemDef } from './commonTypes'
import { ResData } from './resourceTypes';
import { OrderDef } from './commonTypes';
export interface GroupItem {
_key: string;
name: string;
children: GroupItem[];
}
export interface EntityFieldDef {
_key: string;
_type: string;
_name: string;
_dbRequired: boolean;
_unique: boolean;
_description?: string;
_filterField?: string;
_chartInvisible?: boolean;
_entityKey?: string;
_resourceKey?: string;
_dbGroup?: string;
_dateType?: "date" | "year" | "month" | "datetime" | "time";
_textType?: "default" | "url";
_data?: ResData[];
_subForm?: EntityFieldDef[];
}
export interface EntityDef extends CompItemDef {
entityType: "normal" | "inner" | "dataFactory";
sourceType: "self" | "outer";
ownerAppKeys: string[];
enCoding: string;
form: EntityFieldDef[];
indexes: {
name: string,
fields: {
fieldKey: string;
indexType: "asc" | "desc" | "text" | "2dsphere" | "hashed"
}[]
}[],
groups: GroupItem[];
itemGroupKey: string;
version: number;
addIdFlag?: boolean
}
interface FieldChangeDef {
_key: string;
_name: string;
_required: boolean; // 是否必填
_type: string; // 字段类型
_index: boolean; // 是否索引
}
export interface EntityVersionDef extends BaseDef {
order: number;
compKey: string;
entityKey: string;
user: string;
newFields: FieldChangeDef[];
deletedFields: FieldChangeDef[];
}
\ No newline at end of file
////////////////////////////////////////////////////////
//
// 重要 !!!!!!!!!!!!!!!!!!!!
//
// 核心模块代码, 请到ts_basis项目中修改提交
//
////////////////////////////////////////////////////////
import { BaseDef } from "./commonTypes";
import mongoose from "mongoose"
export interface TaskCountDef {
taskCount: {
allCount: number;
task: number;
notify: number;
tabNotify: number;
}
}
export interface CountMsgDef {
count: TaskCountDef,
userKey: string,
messageType: string
}
export interface ShareLogDef extends BaseDef {
compKey: string,
appKey: string,
modKey: string,
screenKey: string,
dashboardKey: string,
chartKey: string,
dataId: mongoose.Types.ObjectId,
name: string,
shareLink: string,
status: "0" | "1",
detailType: "show" | "edit" | "create",
sharer: string,
pageType: string,
expireAt: Date,
fromShareUser: boolean,
formDataStr: string,
iconId: mongoose.Types.ObjectId,
}
export interface SocketOption {
onData: (...args: any) => any,
onError: (...args: any) => any,
onEnd: (...args: any) => any,
event: string,
}
\ No newline at end of file
////////////////////////////////////////////////////////
//
// 重要 !!!!!!!!!!!!!!!!!!!!
//
// 核心模块代码, 请到ts_basis项目中修改提交
//
////////////////////////////////////////////////////////
import { CompItemDef } from './commonTypes'
export interface ResData {
_key: string;
name: string;
description: string;
color: string;
level: number;
children: ResData[];
}
export interface ResourceDef extends CompItemDef {
resType: "dropdown" | "tree";
resData: ResData[];
maxLevel: number;
sourceType: "self" | "outer";
ownerAppKeys: string[];
}
\ No newline at end of file
////////////////////////////////////////////////////////
//
// 重要 !!!!!!!!!!!!!!!!!!!!
//
// 核心模块代码, 请到ts_basis项目中修改提交
//
////////////////////////////////////////////////////////
import { BaseDef } from "./commonTypes";
// --> Region.js
// 使用share的定义
// --> SendLog.js
export interface SendLogDef extends BaseDef {
_key: string;
groupKey: string;
msgType: "mail" | "sms";
sendResult: string;
receiver: string;
content: string;
user: string;
}
////////////////////////////////////////////////////////
//
// 重要 !!!!!!!!!!!!!!!!!!!!
//
// 核心模块代码, 请到ts_basis项目中修改提交
//
////////////////////////////////////////////////////////
import { BaseDef, CascaderDef } from "./commonTypes";
// --> Calendar.js
export interface CalendarDef extends BaseDef {
year: number;
month: number;
date: number;
yearweek: number; // 第几周
yearday: number; // 第几天
week: number; // 星期几
workday: "1" | "2";
}
// --> Region.js
export interface RegionDef extends BaseDef, CascaderDef {
oid: number;
longitude: number;
latitude: number;
}
////////////////////////////////////////////////////////
//
// 重要 !!!!!!!!!!!!!!!!!!!!
//
// 核心模块代码, 请到ts_basis项目中修改提交
//
////////////////////////////////////////////////////////
import { KeyItemDef } from "./commonTypes";
// --> TimeRiver.js
export interface TimeRiverDef extends KeyItemDef {
userKey: string;
nextTrigger: Date | null;
lastTrigger: Date | null;
// companyId__appId
groupKey: string;
remoteHost: string;
remotePath: string;
remoteParams: {
[propName: string]: any;
},
cycleType: "once" | "cycle";
cycleLength: number;
cycleUnit: "sec" | "hour" | "day" | "month" | "year";
status: "wait" | "done";
}
\ No newline at end of file
////////////////////////////////////////////////////////
//
// 重要 !!!!!!!!!!!!!!!!!!!!
//
// 核心模块代码, 请到ts_basis项目中修改提交
//
////////////////////////////////////////////////////////
import config from 'config';
import log4js from 'log4js';
const logger = log4js.getLogger('cloudEnv');
let finalDbConfig: any = null;
let finalRedisConfig: any = null;
let RemoteRedisConfig: any = null;
let RemoteJobRedisConfig: any = null;
function getFinalDBConfig() {
if (finalDbConfig) {
return finalDbConfig;
}
finalDbConfig = config.get("dbConfig");
finalDbConfig = JSON.parse(JSON.stringify(finalDbConfig));
// finalDbConfig = {
// ...config.get("dbConfig")
// }
return finalDbConfig;
}
function getFinalRedisConfig() {
if (finalRedisConfig) {
return finalRedisConfig;
}
finalRedisConfig = config.get("redisConfig");
return finalRedisConfig;
}
function getRemoteRedisConfig() {
if (RemoteRedisConfig) {
return RemoteRedisConfig;
}
RemoteRedisConfig = config.get("remoteRedisConfig");
return RemoteRedisConfig;
}
function getRemoteJobRedisConfig() {
if (RemoteJobRedisConfig) {
return RemoteJobRedisConfig;
}
RemoteJobRedisConfig = config.get("remoteJobRedisConfig");
return RemoteJobRedisConfig;
}
export default {
getFinalDBConfig,
getFinalRedisConfig,
getRemoteRedisConfig,
getRemoteJobRedisConfig
};
////////////////////////////////////////////////////////
//
// 重要 !!!!!!!!!!!!!!!!!!!!
//
// 核心模块代码, 请到ts_basis项目中修改提交
//
////////////////////////////////////////////////////////
import gvar from '../../gvar';
import fs from 'fs'
import path from 'path'
let controllers: { [key: string]: any } = {};
function retrieveControllers(dir: string) {
fs.readdirSync(dir).forEach(file => {
if (fs.statSync(path.join(dir, file)).isDirectory()) {
retrieveControllers(path.join(dir, file));
} else {
let fileSplit: string[] = file.split(".");
if (fileSplit.length > 1) {
let fileName = fileSplit[0];
let extend = fileSplit[fileSplit.length - 1];
if (extend !== "map") {
import(path.join(dir, file)).then((x) => {
controllers[fileName] = x["default"];
});
}
}
}
});
}
retrieveControllers(path.join(gvar.appDir, "api/controllers"));
function getController(modName: string, params: any = {}): any {
return new controllers[modName + "Controller"](params);
}
let managers: { [key: string]: any } = {};
function retrieveManagers(dir: string) {
fs.readdirSync(dir).forEach(file => {
if (fs.statSync(path.join(dir, file)).isDirectory()) {
retrieveManagers(path.join(dir, file));
} else {
let fileSplit: string[] = file.split(".");
let fileName = fileSplit[0];
let extend = fileSplit[fileSplit.length - 1];
if (extend !== "map") {
import(path.join(dir, file)).then((x) => {
if (x[fileName + "Inst"] != null) {
managers[fileName] = x[fileName + "Inst"];
}
else if (x["get" + fileName + "Inst"] != null) {
managers["get" + fileName] = x["get" + fileName + "Inst"];
}
});
}
}
});
}
retrieveManagers(path.join(gvar.appDir, "api/managers"));
function getManager(ManagerName: string): any {
return managers[ManagerName + "Manager"];
}
export default {
getController,
getManager
}
////////////////////////////////////////////////////////
//
// 重要 !!!!!!!!!!!!!!!!!!!!
//
// 核心模块代码, 请到ts_basis项目中修改提交
//
////////////////////////////////////////////////////////
import EventEmitter from "events";
class MyEventEmitter extends EventEmitter { }
const eventBus = new MyEventEmitter();
export default eventBus;
////////////////////////////////////////////////////////
//
// 重要 !!!!!!!!!!!!!!!!!!!!
//
// 核心模块代码, 请到ts_basis项目中修改提交
//
////////////////////////////////////////////////////////
import jwt from 'jsonwebtoken';
const Token = {
encrypt: function (data: any, time: any) { // data加密数据,time过期时间
return jwt.sign(data, "bridata-apaas", { expiresIn: time });
},
decrypt: function (token: any) {
try {
let data = jwt.verify(token, "bridata-apaas");
return {
isValid: true,
data: data
};
} catch (e) {
return {
isValid: false,
data: e
};
}
}
};
export default Token;
////////////////////////////////////////////////////////
//
// 重要 !!!!!!!!!!!!!!!!!!!!
//
// 核心模块代码, 请到ts_basis项目中修改提交
//
////////////////////////////////////////////////////////
import mongoose from 'mongoose'
import cloudEnv from '../cloudEnv';
import tools from '../tools'
import log4js from 'log4js';
const logger = log4js.getLogger('mongo');
const dbConfig = cloudEnv.getFinalDBConfig();
let { connectStr, connectOption } = tools.getConnectionData(dbConfig)
let dbCore = mongoose.createConnection(
connectStr,
connectOption
);
dbCore.on("error", logger.error.bind(console, "connection error:"));
dbCore.once("open", function () {
// we're connected!
logger.info("======== mongo:", cloudEnv.getFinalDBConfig());
});
export default {
dbCore
};
////////////////////////////////////////////////////////
//
// 重要 !!!!!!!!!!!!!!!!!!!!
//
// 核心模块代码, 请到ts_basis项目中修改提交
//
////////////////////////////////////////////////////////
import _ from 'lodash'
import tools from '../tools'
import moment from 'moment'
let schemaDefaultOption: any = {
versionKey: false,
timestamps: true,
minimize: false,
toJSON: {
virtuals: true,
getters: true,
transform: function (doc: any, ret: any) {
delete ret["password"];
delete ret["salt"];
delete ret["__v"];
let sma = doc.schema;
// 处理创建时间和修改时间
// ret["createdAt"] = moment(ret["createdAt"]).format("YYYY-MM-DD HH:mm:ss");
// ret["updatedAt"] = moment(ret["updatedAt"]).format("YYYY-MM-DD HH:mm:ss");
// 下拉类型加上__t_n
_.forOwn(sma.obj, function (value, field) {
// 处理日期字段, createdAt, updatedAt
if (value.type == Date && !value.customized) {
if (typeof value.timeFormat == "string") {
ret[field] = ret[field] ? moment(ret[field]).format(value.timeFormat) : ret[field];
} else if (typeof value.timeFormat == "function") {
ret[field] = value.timeFormat(ret[field]);
} else {
ret[field] = ret[field] ? moment(ret[field]).format("YYYY-MM-DD HH:mm:ss") : ret[field];
}
}
// 二级字段的下拉
if (_.isObject(value) && !_.isArray(value)) {
_.forOwn(value, function (v: any, f: any) {
// 处理下拉类型
if (v && _.isArray(v.types) && ret[field] !== undefined && ret[field][f] !== undefined) {
// 下拉类型
ret[field][`${f}__t_n`] = tools.getEnumFriendlyName(v.types, ret[field][f]);
}
});
}
// 控件组合的下拉
if (_.isArray(value.type) && _.isArray(doc[field])) {
_.forOwn(value.type[0], function (v, f) {
// 处理下拉类型
if (v && _.isArray(v.types) && ret[field] !== undefined) {
// 下拉类型
for (let compoObj of ret[field]) {
compoObj[`${f}__t_n`] = tools.getEnumFriendlyName(v.types, compoObj[f]);
}
}
});
}
// 处理下拉类型
if (_.isArray(value.types) && ret[field] !== undefined) {
// 下拉类型
ret[field + "__t_n"] = tools.getEnumFriendlyName(value.types, ret[field]);
}
if (value.ref && ret[field] !== undefined) {
ret[field + "__t_n"] = ret[field] && ret[field].full_name || ret[field] && ret[field].name || "";
}
});
}
},
toObject: {
virtuals: true,
getters: true
},
id: false
};
let modelDefaultMethods: any = {
};
export {
schemaDefaultOption,
modelDefaultMethods
}
import jwtlib from './jwtlib';
import api_util from '../util/api_util';
import remoteEnv from './remoteEnv';
import axios from 'axios';
// 中间件
let mw: { [key: string]: any } = {
// 获取用户的登录信息
userInfo: async function (req: any, res: any, next: any) {
let authtokenStr = req.headers.authtoken || req.body.authtoken;
// 判断authtoken有效
if (authtokenStr) {
if (authtokenStr.slice(0, 4) == "jwt:") {
let authtoken = authtokenStr.slice(4, authtokenStr.length)
let r = jwtlib.decrypt(authtoken)
if (r.isValid) {
let user: any = r.data;
user.JWTLogin = true;
req.login(user, function (err: Error) {
if (err) {
throw (err);
}
});
}
}
else {
// 直接从compredis中读,此方法不会刷新登录时间
// let authtoken = authtokenStr;
// let compRedis = await remoteEnv.getRemoteRedisClient("comp");
// let obj = await compRedis.get(`${tools.getServiceCachePrefix("comp")}_${tools.getCompLoginCacheKey(authtoken)}`);
// if (obj) {
// let user = JSON.parse(obj);
// req.login(user, function (err: Error) {
// if (err) {
// throw (err);
// }
// });
// }
// 往comp发接口
let authtoken = authtokenStr;
let compRemoteConfig = await remoteEnv.getRemoteConfigByKey("comp");
let headers = {
authtoken
}
let result = await axios.post(compRemoteConfig.host + compRemoteConfig.checkLoginPath, {}, { headers });
if (result.data.res == 0) {
let user = result.data.data;
user.JWTLogin = false;
req.login(user, function (err: Error) {
if (err) {
throw (err);
}
// next();
});
}
}
}
next();
},
// 权限控制中间件,登录用户
loginRequired: async function (req: any, res: any, next: any) {
if (!req.user) {
return res.json({ ...api_util.NotLoginResponse, msg: "没有登录!" });
}
next();
},
jwtLoginRequired: async function (req: any, res: any, next: any) {
if (!req.user) {
return res.json({ ...api_util.NotLoginResponse, msg: "没有登录!" });
}
if (!req.user.JWTLogin) {
return res.json({ ...api_util.NoAuthResponse, msg: "没有权限" });
}
next();
}
};
export default mw;
////////////////////////////////////////////////////////
//
// 重要 !!!!!!!!!!!!!!!!!!!!
//
// 核心模块代码, 请到ts_basis项目中修改提交
//
////////////////////////////////////////////////////////
import cloudEnv from './cloudEnv';
import log4js from 'log4js';
import Redis, {Cluster} from 'ioredis';
const logger = log4js.getLogger('redis');
function createRedis(redisConfig: any): Redis | Cluster {
let redis: Redis | Cluster;
if(redisConfig.isCluster) {
redis = new Redis.Cluster(redisConfig.clusterConfig);
}
else {
redis = new Redis(redisConfig);
}
return redis
}
let finalRedisConfig = cloudEnv.getFinalRedisConfig();
let remoteRedisConfig = cloudEnv.getRemoteRedisConfig();
const redis = createRedis(finalRedisConfig);
redis.on("error", function (err) {
logger.error("Redis error " + err);
});
redis.on("connect", function () {
logger.info("======== redis:", cloudEnv.getFinalRedisConfig());
});
let remoteRedis = createRedis(remoteRedisConfig);
remoteRedis.on("error", function (err) {
logger.error("Remote error " + err);
});
remoteRedis.on("connect", function () {
logger.info("======== remote:", cloudEnv.getRemoteRedisConfig());
});
let subRedis = createRedis(remoteRedisConfig);
subRedis.on("error", function (err) {
logger.error("Sub error " + err);
});
export {
redis,
remoteRedis,
subRedis
};
////////////////////////////////////////////////////////
//
// 重要 !!!!!!!!!!!!!!!!!!!!
//
// 核心模块代码, 请到ts_basis项目中修改提交
//
////////////////////////////////////////////////////////
import { remoteRedis, subRedis } from './redis'
import asyncRedis from 'async-redis';
import log4js from "log4js";
import { DbInfo } from '../def/base/commonTypes';
const logger = log4js.getLogger("remoteEnv");
let remoteConfig: any = null;
async function initRemoteConfig() {
if (remoteConfig != null) {
return remoteConfig;
}
let configStr = await remoteRedis.get("proxy:remoteHostConfig");
if (configStr) {
remoteConfig = JSON.parse(configStr);
return remoteConfig
} else {
throw new Error("需要先启动proxy");
}
}
async function getRemoteConfigByKey(remoteKey: string) {
await initRemoteConfig();
remoteKey = remoteKey.toLowerCase()
return remoteConfig[remoteKey + "RemoteConfig"];
}
async function getRedisConfigByKey(remoteKey: string) {
await initRemoteConfig();
remoteKey = remoteKey.toLowerCase()
return remoteConfig[remoteKey + "RedisConfig"];
}
let remoteRedisMap: {[key: string]: any } = {}
async function getRemoteRedisClient(remoteKey: string): Promise<any> {
if (remoteRedisMap[remoteKey]) {
return remoteRedisMap[remoteKey];
}
let remoteRedisConfig = await getRedisConfigByKey(remoteKey)
remoteRedisMap[remoteKey] = asyncRedis.createClient(remoteRedisConfig);
return remoteRedisMap[remoteKey];
}
async function getDbInfo(compKey: string): Promise<DbInfo> {
let customRemoteConfig = await getRemoteConfigByKey("custom");
let dbinfo: any;
// localSetting改成只控制数据库
if (customRemoteConfig.localSetting){
dbinfo = {
...customRemoteConfig.db,
dbName: compKey,
dbId: compKey
};
// 用于从配置文件中设置不同的数据库
if( customRemoteConfig.dbMap && customRemoteConfig.dbMap[compKey] ){
dbinfo = {
...customRemoteConfig.dbMap[compKey],
dbName: compKey,
dbId: compKey
};
}
}
else {
throw new Error("DbInfo is null!");
}
return dbinfo
}
subRedis.on("message", function (channel, message) {
if (channel == "updateRemoteHostConfig") {
try {
remoteConfig = JSON.parse(message);
} catch (err) {
logger.error(err);
}
}
});
subRedis.subscribe("updateRemoteHostConfig");
export default {
getRemoteConfigByKey,
getRedisConfigByKey,
getRemoteRedisClient,
getDbInfo
};
\ No newline at end of file
////////////////////////////////////////////////////////
//
// 重要 !!!!!!!!!!!!!!!!!!!!
//
// 核心模块代码, 请到ts_basis项目中修改提交
//
////////////////////////////////////////////////////////
import md5 from 'md5'
import moment from 'moment'
import _ from 'lodash'
import mongoose from 'mongoose'
import { DbInfo } from '../def/base/commonTypes'
import log4js from 'log4js';
import { Request } from 'express';
import crypto from 'crypto';
const logger = log4js.getLogger('tools');
function randomString(length: number): string {
let result = "";
let characters = "abcdefghijklmnopqrstuvwxyz";
let charactersLength = characters.length;
for (let i = 0; i < length; i++) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
}
return result;
}
function randomInt(min: number, max: number): number {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min)) + min; // The maximum is exclusive and the minimum is inclusive
}
/**
* 获取enum类型的中文
* types:[]
* value: 可以是字符串或者数组
* 返回一个字符串,如果传入的是数组,则用逗号拼接
*
*/
function getEnumFriendlyName(types: Array<any>, value: any) {
let result = "";
// 下拉类型
if (_.isArray(value)) {
// 多选
let field_name_arr = [];
let set = new Set(value);
for (const elem of types) {
if (set.has(elem._key)) {
field_name_arr.push(elem.name);
}
}
result = field_name_arr.join(",");
} else {
// 单选
let i = _.findIndex(types, function (o: any) {
return o._key == value;
});
result = i >= 0 ? types[i].name : "";
}
return result;
}
/**
* 获取enum类型的中文
* types:[]
* value: 可以是字符串或者数组
* 返回一个字符串,如果传入的是数组,则用逗号拼接
*
*/
function getEnumValue(types: Array<any>, friendlyName: any) {
let value = friendlyName.toString().indexOf(",") > -1 ? friendlyName.split(",") : friendlyName;
let result: any = "";
if (_.isArray(value)) {
// 下拉类型
result = [];
for (let v of value) {
let i = _.findIndex(types, function (o: any) {
return o.name == v;
});
i >= 0 && result.push(types[i]._key);
}
} else {
// 单选
let i = _.findIndex(types, function (o: any) {
return o.name == value;
});
result = i >= 0 ? types[i]._key : null;
}
return result;
}
function getCascaderFriendlyName(types: Array<any>, value: Array<any> = []) {
let retStr = "";
if (!_.isArray(types)) {
return retStr;
}
value.reduce(function (per: Array<any>, cur, index) {
let type: any = per.find(type => type._key == cur);
let typeName = type.name;
if (index != 0) typeName = "/" + typeName;
if (type) retStr += typeName;
return type["children"];
}, types)
return retStr;
}
function getCascaderValue(types: Array<any>, names: any) {
names = Array.isArray(names) ? names : names.split("/");
let ret: any = [];
names.reduce(function (per: Array<any>, cur: any) {
let type = per.find(type => type.name == cur);
ret.push(type._key);
return type["children"];
}, types);
return ret;
}
/**
* 把Excel中的日期的数字转换成为date对象
*
*/
function excelDateToJSDate(serial: number): Date {
let utc_days = Math.floor(serial - 25569);
let utc_value = utc_days * 86400;
let date_info = new Date(utc_value * 1000);
let fractional_day = serial - Math.floor(serial) + 0.0000001;
let total_seconds = Math.floor(86400 * fractional_day);
let seconds = total_seconds % 60;
total_seconds -= seconds;
let hours = Math.floor(total_seconds / (60 * 60));
let minutes = Math.floor(total_seconds / 60) % 60;
return new Date(date_info.getFullYear(), date_info.getMonth(), date_info.getDate(), hours, minutes, seconds);
}
/**
* 获取schema的types
*/
function getSchemaTypes(sch: any) {
sch = JSON.parse(JSON.stringify(sch));
let t: any = {};
// 遍历所有字段的types
_.forOwn(sch, function (value: any, field: any) {
if (value && value.types && _.isArray(value.types) && _.isArray(value.enum)) {
t[field] = value.types;
} else if (_.isObject(value)) {
let valueObj: any = value;
if (!valueObj.type && !valueObj.ref) {
let typesResult = getSchemaTypes(value);
if (typesResult) {
t[field] = typesResult;
}
}
}
});
return _.isEmpty(t) ? undefined : t;
}
async function waitSeconds(n: any): Promise<void> {
// 等 n 秒种,测试异步的时候用的
n = parseInt(n, 10) ? parseInt(n, 10) : 1;
return new Promise(function (resolve: any, reject: any) {
setTimeout(async () => {
try {
resolve();
} catch (e) {
reject();
}
}, n * 1000);
});
}
function getNestedSchema(obj: any, key: any) {
if (key.includes(".")) {
let nestedKeys = key.split(".");
let val = obj;
for (let nk of nestedKeys) {
if (!val) {
return null;
}
if (val[nk] instanceof Array) {
val = val[nk][0];
}
else {
val = val[nk];
}
}
return val;
}
else {
return obj[key];
}
}
function setCascaderArrayVal (obj: any, key: string | null, fKey: string, valueMap: any) {
if (key) {
if (obj[key] && Array.isArray(obj[key]["tree"])) {
for (let item of obj[key]["tree"]) {
setCascaderArrayVal(item, null, fKey, valueMap)
}
}
} else {
if (obj.isLeaf) {
if (obj[fKey] instanceof Array) {
for (let idx = 0; idx < obj[fKey].length; idx++) {
if (obj[fKey][idx]) {
obj[fKey][idx] = getIdString(obj[fKey][idx]) && valueMap[getIdString(obj[fKey][idx])]
|| (getKeyString(obj[fKey][idx]) && valueMap[getKeyString(obj[fKey][idx])]);
}
}
obj[fKey] = (obj[fKey] as any[]).filter(x=>x!=null) // minghao test
}
else {
if (obj[fKey]) {
obj[fKey] = getIdString(obj[fKey]) && valueMap[getIdString(obj[fKey])]
|| (getKeyString(obj[fKey]) && valueMap[getKeyString(obj[fKey])]);
}
}
} else if (Array.isArray(obj["children"])) {
for (let item of obj["children"]) {
setCascaderArrayVal(item, null, fKey, valueMap)
}
}
}
}
function setNestedArrayVal(obj: any, key: any, valueMap: any) {
if (key.includes(".tree.")) {
let keyList = key.split(".");
setCascaderArrayVal(obj, keyList[0], keyList[2], valueMap);
}
else if (key.includes(".")) {
let keyList = key.split(".");
let firstKey = keyList.shift();
let nextKey = keyList.join(".");
if (obj[firstKey]) {
if (obj[firstKey] instanceof Array) {
for (let elemInPVal of obj[firstKey]) {
setNestedArrayVal(elemInPVal, nextKey, valueMap);
}
}
else {
setNestedArrayVal(obj[firstKey], nextKey, valueMap);
}
}
}
else {
if (obj[key] instanceof Array) {
for (let idx = 0; idx < obj[key].length; idx++) {
if (obj[key][idx]) {
obj[key][idx] = getIdString(obj[key][idx]) && valueMap[getIdString(obj[key][idx])]
|| (getKeyString(obj[key][idx]) && valueMap[getKeyString(obj[key][idx])]);
}
}
obj[key] = (obj[key] as any[]).filter(x=>x!=null)
}
else {
if (obj[key]) {
obj[key] = getIdString(obj[key]) && valueMap[getIdString(obj[key])]
|| (getKeyString(obj[key]) && valueMap[getKeyString(obj[key])]);
}
}
}
}
function getCascaderTableIdArray (objs: any[], key: string | null, fKey: string) {
let ids = [];
for (let obj of objs) {
if (key) {
if (obj[key]) {
let nt: any = getCascaderTableIdArray(obj[key]["tree"], null, fKey);
ids.push(...nt);
}
} else if (obj.isLeaf === false) {
let nt: any = getCascaderTableIdArray(obj["children"], null, fKey);
ids.push(...nt);
} else if (obj[fKey]) {
ids.push(obj[fKey]);
}
}
return ids;
}
function getNestedIdArray(objs: any[], key: string): mongoose.Types.ObjectId[] {
if (key.includes(".tree.")) {
let keyList = key.split(".");
return getCascaderTableIdArray(objs, keyList[0], keyList[2]);
}
let ids = [];
for (let obj of objs) {
if (key.includes(".")) {
let keyList = key.split(".");
let firstKey = keyList.shift() || "";
let nextKey = keyList.join(".");
if (obj[firstKey]) {
if (obj[firstKey] instanceof Array) {
let nestedArray = getNestedIdArray(obj[firstKey], nextKey);
ids.push(...nestedArray);
}
else {
let nestedArray = getNestedIdArray([obj[firstKey]], nextKey);
ids.push(...nestedArray);
}
}
}
else {
if (obj[key] instanceof Array) {
ids.push(...obj[key]);
}
else if (obj[key]) {
ids.push(obj[key]);
}
}
}
return ids;
}
function getIdString(objId: any): string {
if (_.isEmpty(objId) || !objId) {
return "";
} else if (objId._id) {
return objId._id.toString();
} else {
return objId.toString();
}
}
function getKeyString(objKey: any): string {
return objKey ? (typeof objKey === "string" ? objKey : objKey._key || "") : "";
}
function getToken(): string {
let random_time_stamp = new Date().getTime() + "" + Math.floor(Math.random() * 10000);
return md5(random_time_stamp);
}
function encode_b36(n: number, level_length: number): string {
let base = 36;
let large_n = n + Math.pow(base, level_length);
let large_string = large_n.toString(base);
return large_string.substr(1, level_length);
}
function decode_b36(s: string): number {
let base = 36;
return parseInt(s, base);
}
function random_b36(seed?: any): string {
let base = 36;
let timeStr = Math.round(new Date().valueOf()).toString(base);
if(seed != null) {
let randomNumA = Math.floor(Math.random() * 36);
return timeStr + randomNumA.toString(base) + seed.toString(base);
}
else {
let randomNumA = Math.floor(Math.random() * 36);
let randomNumB = Math.floor(Math.random() * 36);
return timeStr + randomNumA.toString(base) + randomNumB.toString(base);
}
}
function getTimeByObjectId(objId: any) {
return new Date(parseInt(getIdString(objId).substring(0, 8), 16) * 1000);
}
function sleep(ms: number) { return new Promise((res, rej) => setTimeout(res, ms)) }
async function lock(redisCli: any, lockKey: string) {
let getLock = false;
for(let times = 0; times < 20; times++ ){
let res = await redisCli.setnx(lockKey, "lock");
if(res == 1){
getLock = true
break
}
await sleep(100)
}
if(getLock){
await redisCli.expire(lockKey, 2);
}
else {
throw new Error("当前操作被锁定中,请2秒后再试!")
}
// 2秒删除
}
async function unlock(redisCli: any, lockKey: string) {
await redisCli.del(lockKey)
}
function titleStr(str: string): string {
return str.charAt(0).toUpperCase() + str.slice(1);
}
function generateKey(typeName: string, seed?: any) {
let keyBeginMap: any = {
// file
"Article": "ART",
"AppStore": "APS",
"Category": "CTG",
"DbStore": "DBS",
"DbMod": "DBM",
"DbPackage": "DBP",
"Purchase": "PUR",
// core
"AppRole": "ROL",
"Dashboard": "DAS",
"Mod": "MOD",
"FlowDef": "FLO",
"Report": "REP",
"Screen": "SCR",
"AppItemGroup": "GRO",
"Field": "FIE",
"Resource": "RES",
"Source": "SOU",
// 存储在app端的动态数据
"FlowTask": "MFT",
"FlowNotify": "MFN",
"TabNotify": "MTN",
"UserTask": "UST",
"InnerChart": "ICH",
"numberData": "NDA",
"textData": "TDA",
"menuData": "MDA",
"pivotTableData": "PTD",
"pictureData": "PDA",
"formData": "FDA",
"InnerTable": "ITA",
"StepDef": "STE",
"AppVersion": "VER",
"Tabulation": "TAB",
"ganttData": "GDA",
"FieldGroup": "FIG",
"FileArchive": "FIA",
"EmbedPage": "EBD",
"tableData": "TBD",
"tabsData": "TSD",
"Trigger": "TRI",
"ModApi": "MOA",
"InnerApp": "IAP",
"CompDb": "CMD",
"ShortCut": "SCT",
"Version": "VSN",
"DataFactory": "DAF",
"CalculateAxis": "CCA",
"EntityVersion": "EVS",
"Entity": "ENT",
"Department": "DEP",
"DepartmentGrade": "DMG",
"User": "USR",
"Company": "CPY",
"UserComp": "UCP",
"CompanyMessage": "CMS",
"CompItemGroup": "GRO",
"Archive": "ARC",
"DbApp": "DAP",
"DbAppItem": "DAI",
"DbEntity": "DET",
"DbResource": "DRC",
"DbAppRecord": "DAR",
"customGroup": "CGR",
"FeedBack": "FBK",
"Integral": "ITR",
"SystemNotify": "SNT",
"CompanyNotify": "CNT",
};
let keyBegin = keyBeginMap[typeName];
if (!keyBegin) {
throw new Error(`${typeName} Begin string not found!`);
}
return keyBegin + "_" + random_b36(seed);
}
function getMomentValue(v: moment.MomentInput, dateType: string) {
if (v === undefined || v === null || v === "") {
return "";
}
let dateFormat: any = {
date: "YYYY-MM-DD",
year: "YYYY",
month: "YYYY-MM",
datetime: "YYYY-MM-DD HH:mm:ss",
datetimerange: "YYYY-MM-DD HH:mm:ss",
daterange: "YYYY-MM-DD",
time: "HH:mm:ss"
};
if (dateType === "time" && v && /^\d{1,2}:\d{1,2}:\d{1,2}$/.test(v.toString())) {
v = "2038-01-01 " + v;
}
return v ? moment(v).format(dateFormat[dateType]) : v;
}
function dateIsValid(date: moment.MomentInput): boolean {
return moment(date).isValid();
}
function getCalculateKey(obj: any) {
return "Cal:" + getIdString(obj);
}
// 获取时间差值
function getDateDiff(startTime: Date, endTime: Date, diffType: string): number {
diffType = diffType.toLowerCase();
let sTime = new Date(startTime); //开始时间
let eTime = new Date(endTime); //结束时间
//作为除数的数字
let divNum = 1;
switch (diffType) {
case "second":
divNum = 1000;
break;
case "minute":
divNum = 1000 * 60;
break;
case "hour":
divNum = 1000 * 3600;
break;
case "day":
divNum = 1000 * 3600 * 24;
break;
default:
break;
}
return (eTime.getTime() - sTime.getTime()) / divNum;
}
// 获取级联数据全称
function getCascader(keys: Array<any>, objs: Array<any> = []) {
let val = objs;
let name = [];
for (let key of keys) {
val = val.filter(x => x._key == key);
if (val) {
name.push(val[0].name)
val = val[0]["children"]
}
}
return name.join("/")
}
function getHostPortString(host: string, port: number | string): string {
let hostPort = host
if (port != null) {
hostPort += ":" + port
}
return hostPort
}
function getConnectionData(dbConfig: DbInfo) {
let connectOption: mongoose.ConnectOptions = {
useUnifiedTopology: true,
useNewUrlParser: true,
useFindAndModify: false,
useCreateIndex: true
}
let connectStr = "";
let connectStrOptions = [];
if (dbConfig.user && dbConfig.password) {
connectStr = `mongodb://${dbConfig.user}:${dbConfig.password}@`
connectStrOptions.push("authSource=admin");
}
else {
connectStr = `mongodb://`
}
if (dbConfig.coreCluster) {
let coreClusters = dbConfig.coreCluster;
let clusterArray = coreClusters.map(x => getHostPortString(x.host, x.port));
connectStr += clusterArray.join(",");
if (dbConfig.coreClusterRSName) {
connectStrOptions.push(`replicaSet=${dbConfig.coreClusterRSName}`)
}
if (dbConfig.readPreference) {
connectOption.readPreference = dbConfig.readPreference;
}
}
else if (dbConfig.host != null && dbConfig.port != null) {
let hostPort = getHostPortString(dbConfig.host, dbConfig.port);
connectStr += hostPort
}
connectStr += "/" + dbConfig.dbName
if (connectStrOptions.length > 0) {
connectStr += "?" + connectStrOptions.join("@")
}
return {
connectStr,
connectOption
}
}
function getServiceCachePrefix(serviceKey: string): string {
return "h" + titleStr(serviceKey);
}
function getCompItemCacheKey(modelName: string, compKey: string | undefined, key: string | undefined): string {
return modelName + "_key:" + compKey + "_" + key
}
function getAppItemCacheKey(modelName: string, compKey: string | undefined, appKey: string | undefined, key: string | undefined): string {
return modelName + "_key:" + compKey + "_" + appKey + "_" + key
}
function getKeyItemCacheKey(modelName: string, key: string | undefined): string {
return modelName + "_key:" + key
}
function getIdItemCacheKey(modelName: string, obj: any): string {
return modelName + "_id:" + getIdString(obj);
}
function getCompLoginCacheKey(authtoken: string): string {
return "usertoken:" + authtoken
}
function getBullExcelCacheKey(): string {
return "jobQueue"
}
function getFrontHost(remoteConfig: any, compKey?: string, req?: Request, deviceType?: string): string {
let frontHost = "";
if( compKey && remoteConfig.frontHostMap && remoteConfig.frontHostMap[compKey]){
let key = "";
switch (deviceType) {
case "mobile": key = compKey + "_" + deviceType;
break;
case "pc":
default: key = compKey;
}
frontHost = remoteConfig.frontHostMap[key];
}
if (!frontHost) {
switch (deviceType) {
case "mobile": frontHost = remoteConfig.frontAppHost;
break;
case "pc":
default: frontHost = remoteConfig.frontHost;
}
}
if(req && frontHost.indexOf("${curHost}") != -1) {
if(req.headers.referer)
{
frontHost = frontHost.replace("${curHost}", req.headers.referer.split('/')[2].split(':')[0]);
}
else if(req.headers.host){
let refHost = req.headers.host.split(":")[0];
frontHost = frontHost.replace("${curHost}", refHost);
}
else if(remoteConfig.host) {
let refHOst = remoteConfig.host.split('/')[2].split(':')[0]
frontHost = frontHost.replace("${curHost}", refHOst);
}
}
return frontHost;
}
// 产生len的两倍长度
function getShortHashKey(str: string, len = 3): string {
return crypto.createHash("shake256", { outputLength: len })
.update(str)
.digest("hex");
}
/**
* 根绝输入值生成时间字符串
* 例:2022-02 -> YYYY-MM 。 2022/01 -> YYYY/01
* 其中 fullformatstr 是按每年一月一号零时零分零秒规则补全的数据
* @param datestr 日期格式。例:2022-02
* @returns
*/
function getDateFormatStr(datestr: string): any {
let list = ["Y", "M", "D", "H", "m", "s", "S"];
let i = 0;
let c1 = "-", c2 = ":";
let formatestr = datestr.replace(/\d+([\/\-\: ])?/g, (str: string, character: string): string => {
if (character) {
if (i <= 1) {
c1 = character;
} else if (i === 2) {
} else {
c2 = character;
}
}
let numlen = str.length - (character ? 1 : 0);
return "".padStart(numlen, list[i++]) + (character || "");
});
let fullformatstr = formatestr;
while (i < 7) {
if (i <= 2) {
fullformatstr += (c1 + "01");
} else if (i === 3) {
fullformatstr += " 00";
} else if (i <= 5) {
fullformatstr += (c2 + "00");
} else {
fullformatstr += ".000";
}
++i;
}
return {
formatestr,
fullformatstr
};
}
/**
* 判断选中的值是否是级联类型的叶子节点
*/
function isCascaderLeaf(tree: any[], value: string[]): boolean {
let list: any[] = tree;
for (const key of value) {
let node = list.find(x => x._key === key);
if (!node) { // list 为空时。说明value超出tree范围
return false;
}
list = node.children || [];
}
return list.length === 0;
}
/**
* 创建一个带缓存的 判断选中的值是否是级联类型的叶子节点 的函数
*/
function memoryisCascaderLeaf() {
let map: {[x: string]: boolean} = {};
return function(tree: any[], value: string[]): boolean {
let unique = value.join(",");
if (!(unique in map)) {
map[unique] = isCascaderLeaf(tree, value);
}
return map[unique];
}
}
function isRenderFieldType(fieldType: string) {
return ["tag"].includes(fieldType)
}
function safeStringify (obj: any) {
try {
return JSON.stringify(obj);
} catch (error) {
logger.error(error, obj);
return "";
}
}
function getDataId(params: any, modFormMapByKey: any = {}) {
if (params["$and"]) {
for (let p of params["$and"]) {
getDataId(p, modFormMapByKey);
}
}
if (params["$or"]) {
for (let p of params["$or"]) {
getDataId(p, modFormMapByKey);
}
}
if (params["_id"]) {
convertToMongooseId(params, "_id");
}
const paramKeys = Object.keys(params);
for (let paramKey of paramKeys) {
const _type = modFormMapByKey[paramKey];
if (!_type) continue;
if (_type === "reference") {
// 单条关联
convertToMongooseId(params, paramKey);
} else if (_type == "date") {
// 日期
convertToDate(params, paramKey);
}
}
}
function formatToMongoField(params: any, key: any, convertMethod: any) {
if (typeof params[key] == "object") {
// "$in", "$nin"
if (params[key]["$in"]) {
let items = [];
for (let item of params[key]["$in"]) {
items.push(convertMethod(item));
}
params[key]["$in"] = items;
}
if (params[key]["$nin"]) {
let items = [];
for (let item of params[key]["$nin"]) {
items.push(convertMethod(item));
}
params[key]["$nin"] = items;
}
// "$gt", "$gte", "$lt", "$lte", "$eq", "$ne"
const compareSymbols = ["$gt", "$gte", "$lt", "$lte", "$eq", "$ne"];
for (let symbol of compareSymbols) {
if (!params[key][symbol]) continue;
params[key][symbol] = convertMethod(params[key][symbol]);
}
} else {
params[key] = convertMethod(params[key]);
}
return params;
}
function convertToMongooseId(params: any, key: any) {
const toMongoId = (value: any) => {
return mongoose.Types.ObjectId(getIdString(value));
};
formatToMongoField(params, key, toMongoId);
}
function convertToDate(params: any, key: any) {
const toMongoDate = (value: any) => {
return value && new Date(value) || null;
};
formatToMongoField(params, key, toMongoDate);
}
export default {
isCascaderLeaf,
memoryisCascaderLeaf,
getDateFormatStr,
waitSeconds,
randomString,
randomInt,
getSchemaTypes,
getEnumValue,
getEnumFriendlyName,
excelDateToJSDate,
getNestedSchema,
getIdString,
getToken,
encode_b36,
decode_b36,
random_b36,
getTimeByObjectId,
lock,
unlock,
setNestedArrayVal,
getCascaderTableIdArray,
getNestedIdArray,
generateKey,
getMomentValue,
dateIsValid,
getCalculateKey,
getDateDiff,
getCascader,
getCascaderFriendlyName,
getCascaderValue,
getKeyString,
getConnectionData,
titleStr,
getServiceCachePrefix,
getCompItemCacheKey,
getAppItemCacheKey,
getKeyItemCacheKey,
getIdItemCacheKey,
getCompLoginCacheKey,
getBullExcelCacheKey,
getFrontHost,
getShortHashKey,
isRenderFieldType,
safeStringify,
sleep,
getDataId
};
import BaseExample from '../models/BaseExample';
import { BaseExampleDef } from '../def/base/basisTypes';
import IdItemManager from './base/IdItemManager';
class BaseExampleManager extends IdItemManager<BaseExampleDef> {
}
let BaseExampleManagerInst: BaseExampleManager = new BaseExampleManager(BaseExample)
export {
BaseExampleManager,
BaseExampleManagerInst
};
\ No newline at end of file
import { BaseDef } from "../def/base/commonTypes";
import { AbstractManager, IndexParam, UniqueSearchParam } from "./base/CommonManager";
import mysql from "mysql2/promise";
class ModDataManager implements AbstractManager<any> {
constructor(public conn: mysql.Connection, public table: string, public params: any) {
}
mCreate(params: any): Promise<any> {
let sqlstr = this.conn.format("insert into ?? set ?", [this.table, params]);
let result = this.conn.query(sqlstr);
return result;
}
mIndex(params: IndexParam): Promise<{ total: number; list: any[]; }> {
throw new Error("Method not implemented.");
}
mUpdate(params: any): Promise<any> {
throw new Error("Method not implemented.");
}
mDelete(objP: UniqueSearchParam): Promise<any> {
throw new Error("Method not implemented.");
}
mGet(objP: UniqueSearchParam): Promise<any> {
throw new Error("Method not implemented.");
}
mCount(search: any, limit?: number | undefined): Promise<number> {
throw new Error("Method not implemented.");
}
mSave(params: any): Promise<any> {
throw new Error("Method not implemented.");
}
mInsertMany(objs: any[]): Promise<any[]> {
throw new Error("Method not implemented.");
}
mNativeFind(search: any, fields?: string[] | undefined, opts?: { [key: string]: any; } | undefined): Promise<any[]> {
throw new Error("Method not implemented.");
}
mFindOne(search: any): Promise<any> {
throw new Error("Method not implemented.");
}
mUpdateMany(search: any, updateParams: any, fields?: string[] | undefined, returnEmpty?: boolean | undefined): Promise<any[]> {
throw new Error("Method not implemented.");
}
mDeleteMany(search: any, fields?: string[] | undefined, returnEmpty?: boolean | undefined): Promise<any[]> {
throw new Error("Method not implemented.");
}
mSoftDelete(objP: UniqueSearchParam): Promise<any> {
throw new Error("Method not implemented.");
}
mSoftDeleteMany(search: any, fields?: string[] | undefined, returnEmpty?: boolean | undefined): Promise<any[]> {
throw new Error("Method not implemented.");
}
mTypes(): Promise<any> {
throw new Error("Method not implemented.");
}
mAggregate(list: any[], option?: any): Promise<any[]> {
throw new Error("Method not implemented.");
}
}
////////////////////////////////////////////////////////
//
// 重要 !!!!!!!!!!!!!!!!!!!!
//
// 核心模块代码, 请到ts_basis项目中修改提交
//
////////////////////////////////////////////////////////
import OrderManager from "./OrderManager";
import { AppItemDef } from '../../def/base/commonTypes';
import tools from '../../lib/tools';
import config from 'config';
import { UniqueSearchParam } from './CommonManager';
class AppItemManager<T extends AppItemDef> extends OrderManager<T> {
addInitParam(initParam: any) {
let newKey = tools.generateKey(this.modelName);
initParam._key = initParam._key ? initParam._key : newKey;
super.addInitParam(initParam);
}
async mGetByAppKey(compKey: string, appKey: string, key: string): Promise<T | null> {
return await this.mGet(
{
compKey: compKey,
appKey: appKey,
_key: key
}
)
}
getUniqueSearch(objP: UniqueSearchParam) {
return {
compKey: objP.compKey,
appKey: objP.appKey,
_key: objP._key
}
}
getCacheKey(obj: UniqueSearchParam): string {
return config.get("serviceKey") + "_" + tools.getAppItemCacheKey(this.modelName, obj.compKey, obj.appKey, obj._key);
}
}
export default AppItemManager;
////////////////////////////////////////////////////////
//
// 重要 !!!!!!!!!!!!!!!!!!!!
//
// 核心模块代码, 请到ts_basis项目中修改提交
//
////////////////////////////////////////////////////////
import config from 'config';
import mongoose from 'mongoose';
import { BaseDef } from '../../def/base/commonTypes'
import { redis } from '../../lib/redis';
import tools from '../../lib/tools';
import { AbstractManager, IndexParam, HintItem, UniqueSearchParam } from './CommonManager'
import _ from 'lodash'
abstract class BaseManager<T extends BaseDef> implements AbstractManager<T> {
mod: mongoose.Model<T>;
modelName: string;
cacheSecs: number;
defaultSort: string[];
defaultFields: string[];
constructor(mod: mongoose.Model<T>, params: any = {}) {
this.mod = mod;
this.modelName = mod.modelName;
this.defaultSort = params.defaultSort || ["_id"]
this.defaultFields = params.defaultFields || this.getInitialFields();
this.cacheSecs = params.cacheSecs != undefined ? params.cacheSecs : config.get("cacheSecs");
}
abstract getUniqueSearch(objP: UniqueSearchParam): any;
abstract getCacheKey(obj: UniqueSearchParam): string;
private getInitialFields(): string[] {
let emptyUnitSearch = this.getUniqueSearch({});
emptyUnitSearch._id = undefined; // 保证_id在fields中
return Object.keys(emptyUnitSearch);
}
private getUpdateFields(fields: string[]): string[] {
if (!fields || fields.length == 0) {
return this.defaultFields;
}
else {
for (let field of this.defaultFields) {
if (!fields.includes(field)) {
fields.push(field)
}
}
}
return fields
}
// user 为操作用户
async mCreate(params: any): Promise<T> {
this.addInitParam(params);
params.__new__ = true;
let obj = await this.mSave(params);
return obj;
}
serialize(obj: T): T {
if (obj && (obj as any).toObject != null) {
return (obj as any).toObject({ virtuals: true, getters: false, depopulate: true });
}
else {
return obj;
}
}
processHints(hints: HintItem[]) {
const toReturn: { [key: string]: number } = {};
if (!Array.isArray(hints)) return toReturn;
for (let hint of (hints || [])) {
if (!hint || !hint.fieldKey || !hint.hintOrder) {
continue;
}
hint.hintOrder = Number(hint.hintOrder);
if (_.isNaN(hint.hintOrder)) {
continue;
}
toReturn[hint.fieldKey] = hint.hintOrder;
}
return toReturn;
}
private async countCore(search: any, limit = 0): Promise<number> {
let count: number;
if (limit == 0) {
count = await this.mod.countDocuments(search);
}
else if (limit < 0) {
count = 0;
}
else {
let mongooseQuery = this.mod.find();
mongooseQuery.setOptions({ limit });
count = await mongooseQuery.countDocuments(search);
}
return count;
}
async mIndex(params: IndexParam): Promise<{ total: number; list: (T)[] }> {
let fields = params.fields || [];
let search = this.processBaseSearch(params.search);
let configPaginfo: any = config.get("pagination");
let pagination = params.pagination || {
page: 1,
pagesize: configPaginfo.pagesize
};
// 处理joinSearch结束
let sort = params.sort || this.defaultSort;
let skip = params.pagination && (params.pagination.start || params.pagination.start === 0) ? params.pagination.start : pagination.pagesize * (pagination.page - 1);
let limit = pagination.pagesize;
let findOption: mongoose.QueryOptions = {
skip: skip,
limit: limit,
sort: sort
}
if (params.indexHints) {
findOption.hint = this.processHints(params.indexHints);
}
else if (params.hint) {
findOption.hint = params.hint
}
let objs = await this.mod.find(search, fields, findOption);
let resultObjs = objs.map(x => this.serialize(x));
let total = await this.countCore(search, params.countLimit);
return {
total: total,
list: resultObjs
};
}
async mUpdate(params: any): Promise<T> {
return await this.mSave(params);
}
async mDelete(objP: UniqueSearchParam): Promise<T | null> {
let obj = await this.mod.findOneAndDelete(this.getUniqueSearch(objP));
if (obj) {
this.removeFromBuffer(obj);
return this.serialize(obj);
}
return null;
}
async mSoftDelete(objP: UniqueSearchParam): Promise<T> {
let updateParams: any = {
...this.getUniqueSearch(objP),
visible: false
};
let obj = await this.mUpdate(updateParams);
return obj;
}
async mGet(objP: UniqueSearchParam): Promise<T | null> {
let obj = await this.getFromBuffer(objP);
if (!obj) {
obj = await this.mFindOne(this.getUniqueSearch(objP));
if (obj) {
obj = this.serialize(obj);
await this.setToBuffer(obj);
return obj;
}
return null;
}
return obj;
}
async mCount(search: any, limit = 0): Promise<number> {
return this.countCore(this.processBaseSearch(search), limit);
}
async mSave(params: any): Promise<T> {
let obj: any = null;
let oldObj: any = {};
if (params.__new__) {
params.__new__ = undefined;
obj = await this.mod.create(params);
obj = this.serialize(obj);
}
else {
let search = this.getUniqueSearch(params);
oldObj = await this.mod.findOneAndUpdate(search, params as unknown as mongoose.UpdateQuery<T>);
if (oldObj) {
oldObj = this.serialize(oldObj);
}
obj = {
..._.cloneDeep(oldObj),
..._.cloneDeep(params)
}
}
await this.removeFromBuffer(obj);
obj.__old__ = oldObj;
return obj;
}
async mInsertMany(objs: any[]): Promise<T[]> {
let dbObjs: any = await this.mod.insertMany(objs);
let resultObjs = [];
for (let idx = 0; idx < dbObjs.length; idx++) {
resultObjs.push(this.serialize(dbObjs[idx]));
}
return resultObjs;
}
async mNativeFind(search: any, fields: string[] = [], opts = {}): Promise<T[]> {
let objs = await this.mod.find(this.processBaseSearch(search), fields, opts);
let sObjs = objs.map(x => this.serialize(x));
return sObjs;
}
async mFindOne(search: any): Promise<T | null> {
let obj = await this.mod.findOne(this.processBaseSearch(search))
if (obj) {
return this.serialize(obj);
}
return null;
}
async mUpdateMany(search: any, updateParams: any, fields: Array<string> = [], returnEmpty = false): Promise<T[]> {
fields = this.getUpdateFields(fields);
// 把需要更新的字段加到fields里
for( let updateField in updateParams ){
if( !fields.includes(updateField) ){
fields.push(updateField);
}
}
search = this.processBaseSearch(search);
let returnObjs: T[] = [];
if (this.cacheSecs > 0 || !returnEmpty) {
let dbObjs = await this.mod.find(search, fields);
for (let idx = 0; idx < dbObjs.length; idx++) {
if (!returnEmpty) {
let oldObj = this.serialize(dbObjs[idx]);
let newObj = {
..._.cloneDeep(oldObj),
..._.cloneDeep(updateParams),
__old__: oldObj
}
returnObjs.push(newObj);
}
this.removeFromBuffer(dbObjs[idx]);
}
}
await this.mod.updateMany(search, updateParams);
return returnObjs;
}
async mDeleteMany(search: any, fields: Array<string> = [], returnEmpty = false): Promise<T[]> {
fields = this.getUpdateFields(fields);
search = this.processBaseSearch(search);
// 从缓存中删除,下次重新获取
let returnObjs: T[] = [];
if (this.cacheSecs > 0 || !returnEmpty) {
let dbObjs = await this.mod.find(search, fields);
for (let idx = 0; idx < dbObjs.length; idx++) {
if (!returnEmpty) {
returnObjs.push(this.serialize(dbObjs[idx]));
}
this.removeFromBuffer(dbObjs[idx]);
}
}
await this.mod.deleteMany(search);
return returnObjs;
}
async mSoftDeleteMany(search: any, fields: Array<string> = [], returnEmpty = false): Promise<T[]> {
fields = this.getUpdateFields(fields);
search = this.processBaseSearch(search);
let returnObjs: T[] = [];
if (this.cacheSecs > 0 || !returnEmpty) {
let dbObjs = await this.mod.find(search, fields);
for (let idx = 0; idx < dbObjs.length; idx++) {
if (!returnEmpty) {
returnObjs.push(this.serialize(dbObjs[idx]));
}
this.removeFromBuffer(dbObjs[idx]);
}
}
await this.mod.updateMany(search, { visible: false } as any);
return returnObjs;
}
async mTypes(): Promise<any> {
let t = {};
// 遍历所有字段的types
t = tools.getSchemaTypes(this.mod.schema.obj);
return t;
}
processBaseSearch(search: any): any {
if (search) {
return {
...search,
visible: true
};
}
else {
return {
visible: true
};
}
}
async setToBuffer(obj: T | null): Promise<void> {
if (this.cacheSecs <= 0) return;
if (!obj) return;
await this.setToBufferCore(obj);
}
async setToBufferCore(obj: T): Promise<void> {
delete obj.__old__;
await redis.set(this.getCacheKey(obj), JSON.stringify(obj), "EX", this.cacheSecs);
}
async removeFromBuffer(obj: T): Promise<void> {
if (this.cacheSecs <= 0) return;
await redis.del(this.getCacheKey(obj));
}
addInitParam(initParam: any): void {
}
async getFromBuffer(obj: UniqueSearchParam): Promise<T | null> {
if (this.cacheSecs <= 0) return null;
let cacheObjStr = await redis.get(this.getCacheKey(obj));
if (cacheObjStr) {
let o = JSON.parse(cacheObjStr);
return o;
}
return null;
}
async mAggregate(list: any[], option?: any): Promise<any[]> {
if (option && option.keyTypeMap && Object.keys(option.keyTypeMap).length > 0) {
for (let i of list) {
if (i.$match) {
tools.getDataId(i.$match, option.keyTypeMap);
}
}
}
return this.mod.aggregate(list)
}
}
export default BaseManager;
////////////////////////////////////////////////////////
//
// 重要 !!!!!!!!!!!!!!!!!!!!
//
// 核心模块代码, 请到ts_basis项目中修改提交
//
////////////////////////////////////////////////////////
import { BaseDef, DbInfo } from '../../def/base/commonTypes'
import mongoose from 'mongoose';
export interface HintItem {
fieldKey: string;
hintOrder: number;
}
export interface Pagination {
page: number;
pagesize: number;
start?: number;
}
export interface IndexParam {
fields?: Array<string>;
pagination?: Pagination
search?: any;
sort?: string | string[];
indexHints?: HintItem[]; // 明树云格式
countLimit?: number;
hint?: { [key: string]: number }; // mongo支持格式
metaInfo?: {
isCustomSearch: boolean;
isExport: boolean;
dbAppKey: string;
maxExportNum?: string;
filename?: string;
}
}
export interface UniqueSearchParam {
_id?: mongoose.Types.ObjectId | string | number;
_key?: string;
compKey?: string;
appKey?: string;
}
export type RemoteKey = 'comp' | 'core' | 'mod' | 'resource' | 'file' | 'share' | 'sender' | 'admin' | 'help' | 'ticker' | 'custom' | 'job' | 'log' | 'proxy' | 'dstore' | 'calculator' | 'ppp' | 'cgpt';
export interface RemoteParam {
user: any;
modelName: string;
remoteKey: RemoteKey;
}
export interface CompRemoteParam extends RemoteParam {
compKey: string;
}
export interface AppRemoteParam extends RemoteParam {
compKey: string;
appKey: string;
}
export interface DynamicRemoteParam extends RemoteParam {
compKey: string;
entityKey: string;
}
export abstract class AbstractManager<T extends BaseDef> {
abstract mCreate(params: any): Promise<T>;
abstract mIndex(params: IndexParam): Promise<{ total: number; list: (T)[] }>;
abstract mUpdate(params: any): Promise<T>;
abstract mDelete(objP: UniqueSearchParam): Promise<T | null>;
abstract mGet(objP: UniqueSearchParam): Promise<T | null>;
abstract mCount(search: any, limit?: number): Promise<number>;
abstract mSave(params: any): Promise<T>;
abstract mInsertMany(objs: any[]): Promise<T[]>;
abstract mNativeFind(search: any, fields?: string[], opts?: { [key: string]: any }): Promise<T[]>;
abstract mFindOne(search: any): Promise<T | null>;
abstract mUpdateMany(search: any, updateParams: any, fields?: string[], returnEmpty?: boolean): Promise<T[]>;
abstract mDeleteMany(search: any, fields?: string[], returnEmpty?: boolean): Promise<T[]>;
abstract mSoftDelete(objP: UniqueSearchParam): Promise<T>;
abstract mSoftDeleteMany(search: any, fields?: string[], returnEmpty?: boolean): Promise<T[]>;
abstract mTypes(): Promise<any>;
abstract mAggregate(list: any[], option?: any): Promise<any[]>;
}
////////////////////////////////////////////////////////
//
// 重要 !!!!!!!!!!!!!!!!!!!!
//
// 核心模块代码, 请到ts_basis项目中修改提交
//
////////////////////////////////////////////////////////
import OrderManager from "./OrderManager";
import { CompItemDef } from '../../def/base/commonTypes';
import tools from '../../lib/tools';
import config from 'config';
import { UniqueSearchParam } from './CommonManager';
class CompItemManager<T extends CompItemDef> extends OrderManager<T> {
addInitParam(initParam: any) {
let newKey = tools.generateKey(this.modelName);
initParam._key = initParam._key ? initParam._key : newKey;
super.addInitParam(initParam);
}
async mGetByCompKey(compKey: string, key: string): Promise<T | null> {
return await this.mGet(
{
compKey: compKey,
_key: key
}
)
}
getUniqueSearch(objP: UniqueSearchParam) {
return {
compKey: objP.compKey,
_key: objP._key
}
}
getCacheKey(obj: UniqueSearchParam): string {
return config.get("serviceKey") + "_" + tools.getCompItemCacheKey(this.modelName, obj.compKey, obj._key);
}
}
export default CompItemManager;
////////////////////////////////////////////////////////
//
// 重要 !!!!!!!!!!!!!!!!!!!!
//
// 核心模块代码, 请到ts_basis项目中修改提交
//
////////////////////////////////////////////////////////
import { BaseDef } from '../../def/base/commonTypes';
import tools from '../../lib/tools';
import mongoose from 'mongoose';
import { UniqueSearchParam } from './CommonManager';
import BaseManager from "./BaseManager";
import config from 'config';
class IdItemManager<T extends BaseDef> extends BaseManager<T> {
constructor(mod: mongoose.Model<T>, params: any = {}) {
super(mod, params)
this.cacheSecs = params.cacheSecs != undefined ? params.cacheSecs : 0
}
getUniqueSearch(objP: UniqueSearchParam): any {
return {
_id: objP._id
}
}
getCacheKey(obj: UniqueSearchParam): string {
return config.get("serviceKey") + "_" + tools.getIdItemCacheKey(this.modelName, obj);
}
////////////////////////////////////////////////////////
// for populate
////////////////////////////////////////////////////////
async mFindByIdsWithNull(idList: mongoose.Types.ObjectId[], fields: Array<string> = []): Promise<(T | null)[]> {
let popIdxs = [];
let popObjIds: any[] = [];
let idStringIdxMap: any = {};
let dbSearchFields = fields || [];
// 增加一个全部为空的数组
let objList: (T | null)[] = idList.map(x => null);
for (let idx = 0; idx < idList.length; idx++) {
let objId = idList[idx];
if (!objId) {
continue;
}
popIdxs.push(idx);
popObjIds.push(objId);
idStringIdxMap[tools.getIdString(objId)] = idx;
}
if (popIdxs.length > 0) {
let dbObjs = await this.mod.find({ _id: { "$in": popObjIds } }, dbSearchFields);
for (let dbObj of dbObjs) {
let obj = this.serialize(dbObj);
let popIdx = idStringIdxMap[tools.getIdString(obj)];
objList[popIdx] = obj;
}
}
return objList;
}
async mFindMapByIds(idList: mongoose.Types.ObjectId[], fields: Array<string> = []): Promise<{ [key: string]: T }> {
let objListWithNull = await this.mFindByIdsWithNull(idList, fields);
let returnMap: any = {};
for (let obj of objListWithNull) {
if (obj) {
returnMap[tools.getIdString(obj)] = obj;
}
}
return returnMap;
}
}
export default IdItemManager;
////////////////////////////////////////////////////////
//
// 重要 !!!!!!!!!!!!!!!!!!!!
//
// 核心模块代码, 请到ts_basis项目中修改提交
//
////////////////////////////////////////////////////////
import OrderManager from "./OrderManager";
import { KeyItemDef } from '../../def/base/commonTypes';
import tools from '../../lib/tools';
import mongoose from 'mongoose';
import config from 'config';
import { UniqueSearchParam } from './CommonManager';
class KeyItemManager<T extends KeyItemDef> extends OrderManager<T> {
constructor(mod: mongoose.Model<T>, params: any = {}) {
super(mod, params)
}
addInitParam(initParam: any) {
let newKey = tools.generateKey(this.modelName);
initParam._key = initParam._key ? initParam._key : newKey;
super.addInitParam(initParam);
}
async mGetByKey(key: string): Promise<T | null> {
return await this.mGet(
{
_key: key
}
)
}
getUniqueSearch(objP: UniqueSearchParam) {
return {
_key: objP._key
}
}
getCacheKey(obj: UniqueSearchParam): string {
return config.get("serviceKey") + "_" + tools.getKeyItemCacheKey(this.modelName, obj._key);
}
}
export default KeyItemManager;
////////////////////////////////////////////////////////
//
// 重要 !!!!!!!!!!!!!!!!!!!!
//
// 核心模块代码, 请到ts_basis项目中修改提交
//
////////////////////////////////////////////////////////
import BaseManager from './BaseManager';
import { OrderDef } from '../../def/base/commonTypes';
import mongoose from 'mongoose';
abstract class OrderManager<T extends OrderDef> extends BaseManager<T> {
constructor(mod: mongoose.Model<T>, params: any = {}) {
super(mod, params)
this.defaultSort = params.defaultSort || ["order"]
}
addInitParam(initParam: any) {
initParam.order = initParam.order ? initParam.order : Math.round(new Date().valueOf()) * 1000;
super.addInitParam(initParam);
}
}
export default OrderManager;
////////////////////////////////////////////////////////
//
// 重要 !!!!!!!!!!!!!!!!!!!!
//
// 核心模块代码, 请到ts_basis项目中修改提交
//
////////////////////////////////////////////////////////
import BaseRemoteManager from "./BaseRemoteManager";
import { AppItemDef } from '../../../def/base/commonTypes';
import { AppRemoteParam } from '../CommonManager';
import remoteEnv from "../../../lib/remoteEnv";
import tools from "../../../lib/tools";
class AppItemRemoteManager<T extends AppItemDef> extends BaseRemoteManager<T> {
compKey: string;
appKey: string;
modelName: string;
constructor(params: AppRemoteParam) {
super(params)
this.compKey = params.compKey;
this.appKey = params.appKey;
this.modelName = params.modelName;
}
getBaseUrl(): string {
return `/api/cloud/${this.compKey}/${this.appKey}/${this.modelName}/`
}
async mGetByAppKey(compKey: string, appKey: string, key: string): Promise<T | null> {
// hMod_Entity_key:hb_abc
let cacheKey = tools.getServiceCachePrefix(this.remoteCaller.remoteKey) + "_" + tools.getAppItemCacheKey(this.modelName, compKey, appKey, key);
let itemRedis = await remoteEnv.getRemoteRedisClient(this.remoteCaller.remoteKey)
if (itemRedis) {
let cacheObjStr = await itemRedis.get(cacheKey);
if (cacheObjStr) {
let obj = JSON.parse(cacheObjStr);
return obj;
}
}
return await this.mGet(
{
compKey: compKey,
appKey: appKey,
_key: key
}
)
}
}
export default AppItemRemoteManager;
////////////////////////////////////////////////////////
//
// 重要 !!!!!!!!!!!!!!!!!!!!
//
// 核心模块代码, 请到ts_basis项目中修改提交
//
////////////////////////////////////////////////////////
import { IndexParam, UniqueSearchParam, AbstractManager } from '../CommonManager'
import { BaseDef } from '../../../def/base/commonTypes'
import { RemoteParam } from '../CommonManager';
import RemoteCaller from './RemoteCaller';
abstract class BaseRemoteManager<T extends BaseDef> implements AbstractManager<T> {
remoteCaller: RemoteCaller;
constructor(params: RemoteParam) {
this.remoteCaller = new RemoteCaller(params);
}
abstract getBaseUrl(): string
getActMap(): { [key: string]: string } {
return {
"mGet": "show",
"mNativeFind": "all",
"mFindOne": "findOne",
"mCreate": "create",
"mUpdate": "update",
"mDelete": "delete",
"mInsertMany": "insertMany",
"mCount": "count",
"mIndex": "index",
"mSoftDelete": "softDelete",
"mSoftSearchDelete": "softSearchDelete",
"mUpdateMany": "searchUpdate",
"mDeleteMany": "searchDelete",
"mAggregate": "aggregate",
"mGroupData": "groupData",
}
}
getUrl(act: string): string {
let actMap = this.getActMap()
if (actMap[act] == null) {
throw new Error("Action not defined!");
}
return this.getBaseUrl() + actMap[act];
}
processBaseSearch(search: any): any {
return search
}
async customCall(actName: string, params: any, headers?: any): Promise<any> {
let url = this.getBaseUrl() + actName;
let data = await this.remoteCaller.requestRemoteData(url, params, headers);
return data
}
// user 为操作用户
async mCreate(params: any): Promise<any> {
params.__new__ = true;
let obj = await this.mSave(params);
return obj;
}
async mIndex(params: IndexParam): Promise<{ total: number; list: (T)[] }> {
if( params.search ){
params.search = this.processBaseSearch(params.search);
}
let url = this.getUrl("mIndex");
let data: { total: number; list: T[] } = await this.remoteCaller.requestRemoteData(url, params);
return data
}
async mUpdate(params: any): Promise<T> {
return this.mSave(params)
}
async mSave(params: any): Promise<T> {
let data: any;
if (params.__new__) {
params.__new__ = undefined;
let url = this.getUrl("mCreate");
data = await this.remoteCaller.requestRemoteData(url, params);
}
else {
let url = this.getUrl("mUpdate");
data = await this.remoteCaller.requestRemoteData(url, params);
}
return data
}
async mDelete(objP: UniqueSearchParam): Promise<T | null> {
let url = this.getUrl("mDelete");
let data = await this.remoteCaller.requestRemoteData(url, objP);
return data
}
async mSoftDelete(objP: UniqueSearchParam): Promise<T> {
let url = this.getUrl("mSoftDelete");
let data = await this.remoteCaller.requestRemoteData(url, objP);
return data
}
async mGet(objP: UniqueSearchParam): Promise<T | null> {
let url = this.getUrl("mGet");
let data = await this.remoteCaller.requestRemoteData(url, objP);
return data
}
async mCount(search: any, limit = 0): Promise<number> {
search = this.processBaseSearch(search);
let url = this.getUrl("mCount");
let data = await this.remoteCaller.requestRemoteData(url, { search, limit });
return data.total;
}
async mInsertMany(list: any[]): Promise<T[]> {
let url = this.getUrl("mInsertMany");
let data = await this.remoteCaller.requestRemoteData(url, { list });
return data.list
}
async mNativeFind(search: any, fields: string[] = [], opts: { [key: string]: any } = {}): Promise<T[]> {
search = this.processBaseSearch(search);
let url = this.getUrl("mNativeFind");
let sort = opts.sort;
let hint = opts.hint;
let skip = opts.skip;
let limit = opts.limit;
let metaInfo = opts.metaInfo;
let data = await this.remoteCaller.requestRemoteData(url, { search, fields, sort, hint, skip, limit, countLimit: -1, metaInfo });
return data.list;
}
async mFindOne(search: any): Promise<T | null> {
search = this.processBaseSearch(search);
let url = this.getUrl("mFindOne");
let data = await this.remoteCaller.requestRemoteData(url, { search });
return data;
}
async mUpdateMany(search: any, updateParams: any, fields: Array<string> = [], returnEmpty = false): Promise<T[]> {
search = this.processBaseSearch(search);
let url = this.getUrl("mUpdateMany");
let data = await this.remoteCaller.requestRemoteData(url, { search, updateParams, fields, returnEmpty });
return data.list;
}
async mDeleteMany(search: any, fields: Array<string> = [], returnEmpty = false): Promise<T[]> {
search = this.processBaseSearch(search);
let url = this.getUrl("mDeleteMany");
let data = await this.remoteCaller.requestRemoteData(url, { search, fields, returnEmpty });
return data.list;
}
async mSoftDeleteMany(search: any, fields: Array<string> = [], returnEmpty = false): Promise<T[]> {
search = this.processBaseSearch(search);
let url = this.getUrl("mSoftDeleteMany");
let data = await this.remoteCaller.requestRemoteData(url, { search, fields, returnEmpty });
return data.list;
}
async mTypes(): Promise<any> {
let url = this.getUrl("mTypes");
let data = await this.remoteCaller.requestRemoteData(url, {});
return data;
}
async mAggregate(list: any[], option?: any): Promise<any[]> {
let url = this.getUrl("mAggregate");
let data = await this.remoteCaller.requestRemoteData(url, { list, option });
return data.list
}
async mGroupData (params: any) {
let url = this.getUrl("mGroupData");
let data = await this.remoteCaller.requestRemoteData(url, params);
return data
}
}
export default BaseRemoteManager;
////////////////////////////////////////////////////////
//
// 重要 !!!!!!!!!!!!!!!!!!!!
//
// 核心模块代码, 请到ts_basis项目中修改提交
//
////////////////////////////////////////////////////////
import BaseRemoteManager from "./BaseRemoteManager";
import { CompItemDef } from '../../../def/base/commonTypes';
import { CompRemoteParam } from '../CommonManager';
import remoteEnv from "../../../lib/remoteEnv";
import tools from "../../../lib/tools";
class CompItemRemoteManager<T extends CompItemDef> extends BaseRemoteManager<T> {
compKey: string;
modelName: string;
constructor(params: CompRemoteParam) {
super(params)
this.compKey = params.compKey;
this.modelName = params.modelName;
}
getBaseUrl(): string {
return `/api/cloud/${this.compKey}/${this.modelName}/`
}
async mGetByCompKey(compKey: string, key: string): Promise<T | null> {
// hMod_Entity_key:hb_abc
let cacheKey = tools.getServiceCachePrefix(this.remoteCaller.remoteKey) + "_" + tools.getCompItemCacheKey(this.modelName, compKey, key);
let itemRedis = await remoteEnv.getRemoteRedisClient(this.remoteCaller.remoteKey)
if (itemRedis) {
let cacheObjStr = await itemRedis.get(cacheKey);
if (cacheObjStr) {
let obj = JSON.parse(cacheObjStr);
return obj;
}
}
return await this.mGet(
{
compKey: compKey,
_key: key
}
)
}
}
export default CompItemRemoteManager;
////////////////////////////////////////////////////////
//
// 重要 !!!!!!!!!!!!!!!!!!!!
//
// 核心模块代码, 请到ts_basis项目中修改提交
//
////////////////////////////////////////////////////////
import BaseRemoteManager from "./BaseRemoteManager";
import { DynamicRemoteParam } from '../CommonManager';
import { DbInfo } from "../../../def/base/commonTypes";
class DynamicModRemoteManager extends BaseRemoteManager<any> {
modelName: string;
entityKey: string;
compKey: string;
constructor(params: DynamicRemoteParam) {
super(params)
this.modelName = params.modelName;
this.compKey = params.compKey;
this.entityKey = params.entityKey;
}
getBaseUrl(): string {
return `/api/cloud/${this.compKey}/${this.modelName}/${this.entityKey}/`
}
}
export default DynamicModRemoteManager;
////////////////////////////////////////////////////////
//
// 重要 !!!!!!!!!!!!!!!!!!!!
//
// 核心模块代码, 请到ts_basis项目中修改提交
//
////////////////////////////////////////////////////////
import BaseRemoteManager from "./BaseRemoteManager";
import { BaseDef } from '../../../def/base/commonTypes';
import { RemoteParam } from '../CommonManager';
class IdItemRemoteManager<T extends BaseDef> extends BaseRemoteManager<T> {
modelName: string;
constructor(params: RemoteParam) {
super(params)
this.modelName = params.modelName;
}
getBaseUrl(): string {
return `/api/cloud/${this.modelName}/`
}
}
export default IdItemRemoteManager;
////////////////////////////////////////////////////////
//
// 重要 !!!!!!!!!!!!!!!!!!!!
//
// 核心模块代码, 请到ts_basis项目中修改提交
//
////////////////////////////////////////////////////////
import BaseRemoteManager from "./BaseRemoteManager";
import { KeyItemDef } from '../../../def/base/commonTypes';
import { RemoteParam } from '../CommonManager';
class KeyItemRemoteManager<T extends KeyItemDef> extends BaseRemoteManager<T> {
modelName: string;
constructor(params: RemoteParam) {
super(params)
this.modelName = params.modelName;
}
getBaseUrl(): string {
return `/api/cloud/${this.modelName}/`
}
async mGetByKey(key: string): Promise<T | null> {
return await this.mGet(
{
_key: key
}
)
}
}
export default KeyItemRemoteManager;
////////////////////////////////////////////////////////
//
// 重要 !!!!!!!!!!!!!!!!!!!!
//
// 核心模块代码, 请到ts_basis项目中修改提交
//
////////////////////////////////////////////////////////
import jwtlib from '../../../lib/jwtlib'
import axios, { AxiosRequestConfig, AxiosResponse } from 'axios';
import https from 'https';
import http from 'http';
import config from 'config'
import remoteEnv from '../../../lib/remoteEnv';
import { redis } from '../../../lib/redis';
import { RemoteParam, RemoteKey } from '../CommonManager';
import log4js from 'log4js';
import { Response } from "express";
import { SocketOption } from 'src/api/def/base/proxyTypes';
const logger = log4js.getLogger('RemoteCaller');
class RemoteCaller {
tokenExpireTime: string;
user: any;
remoteKey: RemoteKey;
remoteParams: any;
constructor(params: RemoteParam) {
this.tokenExpireTime = "1200s"; // token 2分钟过期
// this.host = host;
this.remoteParams = params;
this.user = {
"_key": params.user._key,
"user_type": params.user.user_type,
"companies": params.user.companies,
"departments": params.user.departments,
"user_card": params.user.user_card,
"realname": params.user.realname,
"ShareLog": params.user.ShareLog || {}
}
this.remoteKey = params.remoteKey;
}
async getHost(): Promise<string> {
let curConfig = await remoteEnv.getRemoteConfigByKey(this.remoteKey);
if( this.remoteParams && curConfig.hostMap && curConfig.hostMap[this.remoteParams.compKey]){
return curConfig.hostMap[this.remoteParams.compKey]
}
return curConfig.host;
}
async getBackendToken(cacheSec = 2 * 60): Promise<string> {
const tokenKey = `${config.get('serviceKey')}_jwt:${this.user._key}`;
let token = await redis.get(tokenKey);
if (!token) {
token = "jwt:" + jwtlib.encrypt(this.user, this.tokenExpireTime);
await redis.set(tokenKey, token, 'EX', cacheSec); // 默认2分钟
return token;
}
return token;
}
async requestRemoteDataAbs(absUrl: string, params: any, headers = {}) {
try {
// headers可以替换authtoken
let result = await axios.post(absUrl, params,
{
headers: {
...headers,
"authtoken": await this.getBackendToken(),
"refkey": config.get("serviceKey"),
},
maxContentLength: Infinity,
maxBodyLength: Infinity,
timeout: 600000,
httpsAgent: new https.Agent({ keepAlive: true }),
httpAgent: new http.Agent({ keepAlive: true })
}).catch(function (error) {
return error.response;
});
// console.log("result", result)
if (result == null) {
throw new Error("Remote error [" + absUrl + "]: ")
}
if (result.data.res != 0) {
throw new Error("Remote error [" + absUrl + "]: " + result && result.data.msg)
}
return result.data.data;
} catch (error: any) {
logger.error("error msg", error.message)
throw error
}
}
async requestRemoteDataAbsStream(absUrl: string, params: any, headers = {}) {
const authtoken = await this.getBackendToken();
const axConfig: AxiosRequestConfig = {
url: absUrl,
method: 'post',
maxContentLength: Infinity,
timeout: 600000,
httpsAgent: new https.Agent({ keepAlive: true }),
httpAgent: new http.Agent({ keepAlive: true }),
data: params
};
let response: Response;
let socket: any;
let socketOption: SocketOption;
if (params && params.responseType && params.responseType === 'stream') {
axConfig.responseType = 'stream';
delete params.responseType;
if (params.res && params.res.write) {
response = params.res;
delete params.res;
}
if (params.socket) {
socket = params.socket;
delete params.socket;
if (params.socketOption) {
socketOption = params.socketOption;
delete params.socketOption;
}
}
}
axConfig.headers = {
...headers,
refkey: config.get("serviceKey"),
authtoken: authtoken
}
const axiosPromise = new Promise((resolve, reject) => {
axios(axConfig).catch(err => {
reject(err);
}).then(result => {
if (!result) {
resolve;
return;
}
const stream = result.data;
stream.on('data', (data: any | string[]) => {
if (data) {
if (response) response.write(data);
if (socket && socketOption && socketOption.onData) socketOption.onData(socket, socketOption.event, data);
}
});
stream.on('end', (data: any | string[]) => {
if (data) {
if (response) response.end(data);
} else {
if (response) response.end();
}
if (socket && socketOption && socketOption.onEnd) socketOption.onEnd(socket,socketOption.event, data);
resolve;
});
stream.on('error', (err: any) => {
if (response) response.end();
if (socket && socketOption && socketOption.onError) socketOption.onError(socket, socketOption.event, err);
reject(err);
});
});
});
try {
const result = await axiosPromise as AxiosResponse;
if (result == null) {
throw new Error("Remote error [" + absUrl + "]: ")
}
if (result.data.res != 0) {
throw new Error("Remote error [" + absUrl + "]: " + result && result.data.msg)
}
return result.data.data;
} catch (error) {
logger.error("error msg", error)
throw error
}
}
async requestRemoteData(url: string, params: any, headers = {}) {
let host = await this.getHost();
let absUrl = host + url;
if(params.responseType && params.responseType === 'stream') {
return this.requestRemoteDataAbsStream(absUrl, params, headers);
}
return this.requestRemoteDataAbs(absUrl, params, headers)
}
}
export default RemoteCaller;
import CommonModel from './base/CommonModel';
import mongoose from 'mongoose';
import { BaseExampleDef } from '../def/base/basisTypes'
import { schemaDefaultOption, modelDefaultMethods } from '../lib/mongo/plugins'
import con from '../lib/mongo/index'
const BaseExampleSchema = new mongoose.Schema<BaseExampleDef>({
...CommonModel.baseItem,
name: String,
description: String,
amount: Number,
itemType: {
type: String,
enum: ["Mod", "Dashboard", "Report", "InnerApp", "Tabulation", "EmbedPage", "InnerChart", "InnerTable", "AppRole", "Trigger", "FlowDef"],
types: [
{ key: "Mod", name: "工作表" },
{ key: "Dashboard", name: "仪表盘" },
{ key: "InnerApp", name: "应用信息" },
{ key: "Tabulation", name: "自定义页面" },
{ key: "EmbedPage", name: "嵌入页面" },
{ key: "InnerChart", name: "图表" },
{ key: "InnerTable", name: "表格" },
{ key: "AppRole", name: "角色权限" },
{ key: "FlowDef", name: "流程"},
{ key: "Report", name: "报告"},
{ key: "Trigger", name: "触发器"},
{ key: "FileArchive", name: "文件"}
]
},
}, schemaDefaultOption);
for (let m in modelDefaultMethods) {
BaseExampleSchema.methods[m] = modelDefaultMethods[m];
}
let BaseExample = con.dbCore.model("BaseExample", BaseExampleSchema, "core_baseexample");
export default BaseExample
\ No newline at end of file
////////////////////////////////////////////////////////
//
// 重要 !!!!!!!!!!!!!!!!!!!!
//
// 核心模块代码, 请到ts_basis项目中修改提交
//
////////////////////////////////////////////////////////
const baseItem: any = {
visible: {
type: Boolean,
default: true
} // 是否可见
};
const orderItem = {
...baseItem,
order: {
type: Number,
index: true,
required: [true, "顺序不能为空"],
}
};
const nameItem = {
...orderItem,
name: {
type: String,
required: [true, "名称不能为空"]
},
description: {
type: String
},
createType: {
type: String,
enum: ["self", "download"],
types: [
{ "self": "手动创建" },
{ "download": "下载安装" }
],
default: "self"
} // 创建方式
}
const keyItem = {
...orderItem,
_key: {
type: String,
required: [true, "标识不能为空"],
index: true,
unique: true
}
}
const compItem = {
...nameItem,
compKey: {
type: String,
required: [true, "未于公司关联"],
index: true
},
_key: {
type: String,
required: [true, "标识不能为空"],
index: true
}
}
const appItem = {
...nameItem,
_key: {
type: String,
required: [true, "标识不能为空"],
index: true // 加快按app搜索的速度
},
compKey: {
type: String,
required: [true, "未于公司关联"],
index: true
},
appKey: {
type: String,
ref: 'InnerApp',
required: [true, "未与应用关联"],
index: true // 加快按app搜索的速度
},
itemGroupKey: String
};
const cascaderItem = {
name: {
type: String,
required: [true, "名称不能为空"]
},
code: {
type: String,
required: [true, "编码不能为空"],
index: true, // 加快搜索的速度
}, // 编码
level: {
type: Number,
required: [true, "层级不能为空"]
}, // 层级
full_name: {
type: String
}, // 全名
is_leaf: {
type: Boolean,
default: true,
} // 是否是最低层
};
const groupItem: any = {
_key: String,
name: String
};
export default {
baseItem,
orderItem,
nameItem,
keyItem,
compItem,
appItem,
cascaderItem,
groupItem
};
import * as WhereInterface from "./WhereInterface";
export default class MysqlSearchProcessor implements WhereInterface.EqualSearchInterface, WhereInterface.RegexSearchInterface, WhereInterface.CompareSearchInterface {
mysqlWhere: string
constructor(public advSearch: WhereInterface.LogicSearchInterface) {
this.mysqlWhere = this.deal(advSearch);
}
getWhereStr() {
return this.mysqlWhere ? "where " + this.mysqlWhere : "";
}
deal(advSearch?: WhereInterface.LogicSearchInterface | WhereInterface.FieldSearchInterface): string {
if (!advSearch) {
advSearch = this.advSearch;
}
if (advSearch.logic === "and") {
return this.and(advSearch);
} else if (advSearch.logic === "or") {
return this.or(advSearch);
} else if (advSearch.logic === "field") {
return this.field(advSearch);
}
return "";
}
and(advSearch: WhereInterface.LogicSearchInterface): string {
if (advSearch.conditions.length === 0) {
return "";
}
let list: string[] = [];
for (const cdt of advSearch.conditions) {
const result = this.deal(cdt);
if (result) {
list.push(result);
}
}
return list.length ? list.join(" and ") : "";
}
or(advSearch: WhereInterface.LogicSearchInterface): string {
if (advSearch.conditions.length === 0) {
return "";
} else if (advSearch.conditions.length === 1) {
return this.deal(advSearch.conditions[0]);
}
let list: string[] = [];
for (const cdt of advSearch.conditions) {
const result = this.deal(cdt);
if (result) {
list.push(result);
}
}
return list.length ? "(" + list.join(" or ") + ")" : "";
}
field(advSearch: WhereInterface.FieldSearchInterface): string {
const key = advSearch.fieldKey;
const opr = advSearch.fieldOperator;
const vals = advSearch.fieldValue;
if (opr === "isnull" || opr === "notnull") {
return this[opr](key);
}
if (!vals || vals.length === 0) {
return "";
}
if (advSearch.fieldType === "date") {
// TODO: 处理时间类型的值
}
if (opr === "eq" || opr === "ne") {
if (vals.length === 1) {
return this[opr](key, vals[0]);
} else {
return this[opr === "eq" ? "in" : "nin"](key, vals);
}
}
if (opr === "regex" || opr === "startsWith" || opr === "endsWith"
|| opr === "gt" || opr === "gte" || opr === "lt" || opr === "lte") {
let list: string[] = [];
for (const val of vals) {
const wstr = this[opr](key, val);
if (wstr) {
list.push(wstr);
}
}
return list.length ? list.join(" and ") : "";
}
if (["range", "notrange", "rangein", "rangenin", "rangeLeftin", "rangeLeftnin", "rangeRightin", "rangeRightnin"].includes(opr)) {
return this[opr](key, vals[0], vals[1]);
}
throw new Error(`方法(${opr})未定义`);
}
// WhereInterface.EqualSearchInterface
eq(key: string, val: any): string {
return `${key}="${val}"`;
}
ne(key: string, val: any): string {
return `${key}<>"${val}"`;
}
in(key: string, vals: any[]): string {
if (vals.length === 1) {
return this.eq(key, vals[0]);
}
return `${key} in ("${vals.join('","')}")`;
}
nin(key: string, vals: any[]): string {
if (vals.length === 1) {
return this.ne(key, vals[0]);
}
return `${key} not in ("${vals.join('","')}")`;
}
isnull(key: string): string {
return `${key} is null`;
}
notnull(key: string): string {
return `${key} is not null`;
}
// WhereInterface.RegexSearchInterface
regex(key: string, val: string): string {
return `${key} like "%${val}%"`;
}
startsWith(key: string, val: string): string {
return `${key} like "${val}%"`;
}
endsWith(key: string, val: string): string {
return `${key} like "%${val}"`;
}
// WhereInterface.CompareSearchInterface
gt(key: string, val: any): string {
return `${key}>${val}`;
}
gte(key: string, val: any): string {
return `${key}>=${val}`;
}
lt(key: string, val: any): string {
return `${key}<${val}`;
}
lte(key: string, val: any): string {
return `${key}<=${val}`;
}
range(key: string, left: any, right: any): string {
return this.gt(key, left) + " and " + this.lt(key, right);
}
notrange(key: string, left: any, right: any): string {
return this.lt(key, left) + " and " + this.gt(key, right);
}
rangein(key: string, left: any, right: any): string {
return this.gte(key, left) + " and " + this.lte(key, right);
}
rangenin(key: string, left: any, right: any): string {
return this.lte(key, left) + " and " + this.gte(key, right);
}
rangeLeftin(key: string, left: any, right: any): string {
return this.gte(key, left) + " and " + this.lt(key, right);
}
rangeLeftnin(key: string, left: any, right: any): string {
return this.lte(key, left) + " and " + this.gt(key, right);
}
rangeRightin(key: string, left: any, right: any): string {
return this.gt(key, left) + " and " + this.lte(key, right);
}
rangeRightnin(key: string, left: any, right: any): string {
return this.lt(key, left) + " and " + this.gte(key, right);
}
}
\ No newline at end of file
type dbEqualSearch = "eq" | "ne" | "in" | "nin" | "isnull" | "notnull";
type dbRegexSearch = "regex" | "startsWith" | "endsWith";
type dbCompareSearch = "gt" | "gte" | "lt" | "lte" | "range" | "notrange" | "rangein" | "rangenin" | "rangeLeftin" | "rangeLeftnin" | "rangeRightin" | "rangeRightnin";
type dbOpr = dbEqualSearch | dbRegexSearch | dbCompareSearch;
type dbWhereLogic = "and" | "or";
type KVType = {[k: string]: any};
const EqualType: KVType = {
eq: 1,
ne: 2,
in: 3,
nin: 4,
isnull: 5,
notnull: 6
};
const RegexType: KVType = {
regex: 1,
startsWith: 2,
endsWith: 3
};
const CompareType: KVType = {
gt: 1,
gte: 2,
lt: 3,
lte: 4,
range: 5,
notrange: 6,
rangein: 7,
rangenin: 8,
rangeLeftin: 9,
rangeLeftnin: 10,
rangeRightin: 11,
rangeRightnin: 12
};
export function isEqualType(opr: string): boolean {
return !!EqualType[opr];
}
export function isRegexType(opr: string): boolean {
return !!RegexType[opr];
}
export function isCompareType(opr: string): boolean {
return !!CompareType[opr];
}
export interface LogicSearchInterface {
logic: dbWhereLogic;
conditions: (FieldSearchInterface|LogicSearchInterface)[];
}
export interface FieldSearchInterface {
logic: "field";
fieldKey: string;
fieldType: string;
fieldValue: any[];
fieldOperator: dbOpr;
_dateType?: string;
}
export interface EqualSearchInterface {
eq(key: string, val: any): string;
ne(key: string, val: any): string;
in(key: string, vals: any[]): string;
nin(key: string, vals: any[]): string;
isnull(key: string): string;
notnull(key: string): string;
}
export interface RegexSearchInterface {
regex(key: string, val: string): string;
startsWith(key: string, val: string): string;
endsWith(key: string, val: string): string;
}
export interface CompareSearchInterface {
gt(key: string, val: any): string;
gte(key: string, val: any): string;
lt(key: string, val: any): string;
lte(key: string, val: any): string;
range(key: string, left: any, right: any): string;
notrange(key: string, left: any, right: any): string;
rangein(key: string, left: any, right: any): string;
rangenin(key: string, left: any, right: any): string;
rangeLeftin(key: string, left: any, right: any): string;
rangeLeftnin(key: string, left: any, right: any): string;
rangeRightin(key: string, left: any, right: any): string;
rangeRightnin(key: string, left: any, right: any): string;
}
////////////////////////////////////////////////////////
//
// 重要 !!!!!!!!!!!!!!!!!!!!
//
// 核心模块代码, 请到ts_basis项目中修改提交
//
////////////////////////////////////////////////////////
import { BaseDef } from "../../def/base/commonTypes";
import tools from "../../lib/tools";
import cms from "../../lib/cms";
import IdItemManager from "../../managers/base/IdItemManager";
function getPopulateManager(modM: IdItemManager<any>, key: string): IdItemManager<any> {
let fieldObj = tools.getNestedSchema(modM.mod.schema.obj, key);
let modName = null;
if (fieldObj instanceof Array) {
modName = fieldObj[0].ref;
}
else {
modName = fieldObj.ref;
}
return getManager(modName);
}
function getManager(modName: string): IdItemManager<any> {
let manager = cms.getManager(modName);
if (!manager) {
throw new Error("Manager not found!");
}
return manager;
}
async function singlePopulate(modM: IdItemManager<any>, objs: BaseDef[], p: string) {
let pIds = tools.getNestedIdArray(objs, p);
let popMap = await modM.mFindMapByIds(pIds);
for (let obj of objs) {
tools.setNestedArrayVal(obj, p, popMap);
}
}
async function populate<T extends BaseDef>(modM: IdItemManager<T>, objs: T[], populate: string[] | string): Promise<T[]> {
if (typeof (populate) == "string") {
populate = populate.split(" ");
}
for (let p of populate) {
let manager = getPopulateManager(modM, p);
await singlePopulate(manager, objs, p);
}
return objs;
}
export default {
getPopulateManager,
singlePopulate,
populate,
}
\ No newline at end of file
////////////////////////////////////////////////////////
//
// 重要 !!!!!!!!!!!!!!!!!!!!
//
// 核心模块代码, 请到ts_basis项目中修改提交
//
////////////////////////////////////////////////////////
import mongoose from "mongoose";
import tools from "../../lib/tools";
import log4js from 'log4js';
import { schemaDefaultOption, modelDefaultMethods } from '../../lib/mongo/plugins'
import { DbInfo } from "../../def/base/commonTypes";
const logger = log4js.getLogger('connection');
interface ConObj {
dbId: string;
con: mongoose.Connection;
}
let connectionQueque: ConObj[] = [];
let connectionMap: { [key: string]: mongoose.Connection } = {};
const poolSize = 20;
async function getConnection(dbinfo: DbInfo): Promise<mongoose.Connection> {
// 连接在队列中直接返回
if (dbinfo.dbId in connectionMap) {
let bufferCon = connectionMap[dbinfo.dbId];
// connected, connnecting
if ((bufferCon.readyState == 1 || bufferCon.readyState == 2)) {
return bufferCon;
}
else {
// disconnected, disconnecting
// if( bufferCon.readyState == 0 ){
// bufferCon.con.close();
// }
// 不是连接状态,删除重新连接
logger.info("~~~~~~~~~~~~~~~~~~~ disconnected ~~~~~~~~~~~~~~~~~~~~");
let foundIdx = -1;
for (let idx = 0; idx < connectionQueque.length; idx++) {
if (connectionQueque[idx].dbId == dbinfo.dbId) {
foundIdx = idx;
break;
}
}
if (foundIdx >= 0) {
connectionQueque.splice(foundIdx, 1);
}
delete connectionMap[dbinfo.dbId];
}
}
logger.info("~~~~~~~~~~~~~~~~~~~ create connection ~~~~~~~~~~~~~~~~~~~~");
let { connectStr, connectOption } = tools.getConnectionData(dbinfo);
logger.info("connectionStr--->", connectStr);
let modConnection = mongoose.createConnection(
connectStr,
connectOption
);
connectionQueque.push({
dbId: dbinfo.dbId,
con: modConnection
});
connectionMap[dbinfo.dbId] = modConnection;
if (connectionQueque.length > poolSize) {
let conToClose = connectionQueque.shift();
// 数据库连接关闭
if (conToClose) {
await conToClose.con.close();
delete connectionMap[conToClose.dbId];
}
}
return modConnection;
}
async function buildDynamicModel(modDB: mongoose.Connection, schemaObj: mongoose.Schema, dbKey: string, colName: string) {
if (colName == "") {
colName = dbKey;
}
if (!modDB.models[dbKey]) {
for (let defaultMethod in modelDefaultMethods) {
schemaObj.methods[defaultMethod] = modelDefaultMethods[defaultMethod];
}
modDB.model(dbKey, schemaObj, colName);
}
return modDB.models[dbKey];
}
async function getDynamicModel<T>(modelName: string, schema: any, dbinfo: DbInfo, params: any = {}): Promise<mongoose.Model<T>> {
let modDB = await getConnection(dbinfo);
let modSchema = new mongoose.Schema(schema, schemaDefaultOption);
if( params.indexOption ) {
modSchema.index(params.indexOption);
}
let colName = "cust_" + modelName.toLowerCase();
let model = await buildDynamicModel(modDB, modSchema, modelName, colName);
return model;
}
export default {
getConnection,
getDynamicModel
};
\ No newline at end of file
////////////////////////////////////////////////////////
//
// 重要 !!!!!!!!!!!!!!!!!!!!
//
// 核心模块代码, 请到ts_basis项目中修改提交
//
////////////////////////////////////////////////////////
import apiUtil from '../../util/api_util';
function injectSearch(req: any, atrr: string, value: any): void {
if (!value) throw new apiUtil.ParamError("No " + atrr + "!");
if (req.body.search == null) {
req.body.search = {};
}
req.body.search[atrr] = value;
}
function injectParam(req: any, atrr: string, value: any): void {
if (!value) throw new apiUtil.ParamError("No " + atrr + "!");
req.body[atrr] = value;
}
function verifyKey(key: string): void {
let identifyReg = /^[0-9A-Za-z_-]{1,90}$/;
if (!identifyReg.test(key)) {
throw new Error("标识格式不正确,正确格式为3-30位的数字、字母和下划线");
}
}
export default {
injectSearch,
injectParam,
verifyKey
}
\ No newline at end of file
////////////////////////////////////////////////////////
//
// 重要 !!!!!!!!!!!!!!!!!!!!
//
// 核心模块代码, 请到ts_basis项目中修改提交
//
////////////////////////////////////////////////////////
import { Response } from 'express'
import log4js from 'log4js';
const logger = log4js.getLogger('apiUtil');
class LoginError extends Error {
errorNo: number;
constructor(...params: any) {
super(...params);
this.errorNo = 400008;
this.message = "用户名密码错误!";
}
}
class ParamError extends Error {
errorNo: number;
constructor(...params: any) {
super(...params);
this.errorNo = 400020;
this.message = "参数缺失!";
}
}
class ShareError extends Error {
errorNo: number;
constructor(...params: any) {
super(...params);
this.errorNo = 400021;
}
}
let NotLoginResponse = {
data: {},
header: {},
msg: "没有登录!",
res: 400003
};
let NotAdminResponse = {
data: {},
header: {},
msg: "不是公司管理员!",
res: 400006
};
let NoDbResponse = {
data: {},
header: {},
msg: "没有数据库信息!",
res: 400005
};
let NoAuthResponse = {
data: {},
header: {},
msg: "没有权限",
res: 400007
};
let LimitResponse = {
data: {},
header: {},
msg: "没有额度",
res: 400011
};
let NoFileAccess = {
data: {},
header: {},
msg: "没有文件上操作权限!",
res: 400090
};
let NoDef = {
data: {},
header: {},
msg: "接口未定义!",
res: 400404
};
let apiResponse = async function (res: Response, getResult: any) {
let r = {};
try {
let result = await getResult().catch((reason: any) => {
logger.error(reason);
throw reason;
});
if( result && result.hadRedirect ) {
return
}
r = {
data: result,
header: {},
msg: "success",
res: 0
};
return res.json(r);
} catch (e: any) {
r = {
data: e.errorData || {},
header: {},
msg: e.message,
res: e.errorNo || 400001
};
// res.status(400);
res.json(r);
}
};
class RemoteError extends Error {
errorNo: number;
constructor(...params: any) {
super(...params);
this.errorNo = 400092;
}
}
class ConRefusedError extends Error {
errorNo: number;
constructor(...params: any) {
super(...params);
this.errorNo = 400091;
this.message = "远程服务不可访问!"
}
}
export default {
LoginError,
NotLoginResponse,
NotAdminResponse,
apiResponse,
NoAuthResponse,
NoFileAccess,
NoDef,
NoDbResponse,
ConRefusedError,
RemoteError,
LimitResponse,
ParamError,
ShareError
};
////////////////////////////////////////////////////////
//
// 重要 !!!!!!!!!!!!!!!!!!!!
//
// 核心模块代码, 请到ts_basis项目中修改提交
//
////////////////////////////////////////////////////////
import express, { Application, Request, Response, NextFunction } from 'express'
import createError from "http-errors";
import passport from 'passport'
import cookieParser from 'cookie-parser';
import mw from './api/lib/mw'
import router from "./routes/api"
import gvar from './gvar';
const app: Application = express();
passport.serializeUser(function (user: any, done) {
done(null, user);
});
passport.deserializeUser(function (user: any, done) {
done(null, user);
});
app.all("*", function (req, res, next) {
// 设置允许跨域的域名,*代表允许任意域名跨域
res.header("Access-Control-Allow-Origin", "*");
// 允许的header类型
res.header("Access-Control-Allow-Headers", "*");
// 跨域允许的请求方式
res.header("Access-Control-Allow-Methods", "DELETE,PUT,POST,GET,OPTIONS");
if (req.method.toLowerCase() == "options") { res.sendStatus(200); } // 让options尝试请求快速结束
else { next(); }
});
app.enable("trust proxy");
app.enabled('trust proxy');
app.use(express.json({ limit: "1024mb" }));
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(passport.initialize());
gvar.updateApp(app)
if (mw.getIpInfoMiddleware) app.use(mw.getIpInfoMiddleware)
app.use(mw.userInfo);
app.use("/api", router);
app.use(function (req, res, next) {
next(createError(404));
});
app.use(function (err: Error, req: Request, res: Response, next: NextFunction) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get("env") === "development" ? err : {};
// render the error page
res.status(500);
res.json({ error: err })
});
export default app
\ No newline at end of file
#!/usr/bin/env node
////////////////////////////////////////////////////////
//
// 重要 !!!!!!!!!!!!!!!!!!!!
//
// 核心模块代码, 请到ts_basis项目中修改提交
//
////////////////////////////////////////////////////////
/**
* Module dependencies.
*/
import fs from 'fs';
import app from './app';
import gvar from './gvar';
import http from 'http';
import https from 'https';
import config from 'config';
import log4js from 'log4js';
const logger = log4js.getLogger('bin');
/**
* Get port from environment and store in Express.
*/
let serverInfo: any = config.get("server");
let port = serverInfo.PORT || 3000;
app.set('port', port);
/**
* Create HTTP server.
*/
let server = http.createServer(app);
gvar.setSocketIo(server);
/**
* Listen on provided port, on all network interfaces.
*/
server.listen(port);
server.on('error', onError);
server.on('listening', onListening);
if (serverInfo.SSLPORT != null) {
let sslport = serverInfo.SSLPORT;
let privateKey = fs.readFileSync(serverInfo.privateKey, serverInfo.encode);
let certificate = fs.readFileSync(serverInfo.certificate, serverInfo.encode);
let ca = fs.readFileSync(serverInfo.ca, serverInfo.encode);
let credentials = {
key: privateKey,
cert: certificate,
ca: ca
};
let httpsServer = https.createServer(credentials, app);
httpsServer.listen(sslport);
httpsServer.on('error', onError);
httpsServer.on('listening', onListening);
}
/**
* Event listener for HTTP server "error" event.
*/
function onError(error: any) {
if (error.syscall !== 'listen') {
throw error;
}
let bind = typeof port === 'string' ?
'Pipe ' + port :
'Port ' + port;
// handle specific listen errors with friendly messages
switch (error.code) {
case 'EACCES':
logger.error(bind + ' requires elevated privileges');
process.exit(1);
break;
case 'EADDRINUSE':
logger.error(bind + ' is already in use');
process.exit(1);
break;
default:
throw error;
}
}
/**
* Event listener for HTTP server "listening" event.
*/
function onListening() {
let addr: any = server.address();
let bind = typeof addr === 'string' ?
'pipe ' + addr :
'port ' + addr.port;
logger.info('Listening on ' + bind);
}
\ No newline at end of file
import config from 'config'
import log4js from 'log4js'
import { Application } from 'express'
import multer from 'multer'
const appDir = __dirname;
function updateApp(app: Application) {
log4js.configure(config.get('log4jsConfig'));
const logger = log4js.getLogger('http');
app.use(log4js.connectLogger(logger, {
level: 'auto',
format: (req, res, format) => format(`:method ${req.headers.refkey} -> :url :status :res[content-length] - :response-time ms`)
}));
app.use(multer().single("file_stream"));
}
function setSocketIo(server: any) {
}
export default {
setSocketIo,
appDir,
updateApp
}
import express from 'express';
let router = express.Router();
import cloudRouter from './cloud';
router.use("/cloud", cloudRouter);
export default router;
import express from 'express';
let router = express.Router();
import apiUtil from '../api/util/api_util';
import cms from '../api/lib/cms';
import mw from '../api/lib/mw';
router.post("/:mod/:act", [mw.jwtLoginRequired], async function (req: any, res: any) {
let act: string = req.params["act"];
let mod: string = req.params["mod"];
let con: any = cms.getController(mod);
apiUtil.apiResponse(res, async () => {
return await con[act](req, res);
});
});
// 需要compKey
router.post("/:compKey/:mod/:act", [mw.jwtLoginRequired], async function (req: any, res: any) {
let mod = req.params["mod"];
let act = req.params["act"];
let params = {
compKey: req.params["compKey"]
}
let actMap:{[key: string]: string} = {
"index": "compIndex",
"all": "compAll",
"create": "compCreate",
"update": "compUpdate",
"show": "compShow",
"delete": "compDelete",
"searchDelete": "compSearchDelete",
"comp_index": "compIndex",
"comp_all": "compAll",
"comp_create": "compCreate",
"comp_update": "compUpdate",
"comp_show": "compShow",
"comp_delete": "compDelete",
"comp_searchDelete": "compSearchDelete"
};
if (actMap[act] != null) {
act = actMap[act];
}
let con: any = cms.getController(mod, params);
apiUtil.apiResponse(res, async () => {
return await con[act](req, res);
});
});
// 需要compKey, appKey
router.post("/:compKey/:appKey/:mod/:act", [mw.jwtLoginRequired], async function (req: any, res: any) {
let mod = req.params["mod"];
let act = req.params["act"];
let params = {
compKey: req.params["compKey"],
appKey: req.params["appKey"]
}
let actMap:{[key: string]: string} = {
"index": "appIndex",
"all": "appAll",
"create": "appCreate",
"update": "appUpdate",
"show": "appShow",
"delete": "appDelete",
"searchDelete": "appSearchDelete",
"app_index": "appIndex",
"app_all": "appAll",
"app_create": "appCreate",
"app_update": "appUpdate",
"app_show": "appShow",
"app_delete": "appDelete",
"app_searchDelete": "appSearchDelete"
};
if (actMap[act] != null) {
act = actMap[act];
}
let con: any = cms.getController(mod, params);
apiUtil.apiResponse(res, async () => {
return await con[act](req, res);
});
});
export default router;
import { BaseExampleManagerInst } from "../../api/managers/BaseExampleManager";
import assert from "assert";
describe("测试BaseManager", function () {
it("测试 初始数据加载", async function () {
let x: any = await BaseExampleManagerInst.mGet({_id: "5d5224e4f6268da7337cbd01"});
assert(x.name == "明树数据");
});
it('测试 mCreate', async function () {
let resData = await BaseExampleManagerInst.mCreate({
name: '测试001',
description: '创建一条测试数据001',
amount: 1000,
itemType: "Mod",
noField: "a"
})
assert( (resData as any).noField == null )
assert(resData.amount === 1000)
});
it('测试 mCount', async function () {
let resData = await BaseExampleManagerInst.mCreate({
name: '测试011',
description: '创建一条测试数据011',
amount: 1000,
itemType: "Mod",
})
let resData1 = await BaseExampleManagerInst.mCount({
_id: resData._id
})
assert(resData1 === 1)
});
it('测试 mGet', async function () {
let resData = await BaseExampleManagerInst.mCreate({
name: '测试012',
description: '创建一条测试数据012',
amount: 1000,
itemType: "Mod",
})
let resData1: any = await BaseExampleManagerInst.mGet({
_id: resData._id
})
assert(resData1.name === '测试012')
});
it('测试 mUpdate', async function () {
let updateDefaultObj = await BaseExampleManagerInst.mUpdate({
_id: '5d5224e4f6268da7337cbd01',
name: 'Bridata',
description: 'Bridata of BeiJing',
amount: 5000000
})
assert(updateDefaultObj.name === 'Bridata')
});
it('测试 mDelete', async function () {
let testDelObj = await BaseExampleManagerInst.mCreate({
name: '测试数据002',
description: '用于测试 mDdelete',
amount: 3000
})
let delRes: any = await BaseExampleManagerInst.mDelete({
_id: testDelObj._id
})
assert(delRes.name === '测试数据002')
});
it('测试 mSave', async function () {
let saveDefaultObj = await BaseExampleManagerInst.mSave({
_id: '5d5224e4f6268da7337cbd01',
name: 'Bridata',
description: 'Big Bridata of China',
amount: 500000000
})
assert(saveDefaultObj.amount === 500000000)
});
it('测试 mInsertMany', async function () {
let insertObjs = await BaseExampleManagerInst.mInsertMany([
{
name: '插入 wang01',
description: '忽略这条数据 wang01',
amount: 100
},
{
name: '插入 wang02',
description: '忽略这条数据 wang02',
amount: 100
},
{
name: '插入 wang03',
description: '忽略这条数据 wang03',
amount: 100
},
])
assert(insertObjs.length === 3)
});
it('测试 mNativeFind', async function () {
let resData = await BaseExampleManagerInst.mCreate({
name: '测试mNativeFind',
description: '创建一条测试数据mNativeFind',
amount: 1000,
itemType: "Mod",
})
let getNativeObj = await BaseExampleManagerInst.mNativeFind({
_id: resData._id
})
assert(getNativeObj[0].amount === 1000)
});
it('测试 mFindOne', async function () {
let resData = await BaseExampleManagerInst.mCreate({
name: '测试mFindOne',
description: '创建一条测试数据mFindOne',
amount: 1000,
itemType: "Mod",
})
let defaultObj: any = await BaseExampleManagerInst.mFindOne({
_id: resData._id
})
assert(defaultObj.name === '测试mFindOne')
});
it('测试 mUpdateMany', async function () {
let updateObjs = await BaseExampleManagerInst.mUpdateMany(
{
name: {
$in: ['插入 wang01', '插入 wang02', '插入 wang03']
}
},
{
amount: 500
},
[
"_id"
]
)
assert(updateObjs.length === 3)
});
it('测试 mDeleteMany', async function () {
let resData = await BaseExampleManagerInst.mCreate({
name: '测试mDeleteMany',
description: '创建一条测试数据mDeleteMany',
amount: 1000,
itemType: "Mod",
})
let delObjs = await BaseExampleManagerInst.mDeleteMany(
{
_id: resData._id
},
[
'_id', 'name', 'amount'
]
)
assert(delObjs.length === 1)
});
it('测试 mSoftDelete', async function () {
let resData = await BaseExampleManagerInst.mCreate({
name: '测试mSoftDelete',
description: '创建一条测试数据mSoftDelete',
amount: 1000,
itemType: "Mod",
})
let softDelObj = await BaseExampleManagerInst.mSoftDelete({
_id: resData._id
})
assert(softDelObj.name === '测试mSoftDelete')
});
it('测试 mSoftDeleteMany', async function () {
let insertObjs = await BaseExampleManagerInst.mInsertMany([
{
name: '插入 mSoftDeleteMany01',
description: '忽略这条数据 mSoftDeleteMany01',
amount: 2022
},
{
name: '插入 mSoftDeleteMany02',
description: '忽略这条数据 mSoftDeleteMany02',
amount: 2022
},
{
name: '插入 mSoftDeleteMany03',
description: '忽略这条数据 mSoftDeleteMany03',
amount: 2022
},
])
let softDelObjs = await BaseExampleManagerInst.mSoftDeleteMany({
amount: 2022
}, ['name', 'amount'])
assert(softDelObjs.length === 3)
});
it('测试 mTypes', async function () {
let mTypeRes = await BaseExampleManagerInst.mTypes()
assert(mTypeRes.itemType)
});
it('测试 mAggregate', async function () {
let insertObjs = await BaseExampleManagerInst.mInsertMany([
{
name: '插入 mAggregate01',
description: '忽略这条数据 mAggregate01',
amount: 2023,
itemType: 'Mod'
},
{
name: '插入 mAggregate02',
description: '忽略这条数据 mAggregate02',
amount: 2023,
itemType: 'Mod'
},
{
name: '插入 mAggregate03',
description: '忽略这条数据 mAggregate03',
amount: 2023,
itemType: 'Mod'
},
])
let dataRes = await BaseExampleManagerInst.mAggregate(
[
{$match: {amount: 2023}},
{$group: {_id: "$itemType", count:{$sum: 1}}},
{$match: {count: { $gt: 1 }}}
]
)
assert(dataRes.length === 1)
});
it('测试 mIndex', async function () {
let insertObjs = await BaseExampleManagerInst.mInsertMany([
{
name: '插入 mIndex01',
description: '忽略这条数据 mIndex01',
amount: 2024444,
itemType: 'Mod'
},
{
name: '插入 mIndex02',
description: '忽略这条数据 mIndex02',
amount: 2024444,
itemType: 'Mod'
},
{
name: '插入 mIndex03',
description: '忽略这条数据 mIndex03',
amount: 2024444,
itemType: 'Mod'
},
])
let allDetails = await BaseExampleManagerInst.mIndex({
search: {
amount: 2024444
}
})
assert(allDetails.total === 3)
});
});
\ No newline at end of file
import axios from "axios";
import assert from "assert";
import config from "config";
import jwtlib from "../../api/lib/jwtlib";
let serverInfo: any = config.get("server");
let apiUrl = `http://localhost:${serverInfo.PORT}`;
async function getBackendToken(): Promise<string> {
let token = "jwt:" + jwtlib.encrypt({}, "1200s");
return token
}
describe("测试BaseExample相关接口", function () {
it("测试接口 无authtoken访问", async function () {
let resData = await axios(apiUrl + "/api/cloud/BaseExample/index", {
method: "post",
data: {},
headers: {}
});
assert(resData.data.res == 400003);
});
it("测试接口 有authoken访问", async function () {
let resData = await axios(apiUrl + "/api/cloud/BaseExample/index", {
method: "post",
data: {},
headers: {
authtoken: await getBackendToken()
}
});
assert(resData.data.res == 0);
});
it('测试接口 create - delete ', async function(){
let resData = await axios(apiUrl + '/api/cloud/BaseExample/create', {
method: 'post',
data: {
name: '测试接口001',
description: '这是测试create接口创建的数据001',
amount: 100
},
headers: {
authtoken: await getBackendToken()
}
})
assert(resData.data.res == 0);
let resData1 = await axios(apiUrl + '/api/cloud/BaseExample/delete', {
method: 'post',
data: {
_id: resData.data.data._id
},
headers: {
authtoken: await getBackendToken()
}
})
assert(resData1.data.res == 0);
});
it('测试接口 InsertMany', async function() {
let resDatas = await axios(apiUrl + '/api/cloud/BaseExample/insertMany', {
method: 'post',
data: {
list: [
{
name: '测试接口00001',
description: '这是测试create接口创建的数据00001',
amount: 200
},
{
name: '测试接口00002',
description: '这是测试create接口创建的数据00002',
amount: 200
},
{
name: '测试接口00003',
description: '这是测试create接口创建的数据00003',
amount: 200
}
]
},
headers: {
authtoken: await getBackendToken()
}
})
assert(resDatas.data.res == 0);
});
it('测试接口 update', async function(){
let resData = await axios(apiUrl + '/api/cloud/BaseExample/create', {
method: 'post',
data: {
name: '测试修改A0001',
description: '这是测试update接口创建的数据A0001',
amount: 123
},
headers: {
authtoken: await getBackendToken()
}
})
assert(resData.data.res == 0);
let resData1 = await axios(apiUrl + '/api/cloud/BaseExample/update', {
method: 'post',
data: {
_id: resData.data.data._id,
amount: 12345
},
headers: {
authtoken: await getBackendToken()
}
})
assert(resData1.data.res == 0);
});
it('测试接口 show', async function(){
let resData = await axios(apiUrl + '/api/cloud/BaseExample/show', {
method: 'post',
data: {
_id: '5d5224e4f6268da7337cbd01',
},
headers: {
authtoken: await getBackendToken()
}
})
assert(resData.data.res == 0);
});
it('测试接口 searchUpdate', async function(){
let resData = await axios(apiUrl + '/api/cloud/BaseExample/create', {
method: 'post',
data: {
name: '测试searchUpdate A0001',
description: '这是测试searchUpdate接口创建的数据A0001',
amount: 234
},
headers: {
authtoken: await getBackendToken()
}
})
assert(resData.data.res == 0);
let resData1 = await axios(apiUrl + '/api/cloud/BaseExample/searchUpdate', {
method: 'post',
data: {
search: {
_id: resData.data.data._id,
},
updateParams: {
amount: 23400,
},
fields: ['name', 'amount']
},
headers: {
authtoken: await getBackendToken()
}
})
assert(resData1.data.res === 0)
});
it('测试接口 searchDelete', async function(){
let resData = await axios(apiUrl + '/api/cloud/BaseExample/create', {
method: 'post',
data: {
name: '测试searchDelete A0001',
description: '这是测试searchDelete接口创建的数据A0001',
amount: 345
},
headers: {
authtoken: await getBackendToken()
}
})
assert(resData.data.res == 0);
let resData1 = await axios(apiUrl + '/api/cloud/BaseExample/searchDelete', {
method: 'post',
data: {
search: {
_id: resData.data.data._id,
}
},
headers: {
authtoken: await getBackendToken()
}
})
assert(resData1.data.res == 0);
});
it('测试接口 softDelete', async function(){
let resData = await axios(apiUrl + '/api/cloud/BaseExample/create', {
method: 'post',
data: {
name: '测试softDelete A0001',
description: '这是测试softDelete接口创建的数据A0001',
amount: 456
},
headers: {
authtoken: await getBackendToken()
}
})
assert(resData.data.res == 0);
let resData1 = await axios(apiUrl + '/api/cloud/BaseExample/softDelete', {
method: 'post',
data: {
_id: resData.data.data._id,
},
headers: {
authtoken: await getBackendToken()
}
})
assert(resData1.data.res == 0);
});
it('测试接口 softSearchDelete', async function(){
let resData = await axios(apiUrl + '/api/cloud/BaseExample/create', {
method: 'post',
data: {
name: '测试softSearchDelete A0001',
description: '这是测试softSearchDelete接口创建的数据A0001',
amount: 567
},
headers: {
authtoken: await getBackendToken()
}
})
assert(resData.data.res == 0);
let resData1 = await axios(apiUrl + '/api/cloud/BaseExample/softSearchDelete', {
method: 'post',
data: {
search: {
_id: resData.data.data._id,
},
fields: ['name', 'amount']
},
headers: {
authtoken: await getBackendToken()
}
})
assert(resData1.data.res == 0);
});
it("测试接口 count", async function () {
let resData = await axios(apiUrl + "/api/cloud/BaseExample/count", {
method: "post",
data: {},
headers: {
authtoken: await getBackendToken()
}
});
assert(resData.data.res == 0);
});
it("测试接口 findOne", async function () {
let resData = await axios(apiUrl + "/api/cloud/BaseExample/findOne", {
method: "post",
data: {
search: {
_id: '5d5224e4f6268da7337cbd01',
}
},
headers: {
authtoken: await getBackendToken()
}
});
assert(resData.data.res == 0);
});
it("测试接口 types", async function () {
let resData = await axios(apiUrl + "/api/cloud/BaseExample/types", {
method: "post",
data: {},
headers: {
authtoken: await getBackendToken()
}
});
assert(resData.data.res == 0);
});
it("测试接口 aggregate", async function () {
let resData = await axios(apiUrl + "/api/cloud/BaseExample/aggregate", {
method: "post",
data: {
list: [
{$group: {_id: "$itemType", count:{$sum: 1}}},
{ $match: {count: { $gt: 1 }}}
]
},
headers: {
authtoken: await getBackendToken()
}
});
assert(resData.data.res == 0);
});
it("测试接口 all", async function () {
let resData = await axios(apiUrl + "/api/cloud/BaseExample/all", {
method: "post",
data: {},
headers: {
authtoken: await getBackendToken()
}
});
assert(resData.data.res == 0);
});
it("测试接口 index", async function () {
let resData = await axios(apiUrl + "/api/cloud/BaseExample/index", {
method: "post",
data: {},
headers: {
authtoken: await getBackendToken()
}
});
assert(resData.data.res == 0);
});
});
\ No newline at end of file
import CompItemRemoteManager from "../../api/managers/base/remote/CompItemRemoteManager";
import assert from "assert";
import { ResourceDef } from "../../api/def/base/resourceTypes";
describe("测试CompItemRemoteManager", function () {
it("测试 mGetByCompKey", async function () {
let resourceRemoteManager = new CompItemRemoteManager<ResourceDef>({ user: {}, remoteKey: "resource", modelName: "Resource", compKey: "test" });
let resource = await resourceRemoteManager.mGetByCompKey("test", "optype");
assert(resource != null);
assert(resource._key == "optype");
});
});
\ No newline at end of file
import { describe } from "mocha";
import assert from "assert";
describe("测试模版集", function () {
it("测试模版", async function () {
assert(true);
});
});
\ No newline at end of file
////////////////////////////////////////////////////////
//
// 重要 !!!!!!!!!!!!!!!!!!!!
//
// 核心模块代码, 请到ts_basis项目中修改提交
//
////////////////////////////////////////////////////////
import { before } from "mocha";
import cms from "../api/lib/cms";
import fs from "fs";
import { join } from "path";
import gvar from "../gvar";
import config from "config";
import app from '../app';
import http from 'http';
import { remoteRedis, redis } from "../api/lib/redis";
import cloudEnv from "../api/lib/cloudEnv";
import tools from "../api/lib/tools";
let serverInfo: any = config.get("server");
let port = serverInfo.PORT || 3000;
app.set('port', port);
let server = http.createServer(app);
async function inintRemoteCongigRedis() {
let remoteKeys = [
"file",
"resource",
"proxy",
"comp",
"core",
"ticker",
"share",
"log",
"job",
"sender",
"mod",
"admin",
"calculator",
"dstore",
"custom",
"cgpt",
]
let remoteConfig: any = {}
for (let remoteKey of remoteKeys) {
remoteConfig[remoteKey + "RemoteConfig"] = {
host: "",
frontHost: ""
}
// 统一使用remoteRedis
remoteConfig[remoteKey + "RedisConfig"] = cloudEnv.getRemoteRedisConfig();
}
await redis.flushdb();
await remoteRedis.flushdb();
await remoteRedis.set("proxy:remoteHostConfig", JSON.stringify(remoteConfig));
}
before(async function () {
server.listen(port);
await inintRemoteCongigRedis();
let fixturePath = gvar.appDir + "/../data/fixtures";
if (fs.existsSync(fixturePath)) {
let files = fs.readdirSync(fixturePath);
for (let file of files) {
let fileSplit: string[] = file.split(".");
if (fileSplit.length > 1) {
let extend = fileSplit[fileSplit.length - 1];
if (extend == "json") {
let dataJson = await import(join(fixturePath, file));
if (dataJson.remoteKey == null) {
let manager = cms.getManager(dataJson.model);
await manager.mDeleteMany({}, [], true);
for (let data of dataJson.list) {
await manager.mCreate(data);
}
}
else {
let cacheKey = "";
for (let data of dataJson.list) {
if (dataJson.modelType == "compItem") {
cacheKey = tools.getServiceCachePrefix(dataJson.remoteKey) + "_" + tools.getCompItemCacheKey(dataJson.model, data.compKey, data._key);
}
else if (dataJson.modelType == "appItem") {
cacheKey = tools.getServiceCachePrefix(dataJson.remoteKey) + "_" + tools.getAppItemCacheKey(dataJson.model, data.compKey, data.appKey, data._key);
}
if (cacheKey != "") {
remoteRedis.set(cacheKey, JSON.stringify(data), "EX", 1200);
}
}
}
}
}
}
}
});
after(async function () {
server.close();
setTimeout(function () {
process.exit(0);
}, 1000);
});
\ No newline at end of file
{
"compilerOptions": {
/* Visit https://aka.ms/tsconfig to read more about this file */
/* Projects */
// "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
// "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
// "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */
// "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */
// "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
/* Language and Environment */
"target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
// "jsx": "preserve", /* Specify what JSX code is generated. */
// "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
// "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
// "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
// "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
// "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
/* Modules */
"module": "commonjs", /* Specify what module code is generated. */
"rootDir": "./src", /* Specify the root folder within your source files. */
"moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
"baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
// "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
// "types": [], /* Specify type package names to be included without being referenced in a source file. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
// "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
// "resolveJsonModule": true, /* Enable importing .json files. */
// "noResolve": true, /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */
/* JavaScript Support */
"allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */
// "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
/* Emit */
// "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
// "declarationMap": true, /* Create sourcemaps for d.ts files. */
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
"sourceMap": true, /* Create source map files for emitted JavaScript files. */
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
"outDir": "./dist", /* Specify an output folder for all emitted files. */
// "removeComments": true, /* Disable emitting comments. */
// "noEmit": true, /* Disable emitting files from a compilation. */
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
// "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */
// "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
// "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
// "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
// "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
// "newLine": "crlf", /* Set the newline character for emitting files. */
// "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */
// "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */
// "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
// "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */
// "declarationDir": "./", /* Specify the output directory for generated declaration files. */
// "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
/* Interop Constraints */
// "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
"esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
"forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
/* Type Checking */
"strict": true, /* Enable all strict type-checking options. */
// "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
// "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
// "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
// "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
// "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
// "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */
// "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */
// "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
// "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */
// "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */
// "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
// "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
// "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
// "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */
// "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
// "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */
// "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
// "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
/* Completeness */
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
"skipLibCheck": true /* Skip type checking all .d.ts files. */
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment