ze-react-component-library
Version:
ZeroETP React Component Library
885 lines (795 loc) • 23.9 kB
JavaScript
import "antd/es/space/style";
import _Space from "antd/es/space";
import "antd/es/drawer/style";
import _Drawer from "antd/es/drawer";
import "antd/es/message/style";
import _message from "antd/es/message";
import "antd/es/popconfirm/style";
import _Popconfirm from "antd/es/popconfirm";
import "antd/es/button/style";
import _Button from "antd/es/button";
var __assign = this && this.__assign || function () {
__assign = Object.assign || function (t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) {
if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
}
}
return t;
};
return __assign.apply(this, arguments);
};
var __awaiter = this && this.__awaiter || function (thisArg, _arguments, P, generator) {
function adopt(value) {
return value instanceof P ? value : new P(function (resolve) {
resolve(value);
});
}
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) {
try {
step(generator.next(value));
} catch (e) {
reject(e);
}
}
function rejected(value) {
try {
step(generator["throw"](value));
} catch (e) {
reject(e);
}
}
function step(result) {
result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
}
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = this && this.__generator || function (thisArg, body) {
var _ = {
label: 0,
sent: function sent() {
if (t[0] & 1) throw t[1];
return t[1];
},
trys: [],
ops: []
},
f,
y,
t,
g;
return g = {
next: verb(0),
"throw": verb(1),
"return": verb(2)
}, typeof Symbol === "function" && (g[Symbol.iterator] = function () {
return this;
}), g;
function verb(n) {
return function (v) {
return step([n, v]);
};
}
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) {
try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0:
case 1:
t = op;
break;
case 4:
_.label++;
return {
value: op[1],
done: false
};
case 5:
_.label++;
y = op[1];
op = [0];
continue;
case 7:
op = _.ops.pop();
_.trys.pop();
continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
_ = 0;
continue;
}
if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
_.label = op[1];
break;
}
if (op[0] === 6 && _.label < t[1]) {
_.label = t[1];
t = op;
break;
}
if (t && _.label < t[2]) {
_.label = t[2];
_.ops.push(op);
break;
}
if (t[2]) _.ops.pop();
_.trys.pop();
continue;
}
op = body.call(thisArg, _);
} catch (e) {
op = [6, e];
y = 0;
} finally {
f = t = 0;
}
}
if (op[0] & 5) throw op[1];
return {
value: op[0] ? op[1] : void 0,
done: true
};
}
};
var __spreadArray = this && this.__spreadArray || function (to, from) {
for (var i = 0, il = from.length, j = to.length; i < il; i++, j++) {
to[j] = from[i];
}
return to;
};
import React, { useState, useContext, useRef } from "react";
import { useRequest } from "@umijs/hooks";
import _ from "underscore";
import flatten from "flat";
import ProProvider from "@ant-design/pro-provider";
import { EditableProTable } from "@ant-design/pro-table";
import { BetaSchemaForm } from "@ant-design/pro-form";
import { getSchemas } from "zeroetp-api-sdk";
import TsEditor from "../components/TsEditor";
import JsonEditor from "./JsonEditor";
import { customValueTypes, typePropertyOfSchema, formatWithProperty } from "../util";
import { getMeasurements, postMeasurements, deleteMeasurementsByName } from "./apis";
var tsCodeRenderer = {
render: function render(v, props) {
return (props === null || props === void 0 ? void 0 : props.value) ? /*#__PURE__*/React.createElement(TsEditor, __assign({}, props, {
readOnly: true,
height: "100px",
width: "100%"
})) : "-";
},
renderFormItem: function renderFormItem(props) {
return /*#__PURE__*/React.createElement(TsEditor, __assign({}, props === null || props === void 0 ? void 0 : props.fieldProps, {
height: "100px",
width: "100%"
}));
}
};
var optionsOfTypeColumn = __spreadArray(__spreadArray([], typePropertyOfSchema.constraints.enum), ["report"]).map(function (d) {
return {
label: typePropertyOfSchema.constraints.enumText[d] || d,
value: d
};
});
var MeasurementEditor = function MeasurementEditor() {
var _a = useState(false),
drawerVisible = _a[0],
setDrawerVisible = _a[1];
var _b = useState(),
editingRecord = _b[0],
setEditingRecord = _b[1];
var _c = useState(false),
saveLoading = _c[0],
setSaveLoading = _c[1];
var editorRef = useRef();
var values = useContext(ProProvider); // 用来自定义ValueType
// EditableProTable
var _d = useState([]),
editableKeys = _d[0],
setEditableRowKeys = _d[1];
var _e = useState({}),
codeEditorType = _e[0],
setCodeEditorType = _e[1];
var _f = useState(),
codeEditorId = _f[0],
setCodeEditorId = _f[1];
var _g = useState([]),
data = _g[0],
setData = _g[1];
var codeValuesRef = useRef({});
var formRef = useRef();
var _h = useRequest(getMeasurements, {
formatResult: function formatResult(res) {
var v = _.sortBy((res === null || res === void 0 ? void 0 : res.data) || [], "schema");
setData(v.map(function (d) {
return flatten(d, {
safe: true
});
}));
return v;
}
}),
loading = _h.loading,
originalData = _h.data,
reloadData = _h.run;
var _j = useRequest(getSchemas, {
formatResult: function formatResult(res) {
return (res === null || res === void 0 ? void 0 : res.schemas) || [];
}
}),
_k = _j.data,
schemas = _k === void 0 ? [] : _k,
schemasLoading = _j.loading;
var codeColumns = [{
dataIndex: "codeEditorType",
title: "类型",
valueEnum: {
sql: {
text: "sql"
},
js: {
text: "js"
}
},
hideInPayload: true
}, {
dataIndex: "run",
title: "run函数",
valueType: "code",
hideInForm: codeEditorType[codeEditorId] !== "js",
renderFormItem: tsCodeRenderer.renderFormItem
}, {
dataIndex: "shouldSplitGroupby",
title: "shouldSplitGroupby函数",
valueType: "code",
hideInForm: codeEditorType[codeEditorId] !== "js",
renderFormItem: tsCodeRenderer.renderFormItem
}, {
dataIndex: "sql",
title: "sql",
valueType: "code",
hideInForm: codeEditorType[codeEditorId] !== "sql"
}, {
dataIndex: "sqlLeftJoinClause",
title: "sqlLeftJoinClause",
valueType: "code",
hideInForm: codeEditorType[codeEditorId] !== "sql"
}];
var getCodeType = function getCodeType(record) {
var values = __assign(__assign({}, record), codeValuesRef.current[record._id]);
var codeIsJs = values.run || values.shouldSplitGroupby;
return codeIsJs ? "js" : "sql";
};
var onCodeCancel = function onCodeCancel(record) {
var _a;
codeValuesRef.current[record._id] = {};
var type = getCodeType(record);
setCodeEditorType(function (p) {
var _a;
return __assign(__assign({}, p), (_a = {}, _a[record._id] = type, _a));
});
(_a = formRef.current) === null || _a === void 0 ? void 0 : _a.setFieldsValue({
codeEditorType: type
});
};
var columns = [{
title: "Schema",
dataIndex: "schema",
valueType: "select",
fixed: "left",
fieldProps: {
dropdownMatchSelectWidth: false,
options: schemas === null || schemas === void 0 ? void 0 : schemas.map(function (d) {
return {
label: d.name + "\uFF08" + d._id + "\uFF09",
value: d._id
};
})
},
formItemProps: {
rules: [{
required: true,
message: "必填项"
}]
},
width: 160
}, {
title: "指标名",
dataIndex: "name",
valueType: "text",
fixed: "left",
width: 120
}, {
title: "同义词",
dataIndex: "syno",
valueType: "tag",
hideInSearch: true,
width: 200
}, {
title: "类型",
dataIndex: "type",
valueType: "select",
hideInSearch: true,
width: 120,
fieldProps: {
options: optionsOfTypeColumn
},
formItemProps: {
rules: [{
required: true,
message: "必填项"
}]
}
}, {
title: "是否可加?",
dataIndex: "is_additive",
valueType: "radio",
hideInSearch: true,
width: 120,
fieldProps: {
options: [{
label: "是",
value: true
}, {
label: "否",
value: false
}]
}
}, {
title: "代码",
hideInSearch: true,
hideInPayload: true,
width: 120,
render: function render(item, record) {
var codeIsJs = record.run || record.shouldSplitGroupby;
return /*#__PURE__*/React.createElement(BetaSchemaForm, {
layoutType: "ModalForm",
title: "\u4EE3\u7801\u8BE6\u60C5",
initialValues: record,
trigger: /*#__PURE__*/React.createElement(_Button, {
type: "link",
style: {
padding: 0
}
}, "\u70B9\u51FB\u67E5\u770B"),
modalProps: {
width: "80%",
centered: true
},
columns: [{
dataIndex: "run",
title: "run函数",
valueType: "code",
readonly: true,
hideInDescriptions: !codeIsJs,
render: tsCodeRenderer.render
}, {
dataIndex: "shouldSplitGroupby",
title: "shouldSplitGroupby函数",
valueType: "code",
readonly: true,
hideInDescriptions: !codeIsJs,
render: tsCodeRenderer.render
}, {
dataIndex: "sql",
title: "sql",
valueType: "code",
readonly: true,
hideInDescriptions: codeIsJs,
fieldProps: {
style: {
width: "100%",
overflow: "auto"
}
}
}, {
dataIndex: "sqlLeftJoinClause",
title: "sqlLeftJoinClause",
valueType: "code",
readonly: true,
hideInDescriptions: codeIsJs,
fieldProps: {
style: {
width: "100%",
overflow: "auto"
}
}
}].filter(function (d) {
return !d.hideInDescriptions;
}),
submitter: false
});
},
renderFormItem: function renderFormItem(item, _a) {
var record = _a.record;
var type = codeEditorType[record._id] || getCodeType(record);
return /*#__PURE__*/React.createElement(BetaSchemaForm, {
layoutType: "ModalForm",
title: "\u4EE3\u7801\u7F16\u8F91",
formRef: formRef,
initialValues: __assign(__assign(__assign({}, record), codeValuesRef.current[record._id]), {
codeEditorType: type
}),
trigger: /*#__PURE__*/React.createElement(_Button, {
type: "link",
style: {
padding: 0
},
onClick: function onClick() {
setCodeEditorId(record._id);
setCodeEditorType(function (p) {
var _a;
return __assign(__assign({}, p), (_a = {}, _a[record._id] = type, _a));
});
}
}, "\u70B9\u51FB\u4FEE\u6539"),
columns: codeColumns.map(function (d) {
if (d.dataIndex === "codeEditorType") {
return __assign(__assign({}, d), {
fieldProps: {
onChange: function onChange(v) {
var _a;
var values = ((_a = formRef.current) === null || _a === void 0 ? void 0 : _a.getFieldsValue()) || {};
codeValuesRef.current[record._id] = __assign(__assign({}, codeValuesRef.current[record._id] || {}), values);
setCodeEditorType(function (p) {
var _a;
return __assign(__assign({}, p), (_a = {}, _a[record._id] = v, _a));
});
}
}
});
}
return d;
}),
modalProps: {
width: "80%",
centered: true,
onCancel: function onCancel() {
onCodeCancel(record);
}
},
onFinish: function onFinish(values) {
return __awaiter(void 0, void 0, void 0, function () {
return __generator(this, function (_a) {
if (values.codeEditorType === "js") {
codeValuesRef.current[record._id] = __assign(__assign({}, values), {
sql: undefined,
sqlLeftJoinClause: undefined
});
} else {
codeValuesRef.current[record._id] = __assign(__assign({}, values), {
run: undefined,
shouldSplitGroupby: undefined
});
}
return [2
/*return*/
, true];
});
});
}
});
}
}, {
title: "基础指标",
width: 120,
dataIndex: "basePred",
hideInSearch: true,
valueType: "string",
tooltip: "【专家选项】指定此公式在智能归因功能中的结构分析所用的基础聚合指标。例:毛利率的基础聚合指标为销售额,那么毛利率公式的basePred就填销售额。"
}, {
title: "目标",
width: 120,
dataIndex: "target",
hideInSearch: true,
valueType: "number",
render: function render(v, record) {
if (typeof record.target !== "number") {
return "-";
}
return formatWithProperty({
type: record.type,
primal_type: record.primal_type
}, record.target);
}
}, {
title: "单位",
dataIndex: "unit",
width: 120,
tooltip: "例如: (元)。此字段会显示在问答的结果旁边。"
}, {
title: "数字格式",
dataIndex: "ui.formatter",
width: 120,
tooltip: "例如: 0,0.0A。格式配置详情请见使用文档"
}, {
title: "图表格式",
dataIndex: "ui.representation",
width: 120,
valueType: "select",
fieldProps: {
options: [{
label: "柱状图",
value: "column"
}, {
label: "横向柱状图",
value: "bar"
}, {
label: "折线图",
value: "line"
}, {
label: "面积图",
value: "area"
}, {
label: "饼图",
value: "pie"
}]
}
}, {
title: "说明",
dataIndex: "description",
hideInSearch: true,
width: 200
}, {
title: "操作",
width: 160,
valueType: "option",
hideInSearch: true,
hideInPayload: true,
fixed: "right",
render: function render(_text, record, _index, action) {
return [/*#__PURE__*/React.createElement("a", {
key: "editable",
onClick: function onClick() {
var _a;
(_a = action === null || action === void 0 ? void 0 : action.startEditable) === null || _a === void 0 ? void 0 : _a.call(action, record._id);
}
}, "\u7F16\u8F91"), /*#__PURE__*/React.createElement("a", {
key: "expert",
onClick: function onClick() {
setDrawerVisible(true);
setEditingRecord(record);
}
}, "\u4E13\u5BB6"), /*#__PURE__*/React.createElement(_Popconfirm, {
title: "\u662F\u5426\u786E\u5B9A\u5220\u9664",
key: "delete",
onConfirm: function onConfirm() {
return __awaiter(void 0, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
return [4
/*yield*/
, deleteMeasurementsByName(record)];
case 1:
_a.sent();
reloadData();
return [2
/*return*/
];
}
});
});
}
}, /*#__PURE__*/React.createElement(_Button, {
type: "link",
danger: true,
style: {
padding: 0
}
}, "\u5220\u9664"))];
}
}];
var onExpertCancel = function onExpertCancel() {
setDrawerVisible(false);
};
var getPayload = function getPayload(record) {
if (!record) {
return {};
}
var payload = {};
Object.keys(record).forEach(function (k) {
var _a;
var v = (_a = record[k]) !== null && _a !== void 0 ? _a : "";
payload[k] = ("" + v).trim() === "" ? undefined : v;
});
var finalPayload = flatten.unflatten(payload);
if ("index" in finalPayload) {
delete finalPayload._id;
delete finalPayload[finalPayload.index];
delete finalPayload.index;
}
return finalPayload;
};
var onSave = function onSave(rowKey, d) {
return __awaiter(void 0, void 0, void 0, function () {
var target, record, payload;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
setSaveLoading(true);
target = data.find(function (d) {
return d._id === rowKey;
});
if (!target) return [3
/*break*/
, 2];
return [4
/*yield*/
, deleteMeasurementsByName(target)];
case 1:
_a.sent();
_a.label = 2;
case 2:
record = __assign(__assign({}, flatten(d, {
safe: true
})), codeValuesRef.current[rowKey]);
payload = getPayload(record);
return [2
/*return*/
, postMeasurements(payload).then(function () {
_message.success("保存成功");
reloadData();
return true;
}).catch(function (e) {
_message.error("" + e.message); // 如果是edit模式,那么因为之前delete掉了,所以存回来
if (target) {
return postMeasurements(target);
}
return Promise.reject(e);
}).finally(function () {
setSaveLoading(false);
})];
}
});
});
};
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(ProProvider.Provider, {
value: __assign(__assign({}, values), {
valueTypeMap: customValueTypes({
name: "schema",
properties: columns.map(function (d) {
return {
name: d.dataIndex,
type: d.valueType,
primal_type: d.valueType
};
}),
type: "entity",
_id: "schema"
})
})
}, /*#__PURE__*/React.createElement(EditableProTable, {
rowKey: "_id",
scroll: {
x: columns.reduce(function (p, c) {
return p + Number(c.width);
}, 0)
},
recordCreatorProps: {
position: "bottom",
record: function record() {
return {
_id: (Math.random() * 1000000).toFixed(0)
};
}
},
loading: loading || schemasLoading,
search: {
labelWidth: "auto"
},
onReset: function onReset() {
setData(originalData);
},
onSubmit: function onSubmit(filters) {
setData(_.filter(originalData, function (item) {
var keys = Object.keys(filters);
var res = true;
keys.forEach(function (k) {
var _a;
res = res && ((_a = item[k]) === null || _a === void 0 ? void 0 : _a.includes(filters[k]));
});
return res;
}));
},
columns: columns,
value: data,
editable: {
type: "multiple",
editableKeys: editableKeys,
onCancel: function onCancel(rowKey, d, record) {
return __awaiter(void 0, void 0, void 0, function () {
return __generator(this, function (_a) {
onCodeCancel(record);
return [2
/*return*/
, true];
});
});
},
onSave: onSave,
onChange: setEditableRowKeys
}
})), /*#__PURE__*/React.createElement(_Drawer, {
open: drawerVisible,
width: "90%",
maskClosable: false,
onClose: function onClose(e) {
// 取消按esc退出弹窗
if (e.type === "keydown") {
return;
}
onExpertCancel();
},
title: "\u6307\u6807\u7F16\u8F91-" + (editingRecord === null || editingRecord === void 0 ? void 0 : editingRecord.name),
destroyOnClose: true,
footer: /*#__PURE__*/React.createElement("div", {
style: {
display: "flex",
flexDirection: "row-reverse"
}
}, /*#__PURE__*/React.createElement(_Space, null, /*#__PURE__*/React.createElement(_Button, {
onClick: function onClick() {
onExpertCancel();
}
}, "\u53D6\u6D88"), /*#__PURE__*/React.createElement(_Button, {
type: "primary",
onClick: function onClick() {
return __awaiter(void 0, void 0, void 0, function () {
var errors, record, codeIsJs, codeIsSql;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (!editorRef.current) return [3
/*break*/
, 3];
return [4
/*yield*/
, editorRef.current.validate()];
case 1:
errors = _a.sent();
if (errors && errors.length > 0) {
_message.error("校验不通过,请检查!");
return [2
/*return*/
];
}
record = editorRef.current.get();
codeIsJs = record.run || record.shouldSplitGroupby;
codeIsSql = record.sql || record.sqlLeftJoinClause;
if (codeIsJs && codeIsSql) {
_message.error("js\u76F8\u5173\u5B57\u6BB5\uFF08run\u3001shouldSplitGroupby\uFF09\u6216sql\u76F8\u5173\u5B57\u6BB5\uFF08sql\u3001sqlLeftJoinClause\uFF09\n \u4E24\u7EC4\u5B57\u6BB5\u4E0D\u80FD\u540C\u65F6\u5B58\u5728\uFF0C\u8BF7\u68C0\u67E5\uFF01");
return [2
/*return*/
];
}
return [4
/*yield*/
, onSave(editingRecord._id, record)];
case 2:
_a.sent();
setDrawerVisible(false);
_a.label = 3;
case 3:
return [2
/*return*/
];
}
});
});
},
loading: saveLoading
}, "\u786E\u5B9A")))
}, /*#__PURE__*/React.createElement(JsonEditor, {
value: getPayload(editingRecord),
editorRef: editorRef,
editable: true,
isCreate: editingRecord === null
})));
};
export default MeasurementEditor;