UNPKG

@truenewx/tnxvue3

Version:

互联网技术解决方案:Vue3扩展支持

588 lines (568 loc) 22.5 kB
// tnxel.js /** * 基于ElementPlus的扩展支持 */ import ElementPlus, {ElLoading, ElMessage, ElMessageBox} from 'element-plus'; import ElementPlus_zh_CN from 'element-plus/es/locale/lang/zh-cn'; import tnxbs from '@truenewx/tnxcore/src/tnxbs'; // 二次封装组件中使用了Bootstrap的基础样式 import tnxvue from '../tnxvue.js'; import Avatar from './avatar/Avatar.vue'; import Alert from './alert/Alert.vue'; import Button from './button/Button.vue'; import CheckIcon from './check-icon/CheckIcon.vue'; import CloseErrorButton from './close-error-button/CloseErrorButton.vue'; import Curd from './curd/Curd.vue'; import DatePicker from './date-picker/DatePicker.vue'; import DateRange from './date-range/DateRange.vue'; import DateTimePicker from './datetime-picker/DateTimePicker.vue'; import DetailForm from './detail-form/DetailForm.vue'; import Dialog from './dialog/Dialog.vue'; import Drawer from './drawer/Drawer.vue'; import DropdownItem from './dropdown-item/DropdownItem.vue'; import EditTable from './edit-table/EditTable.vue'; import EnumSelect from './enum-select/EnumSelect.vue'; import EnumView from './enum-view/EnumView.vue'; import FetchCascader from './fetch-cascader/FetchCascader.vue'; import FetchSelect from './fetch-select/FetchSelect.vue'; import FetchTags from './fetch-tags/FetchTags.vue'; import FssUpload from './fss-upload/FssUpload.vue'; import FssView from './fss-view/FssView.vue'; import Icon from './icon/Icon.vue'; import InputDropdown from './input-dropdown/InputDropdown.vue'; import InputNumber from './input-number/InputNumber.vue'; import Paged from './paged/Paged.vue'; import PermissionTree from './permission-tree/PermissionTree.vue'; import QueryForm from './query-form/QueryForm.vue'; import QueryTable from './query-table/QueryTable.vue'; import RegionCascader from './region-cascader/RegionCascader.vue'; import Select from './select/Select.vue'; import Slider from './slider/Slider.vue'; import StepsNav from './steps-nav/StepsNav.vue'; import SubmitForm from './submit-form/SubmitForm.vue'; import TabColumn from './table-column/TableColumn.vue'; import Tabs from './tabs/Tabs.vue'; import Transfer from './transfer/Transfer.vue'; import Upload from './upload/Upload.vue'; import './tnxel.css'; const $ = tnxbs.libs.$; export const build = tnxvue.build; export default build('tnxel', () => { const components = Object.assign({}, tnxvue.components, { Avatar, Alert, Button, CheckIcon, CloseErrorButton, Curd, DatePicker, DateRange, DateTimePicker, DetailForm, Dialog, Drawer, DropdownItem, EditTable, EnumSelect, EnumView, FetchCascader, FetchSelect, FetchTags, FssUpload, FssView, Icon, InputDropdown, InputNumber, Paged, PermissionTree, QueryForm, QueryTable, RegionCascader, Select, Slider, StepsNav, SubmitForm, TabColumn, Tabs, Transfer, Upload, }); const dialogContainerClass = 'tnxel-dialog-container'; const drawerContainerClass = 'tnxel-drawer-container'; const tnxel = Object.assign({}, tnxbs, tnxvue, { components, componentDefaultApp: undefined, // 组件的默认app,从服务端获取数据的组件以此为远程请求的默认app dialogInstances: [], // 对话框堆栈 dialog(content, title, buttons, options, contentProps) { this._closeMessage(); let componentOptions = {}; if (window.tnx.util.isComponent(content)) { componentOptions.components = { 'tnxel-dialog-content': content }; content = null; } let componentDefinition = Object.assign({}, Dialog, componentOptions); const dialogId = 'dialog-' + (new Date().getTime()); $('body').append('<div class="' + dialogContainerClass + '" id="' + dialogId + '"></div>'); if (!(buttons instanceof Array)) { buttons = []; } const containerSelector = '.' + dialogContainerClass + '#' + dialogId; options = options || {}; let dialogVm = window.tnx.createVueInstance(componentDefinition, null, { modelValue: true, container: containerSelector, title: title, content: content, contentProps: contentProps, buttons: buttons, theme: options.theme, }); const dialog = dialogVm.mount(containerSelector); dialog.options = Object.assign(dialog.options || {}, options); dialog.options.onClosed = window.tnx.util.function.around(dialog.options.onClosed, function (onClosed) { dialogVm.unmount(); window.tnx.dialogInstances.remove(dialog); let $container = $(containerSelector); $container.next('.el-overlay').remove(); $container.remove(); if (onClosed) { onClosed.call(dialog); } }); window.tnx.dialogInstances.push(dialog); return dialog; }, closeDialog(all, callback) { if (typeof all === 'function') { callback = all; all = false; } if (window.tnx.dialogInstances.length) { let dialog = window.tnx.dialogInstances.pop(); while (dialog) { dialog.close(callback); if (all) { dialog = window.tnx.dialogInstances.pop(); } else { break; } } } }, drawerInstances: [], // 抽屉堆栈 drawer(content, title, buttons, options, contentProps) { this._closeMessage(); let componentOptions = {}; if (this.util.isComponent(content)) { componentOptions.components = { 'tnxel-drawer-content': content }; content = null; } let componentDefinition = Object.assign({}, Drawer, componentOptions); const drawerId = 'drawer-' + (new Date().getTime()); $('body').append('<div class="' + drawerContainerClass + '" id="' + drawerId + '"></div>'); if (!(buttons instanceof Array)) { buttons = []; } const containerSelector = '.' + drawerContainerClass + '#' + drawerId; options = options || {}; let drawerVm = window.tnx.createVueInstance(componentDefinition, null, { content: content, title: title, contentProps: contentProps, buttons: buttons, theme: options.theme, }); const drawer = drawerVm.mount(containerSelector); drawer.id = drawerId; drawer.options = Object.assign(drawer.options || {}, options); drawer.options.onClosed = this.util.function.around(drawer.options.onClosed, function (onClosed) { drawerVm.unmount(); window.tnx.drawerInstances.remove(drawer); let $container = $(containerSelector); $container.next('.el-overlay').remove(); $container.remove(); if (onClosed) { onClosed.call(drawer); } }); window.tnx.drawerInstances.push(drawer); return drawer; }, closeDrawer(all, callback) { if (typeof all === 'function') { callback = all; all = false; } if (window.tnx.drawerInstances.length) { let drawer = window.tnx.drawerInstances.pop(); while (drawer) { drawer.close(callback); if (all) { drawer = window.tnx.drawerInstances.pop(); } else { break; } } } }, _closeMessage() { ElMessage.closeAll(); this.closeLoading(); }, _handleZIndex(selector) { setTimeout(function () { const topZIndex = window.tnx.util.dom.minTopZIndex(2); if (selector.endsWith(':last')) { selector = selector.substring(0, selector.length - ':last'.length); } let element = $(selector); if (element.length > 0) { element = $(element[element.length - 1]); } const zIndex = Number(element.css('zIndex')); if (isNaN(zIndex) || topZIndex > zIndex) { element.css('zIndex', topZIndex); const modal = element.next(); if (modal.is('.v-modal')) { modal.css('zIndex', topZIndex - 1); } } }); }, alert(message, title, callback, options) { this.closeLoading(); if (typeof title === 'function') { options = callback; callback = title; title = '提示'; } options = Object.assign({ dangerouslyUseHTMLString: true, type: 'warning', confirmButtonText: '确定', }, options); this.closeLoading(); ElMessageBox.alert(message, title || '提示', options).then(callback); this._handleZIndex('.el-message-box__wrapper:last'); this.app.eventBus.emit('tnx.alert', options); }, success(message, callback, options) { this.closeLoading(); options = Object.assign({ dangerouslyUseHTMLString: true, }, options, { type: 'success', confirmButtonText: '确定', }); this.closeLoading(); ElMessageBox.alert(message, '成功', options).then(callback); this._handleZIndex('.el-message-box__wrapper:last'); this.app.eventBus.emit('tnx.success', options); }, error(message, callback, options) { this.closeLoading(); options = Object.assign({ dangerouslyUseHTMLString: true, }, options, { type: 'error', confirmButtonText: '确定', }); this.closeLoading(); ElMessageBox.alert(message, '错误', options).then(callback); this._handleZIndex('.el-message-box__wrapper:last'); this.app.eventBus.emit('tnx.error', options); // 打印TypeError对象,便于调试 if (typeof message === 'object' && message.name === 'TypeError') { console.error(message); } }, confirm(message, title, callback, options) { this.closeLoading(); if (typeof title === 'function') { options = callback; callback = title; title = '确认'; } options = Object.assign({ type: 'question', confirmButtonText: '确定', cancelButtonText: '取消', }, options, { dangerouslyUseHTMLString: true, distinguishCancelAndClose: true, }); if (options.type === 'question') { options.type = 'info'; options.icon = tnxvue.libs.Vue.markRaw(Icon.components.QuestionFilled); } if (options.reverse) { options.customClass = 'reverse'; let buttonText = options.confirmButtonText; options.confirmButtonText = options.cancelButtonText; options.cancelButtonText = buttonText; } if (typeof callback === 'function') { options.callback = function (action) { let yes = undefined; if (action === 'confirm') { yes = !options.reverse; } else if (action === 'cancel') { yes = !!options.reverse; } callback(yes); } } this.closeLoading(); ElMessageBox.confirm(message, title, options); this._handleZIndex('.el-message-box__wrapper:last'); this.app.eventBus.emit('tnx.confirm', options); }, toast(message, timeout, callback, options) { this.closeLoading(); if (typeof timeout === 'function') { options = callback; callback = timeout; timeout = undefined; } options = Object.assign({ type: 'success', // 默认为成功主题,可更改为其它主题 offset: this.util.dom.getDocHeight() * 0.4, dangerouslyUseHTMLString: true, }, options, { center: true, // 因为是竖向排列,所以必须居中 showClose: false, message: message, duration: timeout || 1500, customClass: 'tnxel-toast', onClose: callback, }); this._closeMessage(); ElMessage(options); this._handleZIndex('.el-message:last'); this.app.eventBus.emit('tnx.toast', options); }, showLoading(message, callback, options) { if (typeof message !== 'string') { options = callback; callback = message; message = undefined; } if (typeof callback !== 'function') { options = callback; callback = undefined; } options = Object.assign({ dangerouslyUseHTMLString: true, }, options, { text: message, }); this._closeMessage(); try { window.tnx.loadingInstance = ElLoading.service(options); this._handleZIndex('.el-loading-mask'); window.tnx.app.eventBus.emit('tnx.showLoading', options); if (callback) { let vm = window.tnx.loadingInstance.vm; if (vm) { this.nextTickTimeout(vm, callback, 500); } else { callback(); } } } catch (e) { window.tnx.loadingInstance = null; console.error(e); } return window.tnx.loadingInstance; }, closeLoading() { if (window.tnx.loadingInstance) { // 确保绝对的单例 window.tnx.loadingInstance.close(); window.tnx.loadingInstance = undefined; } }, hideLoading() { this.closeLoading(); }, validateUploaded(vm, reject) { let result = true; let formRef = null; let refKeys = Object.keys(vm.$refs); for (let refKey of refKeys) { let refObj = vm.$refs[refKey]; if (Array.isArray(refObj)) { for (let ref of refObj) { if (typeof ref.validateUploaded === 'function') { if (ref.validateUploaded(reject) === false) { result = false; break; } } } } else if (refObj.$el.tagName === 'FORM' && typeof refObj.disable === 'function') { formRef = refObj; } else { if (typeof refObj.validateUploaded === 'function') { if (refObj.validateUploaded(reject) === false) { result = false; break; } } } } if (!result && formRef) { formRef.disable(false); } return result; }, }); tnxel.libs.ElementPlus = ElementPlus; tnxel.install = tnxel.util.function.around(tnxel.install, function (install, vm) { install.call(tnxel, vm); // 始终安装ElementPlus,以避免对于不同Vue实例未安装的问题 vm.use(ElementPlus, { locale: ElementPlus_zh_CN, }); }); tnxel.router.beforeLeave = tnxel.util.function.around(tnxel.router.beforeLeave, function (beforeLeave, router, from) { // 页面跳转前关闭当前页面中可能存在的所有消息框和对话框 window.tnx._closeMessage(); window.tnx.closeDialog(true); beforeLeave.call(window.tnx.router, router, from); }); tnxel.date = { formatDateTime: function (row, column, cellValue) { if (cellValue) { return new Date(cellValue).formatDateTime(); } return undefined; }, formatDate: function (row, column, cellValue) { if (cellValue) { return new Date(cellValue).formatDate(); } return undefined; }, formatTime: function (row, column, cellValue) { if (typeof cellValue === 'number') { cellValue = new Date(cellValue); } if (cellValue instanceof Date) { cellValue = cellValue.formatTime(); } if (typeof cellValue === 'string') { return cellValue; } return undefined; }, formatTimeMinute: function (row, column, cellValue) { if (typeof cellValue === 'number') { cellValue = new Date(cellValue); } if (cellValue instanceof Date) { cellValue = cellValue.formatTimeMinute(); } if (typeof cellValue === 'string') { let array = cellValue.split(':'); if (array.length > 1) { return array[0] + ':' + array[1]; } } return undefined; }, formatDateMinute: function (row, column, cellValue) { if (cellValue) { return new Date(cellValue).formatDateMinute(); } return undefined; }, formatDateMonth: function (row, column, cellValue) { if (cellValue) { return new Date(cellValue).formatDateMonth(); } return undefined; }, formatPermanentableDate: function (row, column, cellValue) { if (Array.isArray(cellValue)) { cellValue = cellValue[column]; } return tnxvue.util.date.formatPermanentableDate(cellValue); }, /** * 将Java标准的日期格式转换为Day.js的日期格式 * @param format Java标准的日期格式 * @returns {String} Day.js的日期格式 */ toDayJsDateFormat(format) { return format.replaceAll('y', 'Y').replaceAll('d', 'D'); }, }; tnxel.number = { formatPercent: function (row, column, cellValue) { if (typeof cellValue !== 'number') { cellValue = parseFloat(cellValue); } if (!isNaN(cellValue)) { return cellValue.toPercent(); } return undefined; } } tnxel.boolean = { items: { getText(type, value) { let items = this[type]; if (Array.isArray(items)) { for (let item of items) { if (item.value === value) { return item.text; } } } return undefined; }, has: [{ value: true, text: '有', }, { value: false, text: '无', }] }, format: function (row, column, cellValue) { if (typeof cellValue === 'boolean') { cellValue = cellValue.toText(); } return cellValue; }, formatHas: function (row, column, cellValue) { if (typeof cellValue === 'boolean') { cellValue = tnxel.boolean.items.getText('has', cellValue); } return cellValue; } } tnxel.table = {} const rpc = tnxel.app.rpc; rpc.handleErrors = tnxel.util.function.around(rpc.handleErrors, function (handleErrors, errors, options) { if (options && options.form) { let forms; if (Array.isArray(options.form)) { forms = options.form; } else { forms = [options.form]; } forms.forEach(form => { if (typeof form.disable === 'function') { form.disable(false); } }); } return handleErrors.call(rpc, errors, options); }); return tnxel; });