feat: 组合详情页添加编辑功能,支持修改名称/策略/状态

This commit is contained in:
claw_bot 2026-03-17 01:54:10 +00:00
parent 69cf5a614a
commit 32e8e8b5eb
2 changed files with 229 additions and 3 deletions

View File

@ -128,9 +128,15 @@
<view class="section-container pb-0"> <view class="section-container pb-0">
<view class="section-header"> <view class="section-header">
<text class="section-title">当前逻辑模型</text> <text class="section-title">当前逻辑模型</text>
<view class="flex-row items-center" @click="goStrategyConfig"> <view class="flex-row items-center gap-2">
<text class="section-sub text-brand">参数配置</text> <view class="edit-btn" @click="openEditModal">
<uni-icons type="right" size="12" color="#064E3B"></uni-icons> <uni-icons type="compose" size="14" color="#064E3B"></uni-icons>
<text class="edit-text">编辑</text>
</view>
<view class="flex-row items-center" @click="goStrategyConfig" v-if="portfolioData.logicModel">
<text class="section-sub text-brand">参数配置</text>
<uni-icons type="right" size="12" color="#064E3B"></uni-icons>
</view>
</view> </view>
</view> </view>
@ -163,6 +169,28 @@
</view> </view>
</template> </template>
</u-card> </u-card>
<!-- 未绑定策略提示 -->
<u-card
v-else
:border="false"
:shadow="false"
:show-head="false"
:show-foot="false"
class="strategy-info-card"
>
<template #body>
<view class="st-left">
<view class="st-icon-box bg-gray-100">
<text class="st-icon-text text-gray"></text>
</view>
<view class="flex-col gap-1">
<text class="st-name">未绑定策略</text>
<text class="st-tag">点击编辑可绑定策略</text>
</view>
</view>
</template>
</u-card>
</view> </view>
<view class="section-container"> <view class="section-container">
@ -441,6 +469,84 @@
</view> </view>
</view> </view>
<!-- 编辑组合弹窗 -->
<view v-if="showEditModal" class="transaction-modal" @click="showEditModal = false">
<view class="modal-content" @click.stop>
<view class="modal-header">
<text class="modal-title">编辑组合</text>
<view class="close-btn" @click="showEditModal = false">
<uni-icons type="close" size="20" color="#6B7280"></uni-icons>
</view>
</view>
<view class="form-content">
<view class="form-item">
<text class="form-label">组合名称</text>
<input
v-model="editForm.name"
class="form-input"
placeholder="请输入组合名称"
/>
</view>
<view class="form-item">
<text class="form-label">绑定策略</text>
<picker :range="strategyOptions" range-key="name" @change="onStrategyChange">
<view class="form-select">
<text>{{ editForm.strategyName || '不绑定策略' }}</text>
<uni-icons type="bottom" size="14" color="#9CA3AF"></uni-icons>
</view>
</picker>
</view>
<view class="form-item">
<text class="form-label">状态</text>
<picker :range="statusOptions" range-key="label" @change="onStatusChange">
<view class="form-select">
<text>{{ statusOptions.find(s => s.value === editForm.status)?.label || '运行中' }}</text>
<uni-icons type="bottom" size="14" color="#9CA3AF"></uni-icons>
</view>
</picker>
</view>
</view>
<view class="modal-footer">
<u-button
class="btn-cancel"
@click="showEditModal = false"
:customStyle="{
backgroundColor: '#FFFFFF',
color: '#6B7280',
fontWeight: '600',
borderRadius: '16rpx',
height: '80rpx',
fontSize: '28rpx',
flex: '1',
border: '2rpx solid #E5E7EB'
}"
>
取消
</u-button>
<u-button
class="btn-confirm"
@click="submitEdit"
:customStyle="{
backgroundColor: '#064E3B',
color: '#FFFFFF',
fontWeight: '600',
borderRadius: '16rpx',
height: '80rpx',
fontSize: '28rpx',
flex: '1',
border: 'none'
}"
>
保存
</u-button>
</view>
</view>
</view>
</view> </view>
</template> </template>
@ -638,6 +744,98 @@ const transactionForm = ref({
const maxSellAmount = ref(0); const maxSellAmount = ref(0);
//
const showEditModal = ref(false);
const editForm = ref({
name: '',
strategyId: null,
strategyName: '',
status: '运行中'
});
const strategyOptions = ref([{ id: null, name: '不绑定策略' }]);
const statusOptions = ref([
{ label: '运行中', value: '运行中' },
{ label: '已暂停', value: '已暂停' },
{ label: '已清仓', value: '已清仓' }
]);
//
const openEditModal = async () => {
editForm.value = {
name: portfolioData.value.name || '',
strategyId: portfolioData.value.strategy?.id || null,
strategyName: portfolioData.value.strategy?.name || '不绑定策略',
status: portfolioData.value.status || '运行中'
};
//
try {
const res = await api.strategies.getStrategies();
if (res.code === 200 && res.data) {
strategyOptions.value = [
{ id: null, name: '不绑定策略' },
...res.data.map(s => ({ id: s.id, name: s.name }))
];
}
} catch (e) {
console.error('获取策略列表失败:', e);
}
showEditModal.value = true;
};
const onStrategyChange = (e) => {
const idx = e.detail.value;
const selected = strategyOptions.value[idx];
editForm.value.strategyId = selected.id;
editForm.value.strategyName = selected.name;
};
const onStatusChange = (e) => {
const idx = e.detail.value;
editForm.value.status = statusOptions.value[idx].value;
};
const submitEdit = async () => {
if (!editForm.value.name?.trim()) {
proxy?.$refs.uToastRef?.show({
type: 'warning',
message: '请输入组合名称',
icon: 'warning'
});
return;
}
uni.showLoading({ title: '保存中...', mask: true });
try {
const response = await api.assets.updatePortfolio(portfolioId.value, {
name: editForm.value.name,
strategyId: editForm.value.strategyId,
status: editForm.value.status
});
if (response.code === 200) {
uni.hideLoading();
proxy?.$refs.uToastRef?.show({
type: 'success',
message: '保存成功',
icon: 'success'
});
showEditModal.value = false;
await fetchPortfolioData();
}
} catch (error) {
console.error('更新组合失败:', error);
uni.hideLoading();
proxy?.$refs.uToastRef?.show({
type: 'error',
message: '保存失败,请重试',
icon: 'error'
});
}
};
// //
const searchResults = ref([]); const searchResults = ref([]);
const searchTimer = ref(null); const searchTimer = ref(null);
@ -1054,6 +1252,24 @@ const deletePortfolio = async () => {
.bg-green-100 { background-color: #ECFDF5; } .bg-green-100 { background-color: #ECFDF5; }
.bg-red { background-color: #EF4444; } .bg-red { background-color: #EF4444; }
.bg-green { background-color: #10B981; } .bg-green { background-color: #10B981; }
.bg-gray-100 { background-color: #F3F4F6; }
.text-gray { color: #9CA3AF; }
/* 编辑按钮 */
.edit-btn {
display: flex;
align-items: center;
gap: 4rpx;
padding: 8rpx 16rpx;
background-color: #D1FAE5;
border-radius: 12rpx;
}
.edit-text {
font-size: 24rpx;
color: #064E3B;
font-weight: 500;
}
.header-section { padding: 20rpx 32rpx; } .header-section { padding: 20rpx 32rpx; }
.asset-card { .asset-card {

View File

@ -353,6 +353,16 @@ export const api = {
console.log('📤 发起 createPortfolio 请求:', data); console.log('📤 发起 createPortfolio 请求:', data);
return post('/api/v1/portfolio', data); return post('/api/v1/portfolio', data);
}, },
/**
* 更新投资组合
* @param {string|number} id - 投资组合ID
* @param {object} data - 更新数据 {name, strategyId, status}
* @returns {Promise} 返回更新结果
*/
updatePortfolio: (id, data) => {
console.log('📤 发起 updatePortfolio 请求:', id, data);
return put(`/api/v1/portfolio/${id}`, data);
},
/** /**
* 获取投资组合策略信号 * 获取投资组合策略信号
* @param {string|number} id - 投资组合ID * @param {string|number} id - 投资组合ID