@truenewx/tnxvue3
Version:
互联网技术解决方案:Vue3扩展支持
588 lines (568 loc) • 22.5 kB
JavaScript
// 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;
});