320 lines
13 KiB
JavaScript
320 lines
13 KiB
JavaScript
const consClients = ylotc.clients;
|
||
|
||
//定价格式化(来自配置)
|
||
const inputFormatPercent = Object.freeze({ precision: 2, append: '%' });
|
||
const inputFormatPercentNegative = Object.freeze({ precision: 2, append: '%', negative: true });
|
||
const inputFormatNegative = Object.freeze({ precision: 2, negative: true });
|
||
|
||
//区间追保结构(RuleType=15)只读回显用常量,与 marginTemplateV2Edit.js 保持一致
|
||
const RangeMarginRuleType = 15;
|
||
//允许配期限档(SpanConfig.BondTerm)的资产类型掩码,本期仅利率债
|
||
const TermTierEnabledUnderlyingMask = 16;
|
||
//利率债区块固定展开的4个期限档([BondTerm值, 展示文案])
|
||
const SpanBondTerms = [['<5y', '≤5y'], ['5y-10y', '(5y-10y]'], ['10y-30y', '(10y-30y]'], ['>30y', '>30y']];
|
||
//标的资产类型标志位 -> 名称(与 marginTemplateV2Edit 的录入区块标题一致)
|
||
const UnderlyingTypeNames = [
|
||
[16, "利率债"], [32, "信用债"], [64, "其它债券"], [128, "股票"], [256, "股指"], [512, "股指期货"],
|
||
[1024, "商品期货"], [2048, "商品现货"], [4096, "新三板挂牌股票"], [8192, "香港股票"], [16384, "香港股指"],
|
||
[32768, "基金及基金专户"], [65536, "黄金期货"], [131072, "国债期货"], [262144, "其他期货"], [524288, "黄金现货"],
|
||
[1048576, "其他现货"], [2097152, "境外期货"], [4194304, "境外现货"], [8388608, "境外股票"], [16777216, "境外股指"],
|
||
[33554432, "汇率"], [67108864, "Shibor"], [134217728, "银行间回购定盘"], [268435456, "利率收益率"], [536870912, "债券指数"]
|
||
];
|
||
|
||
const vue = new Vue({
|
||
el: '#marginTemplateV2Form',
|
||
data: {
|
||
clientMarginTemplate: page.clientMarginTemplate,
|
||
marginTemplates: page.marginTemplates,
|
||
marginTemplate: page.marginTemplate,
|
||
clientLevels: [],
|
||
clientNames: [],
|
||
isClientLevelDisabled: false,
|
||
isClientNameDisabled: false,
|
||
isAdd: page.isAdd
|
||
},
|
||
created: function () {
|
||
this.clientMarginTemplate.ValueDate = new moment(this.clientMarginTemplate.ValueDate).format("YYYY-MM-DD");
|
||
},
|
||
computed: {
|
||
//区间追保结构只读参数组:连续利率债行归一个区块、按固定4档对位(缺档不补造、同档重复/异常档独立成段保留展示);
|
||
//其余行(含ETF子类行)每行独立成块——分组口径与 marginTemplateV2Edit.rebuildSpanBlocks 一致,但只回显不新增行
|
||
ruleRangeBlocks() {
|
||
if (this.marginTemplate.RuleType != RangeMarginRuleType) return [];
|
||
var details = this.marginTemplate.Details || [];
|
||
var that = this;
|
||
var blocks = [];
|
||
var i = 0;
|
||
while (i < details.length) {
|
||
if ((details[i].UnderlyingType || 0) === TermTierEnabledUnderlyingMask) {
|
||
var j = i;
|
||
while (j < details.length && (details[j].UnderlyingType || 0) === TermTierEnabledUnderlyingMask) j++;
|
||
var byTerm = {};
|
||
var extras = [];
|
||
for (var k = i; k < j; k++) {
|
||
var bt = (details[k].SpanConfig && details[k].SpanConfig.BondTerm) || '';
|
||
var canonical = SpanBondTerms.some(function (t) { return t[0] === bt; });
|
||
if (canonical && !byTerm[bt]) byTerm[bt] = details[k]; else extras.push(details[k]);
|
||
}
|
||
var sections = SpanBondTerms.map(function (t) {
|
||
return { key: 't' + t[0], termLabel: t[1], detail: byTerm[t[0]] || null };
|
||
});
|
||
extras.forEach(function (r, xi) {
|
||
sections.push({ key: 'x' + xi, termLabel: that.bondTermLabel(r), detail: r });
|
||
});
|
||
blocks.push({ key: 'i' + i, no: blocks.length + 1, ut: TermTierEnabledUnderlyingMask, isTBond: true, etfKind: '', sections: sections });
|
||
i = j;
|
||
} else {
|
||
var d = details[i];
|
||
blocks.push({
|
||
key: 'i' + i, no: blocks.length + 1, ut: d.UnderlyingType || 0, isTBond: false,
|
||
etfKind: (d.SpanConfig && d.SpanConfig.EtfKind) || '',
|
||
sections: [{ key: 'single', termLabel: '', detail: d }]
|
||
});
|
||
i++;
|
||
}
|
||
}
|
||
return blocks;
|
||
}
|
||
},
|
||
methods: {
|
||
//资产类型标志位掩码 -> 名称(0=全部),与 marginTemplateV2Edit.underlyingTypeNames 一致
|
||
underlyingTypeNames(mask) {
|
||
mask = parseInt(mask) || 0;
|
||
if (mask === 0) return "全部";
|
||
var names = [];
|
||
for (var i = 0; i < UnderlyingTypeNames.length; i++) {
|
||
if ((mask & UnderlyingTypeNames[i][0]) > 0) names.push(UnderlyingTypeNames[i][1]);
|
||
}
|
||
return names.length > 0 ? names.join("、") : "全部";
|
||
},
|
||
//期限档 BondTerm -> 展示文案(空=全部)
|
||
bondTermLabel(detail) {
|
||
var v = (detail.SpanConfig && detail.SpanConfig.BondTerm) || '';
|
||
var map = { '': '全部', '<5y': '≤5y', '5y-10y': '(5y-10y]', '10y-30y': '(10y-30y]', '>30y': '>30y' };
|
||
return map[v] !== undefined ? map[v] : v;
|
||
},
|
||
//区间计价口径文案:按 detail 资产类型切换,与取数侧对齐(债券类=中债估值净价/期初全价×券面总额,其余=收盘价口径),
|
||
//直接沿用 marginTemplateV2Edit.spanText 的判定
|
||
spanText(detail) {
|
||
var ut = (detail && detail.UnderlyingType) || 0;
|
||
var bondMask = 16 | 32 | 64;
|
||
var isBond = ut !== 0 && (ut & ~bondMask) === 0;
|
||
if (!isBond) {
|
||
return {
|
||
priceInit: '参考标的期初净价',
|
||
priceCur: '参考标的当前收盘价',
|
||
priceCurShort1: '参考标的当前收盘价',
|
||
priceCurShort: '参考标的当前收盘价',
|
||
amountBase: '参考标的期初价格 × 参考标的名义份额'
|
||
};
|
||
}
|
||
return {
|
||
priceInit: '期初净价',
|
||
priceCur: '当前净价',
|
||
priceCurShort1: '当前净价',
|
||
priceCurShort: '当前净价',
|
||
amountBase: '期初全价 × 券面总额'
|
||
};
|
||
},
|
||
//changeClient(yldata) {
|
||
// let client = yldata || { id: 0 };
|
||
// this.clientMarginTemplate.ClientId = client.id;
|
||
//},
|
||
changeMarginTemplate() {
|
||
this.marginTemplates.forEach(x => {
|
||
if (this.clientMarginTemplate.MarginTemplateId === x.id) {
|
||
this.marginTemplate = x;
|
||
$('#suitableType').prop('title', this.marginTemplate.TradeTypes);
|
||
}
|
||
});
|
||
|
||
},
|
||
saveMarginTemplateV2() {
|
||
var thisObj = this;
|
||
main.post("/client_margin_template/saveClientMarginTemplate", { clientMarginTemplate: thisObj.clientMarginTemplate }).done(function (resp) {
|
||
try {
|
||
window.parent.reloadmargin_template();
|
||
(parent || window).layer.closeAll();
|
||
} catch (e) { }
|
||
});
|
||
},
|
||
showTemplateDetail(detail) {
|
||
vueDetail.backupDetail = _.cloneDeep(detail);
|
||
detail.ValueDate = new moment(detail.ValueDate).format("YYYY-MM-DD");
|
||
vueDetail.detail = detail;
|
||
vueDetail.isAdd = false;
|
||
vueDetail.ruleType = vue.marginTemplate.RuleType;
|
||
$("#myModal").modal("show");
|
||
},
|
||
SetClientLevelDropDown() {
|
||
$.ajax({
|
||
type: "get",
|
||
url: "/client_margin_template/GetAllClientLevels",
|
||
success: function (data) {
|
||
if (data.obj) {
|
||
for (var i = 0; i < data.obj.length; i++) {
|
||
vue.clientLevels.push(data.obj[i]);
|
||
}
|
||
|
||
if (vue.isAdd) {
|
||
vue.clientMarginTemplate.ClientLevel = data.obj[0].Value;
|
||
}
|
||
|
||
|
||
}
|
||
},
|
||
error: function (msg) {
|
||
alert("error:" + msg);
|
||
}
|
||
});
|
||
},
|
||
SetClientNameDropDown() {
|
||
$.ajax({
|
||
type: "get",
|
||
url: "/client_margin_template/GetAllClients",
|
||
success: function (data) {
|
||
if (data.obj) {
|
||
for (var i = 0; i < data.obj.length; i++) {
|
||
|
||
vue.clientNames.push(data.obj[i]);
|
||
}
|
||
}
|
||
},
|
||
error: function (msg) {
|
||
alert("error:" + msg);
|
||
}
|
||
});
|
||
}
|
||
},
|
||
mounted() {
|
||
if (page.isGFSM) {
|
||
if (this.isAdd) {
|
||
this.isClientNameDisabled = true;
|
||
}
|
||
else {
|
||
if (this.clientMarginTemplate.ClientId == "0") this.isClientNameDisabled = true;
|
||
if (this.clientMarginTemplate.ClientLevel == "") this.isClientLevelDisabled = true;
|
||
}
|
||
|
||
this.SetClientLevelDropDown();
|
||
|
||
}
|
||
this.SetClientNameDropDown();
|
||
if (this.marginTemplate.TradeTypes != null && this.marginTemplate.TradeTypes != 'undefined') {
|
||
$('#suitableType').prop('title', this.marginTemplate.TradeTypes);
|
||
}
|
||
|
||
},
|
||
watch: {
|
||
'clientMarginTemplate.ClientLevel': {
|
||
handler(newVal, oldVal) {
|
||
if (newVal == '') {
|
||
this.isClientLevelDisabled = true;
|
||
this.isClientNameDisabled = false;
|
||
|
||
if (this.clientMarginTemplate.ClientId == '0') {
|
||
if (this.clientNames.length > 0) {
|
||
this.clientMarginTemplate.ClientId = this.clientNames[0].Value;
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
},
|
||
immediate: false
|
||
},
|
||
'clientMarginTemplate.ClientId': {
|
||
handler(newVal, oldVal) {
|
||
if (newVal == '0') {
|
||
this.isClientNameDisabled = true;
|
||
this.isClientLevelDisabled = false;
|
||
if (this.clientMarginTemplate.ClientLevel == '') {
|
||
if (this.clientLevels.length > 0) {
|
||
this.clientMarginTemplate.ClientLevel = this.clientLevels[0].Value;
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
},
|
||
immediate: false
|
||
}
|
||
},
|
||
components: {
|
||
'vue-datepicker': FastVue.vueDatePicker(),
|
||
'vue-number-input': FastVue.vueNumberInput()
|
||
}
|
||
});
|
||
|
||
$(function () {
|
||
$(".datepicker").change(function () {
|
||
var dateVal = $(this).val();
|
||
if (!dateVal) return;
|
||
dateVal = dateVal.replace(/\D/g, '').padStart(4, '0');
|
||
switch (dateVal.length) {
|
||
case 4:
|
||
dateVal = new Date().getFullYear() + dateVal; break;
|
||
case 6:
|
||
dateVal = '20' + dateVal; break;
|
||
case 8: break;
|
||
default:
|
||
dateVal = dateVal.length > 8 ? dateVal.substring(0, 8) : ''; break;
|
||
}
|
||
|
||
if (dateVal) {
|
||
dateVal = moment(dateVal).format('YYYY-MM-DD');
|
||
!/^\d+/.test(dateVal) && (dateVal = '');
|
||
}
|
||
|
||
$(this).datepicker("setDate", dateVal);
|
||
});
|
||
|
||
SetAceDropDown();
|
||
|
||
var width = 152;
|
||
for (var i = 0; i < consClients.length; i++) {
|
||
let ele = document.createElement('span')
|
||
ele.innerText = consClients[i].Name;
|
||
ele.style.fontSize = '14px';
|
||
document.documentElement.append(ele);
|
||
var charLength = ele.offsetWidth + 28;//滚动条
|
||
document.documentElement.removeChild(ele);
|
||
if (charLength > width) {
|
||
width = charLength
|
||
}
|
||
}
|
||
|
||
//if (!page.isGFSM) {
|
||
// let autoClient = FastVue.autocomplete(document.getElementById('ClientId'), {
|
||
// nameField: 'Name', valueField: 'id', searchField: ['Name', 'PinYin'], width: width,
|
||
// lookup: consClients, onSelect: vue.changeClient
|
||
// });
|
||
// let clientId = page.clientMarginTemplate.ClientId;
|
||
// let client = clientId ? consClients.find(x => x.id === clientId) : null;
|
||
// !client && page.isAdd && (client = consClients[0]);
|
||
// autoClient.setData(client);
|
||
// vue.changeClient(client);
|
||
//}
|
||
|
||
});
|
||
|
||
var vueDetail = new Vue({
|
||
el: "#myModal",
|
||
data: {
|
||
detail: {},
|
||
backupDetail: {},
|
||
isAdd: true,
|
||
ruleType: 0,
|
||
},
|
||
created: function () {
|
||
},
|
||
methods: {
|
||
closeModal: function () {
|
||
$('#myModal').modal('hide');
|
||
}
|
||
},
|
||
components: {
|
||
'vue-datepicker': FastVue.vueDatePicker(),
|
||
'vue-number-input': FastVue.vueNumberInput()
|
||
}
|
||
}); |