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>
|
||||
<view class="page-container">
|
||||
<!-- uView Toast 组件 -->
|
||||
<u-toast ref="uToastRef" />
|
||||
|
||||
<view class="section-card">
|
||||
<view class="card-header">
|
||||
@ -21,27 +23,39 @@
|
||||
|
||||
<view class="form-item">
|
||||
<text class="label">选择逻辑模板</text>
|
||||
<picker @change="onStrategyChange" :value="strategyIndex" :range="strategies" range-key="name">
|
||||
<view class="picker-box">
|
||||
<u-picker
|
||||
: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="strategy-dot" :style="{ backgroundColor: selectedStrategy.color }"></view>
|
||||
<text class="picker-text">{{ selectedStrategy.name }}</text>
|
||||
</view>
|
||||
<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>
|
||||
</picker>
|
||||
</u-picker>
|
||||
<text class="helper-text" v-if="selectedStrategy">{{ selectedStrategy.desc }}</text>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<text class="label">组合币种</text>
|
||||
<picker @change="onCurrencyChange" :value="currencyIndex" :range="currencyList" range-key="name">
|
||||
<view class="picker-box">
|
||||
<u-picker
|
||||
: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>
|
||||
<uni-icons type="bottom" size="14" color="#9CA3AF"></uni-icons>
|
||||
<u-icon name="arrow-down" size="14" color="#9CA3AF"></u-icon>
|
||||
</view>
|
||||
</picker>
|
||||
</u-picker>
|
||||
<text class="helper-text">创建后币种不可修改,所有交易只能使用该币种</text>
|
||||
</view>
|
||||
</view>
|
||||
@ -132,17 +146,36 @@
|
||||
<text class="summary-label">预计初始投入</text>
|
||||
<text class="summary-val">¥ {{ totalInvestment }}</text>
|
||||
</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>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, watch } from 'vue';
|
||||
import { ref, computed, watch, getCurrentInstance } from 'vue';
|
||||
import { onShow } from '@dcloudio/uni-app';
|
||||
import { api } from '../../utils/api';
|
||||
|
||||
// 获取 u-toast 实例
|
||||
const { proxy } = getCurrentInstance();
|
||||
const uToastRef = ref();
|
||||
|
||||
const strategies = ref([]);
|
||||
const strategyIndex = ref(-1);
|
||||
// 币种选择
|
||||
@ -153,6 +186,10 @@ const currencyList = ref([
|
||||
]);
|
||||
const currencyIndex = ref(0); // 默认CNY
|
||||
|
||||
// Picker 控制变量
|
||||
const showStrategyPicker = ref(false);
|
||||
const showCurrencyPicker = ref(false);
|
||||
|
||||
// 防止重复请求的标志
|
||||
let isFetching = false;
|
||||
|
||||
@ -288,13 +325,49 @@ const onDateChange = (e, index) => {
|
||||
form.value.stocks[index].date = e.detail.value;
|
||||
};
|
||||
|
||||
const onCurrencyChange = (e) => {
|
||||
currencyIndex.value = e.detail.value;
|
||||
// u-picker 确认方法
|
||||
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 () => {
|
||||
if (!form.value.name) return uni.showToast({ title: '请输入组合名称', icon: 'none' });
|
||||
if (strategyIndex.value === -1) return uni.showToast({ title: '请选择策略', icon: 'none' });
|
||||
if (!form.value.name) {
|
||||
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];
|
||||
|
||||
@ -324,11 +397,12 @@ const submitForm = async () => {
|
||||
const deviation = Math.abs(actualWeight - target.targetWeight);
|
||||
|
||||
if (deviation > 0.05) {
|
||||
return uni.showToast({
|
||||
title: `${stock.name} 权重偏差超过5%,目标${(target.targetWeight*100).toFixed(0)}%,实际${(actualWeight*100).toFixed(0)}%`,
|
||||
icon: 'none',
|
||||
proxy?.$refs.uToastRef?.show({
|
||||
type: 'error',
|
||||
message: `${stock.name} 权重偏差超过5%,目标${(target.targetWeight*100).toFixed(0)}%,实际${(actualWeight*100).toFixed(0)}%`,
|
||||
duration: 3000
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -354,13 +428,21 @@ const submitForm = async () => {
|
||||
const response = await api.assets.createPortfolio(requestData);
|
||||
if (response.code === 200) {
|
||||
uni.hideLoading();
|
||||
uni.showToast({ title: '创建成功', icon: 'success' });
|
||||
proxy?.$refs.uToastRef?.show({
|
||||
type: 'success',
|
||||
message: '创建成功',
|
||||
icon: 'success'
|
||||
});
|
||||
setTimeout(() => uni.navigateBack(), 1500);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('创建投资组合失败:', error);
|
||||
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';
|
||||
}
|
||||
|
||||
/* .btn-submit 样式已通过 u-button 的 customStyle 设置,此处保留空类避免冲突 */
|
||||
.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>
|
||||
@ -1,5 +1,7 @@
|
||||
<template>
|
||||
<view class="page-container">
|
||||
<!-- uView Toast 组件 -->
|
||||
<u-toast ref="uToastRef" />
|
||||
|
||||
|
||||
<view class="header-section">
|
||||
@ -170,17 +172,67 @@
|
||||
</view>
|
||||
|
||||
<view class="action-section fixed-bottom">
|
||||
<button class="btn-delete" @click="deletePortfolio">
|
||||
<uni-icons type="trash" size="20" color="#DC2626"></uni-icons>
|
||||
</button>
|
||||
<button class="btn-buy" @click="handleBuy">
|
||||
<uni-icons type="download" size="18" color="#FFFFFF"></uni-icons>
|
||||
<u-button
|
||||
class="btn-delete"
|
||||
@click="deletePortfolio"
|
||||
:customStyle="{
|
||||
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>
|
||||
</button>
|
||||
<button class="btn-sell" @click="handleSell">
|
||||
<uni-icons type="upload" size="18" color="#064E3B"></uni-icons>
|
||||
</u-button>
|
||||
<u-button
|
||||
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>
|
||||
</button>
|
||||
</u-button>
|
||||
</view>
|
||||
|
||||
<!-- 交易表单弹窗 -->
|
||||
@ -197,11 +249,20 @@
|
||||
<view class="form-item">
|
||||
<text class="form-label">{{ transactionType === 'sell' ? '选择持仓' : '股票代码' }}</text>
|
||||
<view class="relative">
|
||||
<input
|
||||
<u-input
|
||||
v-model="transactionForm.stockCode"
|
||||
class="stock-input"
|
||||
:placeholder="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"
|
||||
@click="handleStockInputClick"
|
||||
/>
|
||||
@ -274,8 +335,38 @@
|
||||
</view>
|
||||
|
||||
<view class="modal-footer">
|
||||
<button class="btn-cancel" @click="showTransactionForm = false">取消</button>
|
||||
<button class="btn-confirm" @click="submitTransaction">确认</button>
|
||||
<u-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>
|
||||
@ -284,9 +375,13 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { ref, onMounted, getCurrentInstance } from 'vue';
|
||||
import { api } from '../../utils/api';
|
||||
|
||||
// 获取 u-toast 实例
|
||||
const { proxy } = getCurrentInstance();
|
||||
const uToastRef = ref();
|
||||
|
||||
// 获取货币符号
|
||||
const getCurrencySymbol = (currency) => {
|
||||
const symbols = {
|
||||
@ -428,7 +523,11 @@ const fetchPortfolioData = async () => {
|
||||
}
|
||||
} catch (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) {
|
||||
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 () => {
|
||||
// 表单验证
|
||||
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);
|
||||
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) {
|
||||
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) {
|
||||
return uni.showToast({ title: '请输入有效的价格', icon: 'none' });
|
||||
proxy?.$refs.uToastRef?.show({
|
||||
type: 'warning',
|
||||
message: '请输入有效的价格',
|
||||
icon: 'warning'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const transactionData = {
|
||||
@ -534,7 +657,11 @@ const submitTransaction = async () => {
|
||||
const response = await api.assets.createTransaction(transactionData);
|
||||
if (response.code === 200) {
|
||||
uni.hideLoading();
|
||||
uni.showToast({ title: '交易提交成功', icon: 'success' });
|
||||
proxy?.$refs.uToastRef?.show({
|
||||
type: 'success',
|
||||
message: '交易提交成功',
|
||||
icon: 'success'
|
||||
});
|
||||
showTransactionForm.value = false;
|
||||
|
||||
// 重新获取交易记录
|
||||
@ -545,7 +672,11 @@ const submitTransaction = async () => {
|
||||
} catch (error) {
|
||||
console.error('创建交易失败:', error);
|
||||
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) {
|
||||
uni.hideLoading();
|
||||
uni.showToast({ title: '删除成功', icon: 'success' });
|
||||
proxy?.$refs.uToastRef?.show({
|
||||
type: 'success',
|
||||
message: '删除成功',
|
||||
icon: 'success'
|
||||
});
|
||||
setTimeout(() => uni.switchTab({ url: '/pages/index/index' }), 1500);
|
||||
} else {
|
||||
throw new Error('删除失败');
|
||||
}
|
||||
} catch (error) {
|
||||
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;
|
||||
}
|
||||
|
||||
/* .btn-delete 样式已通过 u-button 的 customStyle 设置,此处保留空类避免冲突 */
|
||||
.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 {
|
||||
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 {
|
||||
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 {
|
||||
position: fixed;
|
||||
@ -828,16 +935,9 @@ const deletePortfolio = async () => {
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
|
||||
/* .stock-input 已替换为 u-input,样式已通过 customStyle 设置 */
|
||||
.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 {
|
||||
@ -861,29 +961,11 @@ const deletePortfolio = async () => {
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
/* .btn-cancel 和 .btn-confirm 样式已通过 u-button 的 customStyle 设置,此处保留空类避免冲突 */
|
||||
.btn-cancel,
|
||||
.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; }
|
||||
|
||||
|
||||
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