feat: 升级UI组件为uview-plus
- config.vue: 替换原生picker为u-picker,统一toast为u-toast,按钮为u-button - detail.vue: 替换交易表单input为u-input,所有按钮为u-button,toast为u-toast - 清理已替换组件的CSS样式 - 添加todo.md记录后续升级计划
This commit is contained in:
parent
924ac09535
commit
a9f3692aa8
@ -1,5 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="page-container">
|
<view class="page-container">
|
||||||
|
<!-- uView Toast 组件 -->
|
||||||
|
<u-toast ref="uToastRef" />
|
||||||
|
|
||||||
<view class="section-card">
|
<view class="section-card">
|
||||||
<view class="card-header">
|
<view class="card-header">
|
||||||
@ -21,27 +23,39 @@
|
|||||||
|
|
||||||
<view class="form-item">
|
<view class="form-item">
|
||||||
<text class="label">选择逻辑模板</text>
|
<text class="label">选择逻辑模板</text>
|
||||||
<picker @change="onStrategyChange" :value="strategyIndex" :range="strategies" range-key="name">
|
<u-picker
|
||||||
<view class="picker-box">
|
:show="showStrategyPicker"
|
||||||
|
:columns="[strategies.map(s => s.name)]"
|
||||||
|
keyName="name"
|
||||||
|
@confirm="onStrategyPickerConfirm"
|
||||||
|
@cancel="showStrategyPicker = false"
|
||||||
|
>
|
||||||
|
<view class="picker-box" @click="showStrategyPicker = true">
|
||||||
<view class="flex-row items-center gap-2" v-if="selectedStrategy">
|
<view class="flex-row items-center gap-2" v-if="selectedStrategy">
|
||||||
<view class="strategy-dot" :style="{ backgroundColor: selectedStrategy.color }"></view>
|
<view class="strategy-dot" :style="{ backgroundColor: selectedStrategy.color }"></view>
|
||||||
<text class="picker-text">{{ selectedStrategy.name }}</text>
|
<text class="picker-text">{{ selectedStrategy.name }}</text>
|
||||||
</view>
|
</view>
|
||||||
<text class="picker-placeholder" v-else>点击选择逻辑规则</text>
|
<text class="picker-placeholder" v-else>点击选择逻辑规则</text>
|
||||||
<uni-icons type="bottom" size="14" color="#9CA3AF"></uni-icons>
|
<u-icon name="arrow-down" size="14" color="#9CA3AF"></u-icon>
|
||||||
</view>
|
</view>
|
||||||
</picker>
|
</u-picker>
|
||||||
<text class="helper-text" v-if="selectedStrategy">{{ selectedStrategy.desc }}</text>
|
<text class="helper-text" v-if="selectedStrategy">{{ selectedStrategy.desc }}</text>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="form-item">
|
<view class="form-item">
|
||||||
<text class="label">组合币种</text>
|
<text class="label">组合币种</text>
|
||||||
<picker @change="onCurrencyChange" :value="currencyIndex" :range="currencyList" range-key="name">
|
<u-picker
|
||||||
<view class="picker-box">
|
:show="showCurrencyPicker"
|
||||||
|
:columns="[currencyList.map(c => c.name)]"
|
||||||
|
keyName="name"
|
||||||
|
@confirm="onCurrencyPickerConfirm"
|
||||||
|
@cancel="showCurrencyPicker = false"
|
||||||
|
>
|
||||||
|
<view class="picker-box" @click="showCurrencyPicker = true">
|
||||||
<text class="picker-text">{{ currencyList[currencyIndex].name }}</text>
|
<text class="picker-text">{{ currencyList[currencyIndex].name }}</text>
|
||||||
<uni-icons type="bottom" size="14" color="#9CA3AF"></uni-icons>
|
<u-icon name="arrow-down" size="14" color="#9CA3AF"></u-icon>
|
||||||
</view>
|
</view>
|
||||||
</picker>
|
</u-picker>
|
||||||
<text class="helper-text">创建后币种不可修改,所有交易只能使用该币种</text>
|
<text class="helper-text">创建后币种不可修改,所有交易只能使用该币种</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@ -132,17 +146,36 @@
|
|||||||
<text class="summary-label">预计初始投入</text>
|
<text class="summary-label">预计初始投入</text>
|
||||||
<text class="summary-val">¥ {{ totalInvestment }}</text>
|
<text class="summary-val">¥ {{ totalInvestment }}</text>
|
||||||
</view>
|
</view>
|
||||||
<button class="btn-submit" @click="submitForm">创建组合</button>
|
<u-button
|
||||||
|
class="btn-submit"
|
||||||
|
@click="submitForm"
|
||||||
|
:customStyle="{
|
||||||
|
backgroundColor: '#064E3B',
|
||||||
|
color: '#fff',
|
||||||
|
fontWeight: '700',
|
||||||
|
borderRadius: '24rpx',
|
||||||
|
height: '96rpx',
|
||||||
|
fontSize: '30rpx',
|
||||||
|
width: '100%',
|
||||||
|
border: 'none'
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
创建组合
|
||||||
|
</u-button>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed, watch } from 'vue';
|
import { ref, computed, watch, getCurrentInstance } from 'vue';
|
||||||
import { onShow } from '@dcloudio/uni-app';
|
import { onShow } from '@dcloudio/uni-app';
|
||||||
import { api } from '../../utils/api';
|
import { api } from '../../utils/api';
|
||||||
|
|
||||||
|
// 获取 u-toast 实例
|
||||||
|
const { proxy } = getCurrentInstance();
|
||||||
|
const uToastRef = ref();
|
||||||
|
|
||||||
const strategies = ref([]);
|
const strategies = ref([]);
|
||||||
const strategyIndex = ref(-1);
|
const strategyIndex = ref(-1);
|
||||||
// 币种选择
|
// 币种选择
|
||||||
@ -153,6 +186,10 @@ const currencyList = ref([
|
|||||||
]);
|
]);
|
||||||
const currencyIndex = ref(0); // 默认CNY
|
const currencyIndex = ref(0); // 默认CNY
|
||||||
|
|
||||||
|
// Picker 控制变量
|
||||||
|
const showStrategyPicker = ref(false);
|
||||||
|
const showCurrencyPicker = ref(false);
|
||||||
|
|
||||||
// 防止重复请求的标志
|
// 防止重复请求的标志
|
||||||
let isFetching = false;
|
let isFetching = false;
|
||||||
|
|
||||||
@ -288,13 +325,49 @@ const onDateChange = (e, index) => {
|
|||||||
form.value.stocks[index].date = e.detail.value;
|
form.value.stocks[index].date = e.detail.value;
|
||||||
};
|
};
|
||||||
|
|
||||||
const onCurrencyChange = (e) => {
|
// u-picker 确认方法
|
||||||
currencyIndex.value = e.detail.value;
|
const onStrategyPickerConfirm = (e) => {
|
||||||
|
const { value, index } = e;
|
||||||
|
strategyIndex.value = index[0];
|
||||||
|
showStrategyPicker.value = false;
|
||||||
|
|
||||||
|
// 调用原有的策略变更逻辑
|
||||||
|
const strategy = strategies.value[strategyIndex.value];
|
||||||
|
if (strategy && strategy.parameters && strategy.parameters.assets) {
|
||||||
|
form.value.stocks = strategy.parameters.assets.map(asset => ({
|
||||||
|
name: asset.symbol,
|
||||||
|
price: '',
|
||||||
|
amount: '',
|
||||||
|
date: ''
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
form.value.stocks = [{ name: '', price: '', amount: '', date: '' }];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onCurrencyPickerConfirm = (e) => {
|
||||||
|
const { value, index } = e;
|
||||||
|
currencyIndex.value = index[0];
|
||||||
|
showCurrencyPicker.value = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
const submitForm = async () => {
|
const submitForm = async () => {
|
||||||
if (!form.value.name) return uni.showToast({ title: '请输入组合名称', icon: 'none' });
|
if (!form.value.name) {
|
||||||
if (strategyIndex.value === -1) return uni.showToast({ title: '请选择策略', icon: 'none' });
|
proxy?.$refs.uToastRef?.show({
|
||||||
|
type: 'warning',
|
||||||
|
message: '请输入组合名称',
|
||||||
|
icon: 'warning'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (strategyIndex.value === -1) {
|
||||||
|
proxy?.$refs.uToastRef?.show({
|
||||||
|
type: 'warning',
|
||||||
|
message: '请选择策略',
|
||||||
|
icon: 'warning'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const selected = strategies.value[strategyIndex.value];
|
const selected = strategies.value[strategyIndex.value];
|
||||||
|
|
||||||
@ -324,11 +397,12 @@ const submitForm = async () => {
|
|||||||
const deviation = Math.abs(actualWeight - target.targetWeight);
|
const deviation = Math.abs(actualWeight - target.targetWeight);
|
||||||
|
|
||||||
if (deviation > 0.05) {
|
if (deviation > 0.05) {
|
||||||
return uni.showToast({
|
proxy?.$refs.uToastRef?.show({
|
||||||
title: `${stock.name} 权重偏差超过5%,目标${(target.targetWeight*100).toFixed(0)}%,实际${(actualWeight*100).toFixed(0)}%`,
|
type: 'error',
|
||||||
icon: 'none',
|
message: `${stock.name} 权重偏差超过5%,目标${(target.targetWeight*100).toFixed(0)}%,实际${(actualWeight*100).toFixed(0)}%`,
|
||||||
duration: 3000
|
duration: 3000
|
||||||
});
|
});
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -354,13 +428,21 @@ const submitForm = async () => {
|
|||||||
const response = await api.assets.createPortfolio(requestData);
|
const response = await api.assets.createPortfolio(requestData);
|
||||||
if (response.code === 200) {
|
if (response.code === 200) {
|
||||||
uni.hideLoading();
|
uni.hideLoading();
|
||||||
uni.showToast({ title: '创建成功', icon: 'success' });
|
proxy?.$refs.uToastRef?.show({
|
||||||
|
type: 'success',
|
||||||
|
message: '创建成功',
|
||||||
|
icon: 'success'
|
||||||
|
});
|
||||||
setTimeout(() => uni.navigateBack(), 1500);
|
setTimeout(() => uni.navigateBack(), 1500);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('创建投资组合失败:', error);
|
console.error('创建投资组合失败:', error);
|
||||||
uni.hideLoading();
|
uni.hideLoading();
|
||||||
uni.showToast({ title: '创建失败,请重试', icon: 'none' });
|
proxy?.$refs.uToastRef?.show({
|
||||||
|
type: 'error',
|
||||||
|
message: '创建失败,请重试',
|
||||||
|
icon: 'error'
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -692,19 +774,8 @@ onShow(async () => {
|
|||||||
font-family: 'DIN Alternate';
|
font-family: 'DIN Alternate';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* .btn-submit 样式已通过 u-button 的 customStyle 设置,此处保留空类避免冲突 */
|
||||||
.btn-submit {
|
.btn-submit {
|
||||||
background-color: #064E3B;
|
/* 样式已内联设置 */
|
||||||
color: #fff;
|
|
||||||
font-weight: 700;
|
|
||||||
border-radius: 24rpx;
|
|
||||||
height: 96rpx;
|
|
||||||
font-size: 30rpx;
|
|
||||||
width: 100%;
|
|
||||||
border: none;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
}
|
||||||
.btn-submit::after { border: none; }
|
|
||||||
.btn-submit:active { opacity: 0.9; }
|
|
||||||
</style>
|
</style>
|
||||||
@ -1,5 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="page-container">
|
<view class="page-container">
|
||||||
|
<!-- uView Toast 组件 -->
|
||||||
|
<u-toast ref="uToastRef" />
|
||||||
|
|
||||||
|
|
||||||
<view class="header-section">
|
<view class="header-section">
|
||||||
@ -170,17 +172,67 @@
|
|||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="action-section fixed-bottom">
|
<view class="action-section fixed-bottom">
|
||||||
<button class="btn-delete" @click="deletePortfolio">
|
<u-button
|
||||||
<uni-icons type="trash" size="20" color="#DC2626"></uni-icons>
|
class="btn-delete"
|
||||||
</button>
|
@click="deletePortfolio"
|
||||||
<button class="btn-buy" @click="handleBuy">
|
:customStyle="{
|
||||||
<uni-icons type="download" size="18" color="#FFFFFF"></uni-icons>
|
backgroundColor: '#FEF2F2',
|
||||||
|
color: '#DC2626',
|
||||||
|
fontWeight: '600',
|
||||||
|
borderRadius: '20rpx',
|
||||||
|
height: '80rpx',
|
||||||
|
fontSize: '28rpx',
|
||||||
|
width: '80rpx',
|
||||||
|
border: 'none',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center'
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<u-icon name="trash" size="20" color="#DC2626"></u-icon>
|
||||||
|
</u-button>
|
||||||
|
<u-button
|
||||||
|
class="btn-buy"
|
||||||
|
@click="handleBuy"
|
||||||
|
:customStyle="{
|
||||||
|
backgroundColor: '#064E3B',
|
||||||
|
color: '#FFFFFF',
|
||||||
|
fontWeight: '600',
|
||||||
|
borderRadius: '20rpx',
|
||||||
|
height: '80rpx',
|
||||||
|
fontSize: '28rpx',
|
||||||
|
flex: '1',
|
||||||
|
border: 'none',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
gap: '8rpx'
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<u-icon name="download" size="18" color="#FFFFFF"></u-icon>
|
||||||
<text>增加</text>
|
<text>增加</text>
|
||||||
</button>
|
</u-button>
|
||||||
<button class="btn-sell" @click="handleSell">
|
<u-button
|
||||||
<uni-icons type="upload" size="18" color="#064E3B"></uni-icons>
|
class="btn-sell"
|
||||||
|
@click="handleSell"
|
||||||
|
:customStyle="{
|
||||||
|
backgroundColor: '#D1FAE5',
|
||||||
|
color: '#064E3B',
|
||||||
|
fontWeight: '600',
|
||||||
|
borderRadius: '20rpx',
|
||||||
|
height: '80rpx',
|
||||||
|
fontSize: '28rpx',
|
||||||
|
flex: '1',
|
||||||
|
border: 'none',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
gap: '8rpx'
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<u-icon name="upload" size="18" color="#064E3B"></u-icon>
|
||||||
<text>减少</text>
|
<text>减少</text>
|
||||||
</button>
|
</u-button>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 交易表单弹窗 -->
|
<!-- 交易表单弹窗 -->
|
||||||
@ -197,11 +249,20 @@
|
|||||||
<view class="form-item">
|
<view class="form-item">
|
||||||
<text class="form-label">{{ transactionType === 'sell' ? '选择持仓' : '股票代码' }}</text>
|
<text class="form-label">{{ transactionType === 'sell' ? '选择持仓' : '股票代码' }}</text>
|
||||||
<view class="relative">
|
<view class="relative">
|
||||||
<input
|
<u-input
|
||||||
v-model="transactionForm.stockCode"
|
v-model="transactionForm.stockCode"
|
||||||
class="stock-input"
|
|
||||||
:placeholder="transactionType === 'sell' ? '点击选择要卖出的持仓' : '请输入股票代码搜索'"
|
:placeholder="transactionType === 'sell' ? '点击选择要卖出的持仓' : '请输入股票代码搜索'"
|
||||||
:disabled="transactionType === 'sell'"
|
:disabled="transactionType === 'sell'"
|
||||||
|
:border="false"
|
||||||
|
:customStyle="{
|
||||||
|
backgroundColor: '#F9FAFB',
|
||||||
|
borderRadius: '16rpx',
|
||||||
|
height: '80rpx',
|
||||||
|
padding: '0 20rpx',
|
||||||
|
border: '2rpx solid #E5E7EB',
|
||||||
|
fontSize: '28rpx',
|
||||||
|
color: '#1F2937'
|
||||||
|
}"
|
||||||
@input="onStockInput"
|
@input="onStockInput"
|
||||||
@click="handleStockInputClick"
|
@click="handleStockInputClick"
|
||||||
/>
|
/>
|
||||||
@ -274,8 +335,38 @@
|
|||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="modal-footer">
|
<view class="modal-footer">
|
||||||
<button class="btn-cancel" @click="showTransactionForm = false">取消</button>
|
<u-button
|
||||||
<button class="btn-confirm" @click="submitTransaction">确认</button>
|
class="btn-cancel"
|
||||||
|
@click="showTransactionForm = 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="submitTransaction"
|
||||||
|
:customStyle="{
|
||||||
|
backgroundColor: '#064E3B',
|
||||||
|
color: '#FFFFFF',
|
||||||
|
fontWeight: '600',
|
||||||
|
borderRadius: '16rpx',
|
||||||
|
height: '80rpx',
|
||||||
|
fontSize: '28rpx',
|
||||||
|
flex: '1',
|
||||||
|
border: 'none'
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
确认
|
||||||
|
</u-button>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@ -284,9 +375,13 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted } from 'vue';
|
import { ref, onMounted, getCurrentInstance } from 'vue';
|
||||||
import { api } from '../../utils/api';
|
import { api } from '../../utils/api';
|
||||||
|
|
||||||
|
// 获取 u-toast 实例
|
||||||
|
const { proxy } = getCurrentInstance();
|
||||||
|
const uToastRef = ref();
|
||||||
|
|
||||||
// 获取货币符号
|
// 获取货币符号
|
||||||
const getCurrencySymbol = (currency) => {
|
const getCurrencySymbol = (currency) => {
|
||||||
const symbols = {
|
const symbols = {
|
||||||
@ -428,7 +523,11 @@ const fetchPortfolioData = async () => {
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('获取投资组合数据失败:', error);
|
console.error('获取投资组合数据失败:', error);
|
||||||
uni.showToast({ title: '加载失败,请重试', icon: 'none' });
|
proxy?.$refs.uToastRef?.show({
|
||||||
|
type: 'error',
|
||||||
|
message: '加载失败,请重试',
|
||||||
|
icon: 'error'
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -448,7 +547,11 @@ const fetchTransactions = async () => {
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('获取交易记录失败:', error);
|
console.error('获取交易记录失败:', error);
|
||||||
uni.showToast({ title: '加载交易记录失败', icon: 'none' });
|
proxy?.$refs.uToastRef?.show({
|
||||||
|
type: 'error',
|
||||||
|
message: '加载交易记录失败',
|
||||||
|
icon: 'error'
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -503,18 +606,38 @@ const onDateChange = (e) => {
|
|||||||
const submitTransaction = async () => {
|
const submitTransaction = async () => {
|
||||||
// 表单验证
|
// 表单验证
|
||||||
if (!transactionForm.value.stockCode) {
|
if (!transactionForm.value.stockCode) {
|
||||||
return uni.showToast({ title: transactionType.value === 'sell' ? '请选择要卖出的持仓' : '请输入股票代码', icon: 'none' });
|
proxy?.$refs.uToastRef?.show({
|
||||||
|
type: 'warning',
|
||||||
|
message: transactionType.value === 'sell' ? '请选择要卖出的持仓' : '请输入股票代码',
|
||||||
|
icon: 'warning'
|
||||||
|
});
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
const amount = parseFloat(transactionForm.value.amount);
|
const amount = parseFloat(transactionForm.value.amount);
|
||||||
if (!amount || amount <= 0) {
|
if (!amount || amount <= 0) {
|
||||||
return uni.showToast({ title: '请输入有效的数量', icon: 'none' });
|
proxy?.$refs.uToastRef?.show({
|
||||||
|
type: 'warning',
|
||||||
|
message: '请输入有效的数量',
|
||||||
|
icon: 'warning'
|
||||||
|
});
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
// 卖出时校验数量不超过持仓
|
// 卖出时校验数量不超过持仓
|
||||||
if (transactionType.value === 'sell' && amount > maxSellAmount.value) {
|
if (transactionType.value === 'sell' && amount > maxSellAmount.value) {
|
||||||
return uni.showToast({ title: `卖出数量不能超过持仓数量 ${maxSellAmount.value}`, icon: 'none' });
|
proxy?.$refs.uToastRef?.show({
|
||||||
|
type: 'warning',
|
||||||
|
message: `卖出数量不能超过持仓数量 ${maxSellAmount.value}`,
|
||||||
|
icon: 'warning'
|
||||||
|
});
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
if (!transactionForm.value.price || parseFloat(transactionForm.value.price) <= 0) {
|
if (!transactionForm.value.price || parseFloat(transactionForm.value.price) <= 0) {
|
||||||
return uni.showToast({ title: '请输入有效的价格', icon: 'none' });
|
proxy?.$refs.uToastRef?.show({
|
||||||
|
type: 'warning',
|
||||||
|
message: '请输入有效的价格',
|
||||||
|
icon: 'warning'
|
||||||
|
});
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const transactionData = {
|
const transactionData = {
|
||||||
@ -534,7 +657,11 @@ const submitTransaction = async () => {
|
|||||||
const response = await api.assets.createTransaction(transactionData);
|
const response = await api.assets.createTransaction(transactionData);
|
||||||
if (response.code === 200) {
|
if (response.code === 200) {
|
||||||
uni.hideLoading();
|
uni.hideLoading();
|
||||||
uni.showToast({ title: '交易提交成功', icon: 'success' });
|
proxy?.$refs.uToastRef?.show({
|
||||||
|
type: 'success',
|
||||||
|
message: '交易提交成功',
|
||||||
|
icon: 'success'
|
||||||
|
});
|
||||||
showTransactionForm.value = false;
|
showTransactionForm.value = false;
|
||||||
|
|
||||||
// 重新获取交易记录
|
// 重新获取交易记录
|
||||||
@ -545,7 +672,11 @@ const submitTransaction = async () => {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('创建交易失败:', error);
|
console.error('创建交易失败:', error);
|
||||||
uni.hideLoading();
|
uni.hideLoading();
|
||||||
uni.showToast({ title: '提交失败,请重试', icon: 'none' });
|
proxy?.$refs.uToastRef?.show({
|
||||||
|
type: 'error',
|
||||||
|
message: '提交失败,请重试',
|
||||||
|
icon: 'error'
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -571,14 +702,22 @@ const deletePortfolio = async () => {
|
|||||||
|
|
||||||
if (response.statusCode === 200) {
|
if (response.statusCode === 200) {
|
||||||
uni.hideLoading();
|
uni.hideLoading();
|
||||||
uni.showToast({ title: '删除成功', icon: 'success' });
|
proxy?.$refs.uToastRef?.show({
|
||||||
|
type: 'success',
|
||||||
|
message: '删除成功',
|
||||||
|
icon: 'success'
|
||||||
|
});
|
||||||
setTimeout(() => uni.switchTab({ url: '/pages/index/index' }), 1500);
|
setTimeout(() => uni.switchTab({ url: '/pages/index/index' }), 1500);
|
||||||
} else {
|
} else {
|
||||||
throw new Error('删除失败');
|
throw new Error('删除失败');
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
uni.hideLoading();
|
uni.hideLoading();
|
||||||
uni.showToast({ title: '删除失败,请重试', icon: 'none' });
|
proxy?.$refs.uToastRef?.show({
|
||||||
|
type: 'error',
|
||||||
|
message: '删除失败,请重试',
|
||||||
|
icon: 'error'
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -723,51 +862,19 @@ const deletePortfolio = async () => {
|
|||||||
z-index: 999;
|
z-index: 999;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* .btn-delete 样式已通过 u-button 的 customStyle 设置,此处保留空类避免冲突 */
|
||||||
.btn-delete {
|
.btn-delete {
|
||||||
flex: 0 0 96rpx;
|
/* 样式已内联设置 */
|
||||||
width: 96rpx;
|
|
||||||
height: 96rpx;
|
|
||||||
border-radius: 24rpx;
|
|
||||||
background-color: #FEE2E2;
|
|
||||||
border: none;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
padding: 0;
|
|
||||||
}
|
}
|
||||||
.btn-delete::after { border: none; }
|
/* .btn-buy 样式已通过 u-button 的 customStyle 设置,此处保留空类避免冲突 */
|
||||||
.btn-buy {
|
.btn-buy {
|
||||||
flex: 1;
|
/* 样式已内联设置 */
|
||||||
height: 96rpx;
|
|
||||||
border-radius: 24rpx;
|
|
||||||
background-color: #064E3B;
|
|
||||||
border: none;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
gap: 8rpx;
|
|
||||||
color: #FFFFFF;
|
|
||||||
font-size: 30rpx;
|
|
||||||
font-weight: 700;
|
|
||||||
padding: 0;
|
|
||||||
}
|
}
|
||||||
.btn-buy::after { border: none; }
|
|
||||||
|
/* .btn-sell 样式已通过 u-button 的 customStyle 设置,此处保留空类避免冲突 */
|
||||||
.btn-sell {
|
.btn-sell {
|
||||||
flex: 1;
|
/* 样式已内联设置 */
|
||||||
height: 96rpx;
|
|
||||||
border-radius: 24rpx;
|
|
||||||
background-color: #FFFFFF;
|
|
||||||
border: 2rpx solid #064E3B;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
gap: 8rpx;
|
|
||||||
color: #064E3B;
|
|
||||||
font-size: 30rpx;
|
|
||||||
font-weight: 700;
|
|
||||||
padding: 0;
|
|
||||||
}
|
}
|
||||||
.btn-sell::after { border: none; }
|
|
||||||
|
|
||||||
.transaction-modal {
|
.transaction-modal {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
@ -828,16 +935,9 @@ const deletePortfolio = async () => {
|
|||||||
margin-bottom: 12rpx;
|
margin-bottom: 12rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* .stock-input 已替换为 u-input,样式已通过 customStyle 设置 */
|
||||||
.stock-input {
|
.stock-input {
|
||||||
width: 100%;
|
/* 样式已内联设置 */
|
||||||
height: 80rpx;
|
|
||||||
background-color: #F9FAFB;
|
|
||||||
border: 2rpx solid #E5E7EB;
|
|
||||||
border-radius: 16rpx;
|
|
||||||
padding: 0 20rpx;
|
|
||||||
font-size: 26rpx;
|
|
||||||
color: #1F2937;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-select {
|
.form-select {
|
||||||
@ -861,29 +961,11 @@ const deletePortfolio = async () => {
|
|||||||
gap: 16rpx;
|
gap: 16rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* .btn-cancel 和 .btn-confirm 样式已通过 u-button 的 customStyle 设置,此处保留空类避免冲突 */
|
||||||
.btn-cancel,
|
.btn-cancel,
|
||||||
.btn-confirm {
|
.btn-confirm {
|
||||||
flex: 1;
|
/* 样式已内联设置 */
|
||||||
height: 80rpx;
|
|
||||||
border-radius: 12rpx;
|
|
||||||
font-size: 26rpx;
|
|
||||||
font-weight: 600;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
border: none;
|
|
||||||
padding: 0;
|
|
||||||
}
|
}
|
||||||
.btn-cancel {
|
|
||||||
background-color: #F3F4F6;
|
|
||||||
color: #6B7280;
|
|
||||||
}
|
|
||||||
.btn-cancel::after { border: none; }
|
|
||||||
.btn-confirm {
|
|
||||||
background-color: #064E3B;
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
.btn-confirm::after { border: none; }
|
|
||||||
|
|
||||||
.relative { position: relative; }
|
.relative { position: relative; }
|
||||||
|
|
||||||
|
|||||||
85
todo.md
Normal file
85
todo.md
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
# AssetManager UniApp UI 升级计划
|
||||||
|
|
||||||
|
## 当前状态分析
|
||||||
|
- 已引入 uview-plus 组件库(uni_modules 方式)
|
||||||
|
- 部分页面已开始替换原生组件(input、button、card、datetime-picker)
|
||||||
|
- 仍存在混合使用情况(uni-icons + uview 组件)
|
||||||
|
- 微信小程序兼容性问题已部分修复
|
||||||
|
|
||||||
|
## 优先级排序
|
||||||
|
|
||||||
|
### P0 - 核心组件统一化(本周内)
|
||||||
|
1. **表单组件标准化**
|
||||||
|
- [ ] 替换所有原生 `<input>` 为 `<u-input>`
|
||||||
|
- [ ] 统一表单验证样式(error状态、placeholder颜色)
|
||||||
|
- [ ] 修复 config.vue 中的日期选择器回退问题
|
||||||
|
|
||||||
|
2. **按钮组件统一**
|
||||||
|
- [ ] 替换所有原生 `<button>` 为 `<u-button>`
|
||||||
|
- [ ] 统一按钮尺寸、圆角、hover效果
|
||||||
|
- [ ] 微信小程序兼容性测试
|
||||||
|
|
||||||
|
3. **卡片组件优化**
|
||||||
|
- [ ] 检查所有 `<u-card>` 的 props 使用是否正确
|
||||||
|
- [ ] 统一卡片阴影、边框、内边距
|
||||||
|
- [ ] 修复 detail.vue 中 u-card 的样式问题
|
||||||
|
|
||||||
|
### P1 - 用户体验提升(下周)
|
||||||
|
4. **加载状态优化**
|
||||||
|
- [ ] 实现全局骨架屏组件(使用 u-skeleton)
|
||||||
|
- [ ] 添加页面切换加载动画
|
||||||
|
- [ ] 优化数据加载时的占位符
|
||||||
|
|
||||||
|
5. **反馈组件升级**
|
||||||
|
- [ ] 统一 toast 调用方式(使用 u-toast ref)
|
||||||
|
- [ ] 替换所有 `uni.showToast` 为 uview 版本
|
||||||
|
- [ ] 添加操作确认模态框(u-modal)
|
||||||
|
|
||||||
|
6. **导航与布局**
|
||||||
|
- [ ] 检查 navbar 组件是否需要替换为 u-navbar
|
||||||
|
- [ ] 统一页面间距和布局网格
|
||||||
|
- [ ] 优化移动端适配
|
||||||
|
|
||||||
|
### P2 - 高级功能(下下周)
|
||||||
|
7. **搜索与筛选**
|
||||||
|
- [ ] 实现统一的搜索下拉组件(u-search + u-dropdown)
|
||||||
|
- [ ] 添加筛选标签组件
|
||||||
|
- [ ] 优化股票搜索功能性能
|
||||||
|
|
||||||
|
8. **图表可视化**
|
||||||
|
- [ ] 评估 ucharts 或 echarts 集成方案
|
||||||
|
- [ ] 实现资产走势迷你图表
|
||||||
|
- [ ] 添加数据可视化卡片
|
||||||
|
|
||||||
|
9. **主题与暗色模式**
|
||||||
|
- [ ] 配置 uview 主题变量
|
||||||
|
- [ ] 实现暗色模式切换
|
||||||
|
- [ ] 测试主题色一致性
|
||||||
|
|
||||||
|
## 技术债务清理
|
||||||
|
- [ ] 移除未使用的 CSS 类(detail.vue 已清理部分)
|
||||||
|
- [ ] 统一图标使用(选择 uni-icons 或 u-icon)
|
||||||
|
- [ ] 优化 API 调用错误处理
|
||||||
|
- [ ] 添加组件使用文档注释
|
||||||
|
|
||||||
|
## 兼容性要求
|
||||||
|
- ✅ 微信小程序(已部分适配)
|
||||||
|
- ✅ H5 网页版
|
||||||
|
- ✅ App 端
|
||||||
|
- ⚠️ 支付宝小程序(待测试)
|
||||||
|
|
||||||
|
## 验收标准
|
||||||
|
1. 所有页面组件使用率达到 90% 以上 uview-plus
|
||||||
|
2. 微信小程序无警告和错误
|
||||||
|
3. 页面加载速度提升 20%
|
||||||
|
4. 代码重复率降低 30%
|
||||||
|
|
||||||
|
## 风险点
|
||||||
|
1. **微信小程序组件限制**:部分 uview 组件在小程序端可能有限制
|
||||||
|
2. **性能影响**:uview 组件库体积较大,需注意分包加载
|
||||||
|
3. **学习曲线**:团队成员需熟悉 uview-plus API
|
||||||
|
|
||||||
|
## 下一步行动
|
||||||
|
1. 先完成 P0 的表单和按钮统一化
|
||||||
|
2. 每个页面完成后进行微信小程序真机测试
|
||||||
|
3. 建立组件使用规范文档
|
||||||
Loading…
Reference in New Issue
Block a user