UNPKG

vxe-table-demonic

Version:

一个基于 vue 的 PC 端表单/表格组件,支持增删改查、虚拟列表、虚拟树、懒加载、快捷菜单、数据校验、树形结构、打印导出、表单渲染、数据分页、弹窗、自定义模板、渲染器、JSON 配置式...

790 lines (789 loc) 25.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _vue = require("vue"); var _xeUtils = _interopRequireDefault(require("xe-utils")); var _conf = _interopRequireDefault(require("../../v-x-e-table/src/conf")); var _vXETable = require("../../v-x-e-table"); var _utils = require("../../tools/utils"); var _log = require("../../tools/log"); var _dom = require("../../tools/dom"); var _util = require("./util"); var _size = require("../../hooks/size"); var _formConfigItem = _interopRequireDefault(require("./form-config-item")); var _index = _interopRequireDefault(require("../../loading/index")); var _vn = require("../../tools/vn"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var __assign = void 0 && (void 0).__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 Rule = /** @class */function () { function Rule(rule) { Object.assign(this, { $options: rule, required: rule.required, min: rule.min, max: rule.min, type: rule.type, pattern: rule.pattern, validator: rule.validator, trigger: rule.trigger, maxWidth: rule.maxWidth }); } Object.defineProperty(Rule.prototype, "content", { get: function () { return (0, _utils.getFuncText)(this.$options.content || this.$options.message); }, enumerable: false, configurable: true }); Object.defineProperty(Rule.prototype, "message", { get: function () { return this.content; }, enumerable: false, configurable: true }); return Rule; }(); var validErrorRuleValue = function (rule, val) { var type = rule.type, min = rule.min, max = rule.max, pattern = rule.pattern; var isNumType = type === 'number'; var numVal = isNumType ? _xeUtils.default.toNumber(val) : _xeUtils.default.getSize(val); // 判断数值 if (isNumType && isNaN(val)) { return true; } // 如果存在 min,判断最小值 if (!_xeUtils.default.eqNull(min) && numVal < _xeUtils.default.toNumber(min)) { return true; } // 如果存在 max,判断最大值 if (!_xeUtils.default.eqNull(max) && numVal > _xeUtils.default.toNumber(max)) { return true; } // 如果存在 pattern,正则校验 if (pattern && !(_xeUtils.default.isRegExp(pattern) ? pattern : new RegExp(pattern)).test(val)) { return true; } return false; }; function getResetValue(value, resetValue) { if (_xeUtils.default.isArray(value)) { resetValue = []; } return resetValue; } var _default = (0, _vue.defineComponent)({ name: 'VxeForm', props: { collapseStatus: { type: Boolean, default: true }, loading: Boolean, data: Object, size: { type: String, default: function () { return _conf.default.form.size || _conf.default.size; } }, span: { type: [String, Number], default: function () { return _conf.default.form.span; } }, align: { type: String, default: function () { return _conf.default.form.align; } }, titleAlign: { type: String, default: function () { return _conf.default.form.titleAlign; } }, titleWidth: { type: [String, Number], default: function () { return _conf.default.form.titleWidth; } }, titleColon: { type: Boolean, default: function () { return _conf.default.form.titleColon; } }, titleAsterisk: { type: Boolean, default: function () { return _conf.default.form.titleAsterisk; } }, titleOverflow: { type: [Boolean, String], default: null }, vertical: { type: Boolean, default: null }, className: [String, Function], readonly: Boolean, items: Array, rules: Object, preventSubmit: { type: Boolean, default: function () { return _conf.default.form.preventSubmit; } }, validConfig: Object, tooltipConfig: Object, customLayout: { type: Boolean, default: function () { return _conf.default.form.customLayout; } } }, emits: ['update:collapseStatus', 'collapse', 'toggle-collapse', 'submit', 'submit-invalid', 'reset'], setup: function (props, context) { var hasUseTooltip = _vXETable.VXETable.tooltip; var slots = context.slots, emit = context.emit; var xID = _xeUtils.default.uniqueId(); var computeSize = (0, _size.useSize)(props); var reactData = (0, _vue.reactive)({ collapseAll: props.collapseStatus, staticItems: [], formItems: [] }); var internalData = (0, _vue.reactive)({ tooltipTimeout: null, tooltipStore: { item: null, visible: false } }); var $xegrid = (0, _vue.inject)('$xegrid', null); var refElem = (0, _vue.ref)(); var refTooltip = (0, _vue.ref)(); var formMethods = {}; var computeValidOpts = (0, _vue.computed)(function () { return Object.assign({}, _conf.default.form.validConfig, props.validConfig); }); var computeTooltipOpts = (0, _vue.computed)(function () { return Object.assign({}, _conf.default.tooltip, _conf.default.form.tooltipConfig, props.tooltipConfig); }); var refMaps = { refElem: refElem }; var computeMaps = { computeSize: computeSize, computeValidOpts: computeValidOpts, computeTooltipOpts: computeTooltipOpts }; var $xeform = { xID: xID, props: props, context: context, reactData: reactData, xegrid: $xegrid, getRefMaps: function () { return refMaps; }, getComputeMaps: function () { return computeMaps; } }; var callSlot = function (slotFunc, params) { if (slotFunc) { if (_xeUtils.default.isString(slotFunc)) { slotFunc = slots[slotFunc] || null; } if (_xeUtils.default.isFunction(slotFunc)) { return (0, _vn.getSlotVNs)(slotFunc(params)); } } return []; }; var loadItem = function (list) { if (list.length) { if (process.env.NODE_ENV === 'development') { list.forEach(function (item) { if (item.slots) { _xeUtils.default.each(item.slots, function (func) { if (!_xeUtils.default.isFunction(func)) { if (!slots[func]) { (0, _log.errLog)('vxe.error.notSlot', [func]); } } }); } }); } reactData.staticItems = _xeUtils.default.mapTree(list, function (item) { return (0, _util.createItem)($xeform, item); }, { children: 'children' }); } return (0, _vue.nextTick)(); }; var getItems = function () { var itemList = []; _xeUtils.default.eachTree(reactData.formItems, function (item) { itemList.push(item); }, { children: 'children' }); return itemList; }; var getItemByField = function (field) { var rest = _xeUtils.default.findTree(reactData.formItems, function (item) { return item.field === field; }, { children: 'children' }); return rest ? rest.item : null; }; var getCollapseStatus = function () { return reactData.collapseAll; }; var toggleCollapse = function () { var status = !getCollapseStatus(); reactData.collapseAll = status; emit('update:collapseStatus', status); return (0, _vue.nextTick)(); }; var toggleCollapseEvent = function (evnt) { toggleCollapse(); var status = getCollapseStatus(); formMethods.dispatchEvent('toggle-collapse', { status: status, collapse: status, data: props.data }, evnt); formMethods.dispatchEvent('collapse', { status: status, collapse: status, data: props.data }, evnt); }; var clearValidate = function (fieldOrItem) { if (fieldOrItem) { var fields = fieldOrItem; if (!_xeUtils.default.isArray(fieldOrItem)) { fields = [fieldOrItem]; } fields.forEach(function (field) { if (field) { var item = (0, _util.handleFieldOrItem)($xeform, field); if (item) { item.showError = false; } } }); } else { getItems().forEach(function (item) { item.showError = false; }); } return (0, _vue.nextTick)(); }; var reset = function () { var data = props.data; var itemList = getItems(); if (data) { itemList.forEach(function (item) { var field = item.field, resetValue = item.resetValue, itemRender = item.itemRender; if ((0, _utils.isEnableConf)(itemRender)) { var compConf = _vXETable.VXETable.renderer.get(itemRender.name); if (compConf && compConf.itemResetMethod) { compConf.itemResetMethod({ data: data, field: field, property: field, item: item, $form: $xeform, $grid: $xeform.xegrid }); } else if (field) { _xeUtils.default.set(data, field, resetValue === null ? getResetValue(_xeUtils.default.get(data, field), undefined) : _xeUtils.default.clone(resetValue, true)); } } }); } return clearValidate(); }; var resetEvent = function (evnt) { evnt.preventDefault(); reset(); formMethods.dispatchEvent('reset', { data: props.data }, evnt); }; var handleFocus = function (fields) { var el = refElem.value; for (var i = 0; i < fields.length; i++) { var property = fields[i]; var item = getItemByField(property); if (item && (0, _utils.isEnableConf)(item.itemRender)) { var itemRender = item.itemRender; var compConf = _vXETable.VXETable.renderer.get(itemRender.name); var inputElem = null; // 定位到第一个 if (!i) { (0, _dom.scrollToView)(el.querySelector(".".concat(item.id))); } // 如果指定了聚焦 class if (itemRender.autofocus) { inputElem = el.querySelector(".".concat(item.id, " ").concat(itemRender.autofocus)); } // 渲染器的聚焦处理 if (!inputElem && compConf && compConf.autofocus) { inputElem = el.querySelector(".".concat(item.id, " ").concat(compConf.autofocus)); } if (inputElem) { inputElem.focus(); break; } } } }; /** * 校验数据 * 按表格行、列顺序依次校验(同步或异步) * 校验规则根据索引顺序依次校验,如果是异步则会等待校验完成才会继续校验下一列 * 如果校验失败则,触发回调或者 Promise<(ErrMap 校验不通过列的信息)> * 如果是传回调方式这返回一个 (ErrMap 校验不通过列的信息) * * rule 配置: * required=Boolean 是否必填 * min=Number 最小长度 * max=Number 最大长度 * validator=Function({ itemValue, rule, rules, data, property }) 自定义校验,接收一个 Promise * trigger=change 触发方式 */ var validItemRules = function (validType, fields, val) { var data = props.data, formRules = props.rules; var errorMaps = {}; if (!_xeUtils.default.isArray(fields)) { fields = [fields]; } return Promise.all(fields.map(function (property) { var errorRules = []; var syncVailds = []; if (property && formRules) { var rules_1 = _xeUtils.default.get(formRules, property); if (rules_1) { var itemValue_1 = _xeUtils.default.isUndefined(val) ? _xeUtils.default.get(data, property) : val; rules_1.forEach(function (rule) { var type = rule.type, trigger = rule.trigger, required = rule.required, validator = rule.validator; if (validType === 'all' || !trigger || validType === trigger) { if (validator) { var validParams = { itemValue: itemValue_1, rule: rule, rules: rules_1, data: data, field: property, property: property, $form: $xeform }; var customValid = void 0; if (_xeUtils.default.isString(validator)) { var gvItem = _vXETable.VXETable.validators.get(validator); if (gvItem) { if (gvItem.itemValidatorMethod) { customValid = gvItem.itemValidatorMethod(validParams); } else { if (process.env.NODE_ENV === 'development') { (0, _log.warnLog)('vxe.error.notValidators', [validator]); } } } else { if (process.env.NODE_ENV === 'development') { (0, _log.errLog)('vxe.error.notValidators', [validator]); } } } else { customValid = validator(validParams); } if (customValid) { if (_xeUtils.default.isError(customValid)) { errorRules.push(new Rule({ type: 'custom', trigger: trigger, content: customValid.message, rule: new Rule(rule) })); } else if (customValid.catch) { // 如果为异步校验(注:异步校验是并发无序的) syncVailds.push(customValid.catch(function (e) { errorRules.push(new Rule({ type: 'custom', trigger: trigger, content: e ? e.message : rule.content || rule.message, rule: new Rule(rule) })); })); } } } else { var isArrType = type === 'array'; var isArrVal = _xeUtils.default.isArray(itemValue_1); var hasEmpty = true; if (isArrType || isArrVal) { hasEmpty = !isArrVal || !itemValue_1.length; } else if (_xeUtils.default.isString(itemValue_1)) { hasEmpty = (0, _utils.eqEmptyValue)(itemValue_1.trim()); } else { hasEmpty = (0, _utils.eqEmptyValue)(itemValue_1); } if (required ? hasEmpty || validErrorRuleValue(rule, itemValue_1) : !hasEmpty && validErrorRuleValue(rule, itemValue_1)) { errorRules.push(new Rule(rule)); } } } }); } } return Promise.all(syncVailds).then(function () { if (errorRules.length) { errorMaps[property] = errorRules.map(function (rule) { return { $form: $xeform, rule: rule, data: data, field: property, property: property }; }); } }); })).then(function () { if (!_xeUtils.default.isEmpty(errorMaps)) { return Promise.reject(errorMaps); } }); }; var showErrTime; var beginValidate = function (itemList, type, callback) { var data = props.data, formRules = props.rules; var validOpts = computeValidOpts.value; var validRest = {}; var validFields = []; var itemValids = []; clearTimeout(showErrTime); if (data && formRules) { itemList.forEach(function (item) { var field = item.field; if (field && !(0, _util.isHiddenItem)($xeform, item) && (0, _util.isActivetem)($xeform, item)) { itemValids.push(validItemRules(type || 'all', field).then(function () { item.errRule = null; }).catch(function (errorMaps) { var rest = errorMaps[field]; if (!validRest[field]) { validRest[field] = []; } validRest[field].push(rest); validFields.push(field); item.errRule = rest[0].rule; return Promise.reject(rest); })); } }); return Promise.all(itemValids).then(function () { if (callback) { callback(); } }).catch(function () { return new Promise(function (resolve) { showErrTime = window.setTimeout(function () { itemList.forEach(function (item) { if (item.errRule) { item.showError = true; } }); }, 20); if (validOpts.autoPos !== false) { (0, _vue.nextTick)(function () { handleFocus(validFields); }); } if (callback) { callback(validRest); resolve(); } else { resolve(validRest); } }); }); } if (callback) { callback(); } return Promise.resolve(); }; var validate = function (callback) { clearValidate(); return beginValidate(getItems(), '', callback); }; var validateField = function (fieldOrItem, callback) { var fields = []; if (_xeUtils.default.isArray(fieldOrItem)) { fields = fieldOrItem; } else { fields = [fieldOrItem]; } return beginValidate(fields.map(function (field) { return (0, _util.handleFieldOrItem)($xeform, field); }), '', callback); }; var submitEvent = function (evnt) { evnt.preventDefault(); if (!props.preventSubmit) { clearValidate(); beginValidate(getItems()).then(function (errMap) { if (errMap) { formMethods.dispatchEvent('submit-invalid', { data: props.data, errMap: errMap }, evnt); } else { formMethods.dispatchEvent('submit', { data: props.data }, evnt); } }); } }; var closeTooltip = function () { var tooltipStore = internalData.tooltipStore; var $tooltip = refTooltip.value; if (tooltipStore.visible) { Object.assign(tooltipStore, { item: null, visible: false }); if ($tooltip) { $tooltip.close(); } } return (0, _vue.nextTick)(); }; var triggerTitleTipEvent = function (evnt, params) { var item = params.item; var tooltipStore = internalData.tooltipStore; var $tooltip = refTooltip.value; var overflowElem = evnt.currentTarget.children[0]; var content = (overflowElem.textContent || '').trim(); var isCellOverflow = overflowElem.scrollWidth > overflowElem.clientWidth; clearTimeout(internalData.tooltipTimeout); if (tooltipStore.item !== item) { closeTooltip(); } if (content && isCellOverflow) { Object.assign(tooltipStore, { item: item, visible: true }); if ($tooltip) { $tooltip.open(overflowElem, content); } } }; var handleTitleTipLeaveEvent = function () { var tooltipOpts = computeTooltipOpts.value; var $tooltip = refTooltip.value; if ($tooltip) { $tooltip.setActived(false); } if (tooltipOpts.enterable) { internalData.tooltipTimeout = setTimeout(function () { $tooltip = refTooltip.value; if ($tooltip && !$tooltip.isActived()) { closeTooltip(); } }, tooltipOpts.leaveDelay); } else { closeTooltip(); } }; var triggerItemEvent = function (evnt, field, itemValue) { if (field) { return validItemRules(evnt ? ['blur'].includes(evnt.type) ? 'blur' : 'change' : 'all', field, itemValue).then(function () { clearValidate(field); }).catch(function (errorMaps) { var rest = errorMaps[field]; var item = getItemByField(field); if (rest && item) { item.showError = true; item.errRule = rest[0].rule; } }); } return (0, _vue.nextTick)(); }; /** * 更新项状态 * 如果组件值 v-model 发生 change 时,调用改函数用于更新某一项编辑状态 * 如果单元格配置了校验规则,则会进行校验 */ var updateStatus = function (scope, itemValue) { var field = scope.field; return triggerItemEvent(new Event('change'), field, itemValue); }; formMethods = { dispatchEvent: function (type, params, evnt) { emit(type, Object.assign({ $form: $xeform, $grid: $xegrid, $event: evnt }, params)); }, reset: reset, validate: validate, validateField: validateField, clearValidate: clearValidate, updateStatus: updateStatus, toggleCollapse: toggleCollapse, getItems: getItems, getItemByField: getItemByField, closeTooltip: closeTooltip }; var formPrivateMethods = { callSlot: callSlot, triggerItemEvent: triggerItemEvent, toggleCollapseEvent: toggleCollapseEvent, triggerTitleTipEvent: triggerTitleTipEvent, handleTitleTipLeaveEvent: handleTitleTipLeaveEvent }; Object.assign($xeform, formMethods, formPrivateMethods); var staticItemFlag = (0, _vue.ref)(0); (0, _vue.watch)(function () { return reactData.staticItems.length; }, function () { staticItemFlag.value++; }); (0, _vue.watch)(function () { return reactData.staticItems; }, function () { staticItemFlag.value++; }); (0, _vue.watch)(staticItemFlag, function () { reactData.formItems = reactData.staticItems; }); var itemFlag = (0, _vue.ref)(0); (0, _vue.watch)(function () { return props.items ? props.items.length : -1; }, function () { itemFlag.value++; }); (0, _vue.watch)(function () { return props.items; }, function () { itemFlag.value++; }); (0, _vue.watch)(itemFlag, function () { loadItem(props.items || []); }); (0, _vue.watch)(function () { return props.collapseStatus; }, function (value) { reactData.collapseAll = !!value; }); (0, _vue.onMounted)(function () { (0, _vue.nextTick)(function () { if (process.env.NODE_ENV === 'development') { if (props.customLayout && props.items) { (0, _log.errLog)('vxe.error.errConflicts', ['custom-layout', 'items']); } } loadItem(props.items || []); }); }); var renderVN = function () { var _a; var loading = props.loading, className = props.className, data = props.data, customLayout = props.customLayout; var formItems = reactData.formItems; // const formItems: any[] = [] var vSize = computeSize.value; var tooltipOpts = computeTooltipOpts.value; var defaultSlot = slots.default; return (0, _vue.h)('form', { ref: refElem, class: ['vxe-form', className ? _xeUtils.default.isFunction(className) ? className({ items: formItems, data: data, $form: $xeform }) : className : '', (_a = {}, _a["size--".concat(vSize)] = vSize, _a['is--loading'] = loading, _a)], onSubmit: submitEvent, onReset: resetEvent }, [(0, _vue.h)('div', { class: 'vxe-form--wrapper vxe-row' }, customLayout ? defaultSlot ? defaultSlot({}) : [] : formItems.map(function (item, index) { return (0, _vue.h)(_formConfigItem.default, { key: index, itemConfig: item }); })), (0, _vue.h)('div', { class: 'vxe-form-slots', ref: 'hideItem' }, customLayout ? [] : defaultSlot ? defaultSlot({}) : []), /** * 加载中 */ (0, _vue.h)(_index.default, { class: 'vxe-form--loading', modelValue: loading }), /** * 工具提示 */ hasUseTooltip ? (0, _vue.h)((0, _vue.resolveComponent)('vxe-tooltip'), __assign({ ref: refTooltip }, tooltipOpts)) : (0, _vue.createCommentVNode)()]); }; $xeform.renderVN = renderVN; (0, _vue.provide)('$xeform', $xeform); (0, _vue.provide)('$xeformgather', null); (0, _vue.provide)('$xeformitem', null); (0, _vue.provide)('$xeformiteminfo', null); return $xeform; }, render: function () { return this.renderVN(); } }); exports.default = _default;