mirror of
https://gitee.com/baidu/amis.git
synced 2024-11-30 02:48:55 +08:00
Merge branch 'baidu:master' into master
This commit is contained in:
commit
e389050762
@ -534,60 +534,85 @@ Cards 模式支持 [Cards](./cards) 中的所有功能。
|
||||
|
||||
## 查询条件表单
|
||||
|
||||
大部分表格展示有对数据进行检索的需求,CRUD 自身支持通过配置`filter`,实现查询条件过滤表单
|
||||
大部分表格展示有对数据进行检索的需求,CRUD 自身支持通过配置`filter`,实现查询条件过滤表单。`filter` 配置实际上同 [Form](./form/index) 组件,因此支持绝大部分`form`的功能。
|
||||
|
||||
`filter` 配置实际上同 [Form](./form/index) 组件,因此支持绝大部分`form`的功能。
|
||||
在条件搜索区的 `Engine` 输入框中输入任意值查询会发现结果中 `ID` 为 1 - 3 的 `Rendering engine` 列因为返回值中没有对应字段值,被错误填入了与 `filter` 中相同 `name` 的字段值,这是因为表格 Cell 通过[数据链](../../docs/concepts/datascope-and-datachain)获取到了上层数据域 `filter` 中相同字段的数据值。这种情况可以在 CRUD `columns` 对应列配置`"canAccessSuperData": false`禁止访问父级数据域(比如: `Platform`列)。
|
||||
|
||||
```schema: scope="body"
|
||||
{
|
||||
"type": "crud",
|
||||
"name": "crud",
|
||||
"syncLocation": false,
|
||||
"api": "/api/mock2/sample",
|
||||
"filter": {
|
||||
"api": "/api/mock2/crud/table4",
|
||||
"filter": {
|
||||
"debug": true,
|
||||
"title": "条件搜索",
|
||||
"body": [
|
||||
{
|
||||
"type": "flex",
|
||||
"justify": "space-between",
|
||||
"alignItems": "center",
|
||||
"items": [
|
||||
"type": "group",
|
||||
"body": [
|
||||
{
|
||||
"type": "input-text",
|
||||
"name": "keywords",
|
||||
"label": "关键字",
|
||||
"clearable": true,
|
||||
"placeholder": "通过关键字搜索",
|
||||
"size": "sm"
|
||||
},
|
||||
{
|
||||
"type": "button",
|
||||
"actionType": "drawer",
|
||||
"icon": "fa fa-plus",
|
||||
"label": "创建记录",
|
||||
"target": "crud",
|
||||
"closeOnOutside": true,
|
||||
"drawer": {
|
||||
"title": "创建记录",
|
||||
"body": {
|
||||
"type": "form",
|
||||
"api": "post:/api/mock2/sample",
|
||||
"body": [
|
||||
{
|
||||
"type": "input-text",
|
||||
"name": "engine",
|
||||
"label": "Engine"
|
||||
},
|
||||
{
|
||||
"type": "input-text",
|
||||
"name": "browser",
|
||||
"label": "Browser"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
"type": "input-text",
|
||||
"name": "engine",
|
||||
"label": "Engine",
|
||||
"clearable": true,
|
||||
"size": "sm"
|
||||
},
|
||||
{
|
||||
"type": "input-text",
|
||||
"name": "platform",
|
||||
"label": "Platform",
|
||||
"clearable": true,
|
||||
"size": "sm"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
],
|
||||
actions: [
|
||||
{
|
||||
"type": "button",
|
||||
"actionType": "drawer",
|
||||
"icon": "fa fa-plus",
|
||||
"label": "创建记录",
|
||||
"target": "crud",
|
||||
"closeOnOutside": true,
|
||||
"drawer": {
|
||||
"title": "创建记录",
|
||||
"body": {
|
||||
"type": "form",
|
||||
"api": "post:/api/mock2/sample",
|
||||
"body": [
|
||||
{
|
||||
"type": "input-text",
|
||||
"name": "engine",
|
||||
"label": "Engine"
|
||||
},
|
||||
{
|
||||
"type": "input-text",
|
||||
"name": "browser",
|
||||
"label": "Browser"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "reset",
|
||||
"label": "重置"
|
||||
},
|
||||
{
|
||||
"type": "submit",
|
||||
"level": "primary",
|
||||
"label": "查询"
|
||||
}
|
||||
]
|
||||
},
|
||||
"columns": [
|
||||
@ -605,7 +630,8 @@ Cards 模式支持 [Cards](./cards) 中的所有功能。
|
||||
},
|
||||
{
|
||||
"name": "platform",
|
||||
"label": "Platform(s)"
|
||||
"label": "Platform(s)",
|
||||
"canAccessSuperData": false
|
||||
},
|
||||
{
|
||||
"name": "version",
|
||||
|
@ -2,5 +2,5 @@
|
||||
"packages": [
|
||||
"packages/*"
|
||||
],
|
||||
"version": "2.1.1-beta.2"
|
||||
"version": "2.1.1-beta.3"
|
||||
}
|
431
mock/cfc/mock/crud/table4.js
Normal file
431
mock/cfc/mock/crud/table4.js
Normal file
@ -0,0 +1,431 @@
|
||||
/** 部分列字段没有没回值的CASE */
|
||||
module.exports = function (req, res) {
|
||||
const perPage = 10;
|
||||
const page = req.query.page || 1;
|
||||
let items = data.concat();
|
||||
|
||||
if (req.query.keywords) {
|
||||
const keywords = req.query.keywords;
|
||||
items = items.filter(function (item) {
|
||||
return ~JSON.stringify(item).indexOf(keywords);
|
||||
});
|
||||
}
|
||||
|
||||
const validQueryKey = Object.keys(req.query).filter(
|
||||
item => item !== 'keywords' && req.query[item] != null
|
||||
);
|
||||
|
||||
if (validQueryKey.length > 0) {
|
||||
items = items.filter(item =>
|
||||
validQueryKey.every(key => !!~req.query[key].indexOf(item[key] || ''))
|
||||
);
|
||||
}
|
||||
|
||||
const ret = {
|
||||
status: 0,
|
||||
msg: 'ok',
|
||||
data: {
|
||||
count: items.length,
|
||||
rows: items.concat().splice((page - 1) * perPage, perPage)
|
||||
}
|
||||
};
|
||||
|
||||
res.json(ret);
|
||||
};
|
||||
|
||||
const data = [
|
||||
{
|
||||
browser: 'Internet Explorer 4.0',
|
||||
platform: 'Win 95+',
|
||||
version: '4',
|
||||
grade: 'X'
|
||||
},
|
||||
{
|
||||
browser: 'Internet Explorer 5.0',
|
||||
platform: 'Win 95+',
|
||||
version: '5',
|
||||
grade: 'C'
|
||||
},
|
||||
{
|
||||
browser: 'Internet Explorer 5.5',
|
||||
platform: 'Win 95+',
|
||||
version: '5.5',
|
||||
grade: 'A'
|
||||
},
|
||||
{
|
||||
engine: 'Trident',
|
||||
browser: 'Internet Explorer 6',
|
||||
version: '6',
|
||||
grade: 'A'
|
||||
},
|
||||
{
|
||||
engine: 'Trident',
|
||||
browser: 'Internet Explorer 7',
|
||||
version: '7',
|
||||
grade: 'A'
|
||||
},
|
||||
{
|
||||
engine: 'Trident',
|
||||
browser: 'AOL browser (AOL desktop)',
|
||||
platform: 'Win XP',
|
||||
grade: 'A'
|
||||
},
|
||||
{
|
||||
engine: 'Gecko',
|
||||
browser: 'Firefox 1.0',
|
||||
platform: 'Win 98+ / OSX.2+',
|
||||
grade: 'A'
|
||||
},
|
||||
{
|
||||
engine: 'Gecko',
|
||||
browser: 'Firefox 1.5',
|
||||
platform: 'Win 98+ / OSX.2+',
|
||||
version: '1.8'
|
||||
},
|
||||
{
|
||||
engine: 'Gecko',
|
||||
browser: 'Firefox 2.0',
|
||||
platform: 'Win 98+ / OSX.2+',
|
||||
version: '1.8'
|
||||
},
|
||||
{
|
||||
engine: 'Gecko',
|
||||
browser: 'Firefox 3.0',
|
||||
platform: 'Win 2k+ / OSX.3+',
|
||||
version: '1.9',
|
||||
grade: 'A'
|
||||
},
|
||||
{
|
||||
engine: 'Gecko',
|
||||
browser: 'Camino 1.0',
|
||||
platform: 'OSX.2+',
|
||||
version: '1.8',
|
||||
grade: 'A'
|
||||
},
|
||||
{
|
||||
engine: 'Gecko',
|
||||
browser: 'Camino 1.5',
|
||||
platform: 'OSX.3+',
|
||||
version: '1.8',
|
||||
grade: 'A'
|
||||
},
|
||||
{
|
||||
engine: 'Gecko',
|
||||
browser: 'Netscape 7.2',
|
||||
platform: 'Win 95+ / Mac OS 8.6-9.2',
|
||||
version: '1.7',
|
||||
grade: 'A'
|
||||
},
|
||||
{
|
||||
engine: 'Gecko',
|
||||
browser: 'Netscape Browser 8',
|
||||
platform: 'Win 98SE+',
|
||||
version: '1.7',
|
||||
grade: 'A'
|
||||
},
|
||||
{
|
||||
engine: 'Gecko',
|
||||
browser: 'Netscape Navigator 9',
|
||||
platform: 'Win 98+ / OSX.2+',
|
||||
version: '1.8',
|
||||
grade: 'A'
|
||||
},
|
||||
{
|
||||
engine: 'Gecko',
|
||||
browser: 'Mozilla 1.0',
|
||||
platform: 'Win 95+ / OSX.1+',
|
||||
version: '1',
|
||||
grade: 'A'
|
||||
},
|
||||
{
|
||||
engine: 'Gecko',
|
||||
browser: 'Mozilla 1.1',
|
||||
platform: 'Win 95+ / OSX.1+',
|
||||
version: '1.1',
|
||||
grade: 'A'
|
||||
},
|
||||
{
|
||||
engine: 'Gecko',
|
||||
browser: 'Mozilla 1.2',
|
||||
platform: 'Win 95+ / OSX.1+',
|
||||
version: '1.2',
|
||||
grade: 'A'
|
||||
},
|
||||
{
|
||||
engine: 'Gecko',
|
||||
browser: 'Mozilla 1.3',
|
||||
platform: 'Win 95+ / OSX.1+',
|
||||
version: '1.3',
|
||||
grade: 'A'
|
||||
},
|
||||
{
|
||||
engine: 'Gecko',
|
||||
browser: 'Mozilla 1.4',
|
||||
platform: 'Win 95+ / OSX.1+',
|
||||
version: '1.4',
|
||||
grade: 'A'
|
||||
},
|
||||
{
|
||||
engine: 'Gecko',
|
||||
browser: 'Mozilla 1.5',
|
||||
platform: 'Win 95+ / OSX.1+',
|
||||
version: '1.5',
|
||||
grade: 'A'
|
||||
},
|
||||
{
|
||||
engine: 'Gecko',
|
||||
browser: 'Mozilla 1.6',
|
||||
platform: 'Win 95+ / OSX.1+',
|
||||
version: '1.6',
|
||||
grade: 'A'
|
||||
},
|
||||
{
|
||||
engine: 'Gecko',
|
||||
browser: 'Mozilla 1.7',
|
||||
platform: 'Win 98+ / OSX.1+',
|
||||
version: '1.7',
|
||||
grade: 'A'
|
||||
},
|
||||
{
|
||||
engine: 'Gecko',
|
||||
browser: 'Mozilla 1.8',
|
||||
platform: 'Win 98+ / OSX.1+',
|
||||
version: '1.8',
|
||||
grade: 'A'
|
||||
},
|
||||
{
|
||||
engine: 'Gecko',
|
||||
browser: 'Seamonkey 1.1',
|
||||
platform: 'Win 98+ / OSX.2+',
|
||||
version: '1.8',
|
||||
grade: 'A'
|
||||
},
|
||||
{
|
||||
engine: 'Gecko',
|
||||
browser: 'Epiphany 2.20',
|
||||
platform: 'Gnome',
|
||||
version: '1.8',
|
||||
grade: 'A'
|
||||
},
|
||||
{
|
||||
engine: 'Webkit',
|
||||
browser: 'Safari 1.2',
|
||||
platform: 'OSX.3',
|
||||
version: '125.5',
|
||||
grade: 'A'
|
||||
},
|
||||
{
|
||||
engine: 'Webkit',
|
||||
browser: 'Safari 1.3',
|
||||
platform: 'OSX.3',
|
||||
version: '312.8',
|
||||
grade: 'A'
|
||||
},
|
||||
{
|
||||
engine: 'Webkit',
|
||||
browser: 'Safari 2.0',
|
||||
platform: 'OSX.4+',
|
||||
version: '419.3',
|
||||
grade: 'A'
|
||||
},
|
||||
{
|
||||
engine: 'Webkit',
|
||||
browser: 'Safari 3.0',
|
||||
platform: 'OSX.4+',
|
||||
version: '522.1',
|
||||
grade: 'A'
|
||||
},
|
||||
{
|
||||
engine: 'Webkit',
|
||||
browser: 'OmniWeb 5.5',
|
||||
platform: 'OSX.4+',
|
||||
version: '420',
|
||||
grade: 'A'
|
||||
},
|
||||
{
|
||||
engine: 'Webkit',
|
||||
browser: 'iPod Touch / iPhone',
|
||||
platform: 'iPod',
|
||||
version: '420.1',
|
||||
grade: 'A'
|
||||
},
|
||||
{
|
||||
engine: 'Webkit',
|
||||
browser: 'S60',
|
||||
platform: 'S60',
|
||||
version: '413',
|
||||
grade: 'A'
|
||||
},
|
||||
{
|
||||
engine: 'Presto',
|
||||
browser: 'Opera 7.0',
|
||||
platform: 'Win 95+ / OSX.1+',
|
||||
version: '-',
|
||||
grade: 'A'
|
||||
},
|
||||
{
|
||||
engine: 'Presto',
|
||||
browser: 'Opera 7.5',
|
||||
platform: 'Win 95+ / OSX.2+',
|
||||
version: '-',
|
||||
grade: 'A'
|
||||
},
|
||||
{
|
||||
engine: 'Presto',
|
||||
browser: 'Opera 8.0',
|
||||
platform: 'Win 95+ / OSX.2+',
|
||||
version: '-',
|
||||
grade: 'A'
|
||||
},
|
||||
{
|
||||
engine: 'Presto',
|
||||
browser: 'Opera 8.5',
|
||||
platform: 'Win 95+ / OSX.2+',
|
||||
version: '-',
|
||||
grade: 'A'
|
||||
},
|
||||
{
|
||||
engine: 'Presto',
|
||||
browser: 'Opera 9.0',
|
||||
platform: 'Win 95+ / OSX.3+',
|
||||
version: '-',
|
||||
grade: 'A'
|
||||
},
|
||||
{
|
||||
engine: 'Presto',
|
||||
browser: 'Opera 9.2',
|
||||
platform: 'Win 88+ / OSX.3+',
|
||||
version: '-',
|
||||
grade: 'A'
|
||||
},
|
||||
{
|
||||
engine: 'Presto',
|
||||
browser: 'Opera 9.5',
|
||||
platform: 'Win 88+ / OSX.3+',
|
||||
version: '-',
|
||||
grade: 'A'
|
||||
},
|
||||
{
|
||||
engine: 'Presto',
|
||||
browser: 'Opera for Wii',
|
||||
platform: 'Wii',
|
||||
version: '-',
|
||||
grade: 'A'
|
||||
},
|
||||
{
|
||||
engine: 'Presto',
|
||||
browser: 'Nokia N800',
|
||||
platform: 'N800',
|
||||
version: '-',
|
||||
grade: 'A'
|
||||
},
|
||||
{
|
||||
engine: 'Presto',
|
||||
browser: 'Nintendo DS browser',
|
||||
platform: 'Nintendo DS',
|
||||
version: '8.5',
|
||||
grade: 'C'
|
||||
},
|
||||
{
|
||||
engine: 'KHTML',
|
||||
browser: 'Konqureror 3.1',
|
||||
platform: 'KDE 3.1',
|
||||
version: '3.1',
|
||||
grade: 'C'
|
||||
},
|
||||
{
|
||||
engine: 'KHTML',
|
||||
browser: 'Konqureror 3.3',
|
||||
platform: 'KDE 3.3',
|
||||
version: '3.3',
|
||||
grade: 'A'
|
||||
},
|
||||
{
|
||||
engine: 'KHTML',
|
||||
browser: 'Konqureror 3.5',
|
||||
platform: 'KDE 3.5',
|
||||
version: '3.5',
|
||||
grade: 'A'
|
||||
},
|
||||
{
|
||||
engine: 'Tasman',
|
||||
browser: 'Internet Explorer 4.5',
|
||||
platform: 'Mac OS 8-9',
|
||||
version: '-',
|
||||
grade: 'X'
|
||||
},
|
||||
{
|
||||
engine: 'Tasman',
|
||||
browser: 'Internet Explorer 5.1',
|
||||
platform: 'Mac OS 7.6-9',
|
||||
version: '1',
|
||||
grade: 'C'
|
||||
},
|
||||
{
|
||||
engine: 'Tasman',
|
||||
browser: 'Internet Explorer 5.2',
|
||||
platform: 'Mac OS 8-X',
|
||||
version: '1',
|
||||
grade: 'C'
|
||||
},
|
||||
{
|
||||
engine: 'Misc',
|
||||
browser: 'NetFront 3.1',
|
||||
platform: 'Embedded devices',
|
||||
version: '-',
|
||||
grade: 'C'
|
||||
},
|
||||
{
|
||||
engine: 'Misc',
|
||||
browser: 'NetFront 3.4',
|
||||
platform: 'Embedded devices',
|
||||
version: '-',
|
||||
grade: 'A'
|
||||
},
|
||||
{
|
||||
engine: 'Misc',
|
||||
browser: 'Dillo 0.8',
|
||||
platform: 'Embedded devices',
|
||||
version: '-',
|
||||
grade: 'X'
|
||||
},
|
||||
{
|
||||
engine: 'Misc',
|
||||
browser: 'Links',
|
||||
platform: 'Text only',
|
||||
version: '-',
|
||||
grade: 'X'
|
||||
},
|
||||
{
|
||||
engine: 'Misc',
|
||||
browser: 'Lynx',
|
||||
platform: 'Text only',
|
||||
version: '-',
|
||||
grade: 'X'
|
||||
},
|
||||
{
|
||||
engine: 'Misc',
|
||||
browser: 'IE Mobile',
|
||||
platform: 'Windows Mobile 6',
|
||||
version: '-',
|
||||
grade: 'C'
|
||||
},
|
||||
{
|
||||
engine: 'Misc',
|
||||
browser: 'PSP browser',
|
||||
platform: 'PSP',
|
||||
version: '-',
|
||||
grade: 'C'
|
||||
},
|
||||
{
|
||||
engine: 'Other browsers',
|
||||
browser: 'All others',
|
||||
platform: '-',
|
||||
version: '-',
|
||||
grade: 'U'
|
||||
}
|
||||
].map(function (item, index) {
|
||||
return Object.assign({}, item, {
|
||||
id: index + 1
|
||||
});
|
||||
});
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "amis-core",
|
||||
"version": "2.1.1-beta.2",
|
||||
"version": "2.1.1-beta.3",
|
||||
"description": "amis-core",
|
||||
"main": "lib/index.js",
|
||||
"module": "esm/index.js",
|
||||
|
@ -547,7 +547,21 @@ export const CRUDStore = ServiceStore.named('CRUDStore')
|
||||
}
|
||||
|
||||
import('papaparse').then((papaparse: any) => {
|
||||
const csvText = papaparse.unparse(items);
|
||||
// 将数据里的对象转成 json 字符串,不然输出的 csv 没法显示
|
||||
const csvData = [];
|
||||
for (const row of items) {
|
||||
const rowData = {} as {[key: string]: any};
|
||||
for (const key in row) {
|
||||
const value = row[key];
|
||||
if (typeof value === 'object') {
|
||||
rowData[key] = JSON.stringify(value);
|
||||
} else {
|
||||
rowData[key] = value;
|
||||
}
|
||||
}
|
||||
csvData.push(rowData);
|
||||
}
|
||||
const csvText = papaparse.unparse(csvData);
|
||||
if (csvText) {
|
||||
const blob = new Blob(
|
||||
// 加上 BOM 这样 Excel 打开的时候就不会乱码
|
||||
|
@ -1472,10 +1472,14 @@ export function getScrollbarWidth() {
|
||||
}
|
||||
|
||||
// 后续改用 FormulaExec['formula']
|
||||
function resolveValueByName(data: any, name?: string) {
|
||||
function resolveValueByName(
|
||||
data: any,
|
||||
name?: string,
|
||||
canAccessSuper?: boolean
|
||||
) {
|
||||
return isPureVariable(name)
|
||||
? resolveVariableAndFilter(name, data)
|
||||
: resolveVariable(name, data);
|
||||
: resolveVariable(name, data, canAccessSuper);
|
||||
}
|
||||
|
||||
// 统一的获取 value 值方法
|
||||
@ -1486,10 +1490,13 @@ export function getPropValue<
|
||||
data?: any;
|
||||
defaultValue?: any;
|
||||
}
|
||||
>(props: T, getter?: (props: T) => any) {
|
||||
>(props: T, getter?: (props: T) => any, canAccessSuper?: boolean) {
|
||||
const {name, value, data, defaultValue} = props;
|
||||
return (
|
||||
value ?? getter?.(props) ?? resolveValueByName(data, name) ?? defaultValue
|
||||
value ??
|
||||
getter?.(props) ??
|
||||
resolveValueByName(data, name, canAccessSuper) ??
|
||||
defaultValue
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1,14 +1,22 @@
|
||||
import {Evaluator, parse} from 'amis-formula';
|
||||
import {getVariable} from './getVariable';
|
||||
|
||||
export function resolveVariable(path?: string, data: any = {}): any {
|
||||
export function resolveVariable(
|
||||
path?: string,
|
||||
data: any = {},
|
||||
canAccessSuper?: boolean
|
||||
): any {
|
||||
if (path === '&' || path == '$$') {
|
||||
return data;
|
||||
} else if (!path || typeof path !== 'string') {
|
||||
return undefined;
|
||||
} else if (!~path.indexOf(':')) {
|
||||
// 简单用法直接用 getVariable
|
||||
return getVariable(data, path[0] === '$' ? path.substring(1) : path);
|
||||
return getVariable(
|
||||
data,
|
||||
path[0] === '$' ? path.substring(1) : path,
|
||||
canAccessSuper
|
||||
);
|
||||
}
|
||||
|
||||
// window:xxx ls:xxx.xxx
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "amis-formula",
|
||||
"version": "2.1.1-beta.2",
|
||||
"version": "2.1.1-beta.3",
|
||||
"description": "负责 amis 里面的表达式实现,内置公式,编辑器等",
|
||||
"main": "lib/index.js",
|
||||
"types": "lib/index.d.ts",
|
||||
|
@ -3,7 +3,7 @@
|
||||
"main": "lib/index.js",
|
||||
"module": "esm/index.js",
|
||||
"types": "lib/index.d.ts",
|
||||
"version": "2.1.1-beta.2",
|
||||
"version": "2.1.1-beta.3",
|
||||
"description": "",
|
||||
"scripts": {
|
||||
"build": "npm run clean-dist && NODE_ENV=production rollup -c ",
|
||||
@ -33,7 +33,7 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"amis-core": "^2.1.1-beta.2",
|
||||
"amis-core": "^2.1.1-beta.3",
|
||||
"amis-formula": "^2.1.0",
|
||||
"classnames": "2.3.1",
|
||||
"codemirror": "^5.63.0",
|
||||
|
@ -10,19 +10,14 @@
|
||||
@keyframes modalIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
bottom: -999px;
|
||||
transform: translate3d(0, -300px, 0) scale(0.2);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes modalOut {
|
||||
to {
|
||||
opacity: 0;
|
||||
opacity: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
bottom: -999px;
|
||||
transform: translate3d(0, -300px, 0) scale(0.2);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -961,9 +961,7 @@
|
||||
}
|
||||
|
||||
> .#{$ns}Table-fixedTop {
|
||||
.#{$ns}Table-fixedTop-shadow {
|
||||
display: none;
|
||||
}
|
||||
display: none;
|
||||
}
|
||||
|
||||
> .#{$ns}Table-footToolbar {
|
||||
|
@ -277,7 +277,7 @@ exports[`Renderer:range with min & max & step & joinValues 1`] = `
|
||||
class="cxd-TplField"
|
||||
>
|
||||
<span>
|
||||
The form
|
||||
表单
|
||||
</span>
|
||||
</span>
|
||||
</h3>
|
||||
@ -293,18 +293,6 @@ exports[`Renderer:range with min & max & step & joinValues 1`] = `
|
||||
style="display: none;"
|
||||
type="submit"
|
||||
/>
|
||||
<pre>
|
||||
<code
|
||||
class="cxd-Form--debug"
|
||||
>
|
||||
{
|
||||
"range": {
|
||||
"min": 0.2,
|
||||
"max": 0.8
|
||||
}
|
||||
}
|
||||
</code>
|
||||
</pre>
|
||||
<div
|
||||
class="cxd-Form-item cxd-Form-item--normal"
|
||||
data-role="form-item"
|
||||
@ -634,6 +622,22 @@ exports[`Renderer:range with min & max & step & joinValues 1`] = `
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div
|
||||
class="cxd-Panel-footerWrap"
|
||||
>
|
||||
<div
|
||||
class="cxd-Panel-btnToolbar cxd-Panel-footer"
|
||||
>
|
||||
<button
|
||||
class="cxd-Button cxd-Button--primary"
|
||||
type="submit"
|
||||
>
|
||||
<span>
|
||||
Submit
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="resize-sensor"
|
||||
style="position: absolute; left: 0px; top: 0px; right: 0px; bottom: 0px; overflow: scroll; z-index: -1; visibility: hidden;"
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React = require('react');
|
||||
import {render, fireEvent} from '@testing-library/react';
|
||||
import {render, fireEvent, screen, waitFor} from '@testing-library/react';
|
||||
import '../../../src';
|
||||
import {render as amisRender} from '../../../src';
|
||||
import {makeEnv, wait} from '../../helper';
|
||||
@ -233,13 +233,15 @@ test('Renderer:range with tooltipVisible & tooltipPlacement', async () => {
|
||||
});
|
||||
|
||||
test('Renderer:range with min & max & step & joinValues', async () => {
|
||||
const onSubmit = jest.fn();
|
||||
const submitBtnText = 'Submit';
|
||||
const {container} = render(
|
||||
amisRender(
|
||||
{
|
||||
type: 'form',
|
||||
debug: true,
|
||||
api: '/api/xxx',
|
||||
controls: [
|
||||
submitText: submitBtnText,
|
||||
api: '/api/mock/saveForm?waitSeconds=1',
|
||||
body: [
|
||||
{
|
||||
type: 'input-range',
|
||||
name: 'range',
|
||||
@ -250,11 +252,9 @@ test('Renderer:range with min & max & step & joinValues', async () => {
|
||||
showInput: true,
|
||||
joinValues: false
|
||||
}
|
||||
],
|
||||
title: 'The form',
|
||||
actions: []
|
||||
]
|
||||
},
|
||||
{},
|
||||
{onSubmit},
|
||||
makeEnv({})
|
||||
)
|
||||
);
|
||||
@ -280,13 +280,23 @@ test('Renderer:range with min & max & step & joinValues', async () => {
|
||||
).getAttribute('style')
|
||||
).toContain('width: 60%; left: 20%;');
|
||||
|
||||
expect((container.querySelector('.cxd-Form--debug') as Element).innerHTML)
|
||||
.toBe(`{
|
||||
"range": {
|
||||
"min": 0.2,
|
||||
"max": 0.8
|
||||
}
|
||||
}`);
|
||||
await wait(500);
|
||||
const submitBtn = screen.getByRole('button', {name: submitBtnText});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(submitBtn).toBeInTheDocument();
|
||||
});
|
||||
fireEvent.click(submitBtn);
|
||||
|
||||
await wait(500);
|
||||
const formData = onSubmit.mock.calls[0][0];
|
||||
expect(onSubmit).toHaveBeenCalled();
|
||||
expect(formData).toEqual({
|
||||
range: {
|
||||
min: 0.2,
|
||||
max: 0.8
|
||||
}
|
||||
});
|
||||
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "amis",
|
||||
"version": "2.1.1-beta.2",
|
||||
"version": "2.1.1-beta.3",
|
||||
"description": "一种MIS页面生成工具",
|
||||
"main": "lib/index.js",
|
||||
"module": "esm/index.js",
|
||||
@ -40,8 +40,8 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"amis-core": "^2.1.1-beta.2",
|
||||
"amis-ui": "^2.1.1-beta.2",
|
||||
"amis-core": "^2.1.1-beta.3",
|
||||
"amis-ui": "^2.1.1-beta.3",
|
||||
"ansi-to-react": "^6.1.6",
|
||||
"attr-accept": "2.2.2",
|
||||
"blueimp-canvastoblob": "2.1.0",
|
||||
|
@ -1092,10 +1092,12 @@ export default class FormTable extends React.Component<TableProps, TableState> {
|
||||
*/
|
||||
@autobind
|
||||
handlePristineChange(data: Record<string, any>, rowIndex: string) {
|
||||
const {needConfirm} = this.props;
|
||||
const index = Number(rowIndex);
|
||||
|
||||
this.setState(
|
||||
prevState => {
|
||||
const items = cloneDeep(prevState.items);
|
||||
const index = Number(rowIndex);
|
||||
|
||||
if (
|
||||
Number.isInteger(index) &&
|
||||
@ -1109,7 +1111,11 @@ export default class FormTable extends React.Component<TableProps, TableState> {
|
||||
return null;
|
||||
},
|
||||
() => {
|
||||
this.emitValue();
|
||||
if (needConfirm === false) {
|
||||
this.emitValue();
|
||||
} else {
|
||||
Number.isInteger(index) && this.startEdit(index, true);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -66,6 +66,7 @@ export class TableCell extends React.Component<RendererProps> {
|
||||
className: innerClassName,
|
||||
type: (column && column.type) || 'plain'
|
||||
};
|
||||
const canAccessSuperData = schema?.canAccessSuperData !== false;
|
||||
|
||||
// 如果本来就是 type 为 button,不要删除,其他情况下都应该删除。
|
||||
if (schema.type !== 'button' && schema.type !== 'dropdown-button') {
|
||||
@ -77,7 +78,8 @@ export class TableCell extends React.Component<RendererProps> {
|
||||
: render('field', schema, {
|
||||
...omit(rest, Object.keys(schema)),
|
||||
inputOnly: true,
|
||||
value,
|
||||
/** value没有返回值时设置默认值,避免错误获取到父级数据域的值 */
|
||||
value: canAccessSuperData ? value : value ?? '',
|
||||
data
|
||||
});
|
||||
|
||||
|
@ -165,6 +165,11 @@ export type TableColumnObject = {
|
||||
* 是否唯一, 只有在 inputTable 里面才有用
|
||||
*/
|
||||
unique?: boolean;
|
||||
|
||||
/**
|
||||
* 表格列单元格是否可以获取父级数据域值,默认为true,该配置对当前列内单元格生效
|
||||
*/
|
||||
canAccessSuperData?: boolean;
|
||||
};
|
||||
|
||||
export type TableColumnWithType = SchemaObject & TableColumnObject;
|
||||
@ -293,6 +298,11 @@ export interface TableSchema extends BaseSchema {
|
||||
* 开启查询区域,会根据列元素的searchable属性值,自动生成查询条件表单
|
||||
*/
|
||||
autoGenerateFilter?: boolean;
|
||||
|
||||
/**
|
||||
* 表格是否可以获取父级数据域值,默认为false
|
||||
*/
|
||||
canAccessSuperData?: boolean;
|
||||
}
|
||||
|
||||
export interface TableProps extends RendererProps {
|
||||
@ -606,7 +616,6 @@ export default class Table extends React.Component<TableProps, object> {
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const {autoFillHeight, classPrefix: ns} = this.props;
|
||||
const currentNode = findDOMNode(this) as HTMLElement;
|
||||
// 获取小于所有子元素高度之和的父元素
|
||||
let parent: HTMLElement | Window | null = getScrollParent(
|
||||
@ -633,11 +642,6 @@ export default class Table extends React.Component<TableProps, object> {
|
||||
|
||||
this.affixDetect();
|
||||
parent.addEventListener('scroll', this.affixDetect);
|
||||
if (autoFillHeight) {
|
||||
document
|
||||
.querySelector<HTMLElement>(`.${ns}Table-content`)!
|
||||
.addEventListener('scroll', this.affixDetect);
|
||||
}
|
||||
window.addEventListener('resize', this.affixDetect);
|
||||
this.updateAutoFillHeight();
|
||||
window.addEventListener('resize', this.updateAutoFillHeight);
|
||||
@ -812,15 +816,10 @@ export default class Table extends React.Component<TableProps, object> {
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
const {formItem, autoFillHeight, classPrefix: ns} = this.props;
|
||||
const {formItem} = this.props;
|
||||
|
||||
const parent = this.parentNode;
|
||||
parent && parent.removeEventListener('scroll', this.affixDetect);
|
||||
if (autoFillHeight) {
|
||||
document
|
||||
.querySelector<HTMLElement>(`.${ns}Table-content`)!
|
||||
.addEventListener('scroll', this.affixDetect);
|
||||
}
|
||||
window.removeEventListener('resize', this.affixDetect);
|
||||
window.removeEventListener('resize', this.updateAutoFillHeight);
|
||||
(this.updateTableInfoLazy as any).cancel();
|
||||
@ -1061,81 +1060,44 @@ export default class Table extends React.Component<TableProps, object> {
|
||||
|
||||
return store.selectedRows.map(item => item.data);
|
||||
}
|
||||
/**
|
||||
* 滚动重新定位Table-fixedTop
|
||||
*/
|
||||
affixDetect() {
|
||||
const {
|
||||
affixHeader,
|
||||
classPrefix: ns,
|
||||
affixOffsetTop,
|
||||
env,
|
||||
autoFillHeight
|
||||
} = this.props;
|
||||
|
||||
if (!(affixHeader || autoFillHeight) || !this.table) {
|
||||
// if (!this.props.affixHeader || !this.table || this.props.autoFillHeight) {
|
||||
affixDetect() {
|
||||
if (!this.props.affixHeader || !this.table || this.props.autoFillHeight) {
|
||||
return;
|
||||
}
|
||||
|
||||
const ns = this.props.classPrefix;
|
||||
const dom = findDOMNode(this) as HTMLElement;
|
||||
const clip = (this.table as HTMLElement).getBoundingClientRect();
|
||||
const offsetY =
|
||||
this.props.affixOffsetTop ?? this.props.env.affixOffsetTop ?? 0;
|
||||
const headingHeight =
|
||||
dom.querySelector(`.${ns}Table-heading`)?.getBoundingClientRect()
|
||||
.height || 0;
|
||||
const headerHeight =
|
||||
dom.querySelector(`.${ns}Table-headToolbar`)?.getBoundingClientRect()
|
||||
.height || 0;
|
||||
|
||||
const affixed =
|
||||
clip.top - headerHeight - headingHeight < offsetY &&
|
||||
clip.top + clip.height - 40 > offsetY;
|
||||
const affixedDom = dom.querySelector(`.${ns}Table-fixedTop`) as HTMLElement;
|
||||
const affixedShadowDom = dom.querySelector(
|
||||
`.${ns}Table-fixedTop-shadow`
|
||||
) as HTMLElement;
|
||||
const affixedDomHeight =
|
||||
getComputedStyle(affixedDom).getPropertyValue('height');
|
||||
|
||||
if (autoFillHeight) {
|
||||
//! 解决 sticky 不兼容的问题
|
||||
const tableContentDom = document.querySelector<HTMLElement>(
|
||||
`.${ns}Table-content`
|
||||
)!;
|
||||
const clip = tableContentDom.getBoundingClientRect();
|
||||
|
||||
const tableHeaderClip = affixedDom
|
||||
.querySelector(`.${ns}Table-wrapper`)!
|
||||
.getBoundingClientRect();
|
||||
const offsetHeight =
|
||||
affixedDom.getBoundingClientRect().height - tableHeaderClip.height;
|
||||
const offsetY = clip.top - offsetHeight;
|
||||
|
||||
affixedDom.style.cssText += `top: ${offsetY}px;width: ${clip.width}px`;
|
||||
|
||||
affixedDom.classList.add('in');
|
||||
} else {
|
||||
// 配置了 affixHeader
|
||||
const clip = (this.table as HTMLElement).getBoundingClientRect();
|
||||
const offsetY = affixOffsetTop ?? env.affixOffsetTop ?? 0;
|
||||
const headingHeight =
|
||||
dom.querySelector(`.${ns}Table-heading`)?.getBoundingClientRect()
|
||||
.height || 0;
|
||||
const affixedShadowDom = dom.querySelector(
|
||||
`.${ns}Table-fixedTop-shadow`
|
||||
) as HTMLElement;
|
||||
const affixed =
|
||||
clip.top - headerHeight - headingHeight < offsetY &&
|
||||
clip.top + clip.height - 40 > offsetY;
|
||||
|
||||
affixedDom.style.cssText += `top: ${offsetY}px;width: ${
|
||||
(this.table.parentNode as HTMLElement).offsetWidth
|
||||
}px`;
|
||||
affixedShadowDom.style.cssText += `top: ${affixedDomHeight};width: ${
|
||||
(this.table.parentNode as HTMLElement).offsetWidth
|
||||
}px`;
|
||||
|
||||
const preStatus = affixedDom.classList.contains('in');
|
||||
|
||||
affixed
|
||||
? affixedDom.classList.add('in')
|
||||
: affixedDom.classList.remove('in');
|
||||
|
||||
// 出现affixHeader时重新计算列表宽度
|
||||
if (!preStatus && affixed) {
|
||||
this.updateTableInfoLazy();
|
||||
}
|
||||
}
|
||||
affixedDom.style.cssText += `top: ${offsetY}px;width: ${
|
||||
(this.table.parentNode as HTMLElement).offsetWidth
|
||||
}px`;
|
||||
affixedShadowDom.style.cssText += `top: ${affixedDomHeight};width: ${
|
||||
(this.table.parentNode as HTMLElement).offsetWidth
|
||||
}px`;
|
||||
|
||||
affixed
|
||||
? affixedDom.classList.add('in')
|
||||
: affixedDom.classList.remove('in');
|
||||
// store.markHeaderAffix(clip.top < offsetY && (clip.top + clip.height - 40) > offsetY);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user