Compare commits

..

3 Commits

Author SHA1 Message Date
niannian zheng
4ea7c5c2d0 refactor(页面): 优化页面生命周期和组件逻辑
重构页面生命周期钩子,统一使用uni-app的onShow替代vue的onShow
移除重复请求检查逻辑,简化数据获取函数
在配置页面自动填充策略参数并禁用相关输入
移除不必要的添加/删除股票行功能
2026-03-02 19:16:14 +08:00
niannian zheng
43280fa447 refactor: 统一API路径和字段命名,优化数据请求逻辑
- 将API路径从'/api/user/info'改为'api/v1/user/info'以统一版本前缀
- 将数据字段从大驼峰改为小驼峰命名规范
- 使用onShow替代onMounted并添加防重复请求机制
- 移除策略编辑页面的导航栏,简化页面结构
- 优化交易记录页面按钮样式和文案
2026-03-02 19:05:21 +08:00
niannian zheng
291024f9e7 refactor(策略编辑): 优化参数处理逻辑并兼容旧格式
将config字段改为parameters以更清晰表达用途,同时添加对旧config格式的兼容处理
2026-03-02 17:30:44 +08:00
6 changed files with 111 additions and 90 deletions

View File

@ -32,17 +32,13 @@
</view>
<view class="section-card">
<view class="card-header justify-between">
<view class="card-header">
<view class="flex-row items-center gap-2">
<view class="header-icon bg-blue-100">
<uni-icons type="wallet" size="18" color="#1D4ED8"></uni-icons>
</view>
<text class="header-title">初始化记录</text>
</view>
<view class="add-btn" @click="addStockRow">
<uni-icons type="plus" size="14" color="#064E3B"></uni-icons>
<text class="add-text">添加单元</text>
</view>
</view>
<view class="stock-list">
@ -50,14 +46,12 @@
<view class="item-header">
<text class="item-index">单元 #{{ index + 1 }}</text>
<uni-icons type="trash" size="18" color="#EF4444" @click="removeStockRow(index)"
v-if="form.stocks.length > 1"></uni-icons>
</view>
<view class="item-grid">
<view class="grid-col">
<text class="sub-label">单元名称/代码</text>
<input class="mini-input" v-model="item.name" placeholder="如 TMF" />
<input class="mini-input" v-model="item.name" placeholder="如 TMF" disabled />
</view>
<view class="grid-col">
<text class="sub-label">买入均价</text>
@ -95,7 +89,8 @@
</template>
<script setup>
import { ref, computed, onMounted, getCurrentInstance } from 'vue';
import { ref, computed, getCurrentInstance } from 'vue';
import { onShow } from '@dcloudio/uni-app';
const { proxy } = getCurrentInstance();
const api = proxy.$api;
@ -103,6 +98,9 @@ const api = proxy.$api;
const strategies = ref([]);
const strategyIndex = ref(-1);
//
let isFetching = false;
const form = ref({
name: '',
stocks: [
@ -133,6 +131,8 @@ const fetchStrategies = async () => {
id: item.id,
name: item.name,
desc: item.description,
type: item.type,
parameters: item.config ? JSON.parse(item.config) : {},
color: '#10B981'
}));
}
@ -141,26 +141,31 @@ const fetchStrategies = async () => {
}
};
onMounted(async () => {
await fetchStrategies();
});
const onStrategyChange = (e) => {
strategyIndex.value = e.detail.value;
const strategy = strategies.value[strategyIndex.value];
console.log('选择的策略:', strategy);
console.log('策略参数:', strategy?.parameters);
if (strategy && strategy.parameters && strategy.parameters.assets) {
form.value.stocks = strategy.parameters.assets.map(asset => ({
name: asset.symbol,
price: '',
amount: '',
date: ''
}));
console.log('自动填充标的:', form.value.stocks);
} else {
form.value.stocks = [{ name: '', price: '', amount: '', date: '' }];
console.log('未找到标的配置,使用默认值');
}
};
const onDateChange = (e, index) => {
form.value.stocks[index].date = e.detail.value;
};
const addStockRow = () => {
form.value.stocks.push({ name: '', price: '', amount: '', date: '' });
};
const removeStockRow = (index) => {
form.value.stocks.splice(index, 1);
};
const submitForm = async () => {
if (!form.value.name) return uni.showToast({ title: '请输入组合名称', icon: 'none' });
if (strategyIndex.value === -1) return uni.showToast({ title: '请选择策略', icon: 'none' });
@ -196,6 +201,12 @@ const submitForm = async () => {
uni.showToast({ title: '创建失败,请重试', icon: 'none' });
}
};
onShow(async () => {
isFetching = true;
await fetchStrategies();
isFetching = false;
});
</script>
<style scoped>
@ -281,22 +292,6 @@ const submitForm = async () => {
color: #1F2937;
}
/* 添加按钮 */
.add-btn {
display: flex;
align-items: center;
background-color: #ECFDF5;
padding: 8rpx 20rpx;
border-radius: 100rpx;
gap: 8rpx;
}
.add-text {
font-size: 24rpx;
font-weight: 600;
color: #064E3B;
}
/* 表单项 */
.form-item {
margin-bottom: 32rpx;
@ -419,6 +414,12 @@ const submitForm = async () => {
color: #1F2937;
}
.mini-input[disabled] {
background-color: #F3F4F6;
color: #6B7280;
cursor: not-allowed;
}
/* 日期选择 */
.date-picker-display {
background-color: #FFFFFF;

View File

@ -116,18 +116,18 @@
<view class="timeline-box">
<view class="timeline-item" v-for="(log, k) in logs" :key="k">
<view class="tl-left">
<text class="tl-date">{{ log.Date }}</text>
<text class="tl-time">{{ log.Time }}</text>
<text class="tl-date">{{ log.date }}</text>
<text class="tl-time">{{ log.time }}</text>
</view>
<view class="tl-line">
<view class="tl-dot" :class="log.Type === 'buy' ? 'bg-red' : 'bg-green'"></view>
<view class="tl-dot" :class="log.type === 'buy' ? 'bg-red' : 'bg-green'"></view>
<view class="tl-dash" v-if="k !== logs.length - 1"></view>
</view>
<view class="tl-right">
<text class="tl-title">{{ log.Title }}</text>
<text class="tl-desc">{{ log.Type === 'buy' ? '录入增加' : '结出减少' }} {{ log.Amount }}</text>
<text class="tl-title">{{ log.title }}</text>
<text class="tl-desc">{{ log.type === 'buy' ? '增加' : '减少' }} {{ log.amount }}</text>
</view>
</view>
</view>
@ -136,11 +136,11 @@
<view class="action-section fixed-bottom">
<button class="action-btn btn-buy" @click="handleBuy">
<uni-icons type="download" size="20" color="#FFFFFF"></uni-icons>
<text class="btn-text">录入增加 / 比例校准</text>
<text class="btn-text">增加</text>
</button>
<button class="action-btn btn-sell" @click="handleSell">
<uni-icons type="upload" size="20" color="#064E3B"></uni-icons>
<text class="btn-text">结出减少 / 调减</text>
<text class="btn-text">减少</text>
</button>
</view>
@ -148,7 +148,7 @@
<view v-if="showTransactionForm" class="transaction-modal">
<view class="modal-content">
<view class="modal-header">
<text class="modal-title">{{ transactionType === 'buy' ? '录入增加' : '结出减少' }}</text>
<text class="modal-title">{{ transactionType === 'buy' ? '增加' : '减少' }}</text>
<view class="close-btn" @click="showTransactionForm = false">
<uni-icons type="close" size="20" color="#6B7280"></uni-icons>
</view>
@ -302,8 +302,8 @@ onMounted(async () => {
});
const goStrategyConfig = () => {
if (portfolioData.value.strategy?.Id) {
uni.navigateTo({ url: `/pages/strategies/edit/edit?id=${portfolioData.value.strategy.Id}` });
if (portfolioData.value.strategy?.id) {
uni.navigateTo({ url: `/pages/strategies/edit/edit?id=${portfolioData.value.strategy.id}` });
}
};
@ -538,6 +538,16 @@ const submitTransaction = async () => {
font-size: 30rpx;
font-weight: 700;
border: none;
flex-direction: row;
padding: 0 16rpx;
box-sizing: border-box;
}
.btn-text {
font-size: 30rpx;
font-weight: 700;
text-align: center;
line-height: 1.3;
white-space: nowrap;
}
.btn-buy { background-color: #064E3B; color: #FFFFFF; box-shadow: 0 8rpx 20rpx rgba(6, 78, 59, 0.2); }
.btn-buy:active { background-color: #047857; }

View File

@ -91,7 +91,8 @@
</template>
<script setup>
import { ref, onMounted } from 'vue';
import { ref } from 'vue';
import { onShow } from '@dcloudio/uni-app';
import { api } from '../../utils/api';
//
@ -104,6 +105,9 @@ const assetData = ref({
//
const holdings = ref([]);
//
let isFetching = false;
// API
const fetchAssetData = async () => {
try {
@ -113,11 +117,11 @@ const fetchAssetData = async () => {
//
const data = response.data;
assetData.value = {
totalValue: data.TotalValue,
currency: data.Currency,
todayProfit: data.TodayProfit,
todayProfitCurrency: data.TodayProfitCurrency,
totalReturnRate: data.TotalReturnRate
totalValue: data.totalValue,
currency: data.currency,
todayProfit: data.todayProfit,
todayProfitCurrency: data.todayProfitCurrency,
totalReturnRate: data.totalReturnRate
};
console.log('资产数据获取成功');
}
@ -135,18 +139,18 @@ const fetchHoldingsData = async () => {
// items
const items = response.data.items || [];
holdings.value = items.map(item => ({
id: item.Id,
name: item.Name,
tags: item.Tags,
status: item.Status,
statusType: item.StatusType,
iconChar: item.IconChar,
iconBgClass: item.IconBgClass,
iconTextClass: item.IconTextClass,
value: item.Value,
currency: item.Currency,
returnRate: item.ReturnRate,
returnType: item.ReturnType
id: item.id,
name: item.name,
tags: item.tags,
status: item.status,
statusType: item.statusType,
iconChar: item.iconChar,
iconBgClass: item.iconBgClass,
iconTextClass: item.iconTextClass,
value: item.value,
currency: item.currency,
returnRate: item.returnRate,
returnType: item.returnType
}));
console.log('持仓数据获取成功items数量:', holdings.value.length);
console.log('持仓数据:', holdings.value);
@ -156,16 +160,6 @@ const fetchHoldingsData = async () => {
}
};
//
onMounted(async () => {
console.log('首页加载,开始加载数据...');
await Promise.all([
fetchAssetData(),
fetchHoldingsData()
]);
});
const goConfig = () => {
uni.navigateTo({ url: '/pages/config/config' });
};
@ -173,6 +167,18 @@ const goConfig = () => {
const goDetail = (holdingId) => {
uni.navigateTo({ url: `/pages/detail/detail?id=${holdingId}` });
};
onShow(async () => {
console.log('首页显示,刷新数据...');
isFetching = true;
await Promise.all([
fetchAssetData(),
fetchHoldingsData()
]);
isFetching = false;
});
</script>
<style scoped>

View File

@ -1,13 +1,5 @@
<template>
<view class="page-container">
<view class="nav-bar">
<view class="back-btn" @click="uni.navigateBack()">
<uni-icons type="left" size="20" color="#374151"></uni-icons>
</view>
<text class="nav-title">{{ isEditMode ? '编辑策略' : '创建策略' }}</text>
</view>
<view class="section-title">选择逻辑模型</view>
<scroll-view scroll-x class="strategy-scroll" :show-scrollbar="false">
<view class="strategy-row">
@ -352,7 +344,7 @@ const submit = async () => {
description: formData.value.description || currentStrategyInfo.value.description,
riskLevel: formData.value.riskLevel,
tags: tags,
config: JSON.stringify(parameters)
parameters: parameters
};
console.log('保存策略:', strategyData);
@ -398,8 +390,14 @@ const loadStrategyDetail = async (id) => {
formData.value.tags = data.tags ? data.tags.join(', ') : '';
//
const params = data.config ? JSON.parse(data.config) : {};
switch (data.Type) {
let params = {};
if (data.parameters) {
params = data.parameters;
} else if (data.config) {
//
params = JSON.parse(data.config);
}
switch (data.type) {
case 'ma_trend':
formData.value.maType = params.maType || 'SMA';
formData.value.shortPeriod = params.shortPeriod?.toString() || '';

View File

@ -61,13 +61,17 @@
</template>
<script setup>
import { ref, onMounted, getCurrentInstance } from 'vue';
import { ref, getCurrentInstance } from 'vue';
import { onShow } from '@dcloudio/uni-app';
const { proxy } = getCurrentInstance();
const api = proxy.$api;
const strategies = ref([]);
//
let isFetching = false;
const fetchStrategies = async () => {
try {
const response = await api.strategies.getStrategies();
@ -91,8 +95,10 @@ const fetchStrategies = async () => {
}
};
onMounted(async () => {
onShow(async () => {
isFetching = true;
await fetchStrategies();
isFetching = false;
});
const goToAdd = () => {

View File

@ -391,7 +391,7 @@ export const api = {
*/
getUserInfo: () => {
console.log('📤 发起 getUserInfo 请求');
return get('/api/user/info');
return get('api/v1/user/info');
},
/**
* 获取用户统计数据
@ -399,7 +399,7 @@ export const api = {
*/
getUserStats: () => {
console.log('📤 发起 getUserStats 请求');
return get('/api/user/stats');
return get('api/v1/user/stats');
}
}
};