Files
zszq-trs/YLErpWeb/wwwroot/Scripts/fast/fastVue.base.js
T
张名锐 fd2a054764 feat(swap): 实现互换交易价格精度控制功能 init
- 添加 swapPricePrecisionHelper.js 工具类处理价格精度格式化
- 新增 swappriceprecision.js 配置文件定义各类金融产品的精度规则
- 在 EodPositionRisks.cshtml 和 SwapIncome.cshtml 中引入新的价格格式化脚本
- 替换原有的价格格式化函数为基于产品类型的动态精度控制
- 移除旧的价格验证和标准化逻辑,改用新的精度控制机制
- 添加 vue-swap-price-input 组件用于精确的价格输入控制
- 更新 Controller 中的价格处理逻辑以支持新精度格式化方式
2026-07-29 09:44:04 +08:00

594 lines
21 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;
// 粘贴进来的是显示值(可能带 %/‱ 后缀),先按 __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;
}
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() {
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;
}
_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));