pureList fix

This commit is contained in:
梁朝伟 2023-03-08 14:08:15 +08:00
parent f64d1a26e1
commit 8ec93f8f4d
22 changed files with 424 additions and 59 deletions

View File

@ -0,0 +1,3 @@
/// <reference types="react" />
declare const _default: import("react").ComponentType<any>;
export default _default;

View File

@ -0,0 +1,27 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = OakComponent({
isList: false,
properties: {
entity: String,
actions: {
type: Array,
value: [],
},
items: {
type: Array,
value: [],
},
mode: {
type: String,
value: 'cell',
},
column: {
type: Number,
value: 3,
},
},
data: {},
lifetimes: {},
methods: {},
});

11
lib/components/actionBtnPanel/web.d.ts vendored Normal file
View File

@ -0,0 +1,11 @@
/// <reference types="react" />
import { WebComponentProps } from '../../types/Page';
import { EntityDict as BaseEntityDict } from 'oak-domain/lib/base-app-domain';
import { OakActionBtnProps } from '../../types/oakActionBtn';
import { EntityDict } from 'oak-domain/lib/types/Entity';
export default function Render(props: WebComponentProps<EntityDict & BaseEntityDict, keyof EntityDict, false, {
id: string;
entity: string;
oakActions: OakActionBtnProps[];
onClick: (id: string, action: string) => void;
}, {}>): JSX.Element;

View File

@ -0,0 +1,23 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var jsx_runtime_1 = require("react/jsx-runtime");
var antd_1 = require("antd");
var web_module_less_1 = tslib_1.__importDefault(require("./web.module.less"));
var confirm = antd_1.Modal.confirm;
function ItemComponent(props) {
var id = props.id, label = props.label, type = props.type, onClick = props.onClick, action = props.action;
if (type === 'button') {
return ((0, jsx_runtime_1.jsx)(antd_1.Button, tslib_1.__assign({ onClick: function () { return onClick(id, action); } }, { children: label })));
}
return (0, jsx_runtime_1.jsx)("a", tslib_1.__assign({ onClick: function () { return onClick(id, action); } }, { children: label }));
}
function Render(props) {
var methods = props.methods, data = props.data;
var t = methods.t;
var id = data.id, oakActions = data.oakActions, onClick = data.onClick, entity = data.entity;
return ((0, jsx_runtime_1.jsx)("div", tslib_1.__assign({ className: web_module_less_1.default.panelContainer }, { children: (0, jsx_runtime_1.jsx)(antd_1.Space, { children: oakActions === null || oakActions === void 0 ? void 0 : oakActions.map(function (ele, index) {
return ((0, jsx_runtime_1.jsx)(ItemComponent, { id: id, label: ele.label || t("common:".concat(ele.action)) || t("".concat(entity, ":action.").concat(ele.action)), action: ele.action, type: "a", onClick: function (id, action) { return onClick(id, action); } }));
}) }) })));
}
exports.default = Render;

3
lib/components/pureList/index.d.ts vendored Normal file
View File

@ -0,0 +1,3 @@
/// <reference types="react" />
declare const _default: import("react").ComponentType<any>;
export default _default;

View File

@ -0,0 +1,18 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = OakComponent({
isList: false,
formData: function (_a) {
var props = _a.props, features = _a.features;
var colorDict = features.style.getColorDict();
var dataSchema = features.cache.getSchema();
return {
colorDict: colorDict,
dataSchema: dataSchema,
};
},
properties: {},
data: {},
lifetimes: {},
methods: {},
});

23
lib/components/pureList/web.d.ts vendored Normal file
View File

@ -0,0 +1,23 @@
/// <reference types="react" />
import { TableProps } from 'antd';
import type { ColumnType } from 'antd/es/table';
import { EntityDict } from 'oak-domain/lib/types/Entity';
import { WebComponentProps } from '../../types/Page';
import { EntityDict as BaseEntityDict } from 'oak-domain/lib/base-app-domain';
import { ColorDict } from 'oak-domain/lib/types/Style';
import { StorageSchema } from 'oak-domain/lib/types/Storage';
declare type SelfColumn = {
path?: string;
};
declare type Column = SelfColumn & ColumnType<any>;
export default function Render(props: WebComponentProps<EntityDict & BaseEntityDict, keyof EntityDict, false, {
entity: string;
data: any[];
columns: (Column | string)[];
disableOp?: boolean;
tableProps?: TableProps<any>;
handleClick?: (id: string, action: string) => void;
colorDict: ColorDict<EntityDict & BaseEntityDict>;
dataSchema: StorageSchema<EntityDict>;
}, {}>): JSX.Element;
export {};

View File

@ -0,0 +1,85 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var jsx_runtime_1 = require("react/jsx-runtime");
var react_i18next_1 = require("react-i18next");
var antd_1 = require("antd");
var assert_1 = tslib_1.__importDefault(require("assert"));
var usefulFn_1 = require("../../utils/usefulFn");
var lodash_1 = require("oak-domain/lib/utils/lodash");
var dayjs_1 = tslib_1.__importDefault(require("dayjs"));
var actionBtnPanel_1 = tslib_1.__importDefault(require("../actionBtnPanel"));
function decodeTitle(entity, attr) {
var t = (0, react_i18next_1.useTranslation)().t;
if (attr === ('$$createAt$$' || '$$updateAt$$')) {
return t("common:".concat(attr));
}
return t("".concat(entity, ":attr.").concat(attr));
}
function RenderCell(props) {
var content = props.content, entity = props.entity, path = props.path, attr = props.attr, attrType = props.attrType, t = props.t, colorDict = props.colorDict;
var value = (0, lodash_1.get)(content, path);
if (!value) {
return ((0, jsx_runtime_1.jsx)("div", { children: "--" }));
}
// 属性类型是enum要使用标签
else if (attrType === 'enum') {
return ((0, jsx_runtime_1.jsx)(antd_1.Tag, tslib_1.__assign({ color: colorDict[entity][attr][String(value)] }, { children: t("".concat(entity, ":v.").concat(attr, ".").concat(value)) })));
}
else if (attrType === 'datetime') {
return (0, jsx_runtime_1.jsx)("div", { children: (0, dayjs_1.default)(value).format('YYYY-MM-DD HH:mm') });
}
return ((0, jsx_runtime_1.jsx)("div", { children: value }));
}
function Render(props) {
var methods = props.methods, oakData = props.data;
var t = methods.t;
var entity = oakData.entity, data = oakData.data, columns = oakData.columns, _a = oakData.disableOp, disableOp = _a === void 0 ? false : _a, tableProps = oakData.tableProps, handleClick = oakData.handleClick, colorDict = oakData.colorDict, dataSchema = oakData.dataSchema;
var tableColumns = columns.map(function (ele) {
var title = '';
var render = function () { return (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, {}); };
var path;
if (typeof ele === 'string') {
path = ele;
}
else {
path = ele.path;
}
var _a = (0, usefulFn_1.resolutionPath)(dataSchema, entity, path) || {}, useEntity = _a.entity, attr = _a.attr, attribute = _a.attribute;
title = decodeTitle(useEntity, attr);
render = function (value, row) { return ((0, jsx_runtime_1.jsx)(RenderCell, { entity: entity, content: row, path: path, attr: attr, attrType: attribute === null || attribute === void 0 ? void 0 : attribute.type, t: t, colorDict: colorDict })); };
var column = {
align: 'center',
title: title,
dataIndex: typeof ele === 'string' ? ele : ele.dataIndex,
render: render,
};
// 类型如果是枚举类型那么它的宽度一般不超过160
// if (attribute?.type === 'enum') {
// Object.assign(column, {width: 160})
// }
return Object.assign(column, typeof ele !== 'string' && ele);
});
if (tableColumns && tableColumns) {
tableColumns.unshift({ title: '序号', width: 100, render: function (value, record, index) {
return index + 1;
}, });
}
if (!disableOp) {
tableColumns.push({
fixed: 'right',
align: 'center',
title: '操作',
key: 'operation',
width: 300,
render: function (value, row) {
var id = row === null || row === void 0 ? void 0 : row.id;
var oakActions = row === null || row === void 0 ? void 0 : row.oakActions;
(0, assert_1.default)(!!oakActions, '行数据中不存在oakActions, 请禁用(disableOp:true)或添加oakActions');
return ((0, jsx_runtime_1.jsx)(actionBtnPanel_1.default, { id: id, entity: entity, oakActions: oakActions, onClick: function (id, action) { return handleClick && handleClick(id, action); } }));
}
});
}
return ((0, jsx_runtime_1.jsx)(antd_1.Table, tslib_1.__assign({ dataSource: data, scroll: { x: 2200 }, columns: tableColumns }, tableProps)));
}
exports.default = Render;

11
lib/hooks/useFeatures.d.ts vendored Normal file
View File

@ -0,0 +1,11 @@
import { BasicFeatures } from '../features';
import { EntityDict as BaseEntityDict } from 'oak-domain/lib/base-app-domain';
import { Aspect, EntityDict } from 'oak-domain/lib/types';
import { SyncContext } from 'oak-domain/lib/store/SyncRowStore';
import { AsyncContext } from 'oak-domain/lib/store/AsyncRowStore';
declare type ED = EntityDict & BaseEntityDict;
declare type Cxt = AsyncContext<ED>;
declare type FrontCxt = SyncContext<ED>;
declare type AD = Record<string, Aspect<ED, Cxt>>;
export default function useFeatures(): BasicFeatures<ED, Cxt, FrontCxt, AD>;
export {};

9
lib/hooks/useFeatures.js Normal file
View File

@ -0,0 +1,9 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var features_1 = require("../platforms/web/features");
// react 独有
function useFeatures() {
return (0, features_1.useFeatures)();
}
exports.default = useFeatures;
;

6
lib/types/oakActionBtn.d.ts vendored Normal file
View File

@ -0,0 +1,6 @@
export declare type OakActionBtnProps = {
label: string;
action: string;
type?: 'a' | 'button';
ctxType?: string;
};

View File

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

24
lib/utils/usefulFn.d.ts vendored Normal file
View File

@ -0,0 +1,24 @@
import { EntityDict } from "oak-domain/lib/types";
import { StorageSchema } from "oak-domain/lib/types";
export declare function getAttributes(attributes: Record<string, any>): Record<string, any> & {
id: {
type: string;
};
$$createAt$$: {
type: string;
};
$$updateAt$$: {
type: string;
};
$$deleteAt$$: {
type: string;
};
$$seq$$: {
type: string;
};
};
export declare function resolutionPath(dataSchema: StorageSchema<EntityDict>, entity: string, path: string): {
entity: string;
attr: string;
attribute: any;
};

59
lib/utils/usefulFn.js Normal file
View File

@ -0,0 +1,59 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.resolutionPath = exports.getAttributes = void 0;
var tslib_1 = require("tslib");
var assert_1 = tslib_1.__importDefault(require("assert"));
function getAttributes(attributes) {
return Object.assign({}, attributes, {
id: {
type: 'char',
},
$$createAt$$: {
type: 'datetime',
},
$$updateAt$$: {
type: 'datetime',
},
$$deleteAt$$: {
type: 'datetime',
},
$$seq$$: {
type: 'datetime',
},
});
}
exports.getAttributes = getAttributes;
function resolutionPath(dataSchema, entity, path) {
var _entity = entity;
var attr;
(0, assert_1.default)(!path.includes('['), '数组索引不需要携带[],请使用arr.0.value');
if (!dataSchema) {
return {
entity: _entity,
attr: '',
attribute: undefined,
};
}
if (!path.includes('.')) {
attr = path;
}
else {
var strs = path.split('.');
// 最后一个肯定是属性
attr = strs.pop();
// 倒数第二个可能是类名可能是索引
_entity = strs.pop();
// 判断是否是数组索引
if (!Number.isNaN(Number(_entity))) {
_entity = strs.pop().split('$')[0];
}
}
var attributes = getAttributes(dataSchema[_entity].attributes);
var attribute = attributes[attr];
return {
entity: _entity,
attr: attr,
attribute: attribute,
};
}
exports.resolutionPath = resolutionPath;

View File

@ -35,7 +35,7 @@
"i18next-localstorage-backend": "^3.1.3",
"i18next-resource-store-loader": "^0.1.2",
"react": "^18.2.0",
"react-dom": "^18.1.0",
"react-dom": "^18.2.0",
"react-i18next": "^11.18.0",
"react-responsive": "^9.0.0-beta.10",
"react-router-dom": "^6.3.0"

View File

@ -1,4 +1,5 @@
export default OakComponent({
isList: false,
properties: {
entity: String,
actions: {

View File

@ -11,14 +11,14 @@ import {
import { WebComponentProps } from '../../types/Page';
import { EntityDict as BaseEntityDict } from 'oak-domain/lib/base-app-domain';
import { OakActionBtnProps } from '../../types/oakActionBtn';
import { useTranslation } from 'react-i18next';
import { EntityDict } from 'oak-domain/lib/types/Entity';
import Style from './web.module.less';
const { confirm } = Modal;
type Item = {
id: string,
label: string;
label?: string;
action: string;
type?: 'a' | 'button';
};
@ -29,7 +29,6 @@ function ItemComponent(
}
) {
const { id, label, type, onClick, action } = props;
if (type === 'button') {
return (
<Button onClick={() => onClick(id, action)}>
@ -49,6 +48,7 @@ export default function Render(
false,
{
id: string;
entity: string;
oakActions: OakActionBtnProps[];
onClick: (id: string, action: string) => void;
},
@ -62,6 +62,7 @@ export default function Render(
id,
oakActions,
onClick,
entity,
} = data;
return (
<div className={Style.panelContainer}>
@ -70,7 +71,7 @@ export default function Render(
return (
<ItemComponent
id={id}
label={ele.label}
label={ele.label || t(`common:${ele.action}`) || t(`${entity}:action.${ele.action}`)}
action={ele.action}
type="a"
onClick={(id, action) => onClick(id, action)}

View File

@ -0,0 +1,9 @@
{
"component": true,
"usingComponents": {
"l-dialog": "../../miniprogram_npm/lin-ui/dialog/index",
"l-button": "../../miniprogram_npm/lin-ui/button/index",
"popover": "../../miniprogram_npm/popover/popover",
"popover-item": "../../miniprogram_npm/popover/popover-item"
}
}

View File

@ -0,0 +1,19 @@
export default OakComponent({
isList: false,
formData({ props, features }) {
const colorDict = features.style.getColorDict();
const dataSchema = features.cache.getSchema();
return {
colorDict,
dataSchema,
}
},
properties: {
},
data: {
},
lifetimes: {
},
methods: {
},
});

View File

@ -3,11 +3,15 @@ import { useTranslation } from 'react-i18next';
import { Table, Tag, TableProps } from 'antd';
import type { ColumnsType, ColumnType, ColumnGroupType } from 'antd/es/table';
import assert from 'assert';
import useFeatures from '../../hooks/useFeatures';
import { getAttributes } from '../../utils/usefulFn';
import { getAttributes, resolutionPath } from '../../utils/usefulFn';
import { get } from 'oak-domain/lib/utils/lodash';
import dayjs from 'dayjs';
import ActionBtnPanel from '../actionBtnPanel';
import { EntityDict } from 'oak-domain/lib/types/Entity';
import { WebComponentProps } from '../../types/Page';
import { EntityDict as BaseEntityDict } from 'oak-domain/lib/base-app-domain';
import { ColorDict } from 'oak-domain/lib/types/Style';
import { StorageSchema } from 'oak-domain/lib/types/Storage';
type SelfColumn = {
path?: string;
@ -15,15 +19,6 @@ type SelfColumn = {
type Column = SelfColumn & ColumnType<any>;
type Props = {
entity: string;
data: any[];
columns: (Column | string)[];
disableOp?: boolean;
tableProps?: TableProps<any>;
handleClick?: (id: string, action: string) => void;
}
type RenderCellProps = {
content: any;
@ -31,6 +26,8 @@ type RenderCellProps = {
path: string;
attr: string;
attrType: string;
t: (value: string) => string;
colorDict: ColorDict<EntityDict & BaseEntityDict>
}
function decodeTitle(entity: string, attr: string) {
@ -41,49 +38,17 @@ function decodeTitle(entity: string, attr: string) {
return t(`${entity}:attr.${attr}`)
}
// 解析路径, 获取属性类型、属性值、以及实体名称
function Fn(entity: string, path: string) {
let _entity = entity;
let attr: string;
assert(!path.includes('['), '数组索引不需要携带[],请使用arr.0.value')
const features = useFeatures();
const dataSchema = features.cache.getSchema();
if (!path.includes('.')) {
attr = path;
}
else {
const strs = path.split('.');
// 最后一个肯定是属性
attr = strs.pop()!;
// 倒数第二个可能是类名可能是索引
_entity = strs.pop()!;
// 判断是否是数组索引
if (!Number.isNaN(Number(_entity))) {
_entity = strs.pop()!.split('$')[0];
}
}
const attributes = getAttributes(dataSchema[_entity as keyof typeof dataSchema].attributes);
const attribute = attributes[attr];
return {
entity: _entity,
attr,
attribute,
}
}
function RenderCell(props: RenderCellProps) {
const { content, entity, path, attr, attrType } = props;
const { content, entity, path, attr, attrType, t, colorDict } = props;
const value = get(content, path);
const { t } = useTranslation();
const feature = useFeatures();
const colorDict = feature.style.getColorDict();
if (!value) {
return (<div>--</div>);
}
// 属性类型是enum要使用标签
else if (attrType === 'enum') {
return (
<Tag color={colorDict[entity][attr][String(value)]} >
<Tag color={colorDict![entity]![attr]![String(value)]} >
{t(`${entity}:v.${attr}.${value}`)}
</Tag>
)
@ -96,9 +61,37 @@ function RenderCell(props: RenderCellProps) {
)
}
function List(props: Props) {
const { data, columns, entity, disableOp = false, tableProps } = props;
const { t } = useTranslation();
export default function Render(
props: WebComponentProps<
EntityDict & BaseEntityDict,
keyof EntityDict,
false,
{
entity: string;
data: any[];
columns: (Column | string)[];
disableOp?: boolean;
tableProps?: TableProps<any>;
handleClick?: (id: string, action: string) => void;
colorDict: ColorDict<EntityDict & BaseEntityDict>;
dataSchema: StorageSchema<EntityDict>;
},
{
}
>
) {
const { methods, data: oakData } = props;
const { t } = methods;
const {
entity,
data,
columns,
disableOp = false,
tableProps,
handleClick,
colorDict,
dataSchema,
} = oakData;
const tableColumns: ColumnsType<any> = columns.map((ele) => {
let title: string = '';
let render: (value: any, row: any) => React.ReactNode = () => <></>;
@ -109,10 +102,10 @@ function List(props: Props) {
else {
path = ele.path;
}
const { entity: useEntity, attr, attribute } = Fn(entity, path!) || {};
const { entity: useEntity, attr, attribute } = resolutionPath(dataSchema, entity, path!) || {};
title = decodeTitle(useEntity, attr);
render = (value, row) => (
<RenderCell entity={entity} content={row} path={path!} attr={attr} attrType={attribute.type} />
<RenderCell entity={entity} content={row} path={path!} attr={attr} attrType={attribute?.type} t={t} colorDict={colorDict} />
);
const column = {
align: 'center',
@ -141,15 +134,14 @@ function List(props: Props) {
render: (value, row) => {
const id = row?.id;
const oakActions = row?.oakActions;
assert(!!oakActions, '行数据中不存在oakActions, 请禁用(disableOp:true)或添加oakActions')
return (
<ActionBtnPanel id={id} oakActions={oakActions} />
<ActionBtnPanel id={id} entity={entity} oakActions={oakActions} onClick={(id: string, action: string) => handleClick && handleClick(id, action)} />
)
}
})
}
return (
<Table dataSource={data} scroll={{ x: 2200 }} columns={tableColumns} ></Table>
<Table dataSource={data} scroll={{ x: 2200 }} columns={tableColumns} {...tableProps} ></Table>
);
}
export default List;

View File

@ -1,3 +1,7 @@
import assert from "assert";
import { EntityDict } from "oak-domain/lib/types";
import useFeatures from "../hooks/useFeatures";
import { StorageSchema } from "oak-domain/lib/types";
export function getAttributes(attributes: Record<string, any>) {
return Object.assign({}, attributes, {
@ -17,4 +21,38 @@ export function getAttributes(attributes: Record<string, any>) {
type: 'datetime',
},
});
}
export function resolutionPath(dataSchema: StorageSchema<EntityDict>, entity: string, path: string) {
let _entity = entity;
let attr: string;
assert(!path.includes('['), '数组索引不需要携带[],请使用arr.0.value')
if (!dataSchema) {
return {
entity: _entity,
attr: '',
attribute: undefined,
}
}
if (!path.includes('.')) {
attr = path;
}
else {
const strs = path.split('.');
// 最后一个肯定是属性
attr = strs.pop()!;
// 倒数第二个可能是类名可能是索引
_entity = strs.pop()!;
// 判断是否是数组索引
if (!Number.isNaN(Number(_entity))) {
_entity = strs.pop()!.split('$')[0];
}
}
const attributes = getAttributes(dataSchema[_entity as keyof typeof dataSchema].attributes);
const attribute = attributes[attr];
return {
entity: _entity,
attr,
attribute,
}
}

View File

@ -73,6 +73,7 @@
"include": [
"src/**/*.ts",
"src/**/*.tsx",
"./typings/*.d.ts"
],
"exclude": [
"node_modules",