Initial commit

Made-with: Cursor
This commit is contained in:
Daniel
2026-02-28 18:39:00 +08:00
commit a94bd44c3a
49 changed files with 917 additions and 0 deletions

View File

@@ -0,0 +1,6 @@
{
"usingComponents": {
"cooldown-button": "/components/cooldown-button/cooldown-button"
},
"navigationBarTitleText": "创建交易"
}

View File

@@ -0,0 +1,65 @@
Page({
data: {
step: 1,
logic: '',
symbol: '',
direction: 'long' as 'long' | 'short',
entry_price: '',
stop_loss: '',
take_profit: '',
upPct: 0,
downPct: 0,
odds: '',
position_size: '',
},
onLogicInput(e: WechatMiniprogram.CustomEvent) {
this.setData({ logic: (e.detail.value as string).trim() });
},
onSymbolInput(e: WechatMiniprogram.CustomEvent) {
this.setData({ symbol: (e.detail.value as string).trim() });
},
setDir(e: WechatMiniprogram.CustomEvent) {
this.setData({ direction: e.currentTarget.dataset.dir as 'long' | 'short' });
},
onEntryInput(e: WechatMiniprogram.CustomEvent) {
this.setData({ entry_price: e.detail.value as string }, () => this.calc());
},
onStopInput(e: WechatMiniprogram.CustomEvent) {
this.setData({ stop_loss: e.detail.value as string }, () => this.calc());
},
onTpInput(e: WechatMiniprogram.CustomEvent) {
this.setData({ take_profit: e.detail.value as string }, () => this.calc());
},
calc() {
const { entry_price, stop_loss, take_profit, direction } = this.data;
const e = parseFloat(entry_price);
const s = parseFloat(stop_loss);
const t = parseFloat(take_profit);
if (!e || !s || !t) return;
const upPct = direction === 'long' ? ((t - e) / e * 100) : ((e - t) / e * 100);
const downPct = direction === 'long' ? ((e - s) / e * 100) : ((s - e) / e * 100);
const risk = direction === 'long' ? e - s : s - e;
const reward = direction === 'long' ? t - e : e - t;
const odds = risk > 0 && reward > 0 ? (reward / risk).toFixed(2) : '';
this.setData({ upPct: upPct.toFixed(1), downPct: downPct.toFixed(1), odds });
},
nextStep() {
const { step, logic } = this.data;
if (step === 1 && logic.length < 30) return;
if (step === 2) {
this.setData({ position_size: '0.5', odds: this.data.odds || '-' });
}
this.setData({ step: step + 1 });
},
prevStep() {
this.setData({ step: this.data.step - 1 });
},
onConfirm() {
wx.showLoading({ title: '提交中' });
setTimeout(() => {
wx.hideLoading();
wx.showToast({ title: '已创建' });
wx.navigateBack();
}, 800);
},
});

View File

@@ -0,0 +1,33 @@
<view class="page">
<view class="step-indicator">步骤 {{step}} / 3</view>
<view wx:if="{{step === 1}}" class="section card">
<view class="label">交易逻辑≥30字</view>
<textarea class="textarea" value="{{logic}}" placeholder="请输入你的交易逻辑..." maxlength="500" bindinput="onLogicInput" />
<view class="count {{logic.length >= 30 ? 'ok' : ''}}">{{logic.length}}/30</view>
</view>
<view wx:if="{{step === 2}}" class="section card">
<view class="label">标的</view>
<input class="input" value="{{symbol}}" placeholder="如 BTCUSDT" bindinput="onSymbolInput" />
<view class="label">方向</view>
<view class="row">
<view class="option {{direction === 'long' ? 'active' : ''}}" bindtap="setDir" data-dir="long">做多</view>
<view class="option {{direction === 'short' ? 'active' : ''}}" bindtap="setDir" data-dir="short">做空</view>
</view>
<view class="label">入场价、止损价、止盈价</view>
<input class="input" type="digit" value="{{entry_price}}" placeholder="入场价" bindinput="onEntryInput" />
<input class="input" type="digit" value="{{stop_loss}}" placeholder="止损价" bindinput="onStopInput" />
<input class="input" type="digit" value="{{take_profit}}" placeholder="止盈价" bindinput="onTpInput" />
<view class="row calc">上涨% {{upPct}}% 下跌% {{downPct}}%</view>
</view>
<view wx:if="{{step === 3}}" class="section card">
<view class="label">建议仓位(来自后端)</view>
<view class="value">{{position_size || '-'}}</view>
<view class="label">赔率</view>
<view class="value">{{odds || '-'}}</view>
<cooldown-button text="确认提交" duration="3" bind:confirm="onConfirm" />
</view>
<view class="nav">
<button wx:if="{{step > 1}}" bindtap="prevStep">上一步</button>
<button wx:if="{{step < 3}}" bindtap="nextStep" disabled="{{step === 1 && logic.length < 30}}">下一步</button>
</view>
</view>

View File

@@ -0,0 +1,15 @@
.page { padding: 20rpx; }
.section { margin-bottom: 24rpx; }
.step-indicator { color: #888; margin-bottom: 24rpx; font-size: 28rpx; }
.label { color: #666; margin-bottom: 12rpx; font-size: 26rpx; }
.input, .textarea { width: 100%; padding: 20rpx; border: 1rpx solid #ddd; border-radius: 12rpx; box-sizing: border-box; }
.textarea { min-height: 160rpx; }
.count { font-size: 24rpx; color: #888; }
.count.ok { color: #5a9; }
.row { display: flex; gap: 24rpx; margin-bottom: 24rpx; }
.option { flex: 1; padding: 24rpx; text-align: center; border: 1rpx solid #ddd; border-radius: 12rpx; }
.option.active { background: #5a9; color: #fff; border-color: #5a9; }
.calc { justify-content: space-between; color: #666; }
.value { font-size: 36rpx; font-weight: 600; color: #333; margin-bottom: 24rpx; }
.nav { display: flex; gap: 24rpx; margin-top: 40rpx; }
.nav button { flex: 1; }