Skip to content

Commit 77ca6ee

Browse files
authored
Merge pull request #536 from huxianc/feat/shares
feat: 持仓金额改成持仓份额
2 parents 747276c + ac96443 commit 77ca6ee

File tree

3 files changed

+135
-34
lines changed

3 files changed

+135
-34
lines changed

src/shared/typed.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ export interface IAmount {
3434
name: string;
3535
price: number | string;
3636
amount: number;
37+
shares?: number; // 持仓份额,新增字段
3738
priceDate: string;
3839
earnings: number;
3940
unitPrice: number;

src/webview/setAmount.ts

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -64,16 +64,30 @@ function fundDataHandler(fundService: FundService) {
6464
const fundList: LeekTreeItem[] = cloneDeep(fundService.fundList);
6565
const amountObj: any = globalState.fundAmount || {};
6666
const list = fundList.map((item: LeekTreeItem) => {
67+
const fundConfig = amountObj[item.info?.code] || {};
68+
69+
// 兼容旧数据:如果没有份额但有金额和基金净值,计算份额
70+
let shares = fundConfig.shares;
71+
if (!shares && fundConfig.amount && item.info?.yestclose) {
72+
shares = fundConfig.amount / parseFloat(String(item.info.yestclose));
73+
}
74+
75+
// 计算持仓金额:优先使用份额 * 基金净值(昨日净值),否则使用保存的金额
76+
const calculatedAmount = shares && item.info?.yestclose
77+
? shares * parseFloat(String(item.info.yestclose))
78+
: fundConfig.amount || 0;
79+
6780
return {
6881
name: item.info?.name,
6982
code: item.info?.code,
7083
percent: item.info?.percent,
71-
amount: amountObj[item.info?.code]?.amount || 0,
84+
amount: calculatedAmount,
85+
shares: shares || null, // 添加份额字段
7286
earningPercent: item.info?.earningPercent,
7387
unitPrice: item.info?.unitPrice,
7488
// priceDate: formatDate(item.info?.time),
7589
earnings: item.info?.earnings || 0,
76-
yestEarnings: amountObj[item.info.code]?.earnings || 0,
90+
yestEarnings: fundConfig.earnings || 0,
7791
price: item.info?.yestclose,
7892
priceDate: item.info?.yestPriceDate,
7993
};
@@ -93,9 +107,15 @@ function getWebviewContent(panel: WebviewPanel) {
93107
function setAmountCfgCb(data: IAmount[]) {
94108
const cfg: any = {};
95109
data.forEach((item: any) => {
110+
// 计算持仓金额:如果有份额,则使用 单价 * 份额,否则使用原来的金额
111+
const calculatedAmount = item.shares && item.unitPrice
112+
? item.shares * item.unitPrice
113+
: item.amount || 0;
114+
96115
cfg[item.code] = {
97116
name: item.name,
98-
amount: item.amount || 0,
117+
amount: calculatedAmount,
118+
shares: item.shares || null, // 保存份额
99119
price: item.price,
100120
unitPrice: item.unitPrice,
101121
earnings: item.earnings,
@@ -145,11 +165,22 @@ export async function updateAmount() {
145165
const time = GZTIME?.substr(0, 10);
146166
const pdate = PDATE?.substr(0, 10);
147167
const isUpdated = pdate === time; // 判断闭市的时候
148-
const money = amountObj[FCODE]?.amount || 0;
149-
const price = amountObj[FCODE]?.price || 0;
150-
const priceDate = amountObj[FCODE]?.priceDate || '';
168+
const fundConfig = amountObj[FCODE];
169+
const money = fundConfig?.amount || 0;
170+
const price = fundConfig?.price || 0;
171+
const priceDate = fundConfig?.priceDate || '';
172+
151173
if (priceDate !== pdate) {
152-
const currentMoney = (money / price) * NAV;
174+
// 兼容处理:如果没有份额但有历史金额,从金额和基金净值计算份额
175+
if (!fundConfig.shares && money && price) {
176+
fundConfig.shares = parseFloat((money / price).toFixed(2));
177+
}
178+
179+
// 使用份额计算新的持仓金额,如果没有份额则用原逻辑
180+
const currentMoney = fundConfig.shares
181+
? fundConfig.shares * NAV
182+
: (money / price) * NAV;
183+
153184
amountObj[FCODE].amount = toFixed(currentMoney);
154185
if (isUpdated) {
155186
// 闭市的时候保留上一次盈亏值

template/fund-amount.html

Lines changed: 96 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@
3939
font-size: 14px;
4040
}
4141
.item {
42+
display: flex;
43+
justify-content: space-between;
4244
margin-top: 10px;
4345
}
4446
.el-input {
@@ -75,6 +77,19 @@
7577
.unitPriceInput {
7678
width: 100px;
7779
}
80+
.sharesInput {
81+
width: 100px;
82+
}
83+
.input-row {
84+
display: flex;
85+
justify-content: flex-end;
86+
gap: 8px;
87+
}
88+
.input-group {
89+
display: flex;
90+
align-items: center;
91+
gap: 5px;
92+
}
7893
.red {
7994
color: #f56c6c;
8095
}
@@ -152,7 +167,7 @@ <h2 style="text-align: center; color: #409eff">
152167
</h2>
153168

154169
<p style="font-size: 12px; color: #696666; text-align: center">
155-
现在填写金额按昨日净值计算,所以今日加仓的建议明日更新持仓金额
170+
填写持仓份额和成本价,系统将自动计算持仓金额。持仓金额 = 份额 × 基金净值,份额保留两位小数
156171
</p>
157172
<div class="list"></div>
158173
<div class="footer">
@@ -248,28 +263,24 @@ <h2 style="text-align: center; color: #409eff">
248263
if (!priceDate) {
249264
priceDate = item.priceDate;
250265
}
251-
const str =
252-
'<div class="item"><div class="name">' +
253-
item.name +
254-
'(<i class="' +
255-
(earningPercent > 0 ? 'red' : 'green') +
256-
'">' +
257-
earningPercent +
258-
'%</i>)' +
259-
'</div>' +
260-
'<div class="amount el-input">' +
261-
'持仓金额:<input type="number" class="amountInput el-input__inner" id="' +
262-
item.code +
263-
'" value="' +
264-
amount +
265-
'" /> <span class="unit">元</span> </div>' +
266-
'<div class="unitDiv el-input">' +
267-
'持仓成本价:<input type="number" class="unitPriceInput el-input__inner" id="' +
268-
item.code +
269-
'_unit" value="' +
270-
unitPrice +
271-
'" /> <span class="unit">元、</span> </div>' +
272-
'</div>';
266+
// 持仓金额 = 基金净值 * 持有份额
267+
const calculatedAmount = (item.shares && item.price) ? (item.shares * item.price).toFixed(2) : amount.toFixed(2);
268+
const str = `
269+
<div class="item">
270+
<div class="name" data-code="${item.code}">
271+
${item.name}
272+
(<span class="calculated-amount-text">${calculatedAmount}元</span> | <i class="${earningPercent > 0 ? 'red' : 'green'}">${earningPercent}%</i>)
273+
</div>
274+
<div class="input-row">
275+
<div class="input-group">
276+
持仓成本价:<input type="number" class="unitPriceInput el-input__inner" id="${item.code}_unit" value="${unitPrice}" /> <span class="unit">元</span>
277+
</div>
278+
<div class="input-group">
279+
持仓份额:<input type="number" step="0.01" class="sharesInput el-input__inner" id="${item.code}_shares" value="${parseFloat(item.shares.toFixed(2)) || ''}" /> <span class="unit">份</span>
280+
</div>
281+
</div>
282+
</div>
283+
`;
273284

274285
listStr += str;
275286
const earnings = item.earnings || 0;
@@ -455,22 +466,80 @@ <h2 style="text-align: center; color: #409eff">
455466
}
456467

457468
$(function () {
458-
$('.amountInput,.unitPriceInput').on('input', function (e) {
469+
$('.unitPriceInput,.sharesInput').on('input', function (e) {
459470
const value = e.target.value;
460471
if (value.length > 12) {
461472
e.target.value = value.slice(0, 12);
462473
}
474+
475+
// 实时计算持仓金额
476+
const codeMatch = e.target.id.match(/^(.+)_(unit|shares)$/);
477+
if (codeMatch) {
478+
const code = codeMatch[1];
479+
updateCalculatedAmount(code);
480+
}
463481
});
482+
483+
// 份额输入框失焦时格式化为两位小数
484+
$('.sharesInput').on('blur', function (e) {
485+
const value = parseFloat(e.target.value);
486+
if (!isNaN(value)) {
487+
e.target.value = value.toFixed(2);
488+
// 重新触发计算
489+
const codeMatch = e.target.id.match(/^(.+)_shares$/);
490+
if (codeMatch) {
491+
const code = codeMatch[1];
492+
updateCalculatedAmount(code);
493+
}
494+
}
495+
});
496+
497+
// 实时计算持仓金额的函数
498+
function updateCalculatedAmount(code) {
499+
const sharesInput = $('#' + code + '_shares');
500+
const nameDisplay = $('[data-code="' + code + '"] .calculated-amount-text');
501+
502+
// 从fundList中找到对应的基金净值
503+
const fundItem = fundList.find(item => item.code === code);
504+
const shares = parseFloat(parseFloat(sharesInput.val()).toFixed(2)) || 0; // 份额保留两位小数
505+
const netValue = fundItem ? fundItem.price : 0; // 使用基金净值
506+
507+
// 持仓金额 = 基金净值 * 持有份额
508+
const calculatedAmount = shares && netValue ? (shares * netValue).toFixed(2) : '0.00';
509+
510+
// 更新名称中的金额显示
511+
nameDisplay.text(calculatedAmount + '元');
512+
513+
// 重新计算总金额
514+
updateTotalMoney();
515+
}
516+
517+
// 更新总金额
518+
function updateTotalMoney() {
519+
let totalMoney = 0;
520+
$('.calculated-amount-text').each(function() {
521+
const text = $(this).text().replace('元', '');
522+
const amount = parseFloat(text) || 0;
523+
totalMoney += amount;
524+
});
525+
$('#totalMoney').html(totalMoney.toFixed(2));
526+
}
464527
$('#save').click(() => {
465528
// const ammountObj = {};
466529
let totalMoney = 0;
467530
fundList.forEach((item) => {
468-
let amount = $('#' + item.code).val();
469531
let unitPrice = $('#' + item.code + '_unit').val();
470-
amount = isNaN(Number(amount)) ? 0 : Number(amount);
532+
let shares = $('#' + item.code + '_shares').val();
533+
471534
unitPrice = isNaN(Number(unitPrice)) ? 0 : Number(unitPrice);
472-
item.amount = amount; // 持仓金额
535+
shares = isNaN(Number(shares)) || shares === '' ? null : parseFloat(Number(shares).toFixed(2));
536+
537+
// 使用份额和基金净值计算持仓金额
538+
const amount = shares && item.price ? shares * item.price : 0;
539+
540+
item.amount = amount; // 持仓金额(计算得出)
473541
item.unitPrice = unitPrice; // 成本价
542+
item.shares = shares; // 持仓份额
474543
totalMoney += amount; // 持仓金额
475544
// 收益率
476545
if (unitPrice !== 0) {

0 commit comments

Comments
 (0)