fix: 初始化
This commit is contained in:
146
packages/lowcode/package.json
Normal file
146
packages/lowcode/package.json
Normal file
@ -0,0 +1,146 @@
|
||||
{
|
||||
"name": "@crami/frame-lowcode",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"serve": "vue-cli-service serve",
|
||||
"build": "vite build",
|
||||
"vite:dev": "vite",
|
||||
"vite:build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"lint": "vue-cli-service lint",
|
||||
"lint:check": "vue-cli-service lint --no-fix",
|
||||
"prettier": "prettier -c --write '**/*'",
|
||||
"pretty-quick": "pretty-quick",
|
||||
"analyz": "vue-cli-service build --mode analyz",
|
||||
"toJs": "node ./scripts/tsToJs.js",
|
||||
"tsc": "tsc --noEmit && vue-tsc --noEmit",
|
||||
"vue-tsc": "vue-tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"icpx-platform": "workspace:*",
|
||||
"@alilc/lowcode-types": "^1.0.15",
|
||||
"@ant-design/icons-vue": "^6.1.0",
|
||||
"@antv/x6": "^1.33.1",
|
||||
"@antv/x6-vue-shape": "^1.4.2",
|
||||
"@crami/http": "^2.0.10",
|
||||
"@crami/lowcode-hooks": "^1.5.3-r2",
|
||||
"@crami/lowcode-materials": "^0.0.35",
|
||||
"@crami/lowcode-utils": "^1.5.2",
|
||||
"@crami/lowcode-vue-renderer": "1.5.3-r7",
|
||||
"@crami/ui": "^2.0.249",
|
||||
"@crami/ui-types": "^2.0.105",
|
||||
"@studio/formula": "^0.0.10",
|
||||
"@types/lodash-es": "^4.17.6",
|
||||
"ant-design-vue": "^3.1.1",
|
||||
"axios": "^0.27.2",
|
||||
"core-js": "^3.21.1",
|
||||
"dayjs": "^1.11.5",
|
||||
"echarts": "^4.9.0",
|
||||
"lodash-es": "^4.17.21",
|
||||
"moment":"^2.29.4",
|
||||
"numeral": "^2.0.6",
|
||||
"vue": "~3.2.37",
|
||||
"vue-i18n": "~9.2.0-0",
|
||||
"vue-router": "^4.0.14"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/plugin-transform-spread": "^7.16.7",
|
||||
"@babel/plugin-transform-typescript": "^7.16.8",
|
||||
"@rollup/plugin-alias": "^3.1.9",
|
||||
"@surely-vue/table": "2.4.7",
|
||||
"@types/echarts": "^4.9.13",
|
||||
"@types/lodash": "^4.14.181",
|
||||
"@types/node": "^17.0.23",
|
||||
"@types/nprogress": "^0.2.0",
|
||||
"@types/numeral": "2.0.2",
|
||||
"@types/store": "^2.0.2",
|
||||
"@typescript-eslint/eslint-plugin": "^5.18.0",
|
||||
"@typescript-eslint/parser": "^5.18.0",
|
||||
"@vitejs/plugin-legacy": "^1.8.0",
|
||||
"@vitejs/plugin-vue": "^2.3.1",
|
||||
"@vitejs/plugin-vue-jsx": "^1.3.9",
|
||||
"@vue/cli-plugin-babel": "~5.0.4",
|
||||
"@vue/cli-plugin-eslint": "~5.0.4",
|
||||
"@vue/cli-plugin-router": "~5.0.4",
|
||||
"@vue/cli-plugin-typescript": "~5.0.4",
|
||||
"@vue/cli-plugin-vuex": "~5.0.4",
|
||||
"@vue/cli-service": "~5.0.4",
|
||||
"@vue/compiler-sfc": "~3.2.37",
|
||||
"@vue/eslint-config-prettier": "^7.0.0",
|
||||
"@vue/eslint-config-typescript": "^10.0.0",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"babel-plugin-import": "^1.13.3",
|
||||
"cheerio": "^1.0.0-rc.10",
|
||||
"cross-env": "^7.0.3",
|
||||
"echarts-wordcloud": "^1.1.3",
|
||||
"eslint": "^8.12.0",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"eslint-plugin-vue": "^8.6.0",
|
||||
"express": "^4.17.3",
|
||||
"husky": "^7.0.4",
|
||||
"js-base64": "^3.7.2",
|
||||
"js-md5": "^0.7.3",
|
||||
"kill-port-process": "^3.0.1",
|
||||
"less": "^4.1.3",
|
||||
"less-loader": "^10.2.0",
|
||||
"less-vars-to-js": "^1.3.0",
|
||||
"lint-staged": "^12.3.7",
|
||||
"mockjs": "^1.1.0",
|
||||
"prettier": "^2.6.2",
|
||||
"prettier-plugin-style-order": "^0.2.2",
|
||||
"prettier-quick": "^0.0.5",
|
||||
"raw-loader": "^4.0.2",
|
||||
"stylelint": "^14.6.1",
|
||||
"stylelint-config-css-modules": "^4.1.0",
|
||||
"stylelint-config-prettier": "^9.0.3",
|
||||
"stylelint-config-rational-order": "^0.1.2",
|
||||
"stylelint-config-standard": "^25.0.0",
|
||||
"stylelint-declaration-block-no-ignored-properties": "^2.5.0",
|
||||
"stylelint-no-unsupported-browser-features": "^5.0.3",
|
||||
"stylelint-order": "^5.0.0",
|
||||
"stylelint-webpack-plugin": "^3.2.0",
|
||||
"typescript": "~4.6.3",
|
||||
"umi-mock-middleware": "^1.0.0",
|
||||
"vite": "^3.2.1",
|
||||
"vite-plugin-externals": "^0.5.1",
|
||||
"vite-plugin-imp": "^2.3.0",
|
||||
"vite-plugin-pages": "^0.12.2",
|
||||
"vite-plugin-progress": "^0.0.3",
|
||||
"vite-plugin-style-import": "^1.4.1",
|
||||
"vite-plugin-svg-icons": "^2.0.1",
|
||||
"vue-eslint-parser": "^7.11.0",
|
||||
"vue-tsc": "^0.30.6",
|
||||
"webpack-bundle-analyzer": "^4.5.0"
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"pre-commit": "lint-staged && pretty-quick --staged"
|
||||
}
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.{js,jsx,vue,ts,tsx}": [
|
||||
"vue-cli-service lint",
|
||||
"git add"
|
||||
]
|
||||
},
|
||||
"pnpm": {
|
||||
"peerDependencyRules": {
|
||||
"ignoreMissing": [
|
||||
"@babel/core",
|
||||
"camunda-bpmn-js-behaviors",
|
||||
"preact",
|
||||
"webpack",
|
||||
"@bpmn-io/properties-panel",
|
||||
"diagram-js",
|
||||
"rollup"
|
||||
]
|
||||
}
|
||||
},
|
||||
"resolutions": {
|
||||
"esbuild": "0.14.34",
|
||||
"@crami/router": "1.0.7",
|
||||
"@types/node": "17.0.36"
|
||||
}
|
||||
}
|
165
packages/lowcode/src/api/commonApi/model.ts
Normal file
165
packages/lowcode/src/api/commonApi/model.ts
Normal file
@ -0,0 +1,165 @@
|
||||
import { config } from '@crami/lowcode-vue-renderer';
|
||||
import { exports } from '../../bootstrap';
|
||||
import { Http } from '@crami/http';
|
||||
import { HModal } from '@crami/ui';
|
||||
|
||||
interface ModelCommonParam {
|
||||
modelName: string;
|
||||
// dsName: string;
|
||||
// projectCode: string;
|
||||
// version: string;
|
||||
}
|
||||
interface ModelSaveParam {
|
||||
data: { [prop in string]: any }[];
|
||||
}
|
||||
interface ModelUpdateParam {
|
||||
id: string;
|
||||
data: { [prop in string]: any }[];
|
||||
}
|
||||
interface ModelDetailParam {
|
||||
id: string;
|
||||
}
|
||||
interface ModelDeleteParam {
|
||||
id: string;
|
||||
}
|
||||
interface ModelDeleteAllParam {
|
||||
ids: string[];
|
||||
deleteForeignAfterConfirmation?: boolean;
|
||||
}
|
||||
interface ModelBatchParam {
|
||||
ids: string[];
|
||||
}
|
||||
|
||||
function commonParam() {
|
||||
const { projectCode, dsName, version, appId, appCode } = exports.router.currentRoute.value.meta;
|
||||
const userId = config.getGlobalDataSourceParams()?.userId;
|
||||
return {
|
||||
dsName,
|
||||
projectCode,
|
||||
appId,
|
||||
appCode,
|
||||
userId,
|
||||
version,
|
||||
lang: 'zhs',
|
||||
};
|
||||
}
|
||||
|
||||
/** 单表 */
|
||||
|
||||
// 保存
|
||||
export function saveByModel(param: ModelSaveParam & ModelCommonParam): Promise<any> {
|
||||
const _common = commonParam();
|
||||
return Http.post({ url: `/loki-server/domain/save`, params: Object.assign(_common, param) });
|
||||
}
|
||||
|
||||
// 更新
|
||||
export function updateByModel(param: ModelUpdateParam & ModelCommonParam): Promise<any> {
|
||||
const _common = commonParam();
|
||||
return Http.post({ url: `/loki-server/domain/update`, params: Object.assign(_common, param) });
|
||||
}
|
||||
|
||||
// 删除
|
||||
export function deleteByModel(param: ModelDeleteParam & ModelCommonParam): Promise<any> {
|
||||
const _common = commonParam();
|
||||
return Http.request({
|
||||
url: `/loki-server/domain/id`,
|
||||
method: 'DELETE',
|
||||
data: Object.assign(_common, param),
|
||||
});
|
||||
}
|
||||
|
||||
// 批量删除
|
||||
export async function deleteAllByModel(
|
||||
param: ModelDeleteAllParam & ModelCommonParam,
|
||||
): Promise<any> {
|
||||
param.deleteForeignAfterConfirmation = false;
|
||||
|
||||
const data = await getForeignKeyByModel(param.modelName);
|
||||
const hasTip = data?.some(foreignKey => {
|
||||
return foreignKey?.foreignKeyList.some(item => {
|
||||
// 当
|
||||
return item.deletingSourceType === 'deleteAfterConfirmation';
|
||||
});
|
||||
});
|
||||
if (hasTip) {
|
||||
param.deleteForeignAfterConfirmation = await new Promise(resolve => {
|
||||
HModal.confirm({
|
||||
title: '删除提示',
|
||||
content: '是否要删除从表数据?',
|
||||
okText: '删除',
|
||||
okType: 'danger',
|
||||
cancelText: '不删除',
|
||||
onOk() {
|
||||
resolve(true);
|
||||
},
|
||||
onCancel() {
|
||||
resolve(false);
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
const _common = commonParam();
|
||||
return Http.request({
|
||||
url: `/loki-server/domain/ids`,
|
||||
method: 'DELETE',
|
||||
data: Object.assign(_common, param),
|
||||
});
|
||||
}
|
||||
|
||||
// 单条详情
|
||||
export function infoByModel(param: ModelDetailParam & ModelCommonParam): Promise<any> {
|
||||
const _common = commonParam();
|
||||
return Http.request({
|
||||
url: `/loki-server/domain/info`,
|
||||
method: 'GET',
|
||||
params: Object.assign(_common, param),
|
||||
});
|
||||
}
|
||||
|
||||
// 批量详情
|
||||
export function batchInfoByModel(param: ModelBatchParam & ModelCommonParam): Promise<any> {
|
||||
const _common = commonParam();
|
||||
return Http.request({
|
||||
url: `/loki-server/domain/batchInfo`,
|
||||
method: 'GET',
|
||||
params: Object.assign(_common, param),
|
||||
});
|
||||
}
|
||||
|
||||
/** 多表 主外键 */
|
||||
|
||||
// 主外键保存
|
||||
export function saveByModelFk(param): Promise<any> {
|
||||
const _common = commonParam();
|
||||
return Http.post({ url: '/loki-server/domain/saveFk', params: Object.assign(_common, param) });
|
||||
}
|
||||
|
||||
// 主外键更新
|
||||
export function updateByModelFk(param): Promise<any> {
|
||||
const _common = commonParam();
|
||||
return Http.post({ url: '/loki-server/domain/updateFk', params: Object.assign(_common, param) });
|
||||
}
|
||||
|
||||
const modelInfoCache = new Map();
|
||||
/**
|
||||
* 获取模型主外键信息
|
||||
* @param modelName
|
||||
* @returns
|
||||
*/
|
||||
export function getForeignKeyByModel(modelName): Promise<any> {
|
||||
const _cache = modelInfoCache.get(modelName);
|
||||
if (_cache) {
|
||||
return _cache;
|
||||
}
|
||||
const _common = commonParam();
|
||||
return Http.get({
|
||||
url: '/loki-server/model/foreignKey',
|
||||
params: {
|
||||
fileName: modelName,
|
||||
..._common,
|
||||
},
|
||||
}).then(data => {
|
||||
modelInfoCache.set(modelName, data.data);
|
||||
return data.data;
|
||||
});
|
||||
}
|
30
packages/lowcode/src/api/page/index.ts
Normal file
30
packages/lowcode/src/api/page/index.ts
Normal file
@ -0,0 +1,30 @@
|
||||
import { Http } from '@crami/http';
|
||||
import { config } from '@crami/lowcode-vue-renderer';
|
||||
export interface PageSchema {
|
||||
componentsMap: Array<any>;
|
||||
componentsTree: Array<any>;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取schema
|
||||
*
|
||||
* @param pageId
|
||||
* @return Promise<ResponseBody<PageSchema>>
|
||||
*/
|
||||
export function getSchemaById(params: {
|
||||
pageId: string;
|
||||
projectCode: string;
|
||||
appCode: string;
|
||||
}): Promise<any> {
|
||||
const { pageId, projectCode, appCode } = params;
|
||||
return Http.request({
|
||||
url: '/loki-server/page/schema',
|
||||
method: 'GET',
|
||||
params: {
|
||||
fileName: pageId.match(/.*\/(.+).pageSchema/)?.[1],
|
||||
projectCode,
|
||||
appCode,
|
||||
userId: config.getGlobalDataSourceParams()?.userId,
|
||||
},
|
||||
});
|
||||
}
|
41
packages/lowcode/src/bootstrap.ts
Normal file
41
packages/lowcode/src/bootstrap.ts
Normal file
@ -0,0 +1,41 @@
|
||||
import { GetQueryString } from './utils/qs';
|
||||
import { config } from '@crami/lowcode-vue-renderer';
|
||||
|
||||
import '@crami/lowcode-materials/dist/view.css';
|
||||
|
||||
// 注册umd包
|
||||
const _W = window as any;
|
||||
import * as Vue from 'vue';
|
||||
_W.Vue = Vue;
|
||||
import * as cramiBui from '@crami/bui';
|
||||
_W.CramiBui = cramiBui;
|
||||
import * as cramiUI from '@crami/ui';
|
||||
_W.cramiUI = cramiUI;
|
||||
import * as _ from 'lodash-es';
|
||||
_W._ = _;
|
||||
import * as moment from 'moment';
|
||||
_W.moment = moment;
|
||||
import * as antd from 'ant-design-vue';
|
||||
_W.antd = antd;
|
||||
|
||||
// 添加依赖注入
|
||||
export const exports: any = {};
|
||||
|
||||
function bootstrap(define) {
|
||||
exports.router = define.router;
|
||||
|
||||
define.router.afterEach(to => {
|
||||
const { dsName, projectCode, appId, appCode, version } = to.meta || {};
|
||||
const { userId } = to.query;
|
||||
config.setGlobalDataSourceParams({
|
||||
userId: GetQueryString('userId') || userId,
|
||||
dsName,
|
||||
projectCode,
|
||||
appCode,
|
||||
appId,
|
||||
version,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export default bootstrap;
|
25
packages/lowcode/src/components/modal-page/getSchema.ts
Normal file
25
packages/lowcode/src/components/modal-page/getSchema.ts
Normal file
@ -0,0 +1,25 @@
|
||||
import { buildComponents } from '@crami/lowcode-utils';
|
||||
import { getSchemaById } from '../../api/page';
|
||||
import pkgJson from '../../views/preview/packages.json';
|
||||
|
||||
export async function getSchema(params): Promise<{ schema: string; components: any }> {
|
||||
const packages = pkgJson;
|
||||
const projectSchema: any = await getSchemaById(params);
|
||||
if (!projectSchema?.data) {
|
||||
return Promise.reject('获取schema错误');
|
||||
}
|
||||
|
||||
const { componentsMap: componentsMapArray, componentsTree } = projectSchema.data as any;
|
||||
const componentsMap: any = {};
|
||||
|
||||
componentsMapArray.forEach((component: any) => {
|
||||
componentsMap[component.componentName] = component;
|
||||
});
|
||||
|
||||
const libraryMap = {};
|
||||
packages.forEach(({ package: _package, library }) => {
|
||||
libraryMap[_package] = library;
|
||||
});
|
||||
const components = buildComponents(libraryMap, componentsMap);
|
||||
return { schema: componentsTree[0], components };
|
||||
}
|
89
packages/lowcode/src/components/modal-page/index.tsx
Normal file
89
packages/lowcode/src/components/modal-page/index.tsx
Normal file
@ -0,0 +1,89 @@
|
||||
import { defineComponent } from 'vue';
|
||||
import { HModal } from '@crami/ui';
|
||||
import VueRenderer from '@crami/lowcode-vue-renderer';
|
||||
import { getSchema } from './getSchema';
|
||||
|
||||
const config = {
|
||||
create: {
|
||||
title: '新建对象',
|
||||
},
|
||||
update: {
|
||||
title: '编辑对象',
|
||||
},
|
||||
detail: {
|
||||
title: '浏览对象',
|
||||
},
|
||||
};
|
||||
|
||||
const ModalPage = defineComponent({
|
||||
data() {
|
||||
return {
|
||||
title: '',
|
||||
visible: false,
|
||||
schema: '',
|
||||
components: [],
|
||||
modelName: '',
|
||||
};
|
||||
},
|
||||
props: ['params', 'routeMeta', 'userToken'],
|
||||
mounted() {},
|
||||
expose: ['open', 'close'],
|
||||
methods: {
|
||||
async init() {
|
||||
const { projectCode, appCode } = this.routeMeta;
|
||||
const { pageId, __pageType, modelName, title } = this.params;
|
||||
if (pageId) {
|
||||
const { schema, components } = await getSchema({
|
||||
pageId,
|
||||
projectCode,
|
||||
appCode,
|
||||
});
|
||||
this.schema = schema;
|
||||
this.components = components;
|
||||
} else if (__pageType && modelName) {
|
||||
this.schema = Object.assign({}, config[__pageType]?.schema);
|
||||
}
|
||||
this.title = title || config[__pageType]?.title;
|
||||
},
|
||||
open() {
|
||||
this.init();
|
||||
this.visible = true;
|
||||
},
|
||||
close() {
|
||||
this.params?.closeHandler();
|
||||
this.onCancel();
|
||||
},
|
||||
onCancel() {
|
||||
this.visible = false;
|
||||
},
|
||||
},
|
||||
render(props) {
|
||||
const { params, routeMeta, userToken } = props;
|
||||
return (
|
||||
<HModal
|
||||
footer={null}
|
||||
width="70%"
|
||||
visible={this.visible}
|
||||
title={this.title}
|
||||
destroyOnClose={true}
|
||||
onCancel={this.onCancel}
|
||||
>
|
||||
{this.schema && this.visible && (
|
||||
<VueRenderer
|
||||
scope={{
|
||||
...params,
|
||||
routeMeta,
|
||||
userToken,
|
||||
closePage: this.close,
|
||||
cancelPage: this.onCancel,
|
||||
}}
|
||||
schema={this.schema}
|
||||
components={this.components}
|
||||
></VueRenderer>
|
||||
)}
|
||||
</HModal>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
export default ModalPage;
|
2
packages/lowcode/src/standard-resource/index.ts
Normal file
2
packages/lowcode/src/standard-resource/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
import * as LCStandardAction from './scripts';
|
||||
(window as any).LCStandardAction = LCStandardAction;
|
13
packages/lowcode/src/standard-resource/scripts/datasource.ts
Normal file
13
packages/lowcode/src/standard-resource/scripts/datasource.ts
Normal file
@ -0,0 +1,13 @@
|
||||
// 刷新数据源
|
||||
export function refreshDataSource(this: any, params: { dataSource: string; param: string }) {
|
||||
const { dataSource, param } = params;
|
||||
if (!dataSource) return false;
|
||||
|
||||
this.reloadDataSource(dataSource);
|
||||
}
|
||||
// 刷新所有数据源
|
||||
export function refreshDataSourceAll(this: any) {
|
||||
this.reloadDataSource();
|
||||
}
|
||||
|
||||
export function queryGridDataList(params) {}
|
8
packages/lowcode/src/standard-resource/scripts/flow.ts
Normal file
8
packages/lowcode/src/standard-resource/scripts/flow.ts
Normal file
@ -0,0 +1,8 @@
|
||||
export function callMicroFlow(params: any) {
|
||||
(window as any)[params.microflow](params);
|
||||
}
|
||||
export function callNanoFlow(params: any) {
|
||||
(window as any)[params.nanoflow](params);
|
||||
}
|
||||
export function callWorkFlow() {}
|
||||
export function completeUserTask() {}
|
7
packages/lowcode/src/standard-resource/scripts/index.ts
Normal file
7
packages/lowcode/src/standard-resource/scripts/index.ts
Normal file
@ -0,0 +1,7 @@
|
||||
export * from './modal';
|
||||
export * from './test';
|
||||
export * from './datasource';
|
||||
export * from './flow';
|
||||
export * from './method';
|
||||
export * from './object';
|
||||
export * from './page';
|
453
packages/lowcode/src/standard-resource/scripts/method.ts
Normal file
453
packages/lowcode/src/standard-resource/scripts/method.ts
Normal file
@ -0,0 +1,453 @@
|
||||
import { reactive } from 'vue';
|
||||
import { isJSFunction, isJSExpression } from '@alilc/lowcode-types';
|
||||
import { cloneDeep, isUndefined } from 'lodash-es';
|
||||
// 调用组件方法
|
||||
export function callComponentMethod(
|
||||
this: any,
|
||||
params: { component: string; method: string; addImportParam: boolean; params: any },
|
||||
importParam: any,
|
||||
) {
|
||||
const { component, method, addImportParam, params: _params } = params;
|
||||
// 处理单参数的情况
|
||||
if (isJSFunction(_params) || isJSExpression(_params)) {
|
||||
const value = this[_params.value.replace('__self.', '')];
|
||||
if (addImportParam) {
|
||||
this.$refs[component]?.[method](importParam, value);
|
||||
} else {
|
||||
this.$refs[component]?.[method](value);
|
||||
}
|
||||
return;
|
||||
}
|
||||
// 处理参数
|
||||
Object.keys(_params)?.map((key: string) => {
|
||||
if (isJSFunction(_params[key]) || isJSExpression(_params[key])) {
|
||||
const value = this[_params[key].value.replace('__self.', '')];
|
||||
_params[key] = value;
|
||||
}
|
||||
});
|
||||
if (addImportParam) {
|
||||
this.$refs[component]?.[method](importParam, _params);
|
||||
} else {
|
||||
this.$refs[component]?.[method](_params);
|
||||
}
|
||||
}
|
||||
|
||||
// 从表单中获取filter信息,支持HBForm和ProForm
|
||||
function getFilterByForm(formRef: string) {
|
||||
const instance = this.$refs[formRef];
|
||||
const formData = instance?.getData() || {};
|
||||
|
||||
const schemas: any[] = instance.$props.schemas || instance.$attrs.schemas;
|
||||
|
||||
return Object.keys(formData)
|
||||
.filter(key => !!formData[key])
|
||||
.map(key => {
|
||||
const formItem =
|
||||
schemas?.find(_schema => _schema.dataIndex === key || _schema.key === key) || {};
|
||||
return {
|
||||
field: key,
|
||||
value: formData[key],
|
||||
operation: formItem.operation || 'LIKE',
|
||||
andOrFlag: formItem.andOrFlag || 'AND',
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
// 表格搜索
|
||||
export function tableSearch(this: any, params: { component: string; currentNodeId: string }) {
|
||||
const filter = getFilterByForm.bind(this)(params.currentNodeId);
|
||||
const _extraFilter = this.$refs[params.component].$attrs.extraFilter;
|
||||
let extraFilter = [];
|
||||
if (_extraFilter && _extraFilter.length > 0) {
|
||||
extraFilter = _extraFilter.filter(config => {
|
||||
return !isUndefined(config.value);
|
||||
});
|
||||
}
|
||||
this.dataSourceMap?.[`${params.component}__data`]?.load({
|
||||
filter: [...filter, ...extraFilter],
|
||||
});
|
||||
}
|
||||
|
||||
// 主从表格搜索
|
||||
export function doubleTableSearch(
|
||||
this: any,
|
||||
params: { mainTable: string; fromTable: string; currentNodeId: string },
|
||||
) {
|
||||
const filter = getFilterByForm.bind(this)(params.currentNodeId);
|
||||
const extraFilter = this.$refs[params.mainTable].$attrs.extraFilter || [];
|
||||
|
||||
this.dataSourceMap?.[`${params.mainTable}__data`]?.load({
|
||||
filter: [...filter, ...extraFilter],
|
||||
});
|
||||
this[`${params.fromTable}__data`] = { data: [], total: 0 };
|
||||
// this.$refs[params.fromTable].setData([]);
|
||||
}
|
||||
|
||||
interface FromTableSearchParams {
|
||||
fromTable: string;
|
||||
parentField: {
|
||||
type: string;
|
||||
name: string;
|
||||
field: string;
|
||||
};
|
||||
childField: {
|
||||
type: string;
|
||||
name: string;
|
||||
field: string;
|
||||
};
|
||||
}
|
||||
|
||||
// 子表搜索
|
||||
export function fromTableSearch(this: any, params: FromTableSearchParams, event: any, record: any) {
|
||||
const { fromTable, parentField, childField } = params;
|
||||
this.dataSourceMap[`${fromTable}__data`].load({
|
||||
filter: [
|
||||
{
|
||||
field: childField.field,
|
||||
value: record[parentField.field],
|
||||
operation: '=',
|
||||
andOrFlag: 'AND',
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
// 搜索所有表格
|
||||
export function tableSearchAll(this: any) {
|
||||
Object.values(this.$refs).map((ref: any) => {
|
||||
console.log(ref.type);
|
||||
});
|
||||
}
|
||||
|
||||
export function arrParamsToObjParams(params: { name: string; value: any }[]) {
|
||||
const _params = [];
|
||||
params.map(param => {
|
||||
const { name, value } = param;
|
||||
_params.push({
|
||||
field: name,
|
||||
value: value,
|
||||
operation: '=',
|
||||
andOrFlag: 'AND',
|
||||
});
|
||||
});
|
||||
return _params;
|
||||
}
|
||||
|
||||
/**
|
||||
* 树表格根节点获取
|
||||
* @param this
|
||||
* @param params
|
||||
*/
|
||||
export async function treeTableSearch(
|
||||
this: any,
|
||||
params: { component: string; currentNodeId: string },
|
||||
) {
|
||||
const { component, currentNodeId } = params;
|
||||
const key = component || currentNodeId;
|
||||
const dataSourceId = `${key}__data`;
|
||||
const instance = this.$refs[key];
|
||||
const config = instance.$attrs.__treeTableConfig;
|
||||
|
||||
this[dataSourceId] = reactive({
|
||||
total: 0,
|
||||
data: [],
|
||||
});
|
||||
|
||||
// 获取根数据
|
||||
config.map(async child => {
|
||||
const modelName = child.config.modelName;
|
||||
const params = arrParamsToObjParams(child.config.params);
|
||||
|
||||
const { total, data } = await this.dataSourceMap[dataSourceId].load(
|
||||
{
|
||||
filter: [...params],
|
||||
modelName,
|
||||
},
|
||||
{ assignToScope: false },
|
||||
);
|
||||
|
||||
data?.map(item => {
|
||||
item.children = [];
|
||||
item.__node_key__ = child.key;
|
||||
});
|
||||
const { total: prevTotal, data: prevData } = this[dataSourceId];
|
||||
this[dataSourceId] = {
|
||||
total: total + prevTotal,
|
||||
data: [...prevData, ...data],
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
// 根据属性数据和key value获取数据
|
||||
export function getTreeNodeDataByKey(data: any[], key: string, value: any) {
|
||||
if (!data?.length) {
|
||||
return null;
|
||||
}
|
||||
let _cache = null;
|
||||
const fn = arr => {
|
||||
arr.some(item => {
|
||||
if (item[key] === value) {
|
||||
return (_cache = item);
|
||||
} else if (item?.children?.length) {
|
||||
fn(item.children);
|
||||
}
|
||||
});
|
||||
};
|
||||
fn(data);
|
||||
return _cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* 树表格展开
|
||||
* @param this
|
||||
* @param params
|
||||
* @param rest
|
||||
* @returns
|
||||
*/
|
||||
export async function treeTableExpand(
|
||||
this: any,
|
||||
params: { currentNodeId: string; finish?: boolean },
|
||||
...rest
|
||||
) {
|
||||
if (!rest[0]) {
|
||||
return false;
|
||||
}
|
||||
const currentRow = rest[1];
|
||||
const { currentNodeId, finish } = params;
|
||||
// 如果已经存在数据,并且不是强制刷新
|
||||
if (currentRow?.children?.length && !finish) {
|
||||
return false;
|
||||
}
|
||||
currentRow.children = [];
|
||||
|
||||
// 获取信息
|
||||
const key = currentNodeId;
|
||||
const instance = this.$refs[key];
|
||||
const config = instance.$attrs.__treeTableConfig;
|
||||
const rowKey = instance.$props.rowKey;
|
||||
const dataSourceId = `${key}__data`;
|
||||
|
||||
// 获取所在位置和节点
|
||||
const __parentNodeKey = currentRow.__node_key__;
|
||||
const __parentNode = getTreeNodeDataByKey(config, 'key', __parentNodeKey);
|
||||
|
||||
// 获取子数据
|
||||
__parentNode?.children?.map(async child => {
|
||||
const modelName = child.config.modelName;
|
||||
const params = arrParamsToObjParams(child.config.params);
|
||||
// 组装查询参数
|
||||
const filter = [
|
||||
{
|
||||
field: child.config.searchField,
|
||||
value: currentRow[__parentNode.config.valueField],
|
||||
operation: '=',
|
||||
andOrFlag: 'AND',
|
||||
},
|
||||
...params,
|
||||
];
|
||||
const { data } = await this.dataSourceMap[dataSourceId].load(
|
||||
{
|
||||
filter,
|
||||
modelName,
|
||||
},
|
||||
{ assignToScope: false },
|
||||
);
|
||||
// 配置数据信息
|
||||
data.map(item => {
|
||||
if (child?.children?.length) {
|
||||
item.children = [];
|
||||
}
|
||||
item.__node_key__ = child.key;
|
||||
});
|
||||
const currentData = getTreeNodeDataByKey(this[dataSourceId].data, rowKey, currentRow[rowKey]);
|
||||
currentData.children.push(...data);
|
||||
console.log(this[dataSourceId]);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 联动Tab组
|
||||
* @param this
|
||||
* @param params
|
||||
* @param eventParam
|
||||
*/
|
||||
export function selectLinkTabs(
|
||||
this: any,
|
||||
params: { component: string; currentNodeId: string },
|
||||
selectedKeys: Array<string>,
|
||||
node: any,
|
||||
) {
|
||||
const __treeDatasourceConfig = this.$refs[params.currentNodeId].__treeDatasourceConfig;
|
||||
const getNodeByKey = (nodeKey: string) => {
|
||||
const getNodeDeep = (children: any[]): any => {
|
||||
let tempNode: Node | null = null;
|
||||
children.forEach((_node: any) => {
|
||||
if (_node.key === nodeKey) {
|
||||
tempNode = _node;
|
||||
} else {
|
||||
if (_node.children && _node.children.length > 0) {
|
||||
tempNode = getNodeDeep(_node.children);
|
||||
}
|
||||
}
|
||||
});
|
||||
return tempNode;
|
||||
};
|
||||
return getNodeDeep(__treeDatasourceConfig);
|
||||
};
|
||||
// 基于视图的数据源,value5取的就是节点上的key,自定义数据源则要自己塞上NodeKey,
|
||||
// 因为访问的是通用列表查询,后台不存在节点的概念
|
||||
const nodeKey = node.node.dataRef.value5 || node.node.dataRef.NodeKey;
|
||||
const nodeId = node.node.dataRef.value1 || node.node.dataRef.EID;
|
||||
const tempNode = getNodeByKey(nodeKey);
|
||||
const linkTabs = tempNode?.linkConfig?.PageLinkList;
|
||||
if (linkTabs) {
|
||||
const nodeData = node.node.dataRef._nodeData || {};
|
||||
this.$refs[params.component]?.selectLinkTabs(linkTabs, {
|
||||
...tempNode,
|
||||
nodeKey: nodeId,
|
||||
...nodeData,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 懒加载子节点
|
||||
* @param params 参数
|
||||
* @param node 点击的节点
|
||||
* @returns
|
||||
*/
|
||||
export function proTreeLoadData(
|
||||
this: any,
|
||||
params: { dataSourceId: string; treeViewName: string },
|
||||
node: any,
|
||||
) {
|
||||
if (node.isLeaf) {
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
if (node.dataRef.children && node.dataRef.children.length > 0) {
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
const { value1, value2, value3, value4, value5, value6 } = node.dataRef;
|
||||
const _params = {
|
||||
treeViewName: params.treeViewName,
|
||||
loadAllStructure: false,
|
||||
value1: value1,
|
||||
value2: value2,
|
||||
value3: value3,
|
||||
value4: value4,
|
||||
value5: value5,
|
||||
value6: value6,
|
||||
};
|
||||
return this.dataSourceMap[params.dataSourceId].load(_params).then(childData => {
|
||||
if (childData && childData.length > 0) {
|
||||
node.dataRef.children = [...childData];
|
||||
} else {
|
||||
node.dataRef.isLeaf = true;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
function getListByNodes(nodesConfig: any[], treeDataSource) {
|
||||
const promiseArr = nodesConfig
|
||||
.map(node => {
|
||||
if (node?.nodeConfig?.DataSource?.name) {
|
||||
const { name, field } = node.nodeConfig.DataSource;
|
||||
return treeDataSource.load({ modelName: name }).then(res => {
|
||||
if (res && res.total > 0) {
|
||||
const data = res.data;
|
||||
return data.map(item => {
|
||||
return {
|
||||
key: `${node.key}_${item.EID}`,
|
||||
title: item[field],
|
||||
isLeaf: node.isLeaf,
|
||||
NodeKey: node.key,
|
||||
DataSource: cloneDeep(node.DataSource),
|
||||
childNodesConfig: cloneDeep(node.children),
|
||||
_nodeData: item,
|
||||
};
|
||||
});
|
||||
}
|
||||
return [];
|
||||
});
|
||||
} else {
|
||||
// 固定节点
|
||||
return Promise.resolve([
|
||||
{
|
||||
key: `${node.key}_${Date.now()}`,
|
||||
title: node.nodeConfig.NodeName,
|
||||
isLeaf: node.isLeaf,
|
||||
NodeKey: node.key,
|
||||
DataSource: cloneDeep(node.DataSource),
|
||||
childNodesConfig: cloneDeep(node.children),
|
||||
},
|
||||
]);
|
||||
}
|
||||
})
|
||||
.filter(item => item);
|
||||
if (promiseArr.length > 0) {
|
||||
return Promise.all(promiseArr)
|
||||
.then(res => {
|
||||
if (res && res.length > 0) {
|
||||
let resData = [];
|
||||
res.forEach(item => {
|
||||
if (item && item.length > 0) {
|
||||
resData = resData.concat(item);
|
||||
}
|
||||
});
|
||||
return resData;
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
});
|
||||
}
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载根节点数据
|
||||
* @param this
|
||||
* @param params
|
||||
*/
|
||||
export function loadTreeData(this: any, params: { currentNodeId: string }) {
|
||||
const nodeId = params.currentNodeId;
|
||||
const instance = this.$refs[nodeId];
|
||||
const dataSourceId = `treeDataSource_${nodeId}`;
|
||||
// 查找根节点数据源
|
||||
const nodes = instance.__treeDatasourceConfig || [];
|
||||
getListByNodes(nodes, this.dataSourceMap[dataSourceId]).then(resData => {
|
||||
if ((resData as any[]).length > 0) {
|
||||
instance.$.props.treeData = cloneDeep(resData);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载子节点数据
|
||||
* @param this
|
||||
* @param params
|
||||
*/
|
||||
export function loadChildTreeData(this: any, params: { currentNodeId: string }, node: any) {
|
||||
if (node.isLeaf) {
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
if (node.dataRef.HasLoad) {
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
node.dataRef.children = [];
|
||||
const nodeId = params.currentNodeId;
|
||||
const dataSourceId = `treeDataSource_${nodeId}`;
|
||||
// 查找根节点数据源
|
||||
const nodes = node.dataRef.childNodesConfig;
|
||||
return getListByNodes(nodes, this.dataSourceMap[dataSourceId]).then(resData => {
|
||||
node.dataRef.HasLoad = true;
|
||||
const resArr = resData as any[];
|
||||
if (resArr.length > 0) {
|
||||
node.dataRef.children = cloneDeep(resArr);
|
||||
} else {
|
||||
node.dataRef.isLeaf = true;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
11
packages/lowcode/src/standard-resource/scripts/modal.ts
Normal file
11
packages/lowcode/src/standard-resource/scripts/modal.ts
Normal file
@ -0,0 +1,11 @@
|
||||
export interface OpenModalParams {
|
||||
pageId?: string;
|
||||
type?: 'create' | 'update' | 'detail';
|
||||
modelName?: string; // 模型路径
|
||||
}
|
||||
|
||||
// 打开页面弹窗
|
||||
export function openModal(this: any, params: OpenModalParams) {
|
||||
console.log('打开弹窗-openModal', this, params);
|
||||
this?.openModal(params);
|
||||
}
|
286
packages/lowcode/src/standard-resource/scripts/object.ts
Normal file
286
packages/lowcode/src/standard-resource/scripts/object.ts
Normal file
@ -0,0 +1,286 @@
|
||||
import { getTreeNodeDataByKey } from '../../utils';
|
||||
import { message } from '@crami/ui';
|
||||
import {
|
||||
deleteAllByModel,
|
||||
infoByModel,
|
||||
saveByModel,
|
||||
updateByModel,
|
||||
saveByModelFk,
|
||||
updateByModelFk,
|
||||
} from '../../api/commonApi/model';
|
||||
import { openModal } from './modal';
|
||||
import { treeTableExpand, treeTableSearch } from './method';
|
||||
|
||||
// 新建表单
|
||||
export function createObject(
|
||||
this: any,
|
||||
params: { modelName: string; pageId: string; component: string },
|
||||
) {
|
||||
const { pageId, component } = params;
|
||||
openModal.bind(this)({
|
||||
pageId,
|
||||
__pageType: 'create',
|
||||
closeHandler: () => {
|
||||
// 树表格
|
||||
if (this.$refs[component].$attrs.__treeTableConfig) {
|
||||
treeTableSearch.bind(this)({ component });
|
||||
} else {
|
||||
// 普通表格
|
||||
this.reloadDataSource(`${component}__data`);
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// 新建子数据表单
|
||||
export function addChildObject(
|
||||
this: any,
|
||||
params: { modelName: string; pageId: string; component: string },
|
||||
) {
|
||||
const { modelName, pageId, component } = params;
|
||||
const instance = this.$refs[component];
|
||||
const rows = instance.getSelectRows();
|
||||
if (!rows?.length) {
|
||||
message.warn('请选择一条数据');
|
||||
return false;
|
||||
}
|
||||
const currentRow = rows[0];
|
||||
const config = instance.$attrs.__treeTableConfig;
|
||||
const __parentNodeKey = currentRow.__node_key__;
|
||||
const __parentNode = getTreeNodeDataByKey(config, 'key', __parentNodeKey);
|
||||
|
||||
const currentNode = __parentNode?.children?.find(child => child?.config?.modelName === modelName);
|
||||
if (!currentNode) {
|
||||
message.warn('此数据下不存在这种子数据');
|
||||
return false;
|
||||
}
|
||||
|
||||
const __extendData = {
|
||||
[currentNode.config.searchField]: currentRow[__parentNode.config.valueField],
|
||||
};
|
||||
|
||||
openModal.bind(this)({
|
||||
pageId,
|
||||
__extendData,
|
||||
__pageType: 'create',
|
||||
closeHandler: () => {
|
||||
currentRow.children = [];
|
||||
treeTableExpand.bind(this)({ currentNodeId: component, finish: true }, true, currentRow);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// 编辑表单
|
||||
export async function editObject(
|
||||
this: any,
|
||||
params: { modelName: string; pageId: string; component: string },
|
||||
) {
|
||||
const { modelName, pageId } = params;
|
||||
const instance = this.$refs[params.component];
|
||||
const primaryCode = instance.$props.rowKey;
|
||||
const rows = instance.getSelectRows();
|
||||
if (!rows?.length) {
|
||||
return false;
|
||||
}
|
||||
const res = await infoByModel({
|
||||
id: rows[0][primaryCode],
|
||||
modelName,
|
||||
});
|
||||
openModal.bind(this)({
|
||||
pageId,
|
||||
__pageType: 'update',
|
||||
formInitialData: res.data,
|
||||
closeHandler: () => {
|
||||
this.reloadDataSource(`${params.component}__data`);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// 浏览表单
|
||||
export async function detailObject(
|
||||
this: any,
|
||||
params: { modelName: string; pageId: string; component: string },
|
||||
) {
|
||||
const { modelName, pageId } = params;
|
||||
const instance = this.$refs[params.component];
|
||||
const primaryCode = instance.$props.rowKey;
|
||||
const rows = instance.getSelectRows();
|
||||
if (!rows?.length) {
|
||||
return false;
|
||||
}
|
||||
const res = await infoByModel({
|
||||
id: rows[0]?.[primaryCode],
|
||||
modelName,
|
||||
});
|
||||
openModal.bind(this)({
|
||||
pageId,
|
||||
__pageType: 'detail',
|
||||
formInitialData: res.data,
|
||||
});
|
||||
}
|
||||
|
||||
// 保存表单,分为单表、多表
|
||||
export function saveChanges(this: any, params: { currentNodeId: string }) {
|
||||
const { currentNodeId } = params;
|
||||
const instance = this.$refs[currentNodeId];
|
||||
const compName = instance.$.type.name;
|
||||
|
||||
// 单表类型的
|
||||
if (['HBForm', 'ProForm'].includes(compName)) {
|
||||
saveChangesBySingle.bind(this)(instance);
|
||||
}
|
||||
// 主外键类型的
|
||||
if (['HButton'].includes(compName)) {
|
||||
saveChangesByMultip.bind(this)();
|
||||
}
|
||||
}
|
||||
|
||||
// 单表保存
|
||||
function saveChangesBySingle(this: any, instance) {
|
||||
const formData: any = instance.getData();
|
||||
const primaryCode = instance.$attrs.primaryCode;
|
||||
const modelName = this.modelName || instance.$attrs.__modelName || instance.modelName || '';
|
||||
if (!modelName || !formData) {
|
||||
return;
|
||||
}
|
||||
// 混入外部传入的数据
|
||||
if (this.__extendData) {
|
||||
Object.assign(formData, this.__extendData);
|
||||
}
|
||||
if (this.__pageType === 'create' || !this.__pageType) {
|
||||
instance.submitButtonLoading();
|
||||
delete formData[primaryCode];
|
||||
saveByModel({
|
||||
data: formData,
|
||||
modelName,
|
||||
})
|
||||
.then((data: any) => {
|
||||
this?.closePage(data);
|
||||
})
|
||||
.finally(() => {
|
||||
instance.submitButtonLoading();
|
||||
});
|
||||
return false;
|
||||
}
|
||||
if (this.__pageType === 'update') {
|
||||
instance.submitButtonLoading();
|
||||
delete formData['CREATETIME'];
|
||||
updateByModel({
|
||||
id: formData[primaryCode],
|
||||
data: formData,
|
||||
modelName,
|
||||
})
|
||||
.then((data: any) => {
|
||||
this?.closePage(data);
|
||||
})
|
||||
.finally(() => {
|
||||
instance.submitButtonLoading();
|
||||
});
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 多表保存
|
||||
function saveChangesByMultip(this: any) {
|
||||
const instanceKeys = Object.keys(this.$refs);
|
||||
const forms = instanceKeys
|
||||
.filter(key => ['HBForm', 'ProForm'].includes(this.$refs[key].$.type.name))
|
||||
.map(key => this.$refs[key]);
|
||||
const tables = instanceKeys
|
||||
.filter(key => this.$refs[key].$.type.name === 'HBProTable')
|
||||
.map(key => this.$refs[key]);
|
||||
|
||||
const modelName = forms[0].$attrs.__modelName;
|
||||
const primaryCode = forms[0].$attrs.primaryCode;
|
||||
|
||||
const formData: any = forms[0].getData();
|
||||
delete formData['CREATETIME'];
|
||||
|
||||
const pageData = {};
|
||||
Object.keys(formData).map(key => {
|
||||
pageData[`${modelName}_${key}`] = formData[key];
|
||||
});
|
||||
|
||||
if (this.__pageType === 'create' || !this.__pageType) {
|
||||
tables.map(_table => {
|
||||
const keys = _table.$props.columns
|
||||
.filter(column => column.dataIndex !== '__pro-table-custom-operation__')
|
||||
.map(column => column.key || column.dataIndex);
|
||||
const tableModelName = _table.$attrs.__modelName;
|
||||
|
||||
pageData[tableModelName] = _table
|
||||
.getDisplayAllData()
|
||||
.map(setModelNameToTableDataKey(keys, tableModelName));
|
||||
});
|
||||
delete pageData[`${modelName}_${primaryCode}`];
|
||||
saveByModelFk({
|
||||
data: pageData,
|
||||
modelName,
|
||||
}).then((data: any) => {
|
||||
this?.closePage(data);
|
||||
});
|
||||
}
|
||||
if (this.__pageType === 'update') {
|
||||
tables.map(_table => {
|
||||
const keys: string[] = _table.$props.columns
|
||||
.filter(column => column.dataIndex !== '__pro-table-custom-operation__')
|
||||
.map(column => column.key || column.dataIndex);
|
||||
const tableModelName = _table.$attrs.__modelName;
|
||||
const primaryCode = _table.$props.rowKey;
|
||||
|
||||
pageData[`${tableModelName}-insert`] = _table
|
||||
.getAddRows()
|
||||
.map(setModelNameToTableDataKey(keys, tableModelName));
|
||||
const updateKeys: string[] = [...keys];
|
||||
if (!keys.includes(primaryCode)) {
|
||||
updateKeys.push(primaryCode);
|
||||
}
|
||||
pageData[`${tableModelName}-update`] = _table
|
||||
.getUpdateRows()
|
||||
.map(setModelNameToTableDataKey(updateKeys, tableModelName));
|
||||
pageData[`${tableModelName}-delete`] = _table.getDelRows().map(row => row[primaryCode]);
|
||||
});
|
||||
updateByModelFk({
|
||||
id: pageData[`${modelName}_${primaryCode}`],
|
||||
data: pageData,
|
||||
modelName,
|
||||
}).then((data: any) => {
|
||||
this?.closePage(data);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 取消保存
|
||||
export function cancelChanges(this: any) {
|
||||
this?.cancelPage();
|
||||
}
|
||||
|
||||
// 删除记录
|
||||
export function deleteRecord(this: any, params: { component: string }) {
|
||||
const instance = this.$refs[params.component];
|
||||
const rows = instance.getSelectRows();
|
||||
const primaryCode = instance.$props.rowKey;
|
||||
if (!rows?.length) {
|
||||
return;
|
||||
}
|
||||
const modelName = instance.$attrs.__modelName || instance.modelName || this.modelName || '';
|
||||
deleteAllByModel({
|
||||
ids: rows.map(row => row[primaryCode]),
|
||||
modelName,
|
||||
}).then(() => {
|
||||
instance.removeSelectedRows();
|
||||
});
|
||||
}
|
||||
|
||||
// 工具函数——————————————————————————————————
|
||||
|
||||
// 设置模型名称到表格数据上
|
||||
function setModelNameToTableDataKey(keys, modelName) {
|
||||
return item => {
|
||||
const _rowData = {};
|
||||
keys.map(key => {
|
||||
_rowData[`${modelName}_${key}`] = item[key];
|
||||
});
|
||||
return _rowData;
|
||||
};
|
||||
}
|
34
packages/lowcode/src/standard-resource/scripts/page.ts
Normal file
34
packages/lowcode/src/standard-resource/scripts/page.ts
Normal file
@ -0,0 +1,34 @@
|
||||
// 打开页面
|
||||
export function showAPage(this: any, params: any) {
|
||||
this.showAPage(params);
|
||||
}
|
||||
export function closePage(this: any) {
|
||||
this.$router.back();
|
||||
}
|
||||
export function showWorkFlowAdminPage() {}
|
||||
export function showUserTaksPage() {}
|
||||
export function syncchronize() {}
|
||||
export function signOut() {}
|
||||
export function openLink(this: any, params: any) {
|
||||
if (!params.address) {
|
||||
return;
|
||||
}
|
||||
let prefix = '';
|
||||
switch (params.linktype) {
|
||||
case 'email':
|
||||
prefix = 'emailto:';
|
||||
break;
|
||||
|
||||
case 'tel':
|
||||
prefix = 'tel:';
|
||||
break;
|
||||
case 'text':
|
||||
prefix = 'sms:';
|
||||
break;
|
||||
case 'web':
|
||||
default:
|
||||
prefix = '';
|
||||
}
|
||||
|
||||
window.open(`${prefix}${params.address}`);
|
||||
}
|
4
packages/lowcode/src/standard-resource/scripts/test.ts
Normal file
4
packages/lowcode/src/standard-resource/scripts/test.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export function testFn(this: any, params: any) {
|
||||
console.log('testFn:this', this);
|
||||
console.log('testFn:params', params);
|
||||
}
|
2
packages/lowcode/src/utils/index.ts
Normal file
2
packages/lowcode/src/utils/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export * from './tree';
|
||||
export * from './qs';
|
4
packages/lowcode/src/utils/qs.ts
Normal file
4
packages/lowcode/src/utils/qs.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export const GetQueryString = (name: string) => {
|
||||
const reg = new RegExp('(?<=(?:^|&|\\?)' + name + '=)([^&]*)(?=(&|$))', 'g');
|
||||
return window.location.search.match(reg)?.[0];
|
||||
};
|
18
packages/lowcode/src/utils/tree.ts
Normal file
18
packages/lowcode/src/utils/tree.ts
Normal file
@ -0,0 +1,18 @@
|
||||
// 根据属性数据和key value获取数据
|
||||
export function getTreeNodeDataByKey(data: any[], key: string, value: any) {
|
||||
if (!data?.length) {
|
||||
return null;
|
||||
}
|
||||
let _cache = null;
|
||||
const fn = arr => {
|
||||
arr.some(item => {
|
||||
if (item[key] === value) {
|
||||
return (_cache = item);
|
||||
} else if (item?.children?.length) {
|
||||
fn(item.children);
|
||||
}
|
||||
});
|
||||
};
|
||||
fn(data);
|
||||
return _cache;
|
||||
}
|
99
packages/lowcode/src/views/preview/helper.ts
Normal file
99
packages/lowcode/src/views/preview/helper.ts
Normal file
@ -0,0 +1,99 @@
|
||||
import { getSchemaById as getSchemaFromServer } from '../../api/page';
|
||||
import pkgJson from './packages.json';
|
||||
import _projectSchema from './projectSchema.json';
|
||||
import { buildComponents } from '@crami/lowcode-utils';
|
||||
import { isNull, isUndefined } from 'lodash-es';
|
||||
import { evaluate } from '@studio/formula';
|
||||
|
||||
export const getSchemaById = async (params: {
|
||||
pageId: string;
|
||||
projectCode: string;
|
||||
appCode: string;
|
||||
}) => {
|
||||
const packages = pkgJson;
|
||||
let projectSchema: any = await getSchemaFromServer(params);
|
||||
if (!projectSchema.data) {
|
||||
projectSchema = _projectSchema;
|
||||
} else {
|
||||
projectSchema = projectSchema.data;
|
||||
}
|
||||
const { componentsMap: componentsMapArray, componentsTree } = projectSchema as any;
|
||||
const componentsMap: any = {};
|
||||
componentsMapArray.forEach((component: any) => {
|
||||
componentsMap[component.componentName] = component;
|
||||
});
|
||||
|
||||
const libraryMap = {};
|
||||
packages.forEach(({ package: _package, library }) => {
|
||||
libraryMap[_package] = library;
|
||||
});
|
||||
const components = buildComponents(libraryMap, componentsMap);
|
||||
return { schema: componentsTree[0], components };
|
||||
};
|
||||
export interface ParamItem {
|
||||
key: string;
|
||||
label: string;
|
||||
valueType: string;
|
||||
required?: boolean;
|
||||
}
|
||||
|
||||
export function normalizePageParams(
|
||||
pageParams: { [key: string]: any },
|
||||
pageParamsConfig: Array<ParamItem>,
|
||||
formularData: any,
|
||||
) {
|
||||
let newParams = {};
|
||||
if (pageParamsConfig && pageParamsConfig.length > 0) {
|
||||
newParams = pageParamsConfig.reduce((params: { [key: string]: any }, curItem: ParamItem) => {
|
||||
const { valueType, key } = curItem;
|
||||
const value = pageParams[key];
|
||||
if (isUndefined(value)) {
|
||||
return params;
|
||||
}
|
||||
if (valueType === 'object' || valueType === 'array') {
|
||||
try {
|
||||
params[key] = JSON.parse(value);
|
||||
} catch (error) {
|
||||
console.warn(`json解析异常,数据 \n ${value}`);
|
||||
}
|
||||
} else if (valueType === 'formular') {
|
||||
// 执行公式
|
||||
if (!isNull(value)) {
|
||||
const result = evalFormula(value, formularData);
|
||||
if (!isUndefined(result)) {
|
||||
params[key] = result;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
params[key] = value;
|
||||
}
|
||||
return params;
|
||||
}, {});
|
||||
}
|
||||
return newParams;
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行公式
|
||||
* @param expression 公式
|
||||
* @param data 变量值对象
|
||||
* @returns 执行结果
|
||||
*/
|
||||
export function evalFormula(expression: string, data?: object) {
|
||||
const curData = data || {};
|
||||
let result;
|
||||
try {
|
||||
result = evaluate(expression, curData, {
|
||||
evalMode: true, // evalMode 为 true 时,不用 ${} 包裹也可以执行,
|
||||
allowFilter: false,
|
||||
});
|
||||
} catch (e) {
|
||||
console.warn(
|
||||
'[evalFormula]表达式执行异常,当前表达式: ',
|
||||
expression,
|
||||
',当前上下文数据: ',
|
||||
data,
|
||||
);
|
||||
}
|
||||
return result;
|
||||
}
|
3
packages/lowcode/src/views/preview/index.ts
Normal file
3
packages/lowcode/src/views/preview/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
import Preview from './preview';
|
||||
import PreviewOnly from './previewOnly';
|
||||
export { Preview, PreviewOnly };
|
94
packages/lowcode/src/views/preview/packages.json
Normal file
94
packages/lowcode/src/views/preview/packages.json
Normal file
@ -0,0 +1,94 @@
|
||||
[
|
||||
{
|
||||
"package": "loadsh",
|
||||
"version": "0.0.4",
|
||||
"urls": ["./cdn/npm/loadsh@0.0.4/lodash.min.js"],
|
||||
"library": "_"
|
||||
},
|
||||
{
|
||||
"package": "xlsx",
|
||||
"version": "0.18.5",
|
||||
"urls": ["./cdn/npm/xlsx@0.18.5/dist/xlsx.full.min.js"],
|
||||
"library": "XLSX"
|
||||
},
|
||||
{
|
||||
"package": "vue",
|
||||
"version": "3.2.37",
|
||||
"urls": ["./cdn/npm/vue@3.2.37/dist/vue.global.js"],
|
||||
"editUrls": ["./cdn/npm/vue@3.2.37/dist/vue.global.js"],
|
||||
"library": "Vue"
|
||||
},
|
||||
{
|
||||
"package": "vue-i18n",
|
||||
"version": "9.2.2",
|
||||
"urls": ["./cdn/npm/vue-i18n@9.2.2/dist/vue-i18n.global.js"],
|
||||
"editUrls": ["./cdn/npm/vue-i18n@9.2.2/dist/vue-i18n.global.js"],
|
||||
"library": "VueI18n"
|
||||
},
|
||||
{
|
||||
"package": "@vueuse/shared",
|
||||
"version": "8.9.4",
|
||||
"urls": ["./cdn/npm/@vueuse/shared@8.9.4/index.iife.min.js"],
|
||||
"library": "VueUseShared"
|
||||
},
|
||||
{
|
||||
"package": "@vueuse/core",
|
||||
"version": "8.9.4",
|
||||
"urls": ["./cdn/npm/@vueuse/core@8.9.4/index.iife.min.js"],
|
||||
"library": "VueUse"
|
||||
},
|
||||
{
|
||||
"package": "dayjs",
|
||||
"version": "1.11.4",
|
||||
"urls": ["./cdn/npm/dayjs@1.11.4/dayjs.min.js"],
|
||||
"library": "dayjs"
|
||||
},
|
||||
{
|
||||
"package": "ant-design-vue",
|
||||
"version": "3.2.10",
|
||||
"urls": [
|
||||
"./cdn/npm/ant-design-vue@3.2.10/dist/antd.min.js",
|
||||
"./cdn/npm/ant-design-vue@3.2.10/dist/antd.min.css"
|
||||
],
|
||||
"library": "antd"
|
||||
},
|
||||
{
|
||||
"package": "@surely-vue/table",
|
||||
"version": "2.4.3",
|
||||
"urls": [
|
||||
"./cdn/npm/@surely-vue/table@2.4.7/dist/index.min.js",
|
||||
"./cdn/npm/@surely-vue/table@2.4.7/dist/index.min.css"
|
||||
],
|
||||
"library": "STable"
|
||||
},
|
||||
{
|
||||
"package": "echarts",
|
||||
"version": "5.3.3",
|
||||
"urls": ["./cdn/npm/echarts@5.3.3/dist/echarts.min.js"],
|
||||
"library": "echarts"
|
||||
},
|
||||
{
|
||||
"package": "@crami/ui",
|
||||
"version": "2.0.162",
|
||||
"urls": ["./cdn/crami/crami-ui/crami-monorepo.umd.js", "./cdn/crami/crami-ui/style.css"],
|
||||
"library": "cramiUI"
|
||||
},
|
||||
{
|
||||
"package": "@crami/bui-platform",
|
||||
"version": "2.0.259",
|
||||
"urls": ["./cdn/crami/platform/crami-bui-monorepo.umd.js"],
|
||||
"library": "CramiBUIPlatform"
|
||||
},
|
||||
{
|
||||
"package": "@crami/bui",
|
||||
"version": "2.0.331",
|
||||
"urls": ["./cdn/crami/crami-bui/crami-bui-monorepo.umd.js", "./cdn/crami/crami-bui/style.css"],
|
||||
"library": "CramiBui"
|
||||
},
|
||||
{
|
||||
"package": "@crami/lowcode-materials",
|
||||
"version": "0.0.0",
|
||||
"urls": ["./cdn/crami/crami-lc/view.js", "./cdn/crami/crami-lc/view.css"],
|
||||
"library": "CramiLcUi"
|
||||
}
|
||||
]
|
5
packages/lowcode/src/views/preview/preview.css
Normal file
5
packages/lowcode/src/views/preview/preview.css
Normal file
@ -0,0 +1,5 @@
|
||||
.lowcode-plugin-sample-preview,
|
||||
.lowcode-plugin-sample-preview-content {
|
||||
/* height: calc(100vh - 256px); */
|
||||
height: auto;
|
||||
}
|
96
packages/lowcode/src/views/preview/preview.tsx
Normal file
96
packages/lowcode/src/views/preview/preview.tsx
Normal file
@ -0,0 +1,96 @@
|
||||
import { defineComponent, onMounted, reactive, h, createVNode, render } from 'vue';
|
||||
import VueRenderer from '@crami/lowcode-vue-renderer';
|
||||
import { Spin } from '@crami/ui';
|
||||
import './preview.css';
|
||||
import ModalPage from '../../components/modal-page';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { getSchemaById, normalizePageParams } from './helper';
|
||||
import { previewProps } from './props';
|
||||
import type { MenuRouteMeta } from 'pro-vip/src/router/typing';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'editor-preview',
|
||||
props: previewProps,
|
||||
setup(props) {
|
||||
const data = reactive<any>({});
|
||||
|
||||
// 获取token
|
||||
let tokenStr = '';
|
||||
const hostToken = localStorage.getItem('token');
|
||||
const clientToken = localStorage.getItem('access_token');
|
||||
if (hostToken) {
|
||||
tokenStr = JSON.parse(hostToken)?.token || '';
|
||||
} else if (clientToken) {
|
||||
tokenStr = clientToken;
|
||||
}
|
||||
const userToken = `Bearer ${tokenStr}`;
|
||||
|
||||
// 获取当前路由
|
||||
const route = useRoute();
|
||||
const { projectCode, appCode } = route.meta as Required<MenuRouteMeta>;
|
||||
console.log('routermeta', route.meta);
|
||||
|
||||
onMounted(async () => {
|
||||
const CramiLcUi = await import('@crami/lowcode-materials');
|
||||
const _W = window as any;
|
||||
_W.CramiLcUi = CramiLcUi;
|
||||
|
||||
// 获取schema
|
||||
if (props.pageId) {
|
||||
Object.assign(
|
||||
data,
|
||||
await getSchemaById({
|
||||
pageId: props.pageId,
|
||||
projectCode,
|
||||
appCode,
|
||||
}),
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
return () => {
|
||||
const { schema, components } = data;
|
||||
|
||||
// 定义一个弹窗方法
|
||||
async function openModal(params: any) {
|
||||
const vnode = createVNode(ModalPage, {
|
||||
params,
|
||||
components,
|
||||
routeMeta: route.meta,
|
||||
userToken,
|
||||
key: Math.random(),
|
||||
});
|
||||
render(vnode, document.body);
|
||||
vnode.component?.ctx?.open();
|
||||
}
|
||||
|
||||
if (!schema || !components) {
|
||||
return h(Spin);
|
||||
}
|
||||
|
||||
// 处理页面传参
|
||||
const _pageParams = route.meta.pageParams
|
||||
? JSON.parse(route.meta.pageParams as string)
|
||||
: props.pageParams;
|
||||
const formularData = {
|
||||
projectCode,
|
||||
appCode,
|
||||
};
|
||||
const pageParams = normalizePageParams(_pageParams, schema.pageParamsConfig, formularData);
|
||||
|
||||
return h('div', { class: 'lowcode-plugin-sample-preview' }, [
|
||||
h(VueRenderer, {
|
||||
scope: {
|
||||
openModal,
|
||||
routeMeta: route.meta,
|
||||
userToken,
|
||||
pageParams: pageParams,
|
||||
},
|
||||
class: 'lowcode-plugin-sample-preview-content',
|
||||
schema,
|
||||
components,
|
||||
}),
|
||||
]);
|
||||
};
|
||||
},
|
||||
});
|
60
packages/lowcode/src/views/preview/previewOnly.tsx
Normal file
60
packages/lowcode/src/views/preview/previewOnly.tsx
Normal file
@ -0,0 +1,60 @@
|
||||
import { defineComponent, onMounted, reactive, toRefs, h, createVNode, render, inject } from 'vue';
|
||||
import VueRenderer from '@crami/lowcode-vue-renderer';
|
||||
import { Spin } from '@crami/ui';
|
||||
import './preview.css';
|
||||
import ModalPage from '@/components/modal-page';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { getSchemaById, normalizePageParams } from './helper';
|
||||
import { previewProps } from './props';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'EditorPreviewOnly',
|
||||
props: previewProps,
|
||||
mounted() {},
|
||||
setup(props) {
|
||||
const data = reactive<any>({});
|
||||
const { pageId } = toRefs(props);
|
||||
const projectCode = inject('projectCode', { value: '' });
|
||||
const appCode = inject('appCode', { value: '' });
|
||||
onMounted(async () => {
|
||||
if (pageId.value) {
|
||||
Object.assign(data, await getSchemaById(pageId.value, projectCode.value, appCode.value));
|
||||
}
|
||||
});
|
||||
const route = useRoute();
|
||||
const token: any = JSON.parse(localStorage.getItem('token') || '');
|
||||
const userToken = `Bearer ${token?.token || ''}`;
|
||||
|
||||
return () => {
|
||||
const { schema, components } = data;
|
||||
if (!schema || !components) {
|
||||
return h(Spin);
|
||||
}
|
||||
|
||||
async function openModal(params: any) {
|
||||
const vnode = createVNode(ModalPage, {
|
||||
params,
|
||||
components,
|
||||
routeMeta: route.meta,
|
||||
userToken,
|
||||
});
|
||||
render(vnode, document.body);
|
||||
vnode.component.ctx.open();
|
||||
}
|
||||
const pageParams = normalizePageParams(props.pageParams, schema.pageParamsConfig);
|
||||
return h('div', { class: 'lowcode-plugin-sample-preview' }, [
|
||||
h(VueRenderer, {
|
||||
scope: {
|
||||
openModal,
|
||||
routeMeta: route.meta,
|
||||
userToken,
|
||||
pageParams: pageParams,
|
||||
},
|
||||
class: 'lowcode-plugin-sample-preview-content',
|
||||
schema,
|
||||
components,
|
||||
}),
|
||||
]);
|
||||
};
|
||||
},
|
||||
});
|
99
packages/lowcode/src/views/preview/projectSchema.json
Normal file
99
packages/lowcode/src/views/preview/projectSchema.json
Normal file
@ -0,0 +1,99 @@
|
||||
{
|
||||
"version": "1.0.0",
|
||||
"componentsMap": [
|
||||
{
|
||||
"package": "@crami/lowcode-materials",
|
||||
"version": "0.0.0",
|
||||
"exportName": "CramiCol",
|
||||
"destructuring": true,
|
||||
"componentName": "CramiCol"
|
||||
},
|
||||
{
|
||||
"package": "@crami/lowcode-materials",
|
||||
"version": "0.0.0",
|
||||
"exportName": "CramiRow",
|
||||
"destructuring": true,
|
||||
"componentName": "CramiRow"
|
||||
},
|
||||
{
|
||||
"package": "@crami/lowcode-materials",
|
||||
"version": "0.0.0",
|
||||
"exportName": "CramiRowColContainer",
|
||||
"destructuring": true,
|
||||
"componentName": "CramiRowColContainer"
|
||||
},
|
||||
{
|
||||
"package": "@crami/lowcode-materials",
|
||||
"version": "0.0.0",
|
||||
"exportName": "CramiBlockCell",
|
||||
"destructuring": true,
|
||||
"componentName": "CramiBlockCell"
|
||||
},
|
||||
{
|
||||
"package": "@crami/lowcode-materials",
|
||||
"version": "0.0.0",
|
||||
"exportName": "CramiTabPanel",
|
||||
"destructuring": true,
|
||||
"componentName": "CramiTabPanel"
|
||||
},
|
||||
{
|
||||
"package": "@crami/lowcode-materials",
|
||||
"version": "0.0.0",
|
||||
"exportName": "CramiTabs",
|
||||
"destructuring": true,
|
||||
"componentName": "CramiTabs"
|
||||
},
|
||||
{
|
||||
"package": "@crami/lowcode-materials",
|
||||
"version": "0.0.0",
|
||||
"exportName": "CramiBlock",
|
||||
"destructuring": true,
|
||||
"componentName": "CramiBlock"
|
||||
},
|
||||
{
|
||||
"package": "@crami/lowcode-materials",
|
||||
"version": "0.0.0",
|
||||
"exportName": "CramiPage",
|
||||
"destructuring": true,
|
||||
"componentName": "CramiPage"
|
||||
},
|
||||
{ "devMode": "lowCode", "componentName": "Page" }
|
||||
],
|
||||
"componentsTree": [
|
||||
{
|
||||
"componentName": "Page",
|
||||
"id": "node_ocl7spc2i41",
|
||||
"props": { "ref": "node_ocl7spc2i41" },
|
||||
"fileName": "/",
|
||||
"state": {
|
||||
"text": { "type": "JSExpression", "value": "\"outer\"" },
|
||||
"isShowDialog": { "type": "JSExpression", "value": "false" },
|
||||
"info": {
|
||||
"type": "JSExpression",
|
||||
"value": "{\n \"info\": \"\",\n \"user\": {\n \"username\": \"\",\n \"password\": \"\"\n }\n}"
|
||||
}
|
||||
},
|
||||
"dataSource": { "list": [] },
|
||||
"css": "body, html {background: rgba(0, 0, 0, 0);}",
|
||||
"lifeCycles": {
|
||||
"mounted": {
|
||||
"type": "JSFunction",
|
||||
"value": "function mounted() {\n console.log('did mount');\n}"
|
||||
},
|
||||
"unmounted": {
|
||||
"type": "JSFunction",
|
||||
"value": "function unmounted() {\n console.log('will unmount');\n}"
|
||||
}
|
||||
},
|
||||
"methods": {},
|
||||
"hidden": false,
|
||||
"title": "页面",
|
||||
"isLocked": false,
|
||||
"condition": true,
|
||||
"conditionGroup": "",
|
||||
"utils": [],
|
||||
"children": []
|
||||
}
|
||||
],
|
||||
"i18n": {}
|
||||
}
|
12
packages/lowcode/src/views/preview/props.ts
Normal file
12
packages/lowcode/src/views/preview/props.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import type { PropType } from 'vue';
|
||||
|
||||
export const previewProps = {
|
||||
pageId: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
pageParams: {
|
||||
type: Object as PropType<Array<{ [propsKey: string]: any }>>,
|
||||
default: () => ({}),
|
||||
},
|
||||
};
|
Reference in New Issue
Block a user