@form-create/designer
Version:
好用的Vue低代码可视化表单设计器,可以通过拖拽的方式快速创建表单,提高开发者对表单的开发效率。
499 lines (448 loc) • 14.2 kB
JavaScript
import is, {hasProperty} from '@form-create/utils/lib/type';
import {parseFn} from '@form-create/utils/lib/json';
import toCase from '@form-create/utils/lib/tocase';
import {computed, isRef, ref, unref} from 'vue';
import ZhCn from '../locale/zh-cn';
import {message} from './message';
export function makeRequiredRule() {
return {
type: 'Required', field: 'formCreate$required', title: '是否必填'
};
}
export function empty(value) {
if (value === undefined || value === null) {
return true;
}
if (Array.isArray(value) && Array.isArray(value) && !value.length) {
return true;
}
return typeof value === 'string' && !value;
}
export function addAutoKeyMap(cm) {
}
export function makeTreeOptions(pre, config, level, data = []) {
if (!config.id) {
config.id = 1;
}
level && level--;
for (let i = 0; i < 3; i++) {
const item = {
[config.label]: pre + level * 10 + (i + 1),
[config.value]: '' + config.id++,
};
if (level) {
makeTreeOptions(pre, config, level, item.children = []);
}
data.push(item);
}
return data;
}
export function makeOptionsRule(t, to) {
const options = [
{'label': t('fetch.optionsType.struct'), 'value': 2},
{'label': t('fetch.optionsType.fetch'), 'value': 1},
];
const control = [
{
value: 1,
rule: [
{
type: 'FetchConfig',
field: 'formCreateEffect>fetch',
props: {
to
}
}
]
},
{
value: 2,
rule: [
{
type: 'TableOptions',
field: 'formCreate' + upper(to).replace('.', '>'),
props: {
column: [{label: t('props.key'), key: 'label'}, {value: true, label: t('props.value'), key: 'value'}],
keyValue: 'label'
}
},
],
}
];
return {
type: 'radio',
title: t('props.options'),
field: '_optionType',
value: 2,
options,
props: {
type: 'button'
},
control
};
}
export function makeTreeOptionsRule(t, to, label, value) {
const options = [
{'label': t('fetch.optionsType.struct'), 'value': 2},
{'label': t('fetch.optionsType.fetch'), 'value': 1},
];
const control = [
{
value: 1,
rule: [
{
type: 'FetchConfig',
field: 'formCreateEffect>fetch',
props: {
to
}
}
]
},
{
value: 2,
rule: [
{
type: 'TreeOptions',
field: 'formCreate' + upper(to).replace('.', '>'),
props: {
columns: {
label,
value
},
keyValue: label,
}
},
],
}
];
return {
type: 'radio',
title: t('props.options'),
field: '_optionType',
value: 2,
options,
props: {
type: 'button'
},
control
};
}
export function upper(str) {
return str.replace(str[0], str[0].toLocaleUpperCase());
}
export const toJSON = function (val) {
const type = /object ([a-zA-Z]*)/.exec(Object.prototype.toString.call(val));
if (type && _toJSON[type[1].toLowerCase()]) {
return _toJSON[type[1].toLowerCase()](val);
} else {
return val;
}
};
const _toJSON = {
object: function (val) {
var json = [];
for (var i in val) {
if (!hasProperty(val, i)) continue;
json.push(
toJSON(i) + ': ' +
((val[i] != null) ? toJSON(val[i]) : 'null')
);
}
return '{\n ' + json.join(',\n ') + '\n}';
},
function: function (val) {
val = '' + val;
var exec = (/^ *([\w]+) *\(/).exec(val);
if (exec && exec[1] !== 'function') {
return 'function ' + val;
}
return val;
},
array: function (val) {
for (var i = 0, json = []; i < val.length; i++)
json[i] = (val[i] != null) ? toJSON(val[i]) : 'null';
return '[' + json.join(', ') + ']';
},
string: function (val) {
var tmp = val.split('');
for (var i = 0; i < tmp.length; i++) {
var c = tmp[i];
(c >= ' ') ?
(c === '\\') ? (tmp[i] = '\\\\') :
(c === '"') ? (tmp[i] = '\\"') : 0 :
(tmp[i] =
(c === '\n') ? '\\n' :
(c === '\r') ? '\\r' :
(c === '\t') ? '\\t' :
(c === '\b') ? '\\b' :
(c === '\f') ? '\\f' :
(c = c.charCodeAt(), ('\\u00' + ((c > 15) ? 1 : 0) + (c % 16)))
);
}
return '"' + tmp.join('') + '"';
}
};
export const deepParseFn = function (target) {
if (target && typeof target === 'object') {
for (let key in target) {
if (Object.prototype.hasOwnProperty.call(target, key)) {
let data = target[key];
if (Array.isArray(data) || is.Object(data)) {
deepParseFn(data);
}
if (is.String(data)) {
target[key] = parseFn(data);
}
}
}
}
return target;
};
export function deepGet(object, path, defaultValue) {
path = (path || '').split('.');
let index = 0,
length = path.length;
while (object != null && index < length) {
object = object[path[index++]];
}
return (index && index === length) ? (object !== undefined ? object : defaultValue) : defaultValue;
}
export const buildTranslator = (locale) => (path, option) => translate(path, option, unref(locale));
export const translate = (path, option, locale) =>
deepGet(locale, path, '').replace(
/\{(\w+)\}/g,
(_, key) => `${option?.[key] ?? `{${key}}`}`
);
export const buildLocaleContext = (locale) => {
const lang = computed(() => unref(locale).name);
const name = computed(() => upper(toCase(lang.value || '')));
const localeRef = isRef(locale) ? locale : ref(locale);
return {
lang,
name,
locale: localeRef,
t: buildTranslator(locale),
};
};
export const useLocale = (locale) => {
return buildLocaleContext(computed(() => locale.value || ZhCn));
};
export const localeOptions = (t, options, prefix) => {
return options.map(opt => {
opt.label = t((prefix || 'props') + '.' + opt.label || opt.value) || opt.label;
return opt;
});
};
export const localeProps = (t, prefix, rules) => {
return rules.map(rule => {
if (rule.field === 'formCreate$required') {
rule.title = t('validate.required') || rule.title;
} else if (rule.field && rule.field !== '_optionType') {
rule.title = t('com.' + prefix + '.' + rule.field) || rule.title;
}
if (rule.type === 'template' && is.trueArray(rule.children)) {
rule.children = localeProps(t, prefix, rule.children);
}
return rule;
});
};
export const getRuleTree = (children) => {
const tree = [];
children && children.forEach(rule => {
if (rule._fc_drag_tag) {
const item = {
id: rule.__fc__.id,
rule,
children: getRuleTree(rule.children),
};
if (!item.children.length) {
delete item.children;
}
tree.push(item);
} else {
tree.push(...getRuleTree(rule.children));
}
});
return tree;
};
export const getFormRuleDescription = (tree) => {
const getTree = (children) => {
const tree = [];
children && children.forEach(rule => {
if (rule.field) {
rule.children = getTree(rule.children || []);
if (!rule.children.length) {
delete rule.children;
}
tree.push(rule);
} else {
tree.push(...getTree(rule.children || []));
}
});
return tree;
};
return getTree(tree);
};
export const getRuleDescription = (children) => {
const getTree = (children) => {
const tree = [];
children && children.forEach(rule => {
if (typeof rule !== 'object') {
return;
}
if (rule._fc_drag_tag) {
const item = {
_fc_id: rule._fc_id,
type: rule.type,
field: rule.field,
title: rule.title,
name: rule.name,
slot: rule.slot,
props: {...rule.props || {}},
children: getTree(rule.children || [])
};
if (rule.children && typeof rule.children[0] === 'string') {
item.content = rule.children[0];
}
if (!item.children.length) {
delete item.children;
}
tree.push(item);
} else {
tree.push(...getTree(rule.children));
}
});
return tree;
};
return getTree(children);
};
export function getInjectArg(t) {
return {
name: '$inject',
columns: [
{label: '$inject.api', info: t('event.inject.api'), type: 'Api'},
{label: '$inject.rule', info: t('event.inject.rule'), type: 'Rule[]'},
{label: '$inject.self', info: t('event.inject.self'), type: 'Rule'},
{label: '$inject.option', info: t('event.inject.option'), type: 'Object'},
{label: '$inject.args', info: t('event.inject.args'), type: 'Array'},
]
};
}
export function isElementInside(x, y, element) {
const rect = element.getBoundingClientRect();
return x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom;
}
export function isNull(v) {
return ['', null, undefined].indexOf(v) !== -1;
}
export function formTemplate(json, options) {
return `<template>
<form-create
:value.sync="formData"
v-model="fapi"
:rule="rule"
:option="option"
@submit="onSubmit"
></form-create>
</template>
<script>
import formCreate from "@form-create/element-ui";
export default {
components: {
formCreate: formCreate.$form()
},
data () {
const option = formCreate.parseJson('${options.replaceAll('\\', '\\\\').replaceAll('\'', '\\')}');
return {
formData: {},
fapi: null,
rule: formCreate.parseJson('${json.replaceAll('\\', '\\\\').replaceAll('\'', '\\')}'),
option: option
}
},
methods: {
onSubmit (formData) {
//todo 提交表单
}
}
}
<\/script>`;
}
export function htmlTemplate(json, options) {
return `<html lang="zh">
<head>
<meta charset="UTF-8">
<!-- Import style -->
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css"/>
<!-- Import Vue 2.7 -->
<script src="https://unpkg.com/vue@2"></script>
<!-- Import element-ui -->
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
<!-- Import formCreate -->
<script src="https://unpkg.com/@form-create/element-ui@super"><\/script>
</head>
<body>
<div id="app">
<form-create :rule="rule" :option="options" v-model:value="formData" v-model="api" @submit="onSubmit"></form-create>
</div>
<script>
Vue.use(ELEMENT);
Vue.use(formCreate);
new Vue({
el: '#app',
data() {
return {
rule: formCreate.parseJson('${json.replaceAll('\\', '\\\\').replaceAll('\'', '\\\'')}'),
options: formCreate.parseJson('${options.replaceAll('\\', '\\\\').replaceAll('\'', '\\\'')}'),
formData: {},
api: null,
};
},
methods: {
onSubmit(formData){
console.log('submit', formData);
}
}
})
</script>
</body>
</html>`
}
export function escapeRegExp(str) {
return str.replace(/[\ .*+?^${}()|[\]\\]/g, '\\$&');
}
export function compareVersion(v1, v2) {
const a1 = v1.split('.');
const a2 = v2.split('.');
const minLength = Math.min(a1.length, a2.length);
for (var i = 0; i < minLength; i++) {
var diff = parseInt(a1[i], 10) - parseInt(a2[i], 10);
if (diff > 0) {
return 1;
} else if (diff < 0) {
return -1;
}
}
return a1.length === a2.length ? 0 : (a1.length < a2.length ? -1 : 1);
}
export function copyTextToClipboard(text) {
const textArea = document.createElement('textarea');
textArea.style.position = 'fixed';
textArea.style.top = 0;
textArea.style.left = '-9999px';
textArea.value = text;
document.body.appendChild(textArea);
textArea.focus();
textArea.select();
try {
document.execCommand('copy');
} catch (err) {
console.log('Oops, unable to copy');
}
message('已复制!', 'success');
document.body.removeChild(textArea);
}
export function uniqueArray(arr) {
return arr.filter((item, index) => arr.indexOf(item) === index);
}