Merge branch 'glms/feature/1.4.2' into glms/feature/0812_zmr_divPower

# Conflicts:
#	YLErpDAL/Modules/EodModule/BondPaymentService.cs
#	YLErpDAL/Modules/SwapModule/SwapDealService.cs
This commit is contained in:
张名锐
2026-08-20 16:21:13 +08:00
158 changed files with 7931 additions and 3252 deletions
@@ -109,9 +109,52 @@ const vueTradeType = function () {
};
};
//标的选择组件
//标的选择组件(EQD-7049:改为服务端搜索,不再依赖全量 ylotc.underlyings,避免十几万标的整段下载卡死)
const vueUnderlying = function () {
const _suggestionTpl = _.template($('#underlyingSuggestionTpl').html());
// 标的缓存:按 品种|关键词 隔离;乱序响应由 token 丢弃(helper 收在函数内,避免全局绑定冲突)
const _cache = {};
const _tokens = {};
function _fetch(varietyId, query, cb) {
var key = (varietyId || 0) + '|' + (query || '');
var token = (_tokens[key] = (_tokens[key] || 0) + 1);
var postData = {
FilterCode: (query || '').toUpperCase(),
VarietyId: varietyId || 0,
MaxShowLength: 20,
BlackLimit: 1,
UseForTrading: true,
IncludeMatured: true,
CheckLaunch: true
};
main.post('/frontdata/AjaxGetUnderlyingSelect', postData).done(function (res) {
if (_tokens[key] !== token) return; // 丢弃过期响应
var arr = (res && (res.obj || res.data)) || [];
var norm = arr.map(function (x) {
return {
Code: x.Code,
Name: x.Name,
InstrumentType: x.InstrumentType,
VarietyId: x.VarietyId,
Disallow: !!x.Disallow,
IsCombined: !!x.IsSynthetic || !!x.IsBasket,
BlackWhiteState: x.BlackWhiteState || 0,
PinYin: x.PinYin || ''
};
});
cb && cb(norm);
});
}
function _filter(list, query, varietyId) {
if (!query) return (list || []).slice(0, 20);
query = query.toUpperCase();
return (list || []).filter(function (x) {
if (varietyId && x.VarietyId !== varietyId) return false;
if (x.IsCombined) return false; // 与原逻辑一致:搜索时排除组合标的
return (x.Code && x.Code.toUpperCase().indexOf(query) !== -1)
|| (x.PinYin && x.PinYin.toUpperCase().indexOf(query) !== -1);
}).slice(0, 20);
}
return {
props: ['underlying'],
data() {
@@ -120,27 +163,24 @@ const vueUnderlying = function () {
mounted() {
var self = this;
this.jqInput = $(this.$el).children(0);
// EQD-7049:预拉默认20条(当前品种),避免下拉空白
_fetch(self.underlying.VarietyId, '', function (list) {
_cache[self.underlying.VarietyId || 0] = list;
try { $(self.jqInput).autocomplete('search', ''); } catch (e) {}
});
this.autoctrl = FastVue.autocomplete(this.jqInput, {
valueField: 'Code',
lookup(query, callback) {
var arr = [];
if (!query) {
var varietyId = self.underlying.VarietyId;
ylotc.underlyings.forEach(x => {
(!varietyId || x.VarietyId === varietyId) && arr.push(x);
});
} else {
query = query.toUpperCase();
ylotc.underlyings.forEach(x => {
if (x.Code.toUpperCase().indexOf(query) !== -1 || x.PinYin && x.PinYin.indexOf(query) !== -1 && !x.IsCombined) {
arr.push(x);
}
var varietyId = self.underlying.VarietyId;
var cached = _cache[varietyId || 0] || [];
var immediate = _filter(cached, query, varietyId);
if (query) {
// 有输入时异步向服务端搜索并刷新缓存(乱序响应由 token 丢弃)
_fetch(varietyId, query, function (list) {
_cache[varietyId || 0] = list;
});
}
if (arr.length < 30) {
arr = _.sortBy(arr, x => x.Code);
}
return arr;
return immediate;
},
onSelect(data) {
if (self.underlying !== data) {
@@ -1430,6 +1470,12 @@ const vueTrade = function () {
//更新标的
updateUnderlying(reqData, fromSelect) {
let self = this;
// EQD-7049:新建空白页未选标的/品种/类型时,跳过必然失败的后端默认标的查询,避免报“标的信息缺失”
var hasQueryKey = !!(reqData.UnderlyingCode || reqData.InstrumentType || reqData.VarietyId > 0);
if (!hasQueryKey) {
!fromSelect && (self.viewState.underlying = tradeHelper.getEmptyUnderlying());
return;
}
var instTypeChanged = !!reqData.InstrumentType;
!fromSelect && (self.viewState.underlying = tradeHelper.getEmptyUnderlying());
main.post("/pricing/AjaxGetUnderlying", reqData).done(function (resp) {
@@ -108,9 +108,52 @@ const vueTradeType = function () {
};
};
//标的选择组件
//标的选择组件(EQD-7049:改为服务端搜索,不再依赖全量 ylotc.underlyings,避免十几万标的整段下载卡死)
const vueUnderlying = function () {
const _suggestionTpl = _.template($('#underlyingSuggestionTpl').html());
// 标的缓存:按 品种|关键词 隔离;乱序响应由 token 丢弃(helper 收在函数内,避免全局绑定冲突)
const _cache = {};
const _tokens = {};
function _fetch(varietyId, query, cb) {
var key = (varietyId || 0) + '|' + (query || '');
var token = (_tokens[key] = (_tokens[key] || 0) + 1);
var postData = {
FilterCode: (query || '').toUpperCase(),
VarietyId: varietyId || 0,
MaxShowLength: 20,
BlackLimit: 1,
UseForTrading: true,
IncludeMatured: true,
CheckLaunch: true
};
main.post('/frontdata/AjaxGetUnderlyingSelect', postData).done(function (res) {
if (_tokens[key] !== token) return; // 丢弃过期响应
var arr = (res && (res.obj || res.data)) || [];
var norm = arr.map(function (x) {
return {
Code: x.Code,
Name: x.Name,
InstrumentType: x.InstrumentType,
VarietyId: x.VarietyId,
Disallow: !!x.Disallow,
IsCombined: !!x.IsSynthetic || !!x.IsBasket,
BlackWhiteState: x.BlackWhiteState || 0,
PinYin: x.PinYin || ''
};
});
cb && cb(norm);
});
}
function _filter(list, query, varietyId) {
if (!query) return (list || []).slice(0, 20);
query = query.toUpperCase();
return (list || []).filter(function (x) {
if (varietyId && x.VarietyId !== varietyId) return false;
if (x.IsCombined) return false; // 与原逻辑一致:搜索时排除组合标的
return (x.Code && x.Code.toUpperCase().indexOf(query) !== -1)
|| (x.PinYin && x.PinYin.toUpperCase().indexOf(query) !== -1);
}).slice(0, 20);
}
return {
props: ['underlying'],
data() {
@@ -119,27 +162,24 @@ const vueUnderlying = function () {
mounted() {
var self = this;
this.jqInput = $(this.$el).children(0);
// EQD-7049:预拉默认20条(当前品种),避免下拉空白
_fetch(self.underlying.VarietyId, '', function (list) {
_cache[self.underlying.VarietyId || 0] = list;
try { $(self.jqInput).autocomplete('search', ''); } catch (e) {}
});
this.autoctrl = FastVue.autocomplete(this.jqInput, {
valueField: 'Code',
lookup(query, callback) {
var arr = [];
if (!query) {
var varietyId = self.underlying.VarietyId;
ylotc.underlyings.forEach(x => {
(!varietyId || x.VarietyId === varietyId) && arr.push(x);
});
} else {
query = query.toUpperCase();
ylotc.underlyings.forEach(x => {
if (x.Code.toUpperCase().indexOf(query) !== -1 || x.PinYin && x.PinYin.indexOf(query) !== -1 && !x.IsCombined) {
arr.push(x);
}
var varietyId = self.underlying.VarietyId;
var cached = _cache[varietyId || 0] || [];
var immediate = _filter(cached, query, varietyId);
if (query) {
// 有输入时异步向服务端搜索并刷新缓存(乱序响应由 token 丢弃)
_fetch(varietyId, query, function (list) {
_cache[varietyId || 0] = list;
});
}
if (arr.length < 30) {
arr = _.sortBy(arr, x => x.Code);
}
return arr;
return immediate;
},
onSelect(data) {
if (self.underlying !== data) {
@@ -1044,6 +1084,12 @@ const vueTrade = function () {
//更新标的
updateUnderlying(reqData, fromSelect) {
let self = this;
// EQD-7049:新建空白页未选标的/品种/类型时,跳过必然失败的后端默认标的查询,避免报“标的信息缺失”
var hasQueryKey = !!(reqData.UnderlyingCode || reqData.InstrumentType || reqData.VarietyId > 0);
if (!hasQueryKey) {
!fromSelect && (self.viewState.underlying = tradeHelper.getEmptyUnderlying());
return;
}
var instTypeChanged = !!reqData.InstrumentType;
!fromSelect && (self.viewState.underlying = tradeHelper.getEmptyUnderlying());
main.post("/pricing/AjaxGetUnderlying", reqData).done(function (resp) {
@@ -2000,9 +2000,6 @@ const subView = (function (jqGridMgr) {
if (tradeType === "收益互换") {
srcurl = "/swaptrade2/SwapUnwind/?enid=" + encryptId;
if (StructureType=="多空组合") {
srcurl = "/swaptrade2/SwapLongShortUnwind/?enid=" + encryptId;
}
area = ["1300px", "720px"];
}
if (tradeType.indexOf("远期") >= 0) {
@@ -112,7 +112,7 @@ const vue = new Vue({
this.multiplier,
isUseApproval);
this.interestList = model.FlowEvents.filter((item) => {
return item.InterestMode == 1 || item.InterestMode == 2 || item.InterestMode == 7 || item.InterestMode == 8 || item.InterestMode == 9;
return item.InterestMode == 1 || item.InterestMode == 2 || item.InterestMode == 9;
});
this.marginList = model.FlowEvents.filter((item) => {
return item.InterestMode == 5 || item.InterestMode == 6;
@@ -255,7 +255,7 @@ const vue = new Vue({
var postData = { ValueDate: thisObj.deal.ValueDate, unwindDate: thisObj.deal.UnwindDate, tradeId: thisObj.deal.SwapTradeId, closePercent: 1, eventType:3 }
main.post("/swaptrade2/GetUnwindInterestList", postData, { async: true }).done(function (resp) {
thisObj.interestList = resp.obj.filter((item) => {
return item.InterestMode == 1 || item.InterestMode == 2 || item.InterestMode == 7 || item.InterestMode == 8 || item.InterestMode == 9;
return item.InterestMode == 1 || item.InterestMode == 2 || item.InterestMode == 9;
});
thisObj.marginList = resp.obj.filter((item) => {
return item.InterestMode == 5 || item.InterestMode == 6;
@@ -1,228 +0,0 @@
//otcformat禁止千分位分组
window.otcformat.options.disableGrouping = true;
const inputFormatEqvNotional = swapPricePrecision.getCommonInputFormat('amount', { append: '' });
const swapInstrumentType = (model.FlowEvents || []).find(item => item && item.UnderlyingInstrumentType)?.UnderlyingInstrumentType || model.UnderlyingInstrumentType || '';
const formatSwapAmount = value => swapPricePrecision.normalizeCommon('amount', value);
const formatSwapQuantity = value => swapPricePrecision.normalizeCommon('quantity', value, swapInstrumentType);
let ValueDate = model.ValueDate;
const vue = new Vue({
el: '#vueDiv',
data: {
deal: model,
interestList: [],
marginList: [],
},
computed: {
maxUnwindDate() {
return ValueDate;
},
minStartDate() {
return this.deal.StartDate;
}
},
created() {
this.initDeal();
this.setValueDate();
},
methods: {
formatAmount(value) {
return swapPricePrecision.formatCommon('amount', value);
},
formatQuantity(value) {
return swapPricePrecision.formatCommon('quantity', value, swapInstrumentType);
},
initDeal() {
this.interestList = model.FlowEvents.filter((item) => {
return item.InterestMode == 1 || item.InterestMode == 2 || item.InterestMode == 7 || item.InterestMode == 8 || item.InterestMode == 9;
});
this.marginList = model.FlowEvents.filter((item) => {
return item.InterestMode == 5 || item.InterestMode == 6;
});
},
setValueDate(e) {//修改平仓日期
if (e) {
this.deal.ValueDate = e;
this.deal.UnwindDate = e;
}
if (!isUseApproval) {
this.getInterestList();
} else {
this.dataFormat();
}
},
dataFormat() {
this.deal.NotionalValue = formatSwapAmount(this.deal.NotionalValue);
this.deal.PosiNotionalValue = formatSwapAmount(this.deal.PosiNotionalValue);
this.deal.NotionalQty = formatSwapQuantity(this.deal.NotionalQty);
this.deal.PositionQty = formatSwapQuantity(this.deal.PositionQty);
this.deal.SwapCloseAmount = formatSwapAmount(this.deal.SwapCloseAmount);
this.interestList.forEach(x => {
//x.Principal = formatSwapAmount(x.Principal);
//x.Rate = otcformat.fixed6(x.Rate);
x.InterestFee = formatSwapAmount(x.InterestFee);
x.InterestAmount = formatSwapAmount(x.InterestAmount);
x.InterestClosePnL = formatSwapAmount(x.InterestClosePnL);
//x.InterestStartDate = x.InterestStartDate ? x.InterestStartDate.substr(0, 10) : "";
//x.InterestEndDate = x.InterestEndDate ? x.InterestEndDate.substr(0, 10) : "";
});
this.marginList.forEach(x => {
x.InterestFee = formatSwapAmount(x.InterestFee);
x.InterestAmount = formatSwapAmount(x.InterestAmount);
x.InterestClosePnL = formatSwapAmount(x.InterestClosePnL);
});
},
changeInterestAmount(item) {//修改利息金额
let interestRatio = item.InterestDirection == 1 ? 1 : -1;
item.InterestClosePnL = formatSwapAmount(parseFloat(item.InterestAmount) * interestRatio + parseFloat(item.InterestFee));
this.calcCloseAmount();
},
calcCloseAmount() {//计算平仓总额=浮动收取+利息收取-浮动支付-利息支付
let thisObj = this;
thisObj.deal.SwapCloseAmount = 0;
thisObj.deal.SwapRealizedPnL = 0;
thisObj.deal.SwapMarginRebatePnl = 0;
thisObj.deal.SwapMarginAmount = 0;
this.interestList.forEach(x => {
/*let interestRatio = x.InterestDirection == 1 ? 1 : -1;*/
let interestAmount = parseFloat(x.InterestClosePnL);
thisObj.deal.SwapCloseAmount = parseFloat(thisObj.deal.SwapCloseAmount) + interestAmount;
thisObj.deal.SwapRealizedPnL = parseFloat(thisObj.deal.SwapRealizedPnL) + interestAmount;
});
this.marginList.forEach(x => {
let interestAmount = parseFloat(x.InterestClosePnL);
thisObj.deal.SwapCloseAmount = parseFloat(thisObj.deal.SwapCloseAmount) + interestAmount;
thisObj.deal.SwapMarginRebatePnl = parseFloat(thisObj.deal.SwapMarginRebatePnl) + interestAmount;
thisObj.deal.SwapRealizedPnL = parseFloat(thisObj.deal.SwapRealizedPnL) + interestAmount;
thisObj.deal.SwapMarginAmount = parseFloat(thisObj.deal.SwapMarginAmount) + parseFloat(x.InterestPrincipal);
});
thisObj.deal.SwapCloseAmount = formatSwapAmount(thisObj.deal.SwapCloseAmount);
thisObj.deal.SwapRealizedPnL = formatSwapAmount(thisObj.deal.SwapRealizedPnL);
thisObj.deal.SwapMarginRebatePnl = formatSwapAmount(thisObj.deal.SwapMarginRebatePnl);
thisObj.deal.SwapMarginAmount = formatSwapAmount(thisObj.deal.SwapMarginAmount);
},
getInterestList() {//根据平仓日期获取利息腿信息
var thisObj = this;
var postData = { valueDate: thisObj.deal.ValueDate, unwindDate: thisObj.deal.UnwindDate, tradeId: thisObj.deal.SwapTradeId, closePercent: 1, eventType: 3 }
main.post("/swaptrade2/GetUnwindInterestList", postData, { async: true }).done(function (resp) {
thisObj.interestList = resp.obj.filter((item) => {
return item.InterestMode == 1 || item.InterestMode == 2 || item.InterestMode == 7 || item.InterestMode == 8 || item.InterestMode == 9;
});
thisObj.marginList = resp.obj.filter((item) => {
return item.InterestMode == 5 || item.InterestMode == 6;
});
thisObj.calcCloseAmount();
thisObj.dataFormat();
});
},
incomeTrade() {//互换
var thisObj = this;
if (main.isEmpty(thisObj.deal.ValueDate)) {
main.message("请输入平仓日期");
return;
}
let reqObj = _.cloneDeep(thisObj.deal);
let marginCloneList = _.cloneDeep(thisObj.marginList);
reqObj.FlowEvents = _.cloneDeep(thisObj.interestList);
marginCloneList.forEach((item) => {
reqObj.FlowEvents.push(item);
})
var postData = { unwindData: reqObj };
var msg = "确认提交收益结算?";
var postUrl = "/swaptrade2/SwapLongShortJson";
if (g_isShowReCheckClose) {
msg = "确认提交收益结算审核?";
postUrl = "/swaptrade2/ApplyUnwind";
postData.eventType = 3;//互换3,平仓2
}
main.confirm(msg,
function () {
//重新计算百分比
var thisObj2 = thisObj;
main.post(postUrl, { unwindData: reqObj }).done(function (res) {
if (res.success) {
thisObj2.closetrade_cashWindow();
}
else {
try {
thisObj2.closetrade_cashWindow();
} catch (e) {
}
}
});
});
},
getSumbitText: function () {
return g_isShowReCheckClose ? "审核提交" : "保存";
},
submitApproval(status) {
var pop = '';
if (status === 'pass') {
pop = "确认通过审批?";
}
if (status === 'reject') {
pop = "确认拒绝?";
}
var confirmFunc = function (additionalProcessing) {
var pData = { tradeId: trade.id, status: status, text: "" };
if (!main.isEmpty(additionalProcessing)) {
pData.additionalProcessing = additionalProcessing;
}
var thisObj2 = thisObj;
main.post("/processtradelog/UpdateTradeProcessLog", pData).done(
function (data) {
if (data.obj && data.obj.proccessType == "AdditionalProcessing") {
if (data.obj.type == "LackOfMoney") {
var htmlContent = `<div style="padding:10px">${data.obj.message}</div>`;
var lackMoneyConfirmLayer = main.open2("提示",
htmlContent,
{
area: ["430px", "175px"],
btn: ['交易特批', '取消'],
yes: function (index, layero) {
var layerIndex = lackMoneyConfirmLayer;
main.confirm("客户资金或授信不足,强制成交会导致本机构产生风险!要继续审批通过?", function () {
layer.close(layerIndex);
confirmFunc("LackOfMoney");
});
},
cancel: function (index, layero) {
if (window.parent && window.parent.reloadtrade) {
thisObj2.closetrade_cashWindow();
}
(parent || window).layer.closeAll();
}
});
}
return;
}
(parent || window).main.message(data.msg);
try { thisObj2.closetrade_cashWindow(); }
catch (e) { }
if (parent) {
parent.layer.closeAll();
}
});
}
main.confirm(pop, confirmFunc);
},
closetrade_cashWindow: function () {
layer.closeMe('reloadData');
},
closeCurrentWindow: function () {
try {
if (window.parent && window.parent.reload) window.parent.reload();
} catch (e) {
}
try {
var layer = window.parent.layer;
layer.close(layer.getFrameIndex(window.name));
} catch (e) {
}
}
},
components: {
'vue-datepicker': FastVue.vueDatePicker(),
'vue-number-input': FastVue.vueNumberInput(),
}
});
@@ -868,9 +868,6 @@ const vue = new Vue({
}
},
changeInterestMode(item) {
if (item.InterestMode == 7 || item.InterestMode == 8) {
item.InterestType = 0;
}
},
changeInterestType(item) {
if (!item.interest_rest_days) {
@@ -1462,28 +1459,7 @@ const vue = new Vue({
},
// 多空组合利息腿校验
checkSwapRateList() {
var thisObj = this;
var longInterestModelCount = 0;
var shortInterestModelCount = 0;
var check = true;
if (thisObj.getSwapList != null) {
thisObj.getSwapList.forEach((val, num, arr) => {
if (val.InterestMode==7) {
longInterestModelCount++;
}
if (val.InterestMode == 8) {
shortInterestModelCount++;
}
});
}
if (longInterestModelCount > 1) {
check = false;
main.message("计息基本类型为多头存续名义本金的利息腿只能有一条");
}
if (shortInterestModelCount > 1) {
check = false;
main.message("计息基本类型为空头存续名义本金的利息腿只能有一条");
}
return check;
},
//观察日起始日期跟交易起始日期检查
@@ -1619,7 +1595,7 @@ const vue = new Vue({
//初始化利息端列表
initSwapRateList() {
var thisObj = this;
thisObj.getSwapList = thisObj.trade.swap_positions.filter(x => { if ((x.UnderlyingCode == null || x.UnderlyingCode.length == 0) && x.IsInitial && (x.InterestMode == 1 || x.InterestMode == 2 || x.InterestMode == 7 || x.InterestMode == 8 || x.InterestMode == 9)) return x; });
thisObj.getSwapList = thisObj.trade.swap_positions.filter(x => { if ((x.UnderlyingCode == null || x.UnderlyingCode.length == 0) && x.IsInitial && (x.InterestMode == 1 || x.InterestMode == 2 || x.InterestMode == 9)) return x; });
thisObj.getSwapList.forEach((val, num, arr) => {
arr[num].index = num;
arr[num].category_tag = arr[num].category_tag || '互换利率';
@@ -330,46 +330,6 @@ function unWindSwap(id) {
}
});
}
function unWindSwapLongShort(id) {
var title = "交易平仓";
var srcurl = "/swaptrade2/SwapLongShortUnwind/?enid=" + id;
main.post("/swaptrade2/CheckEodTrade?enid=" + id).done(function (res) {
if (res.success) {
main.open(title,
srcurl,
{
area: ["1300px", "780px"],
end: function () {
if (window.parent && window.parent.reloadtrade) {
window.parent.reloadtrade();
}
}
});
} else {
main.message(res.message);
}
});
}
function unWindLongShortSwap(id) {
var title = "期间互换";
var srcurl = "/swaptrade2/SwapLongShortSwap/?enid=" + id;
main.post("/swaptrade2/CheckEodTrade?enid=" + id).done(function (res) {
if (res.success) {
main.open(title,
srcurl,
{
area: ["1300px", "780px"],
end: function () {
if (window.parent && window.parent.reloadtrade) {
window.parent.reloadtrade();
}
}
});
} else {
main.message(res.message);
}
});
}
function extensionTime(id) {
var title = "展期信息";
var srcurl = "/swaptrade2/ExtensionTime/?enid=" + id;
@@ -1,197 +0,0 @@
//otcformat禁止千分位分组
window.otcformat.options.disableGrouping = true;
const inputFormatEqvNotional = swapPricePrecision.getCommonInputFormat('amount', { append: '' });
const swapInstrumentType = (model.FlowEvents || []).find(item => item && item.UnderlyingInstrumentType)?.UnderlyingInstrumentType || model.UnderlyingInstrumentType || '';
const formatSwapAmount = value => swapPricePrecision.normalizeCommon('amount', value);
const formatSwapQuantity = value => swapPricePrecision.normalizeCommon('quantity', value, swapInstrumentType);
let dealDate = model.DealDate;
const vue = new Vue({
el: '#vueDiv',
data: {
deal: model,
interestList: [],
marginList: [],
oriClosePercent: model.ClosePercent
},
computed: {
minStartDate() {
return dealDate;
}
},
created() {
this.initDeal();
this.calcCloseAmount();
this.dataFormat();
},
methods: {
formatAmount(value) {
return swapPricePrecision.formatCommon('amount', value);
},
formatQuantity(value) {
return swapPricePrecision.formatCommon('quantity', value, swapInstrumentType);
},
initDeal() {
this.interestList = model.FlowEvents.filter((item) => {
return item.InterestMode == 1 || item.InterestMode == 2 || item.InterestMode == 7 || item.InterestMode == 8 || item.InterestMode == 9;
});
this.marginList = model.FlowEvents.filter((item) => {
return item.InterestMode == 5 || item.InterestMode == 6;
});
},
dataFormat() {
this.deal.NotionalValue = formatSwapAmount(this.deal.NotionalValue);
this.deal.PosiNotionalValue = formatSwapAmount(this.deal.PosiNotionalValue);
this.deal.NotionalQty = formatSwapQuantity(this.deal.NotionalQty);
this.deal.SwapCloseAmount = formatSwapAmount(this.deal.SwapCloseAmount);
this.deal.PositionQty = formatSwapQuantity(this.deal.PositionQty);
this.interestList.forEach(x => {
//x.Principal = formatSwapAmount(x.Principal);
//x.Rate = otcformat.fixed6(x.Rate);
x.InterestAmount = formatSwapAmount(x.InterestAmount);
x.InterestClosePnL = formatSwapAmount(x.InterestClosePnL);
//x.InterestStartDate = x.InterestStartDate ? x.InterestStartDate.substr(0, 10) : "";
//x.InterestEndDate = x.InterestEndDate ? x.InterestEndDate.substr(0, 10) : "";
});
this.marginList.forEach(x => {
x.InterestAmount = formatSwapAmount(x.InterestAmount);
x.InterestClosePnL = formatSwapAmount(x.InterestClosePnL);
});
},
changeInterestAmount(item) {//修改利息金额
let interestRatio = item.InterestDirection == 1 ? 1 : -1;
item.InterestClosePnL = formatSwapAmount(parseFloat(item.InterestAmount) * interestRatio+ parseFloat(item.InterestFee));
this.calcCloseAmount();
},
calcCloseAmount() {//计算平仓总额=浮动收取+利息收取-浮动支付-利息支付
let thisObj = this;
thisObj.deal.SwapCloseAmount = 0;
thisObj.deal.SwapRealizedPnL = 0;
thisObj.deal.SwapMarginRebatePnl = 0;
thisObj.deal.SwapMarginAmount = 0;
this.interestList.forEach(x => {
/*let interestRatio = x.InterestDirection == 1 ? 1 : -1;*/
let interestAmount = parseFloat(x.InterestClosePnL);
thisObj.deal.SwapCloseAmount = parseFloat(thisObj.deal.SwapCloseAmount) + interestAmount;
thisObj.deal.SwapRealizedPnL = parseFloat(thisObj.deal.SwapRealizedPnL) + interestAmount;
});
this.marginList.forEach(x => {
let interestAmount = parseFloat(x.InterestClosePnL);
let interestRatio = x.InterestDirection == 1 ? -1 : 1;
thisObj.deal.SwapCloseAmount = parseFloat(thisObj.deal.SwapCloseAmount) + interestAmount;
thisObj.deal.SwapMarginRebatePnl = parseFloat(thisObj.deal.SwapMarginRebatePnl) + interestAmount;
thisObj.deal.SwapRealizedPnL = parseFloat(thisObj.deal.SwapRealizedPnL) + interestAmount;
thisObj.deal.SwapMarginAmount = parseFloat(thisObj.deal.SwapMarginAmount) + parseFloat(x.InterestPrincipal) * interestRatio;
});
thisObj.deal.SwapCloseAmount = formatSwapAmount(thisObj.deal.SwapCloseAmount);
thisObj.deal.SwapRealizedPnL = formatSwapAmount(thisObj.deal.SwapRealizedPnL);
thisObj.deal.SwapMarginRebatePnl = formatSwapAmount(thisObj.deal.SwapMarginRebatePnl);
thisObj.deal.SwapMarginAmount = formatSwapAmount(thisObj.deal.SwapMarginAmount);
},
closeTrade() {//平仓
var thisObj = this;
let reqObj = _.cloneDeep(thisObj.deal);
let marginCloneList = _.cloneDeep(thisObj.marginList);
reqObj.FlowEvents = _.cloneDeep(thisObj.interestList);
marginCloneList.forEach((item) => {
reqObj.FlowEvents.push(item);
})
var postData = { unwindData: reqObj };
var msg = "确认提交平仓?";
var postUrl = "/swaptrade2/SwapLongShortUnwindJson";
if (g_isShowReCheckClose) {
msg = "确认提交平仓审核?";
postUrl = "/swaptrade2/ApplyUnwind";
postData.eventType = 2;//互换3,平仓2
}
main.confirm(msg,
function () {
//重新计算百分比
var thisObj2 = thisObj;
main.post(postUrl, postData).done(function (res) {
if (res.success) {
thisObj2.closetrade_cashWindow();
}
else {
try {
thisObj2.closetrade_cashWindow();
} catch (e) {
}
}
});
});
},
getSumbitText: function () {
return g_isShowReCheckClose ? "审核提交" : "保存";
},
submitApproval(status) {
var pop = '';
if (status === 'pass') {
pop = "确认通过审批?";
}
if (status === 'reject') {
pop = "确认拒绝?";
}
let thisObj = this;
var confirmFunc = function (additionalProcessing) {
var pData = { tradeId: thisObj.deal.SwapTradeId, status: status, text: "" };
if (!main.isEmpty(additionalProcessing)) {
pData.additionalProcessing = additionalProcessing;
}
var thisObj2 = thisObj;
main.post("/processtradelog/UpdateTradeProcessLog", pData).done(
function (data) {
if (data.obj && data.obj.proccessType == "AdditionalProcessing") {
if (data.obj.type == "LackOfMoney") {
var htmlContent = `<div style="padding:10px">${data.obj.message}</div>`;
var lackMoneyConfirmLayer = main.open2("提示",
htmlContent,
{
area: ["430px", "175px"],
btn: ['交易特批', '取消'],
yes: function (index, layero) {
var layerIndex = lackMoneyConfirmLayer;
main.confirm("客户资金或授信不足,强制成交会导致本机构产生风险!要继续审批通过?", function () {
layer.close(layerIndex);
confirmFunc("LackOfMoney");
});
},
cancel: function (index, layero) {
if (window.parent && window.parent.reloadtrade) {
thisObj2.closetrade_cashWindow();
}
(parent || window).layer.closeAll();
}
});
}
return;
}
(parent || window).main.message(data.msg);
try { thisObj2.closetrade_cashWindow(); }
catch (e) { }
if (parent) {
parent.layer.closeAll();
}
});
}
main.confirm(pop, confirmFunc);
},
closetrade_cashWindow: function () {
layer.closeMe('reloadData');
},
closeCurrentWindow: function () {
try {
if (window.parent && window.parent.reload) window.parent.reload();
} catch (e) {
}
try {
var layer = window.parent.layer;
layer.close(layer.getFrameIndex(window.name));
} catch (e) {
}
}
},
components: {
'vue-datepicker': FastVue.vueDatePicker(),
'vue-number-input': FastVue.vueNumberInput(),
}
});
@@ -110,7 +110,7 @@ const vue = new Vue({
this.floatPosition = positions[0];
this.initPosiNetPrice = this.floatPosition.PosiGrossPrice;
this.interestList = model.FlowEvents.filter((item) => {
return item.InterestMode == 1 || item.InterestMode == 2 || item.InterestMode == 7 || item.InterestMode == 8 || item.InterestMode == 9;
return item.InterestMode == 1 || item.InterestMode == 2 || item.InterestMode == 9;
});
this.marginList = model.FlowEvents.filter((item) => {
return item.InterestMode == 5 || item.InterestMode == 6;
@@ -368,14 +368,14 @@ const vue = new Vue({
getInterestList() {//根据平仓日期获取利息腿信息
var thisObj = this;
// closePercent 按"占期初(original)"语义(A)传给后端,由 GetUnwindInterestList 转为"占剩余(B)"计算
var postData = { valueDate: thisObj.deal.ValueDate, unwindDate: thisObj.deal.ValueDate, tradeId: thisObj.deal.SwapTradeId, closePercent: thisObj.deal.ClosePercent, eventType: 2, notionalValue: thisObj.deal.NotionalValue, posiNotionalValue: thisObj.deal.PosiNotionalValue }
var postData = { valueDate: thisObj.deal.ValueDate, unwindDate: thisObj.deal.ValueDate, tradeId: thisObj.deal.SwapTradeId, closePercent: thisObj.deal.ClosePercent, eventType: 2, notionalValue: thisObj.deal.NotionalValue, posiNotionalValue: thisObj.deal.PosiNotionalValue, isPenaltyInterest: thisObj.deal.IsPenaltyInterest == true } // EQD-6977 是否罚息:预览即含罚息(其他费用含罚息)
// 调试埋点(?otcdebug=1):记录实际发给后端的平仓比例——未来若"改比例利息腿不动",
// 对比此处请求比例 与 下方返回各腿 principal/amount 是否随比例变化,即可定位是前端没传对还是后端没缩放。
if (window.otcDebug) window.otcDebug.log('[unwind] getInterestList → POST closePercent=', thisObj.deal.ClosePercent,
' closeNotionalValue=', thisObj.deal.CloseNotionalValue, ' posiNotionalValue=', thisObj.deal.PosiNotionalValue);
main.post("/swaptrade2/GetUnwindInterestList", postData, { async: true }).done(function (resp) {
thisObj.interestList = resp.obj.filter((item) => {
return item.InterestMode == 1 || item.InterestMode == 2 || item.InterestMode == 7 || item.InterestMode == 8 || item.InterestMode == 9;
return item.InterestMode == 1 || item.InterestMode == 2 || item.InterestMode == 9;
});
thisObj.marginList = resp.obj.filter((item) => {
return item.InterestMode == 5 || item.InterestMode == 6;
@@ -53,7 +53,8 @@ var app = new Vue({
{ text: '交易新增与修改', value: '2' },
{ text: '交易了结', value: '6' },
/* { text: '资信与授信', value: '3' },*/
{ text: '出金', value: '4' }
{ text: '出金', value: '4' },
{ text: '黑名单', value: '7' }
],
isOpen: false,
@@ -62,12 +63,14 @@ var app = new Vue({
isCredit: false,
isOutCash: false,
isClient: false,
isClientBlack: false,
openItems: [],
clientItems: [],
tradeItems: [],
closeItems: [],
creditItems: [],
outCashItems: [],
clientBlackItems: [],
openCounter: 0,
tradeCounter: 0,
creditCounter: 0,
@@ -140,6 +143,7 @@ var app = new Vue({
thisObj.isCredit = false;
thisObj.isOutCash = false;
thisObj.isClient = false;
thisObj.isClientBlack = false;
} else if (thisObj.selected === '2') {
thisObj.isOpen = false;
thisObj.isTrade = true;
@@ -147,6 +151,7 @@ var app = new Vue({
thisObj.isCredit = false;
thisObj.isOutCash = false;
thisObj.isClient = false;
thisObj.isClientBlack = false;
} else if (thisObj.selected === '6') { // 需求②:交易了结流程
thisObj.isOpen = false;
thisObj.isTrade = false;
@@ -154,6 +159,7 @@ var app = new Vue({
thisObj.isCredit = false;
thisObj.isOutCash = false;
thisObj.isClient = false;
thisObj.isClientBlack = false;
} else if (thisObj.selected === '3') {
thisObj.isOpen = false;
thisObj.isTrade = false;
@@ -161,6 +167,7 @@ var app = new Vue({
thisObj.isCredit = true;
thisObj.isOutCash = false;
thisObj.isClient = false;
thisObj.isClientBlack = false;
}
else if (thisObj.selected === '4') {
thisObj.isOpen = false;
@@ -169,6 +176,7 @@ var app = new Vue({
thisObj.isCredit = false;
thisObj.isOutCash = true;
thisObj.isClient = false;
thisObj.isClientBlack = false;
}
else if (thisObj.selected === '5') {
thisObj.isOpen = false;
@@ -177,6 +185,16 @@ var app = new Vue({
thisObj.isCredit = false;
thisObj.isOutCash = false;
thisObj.isClient = true;
thisObj.isClientBlack = false;
}
else if (thisObj.selected === '7') {
thisObj.isOpen = false;
thisObj.isTrade = false;
thisObj.isClose = false;
thisObj.isCredit = false;
thisObj.isOutCash = false;
thisObj.isClient = false;
thisObj.isClientBlack = true;
}
else {
thisObj.isOpen = false;
@@ -185,6 +203,7 @@ var app = new Vue({
thisObj.isCredit = false;
thisObj.isOutCash = false;
thisObj.isClient = false;
thisObj.isClientBlack = false;
}
thisObj.getProcess();
},
@@ -385,6 +404,18 @@ var app = new Vue({
thisObj.addCloseNode(index, child, node);
return;
}
else if (selectType === "7") { //黑名单
var item = {
Type: 'ClientBlackProcess',
Index: index + 1,
SelectValue: 0
};
thisObj.clientBlackItems.splice(index, 0, item);
thisObj.clientBlackItems.forEach(function (x, itemIndex) {
x.Index = itemIndex + 1;
});
return;
}
},
delProcess: function (openItem) {
@@ -417,6 +448,14 @@ var app = new Vue({
});
return;
}
else if (selectType === "7") {//黑名单
var index = thisObj.clientBlackItems.indexOf(openItem);
thisObj.clientBlackItems.splice(index, 1);
thisObj.clientBlackItems.forEach(function (x, itemIndex) {
x.Index = itemIndex + 1;
});
return;
}
},
addOpenProcess(index, child, node) {
var thisObj = this;
@@ -528,6 +567,10 @@ var app = new Vue({
thisObj.saveCloseProcess();
return;
}
else if (selectType === "7") { //黑名单
thisObj.clientBlackOk();
return;
}
},
openOk() {
var thisObj = this;
@@ -857,6 +900,38 @@ var app = new Vue({
});
}
},
clientBlackOk() {
var thisObj = this;
var items = thisObj.clientBlackItems;
for (var i = 0; i < items.length; i++) {
if (items[i].SelectValue === "" || items[i].SelectValue === 0) {
main.message('流程中断,请重新选择');
return;
}
for (var j = i + 1; j < items.length; j++) {
if (parseInt(items[i].SelectValue) === parseInt(items[j].SelectValue)) {
main.message('流程包含重复项,请重新选择');
return;
}
}
}
if (items.length > 0) {
main.confirm("确认修改黑名单审批流程?", function () {
main.post("/AccountOpeningProcess/AddProcess",
{ type: "ClientBlackProcess", data: items },
{ async: false }).done(function () {
thisObj.getProcess();
});
});
} else {
main.confirm("删除审批流程后,黑名单变更会直接生效,确认删除?", function () {
main.post("/AccountOpeningProcess/AddProcess",
{ type: "ClientBlackProcess" },
{ async: false });
});
}
},
getProcess() {
var thisObj = this;
thisObj.openItems = [];
@@ -865,6 +940,7 @@ var app = new Vue({
thisObj.creditItems = [];
thisObj.outCashItems = [];
thisObj.clientItems = [];
thisObj.clientBlackItems = [];
main.post("/AccountOpeningProcess/GetProcess",
{},
{ async: false }).done(
@@ -945,6 +1021,14 @@ var app = new Vue({
triggerCondition: value.triggerCondition
});
});
(res.ClientBlackProcess || []).forEach(function (value) {
thisObj.clientBlackItems.push({
id: value.id,
Type: value.processType,
Index: value.order,
SelectValue: value.roleId
});
});
// 需求①:加载后把 triggerCondition(JSON)解析为结构化对象供 UI 编辑
['openItems', 'tradeItems', 'closeItems', 'clientItems'].forEach(function (arr) {
thisObj[arr].forEach(function (item) {
@@ -731,9 +731,6 @@ function passorreinfo(eid, tradeType, status, isGroup, StructureType) {
else if (tradeType === "收益互换") {
weight = "95%";
url = "/swaptrade2/SwapUnwind/?enid=" + eid + "&isUseApproval=" + true;
if (StructureType == "多空组合") {
url = "/swaptrade2/SwapLongShortUnwind/?enid=" + eid + "&isUseApproval=" + true;
}
height = "800px";
}
else {
@@ -744,9 +741,6 @@ function passorreinfo(eid, tradeType, status, isGroup, StructureType) {
weight = "95%";
title = "互换审批";
url = "/swaptrade2/SwapIncome/?enid=" + eid + "&isUseApproval=" + true;
if (StructureType == "多空组合") {
url = "/swaptrade2/SwapLongShortSwap/?enid=" + eid + "&isUseApproval=" + true;
}
height = "800px";
}
else if (status === "行权待复核") {
@@ -883,9 +877,6 @@ function unWindSelect(id, tradeType, isReCheck, StructureType) {
});
} else if (tradeType == "收益互换") {
var url = "/swaptrade2/SwapUnwind/?enid=" + id + "&isUseApproval=" + true;;
if (StructureType == "多空组合") {
url = "/swaptrade2/SwapLongShortUnwind/?enid=" + id + "&isUseApproval=" + true;;
}
main.open(title, url, {
area: ["1300px", "720px"],
end: function () {