Files
zszq-trs/YLErpWeb/wwwroot/Scripts/fast/fastVue.base.js
T
hjhan 05826fe7d5 debug(fast): 为 numberInput 粘贴路径加 F12 诊断日志并清理 bundle.js 中的 BOM
- fastVue.base.js: 在 __onInput 粘贴分支和 __change 加入 console.log,
  输出 raw/parsed/append/percent,便于在浏览器 F12 排查粘贴值实际走向
- 重新生成 bundle.js,并去掉每个输入文件头的 BOM,避免 bundle.js 中间出现 ZWN BSP 不可见字符
2026-07-15 11:08:25 +08:00

597 lines
22 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
(function (window, $) {
function FastVue() {
}
FastVue.noop = function (a, b, c) { };
//解析数字,返回值:NAN或正常数字或''(输入参数为空)
FastVue.parseNumber = function (val,percent) {
switch (typeof val) {
case 'number': return val;
case 'string':
{
val = val.trim();
if (val === '') return '';
let isPercent = val.endsWith('%') || percent==true;
if (isPercent) {
val = val.replace(/%+$/, '');
if (val === '') return '';
}
if (val.endsWith('‱')) {
val = val.replace(/‱+$/, '');
if (val === '') return '';
}
let number = new Number(val);
return isPercent ? number / 100 : number;
}
default: return Number.NaN;
}
};
FastVue.extend = $.extend;
FastVue.setWidth = function (el, width) {
width && (el.style.width = typeof width === 'number' ? width + 'px' : width);
};
FastVue.getDomElement = function (el) {
if (!el) return null;
if (typeof el === 'string') {
return document.getElementById(el.startsWith('#') ? el.substring(1) : el);
}
el instanceof jQuery && (el = el[0]);
return el;
};
function Form(options) {
if (!(this instanceof Form)) {
throw 'FastVue.Form is a constructor and should be called with the `new` keyword';
}
this.data = {};
this.layout = {
display: 'inline',
title: {
width: 100
},
input: {
width: '165px'
}
};
this.submit = {
url: '',
before() { },
after() { }
};
this.fields = {};
this.view = {};
this.init(options);
}
FastVue.Form = Form;
window.FastVue = FastVue;
}(window, jQuery));
//autocomplete
(function (window, $) {
function __resetLookup(options, context) {
if (options.lookupFn) {
let lookupFn = options.lookupFn;
return options.lookup = function (query, callback) {
let queryLowerCase = (query || '').toLowerCase();
let suggestions = lookupFn.call(context) || [];
if (queryLowerCase) {
if (options.searchField) {
suggestions = suggestions.filter(data => {
return options.searchField.some(x => (data[x] || '').toLowerCase().indexOf(queryLowerCase) !== -1);
});
} else {
suggestions = suggestions.filter(data => {
return (data[options.valueField] || '').toLowerCase().indexOf(queryLowerCase) !== -1;
});
}
}
if (typeof suggestions[0] !== 'object') {
suggestions = suggestions.map(x => new Object({ value: x, data: x }));
} else {
suggestions = suggestions ? suggestions.map(x => {
return { value: x[options.nameField], data: x };
}) : [];
}
callback({ suggestions: suggestions });
};
}
if (!options.lookup) return;
if (typeof options.lookup === 'function') {
let lookupFn = options.lookup;
return options.lookup = function (query, callback) {
let queryLowerCase = (query || '').toLowerCase();
let suggestions = lookupFn.call(context, queryLowerCase) || [];
if (typeof suggestions[0] !== 'object') {
suggestions = suggestions.map(x => new Object({ value: x, data: x }));
} else {
suggestions = suggestions.map(x => {
return { value: x[options.nameField], data: x };
});
}
callback({ suggestions: suggestions });
};
}
if (Array.isArray(options.lookup)) {
let lookup = options.lookup;
if (typeof lookup[0] !== 'object') {
return options.lookup = lookup.map(x => new Object({ value: x, data: x }));
}
options.lookup = lookup.map(x => {
return { value: x[options.nameField], data: x };
});
if (options.searchField) {
options.lookupFilter = function (suggestion, originalQuery, queryLowerCase) {
return options.searchField.some(x => (suggestion.data[x] || '').toLowerCase().indexOf(queryLowerCase) !== -1);
};
} else {
options.lookupFilter = function (suggestion, originalQuery, queryLowerCase) {
return (suggestion.value || '').toLowerCase().indexOf(queryLowerCase) !== -1;
};
}
} else {
throw '[autocomplete.lookup]必须为数组或函数';
}
}
FastVue.autocomplete = function (el, options, context) {
!context && (context = this);
el = FastVue.getDomElement(el)
if (!el) throw '[FastVue.autocomplete]el is null or undefined:' + (options ? options.debugInfo : '');
let _el = el;//_el对应nameField
options = Object.assign({ minChars: 0, autoSelectFirst: true }, options);
!options.valueField && (options.valueField = options.nameField || 'value');
!options.nameField && (options.nameField = options.valueField);
if (options.nameField !== options.valueField) {
_el = el.cloneNode(true);
_el.setAttribute('name', '');
_el.setAttribute('value', '');
_el.id && _el.setAttribute('id', _el.id + '_auto');
el.setAttribute('type', 'hidden');
if (!el.parentNode) {
document.createElement("div").append(el);
}
el.parentNode.insertBefore(_el, el);
el.dataset.autocompleteClone = _el;
}
__resetLookup(options, context);
const onSelectFn = options.onSelect;
options.onSelect = function (suggestion) {
_el.dataset.select = '1';
if (options.nameField !== options.valueField) {
el.value = suggestion.data[options.valueField];
}
onSelectFn && onSelectFn(suggestion.data);
};
$(_el).autocomplete('dispose');
$(_el).on('focus', function () {
this.setAttribute("placeholder", this.value);
this.value = '';
this.dataset.select = '';
}).on('blur', function () {
!this.dataset.select && (this.value = this.getAttribute("placeholder"));
this.setAttribute("placeholder", '');
}).on('keydown', function (event) {
if ((event.which || event.keyCode) === 13) {
event.preventDefault();
event.stopPropagation();
$(this).blur();
}
}).autocomplete(options);
return {
setData(data) {
if (options.nameField === options.valueField) {
_el.value = (typeof data === 'object' ? data[options.nameField] : data) || '';
} else if (data) {
el.value = data[options.valueField] || '';
_el.value = data[options.nameField] || '';
} else {
_el.value = el.value = '';
}
},
dispose() {
$(_el).autocomplete('dispose');
$(_el).remove();
},
toggleDisabled(disabled) {
_el.disabled = typeof disabled === 'undefined' ? !_el.disabled : !!disabled;
},
clearCache() {
$(_el).autocomplete('clearCache');
},
setOptions(newOptions) {
$(_el).autocomplete('setOptions', Object.assign({}, options, newOptions));
}
};
};
//静态dispose方法
FastVue.autocomplete.dispose = function (el) {
(el instanceof jQuery) && (el = el.get(0));
if (!el) return;
$(el).autocomplete('dispose');
el.dataset && $(el.dataset.autocompleteClone).autocomplete('dispose');
};
}(FastVue, jQuery));
//numberInput
(function (window, $) {
FastVue.numberInput = function (el, options) {
let _el = typeof el === 'string' ? document.getElementById(el.replace(/^#/, '')) : el instanceof jQuery ? el[0] : el;
if (!_el) {
throw "[FastVue.numberInput]not found el:" + el;
}
let _ctrlV = false, _chnInput = -1;
let _options = { append: '', precision: 2, negative: false, grouping: false };
function getValue() {
let val = _el.value;
if (val && val !== _options.append) {
_options.append && _options.append !== '%' && _options.append !== '‱' && (val = val.replace(new RegExp(_options.append + "$"), ''));
return FastVue.parseNumber(val, _options.percent);
}
return '';
}
function setOptions(options) {
options = Object.assign(_options, options);
!options.append && (options.append = '');
let precision = parseInt(options.precision) || 0;
options.precision = precision < 0 ? 0 : precision;
options.negative = !!options.negative;
_options = options;
setValue(getValue());
}
function setValue(value) {
if (value || value === 0) {
let oval = parseFloat(value) || 0;
if (_options.append === '%' || _options.percent == true) {
oval *= 100;
}
else if (_options.append ==="‱") {
oval *= 10000;
}
if (_options.precision > 0) {
let str = main.formatNumber(oval, _options.precision, { grouping: _options.grouping });
if (typeof value === 'number' && str.endsWith("0") && str.includes('.')) {
str = str.replace(/\.?0+$/, '');
}
_el.value = str + _options.append;
} else {
let str = main.formatNumber(Math.floor(oval), 0, { grouping: _options.grouping });
_el.value = str + _options.append;
}
} else {
_el.value = '';
}
}
function checkDotInput() {
if (this.selectionStart >= this.value.length) {
return _options.append && this.value.endsWith(_options.append) ? false : this.value.indexOf('.') < 0;
}
if (this.value.length - _options.append.length - this.selectionEnd > _options.precision) {
return false;
}
return this.value.substring(0, this.selectionStart).indexOf('.') < 0 && this.value.substring(this.selectionEnd, this.value.length).indexOf('.') < 0;
}
function __keyHandle(event) {
if (!event) return false;
_chnInput = -1;
let charCode = event.which || event.keyCode;
switch (charCode) {
case 8: //break space
return !_options.append || !this.value.endsWith(_options.append) || this.selectionStart < this.value.length - _options.append.length + 1;
case 9: //tab
case 35: //end
case 36: //home
case 37: //left arrow
case 39: //right arrow
case 42: //print
case 116: //F5
return true;
case 46: //del
return !_options.append || !this.value.endsWith(_options.append) || this.selectionStart < this.value.length - _options.append.length;
case 229:
return _chnInput = this.selectionStart;
}
if (event.shiftKey) return false;
switch (charCode) {
case 109: //negative sign(-)
return _options.negative && this.selectionStart < 1 && this.value.charAt(0) !== '-';
case 189: //negative sign(-_)
return _options.negative && !event.shiftKey && this.selectionStart < 1 && this.value.charAt(0) !== '-';
case 110: //dot(.)
return _options.precision > 0 && checkDotInput.call(this);
case 190: //dot(.>)
return _options.precision > 0 && !event.shiftKey && checkDotInput.call(this);
case 13: //enter
case 108: //enter
$(this).blur();
return true;
case 67: //ctrl+c
return event.ctrlKey;
case 86: //ctrl+v
return event.ctrlKey && (_ctrlV = true);
default:
if (charCode < 48 || charCode > 57 && (charCode < 96 || charCode > 105)) {
return false;
}
if (this.selectionStart === 0) {
return !this.value || this.value.charAt(this.selectionEnd) !== '-';
}
if (_options.precision < 1) {
return true;
}
if (this.selectionStart >= this.value.length && _options.append && this.value.endsWith(_options.append)) {
return false;
}
if (this.selectionEnd > this.selectionStart) {
return /\d/.test(this.value.substring(this.selectionStart, this.selectionEnd));
} else {
let dotIndex = this.value.lastIndexOf('.', this.selectionStart - 1);
return dotIndex < 0 || !/\d/.test(this.value[dotIndex + _options.precision]);
}
}
}
//处理中文字符输入
function __onChineseInput(chnPos) {
if (this.value.length < chnPos) {
chnPos = this.value.length - 1;
}
let ch = this.value.charCodeAt(chnPos);
if (ch > 47 && ch < 58) {
chnPos += 1;
}
else if (ch === 46 || ch === 12290) {
if (_options.precision > 0 && !/\d/.test(this.value[this.selectionStart + _options.precision])
&& this.value.lastIndexOf('.', chnPos - 1) < 0 && this.value.indexOf('.', this.selectionStart) < 0) {
if (ch === 12290) {
this.value = this.value.substring(0, chnPos) + '.' + this.value.substring(this.selectionStart);
this.setSelectionRange(chnPos + 1, chnPos + 1);
return;
}
chnPos += 1;
}
}
else if (chnPos === 0 && ch === 45 && _options.negative && this.value[this.selectionStart] !== '-') { //负号
return;
} else {
for (; chnPos >= 0; chnPos--) {
ch = this.value.charCodeAt(chnPos);
if (ch === 46 || ch > 47 && ch < 58 || chnPos === 0 && ch === 45 && _options.negative) {
chnPos += 1;
break;
}
}
}
this.value = this.value.substring(0, chnPos) + this.value.substring(this.selectionStart);
this.setSelectionRange(chnPos, chnPos);
}
//处理字符输入
function __onInput() {
if (_ctrlV) {
_ctrlV = false;
console.log('[numberInput paste] raw=', this.value, 'append=', _options.append, 'percent=', _options.percent);
// 粘贴进来的是显示值(可能带 %/‱ 后缀),先按 __change 同款口径解析为模型值再回显,
// 避免 setValue 把显示值再乘以 100/10000#EQD-5914 债券价格粘贴 ×100
let f = '';
if (this.value && this.value !== _options.append) {
f = parseFloat(this.value.replaceAll(",", "")) || 0;
if (_options.append === '%' || _options.percent == true) f /= 100;
else if (_options.append === '‱') f /= 10000;
}
console.log('[numberInput paste] parsed=', f);
return setValue(f);
}
if (_chnInput >= 0) {
__onChineseInput.call(this, _chnInput);
}
if (!_options.append || !this.value) return;
let appended = true;
if (this.value !== _options.append) {
appended = this.value.endsWith(_options.append);
}
if (!appended) {
let caretPos = this.selectionStart;
this.value += _options.append;
this.setSelectionRange(caretPos, caretPos);
} else if (_options.negative && this.selectionStart === 2 && this.value[1] === '-') {
this.value = this.value.substring(1);
this.setSelectionRange(1, 1);
}
}
//输入完成处理
function __change() {
console.log('[numberInput change] raw=', this.value, 'append=', _options.append, 'percent=', _options.percent);
let f = '';
if (this.value && this.value !== _options.append) {
f = parseFloat(this.value.replaceAll(",", "")) || 0;
if (_options.append === '%' || _options.percent == true) f /= 100;
else if (_options.append === '‱') f /= 10000;
}
console.log('[numberInput change] parsed=', f, 'value=', this.value);
_options.onchange && _options.onchange(f, this.value);
}
//功能禁用
function __disable() {
return false;
}
setOptions(options);
$(_el).on('keydown', __keyHandle).on('dragenter', __disable).on('input', __onInput).on('change', __change);
return {
isEmpty() {
return !_el.value || _el.value === _options.append;
},
getValue: getValue,
setValue: setValue,
setOptions: setOptions,
getOptions() {
return Object.assign({}, _options);
},
dispose() {
$(_el).off();
}
};
};
//静态dispose方法
FastVue.numberInput.dispose = function (el) {
(el instanceof jQuery ? el : $(el)).off();
};
}(FastVue, jQuery));
//FastVue.vueNumberInput
//数字输入组件(借助FastVue.numberInput)
(function (global) {
global.vueNumberInput = function () {
return {
props: {
value: {
type: Number,
default: ''
},
format: {
type: Object,
default: {
append: '',
precision: 2,
negative: false,
grouping: false,
percent: false
}
},
disabled: {
type: Boolean
},
ret_type: {
type: Number,
default: 0
}
},
data() {
return { inputctrl: null,init:true};
},
mounted() {
let self = this;
let options = FastVue.extend({ onchange: this.onchange }, this.format);
this.inputctrl = FastVue.numberInput(this.$el, options);
this.inputctrl.setValue(this.value)
},
methods: {
onchange(value, text) {
this.init = false;
this.$emit('input', this.ret_type === 1 ? text : value);
}
},
watch: {
value(val, old) {
let val1 = '';
switch (typeof val) {
case 'number':
val1 = val || 0; break;
case 'string':
if (val) {
val1 = parseFloat(val) || 0;
if (val1 && (val.trimEnd().endsWith('%') || (this.format.percent && !this.init))) {
val1 /= 100;
} else if (val1 && (val.trimEnd().endsWith('‱'))){
val1 /= 10000;
}
}
break;
}
if (!this.inputctrl.isEmpty()) {
let val2 = this.inputctrl.getValue();
if (Math.abs(val1 - val2) < 1e-10) return;
}
this.$nextTick(function () {
this.inputctrl.setValue(val1);
});
},
format: {
deep: true,
handler(val) {
this.inputctrl.setOptions(val);
this.$nextTick(function () {
this.inputctrl.setValue(this.value);
});
}
}
},
destroyed() {
FastVue.numberInput.dispose(this.$el);
},
template: '<input type="text" v-bind:disabled="disabled">'
};
};
}(window.FastVue));