Browse Source

新增假的迁移股票的方法;增加选中股票的逻辑;新增底部操作框;

lihuilin/feature-20251024095243-我的
宋杰 3 weeks ago
parent
commit
d8f3f8e2f0
  1. 34
      api/home/mySelections.js
  2. 433
      pages/customStockList/customStockList.vue

34
api/home/mySelections.js

@ -325,6 +325,37 @@ class MySelectionsAPI {
throw error throw error
} }
} }
/**
* 更新自选股分组假接口
* @param {Function} successCallback - 成功回调函数
* @param {Function} failCallback - 失败回调函数
* @param {Object} data - 请求参数 {stockId: number, groupId: number}
* @returns {Promise}
*/
static async updateUserStockGroup(successCallback, failCallback = null, data = {}) {
const url = '/api/homePage/userStock/updateGroup'
try {
const response = await http({
url: url,
method: 'POST',
data: data
})
console.log('更新自选股分组 - 响应:', response)
if (successCallback && typeof successCallback === 'function') {
successCallback(response)
}
return response
} catch (error) {
console.error('更新自选股分组 - 失败:', error)
if (failCallback && typeof failCallback === 'function') {
failCallback(error)
}
throw error
}
}
} }
// 导出API类 // 导出API类
@ -341,5 +372,6 @@ export const {
updateUserStockGroupName, updateUserStockGroupName,
deleteUserStockGroup, deleteUserStockGroup,
deleteUserStock, deleteUserStock,
addUserStock
addUserStock,
updateUserStockGroup
} = MySelectionsAPI } = MySelectionsAPI

433
pages/customStockList/customStockList.vue

@ -66,7 +66,18 @@
v-for="stock in stockList" v-for="stock in stockList"
:key="stock.id" :key="stock.id"
class="stock-item" class="stock-item"
@click="handleStockClick(stock)"
> >
<!-- 多选模式下显示复选框 -->
<view v-if="isMultiSelectMode" class="checkbox-container">
<view
:class="['checkbox', selectedStockIds.includes(stock.id) ? 'checked' : '']"
@click.stop="toggleStockSelection(stock.id)"
>
<text v-if="selectedStockIds.includes(stock.id)" class="checkbox-icon"></text>
</view>
</view>
<view class="stock-info"> <view class="stock-info">
<text class="stock-name">{{ stock.name || stock.code }}</text> <text class="stock-name">{{ stock.name || stock.code }}</text>
<text class="stock-code">{{ stock.code }}</text> <text class="stock-code">{{ stock.code }}</text>
@ -81,11 +92,58 @@
</view> </view>
</view> </view>
</view> </view>
<!-- 多选模式下的底部操作栏 -->
<view v-if="isMultiSelectMode" class="bottom-toolbar">
<view class="toolbar-left">
<text class="selected-count">已选择 {{ selectedStockIds.length }} 只股票</text>
<text class="select-all-btn" @click="toggleSelectAll">
{{ isAllSelected ? '取消全选' : '全选' }}
</text>
</view>
<view class="toolbar-right">
<button
class="add-to-group-btn"
:disabled="selectedStockIds.length === 0"
@click="showGroupSelectModal = true"
>
添加至分组
</button>
</view>
</view>
<!-- 分组选择弹窗 -->
<view v-if="showGroupSelectModal" class="modal-overlay" @click="closeGroupSelectModal">
<view class="group-select-modal" @click.stop>
<view class="modal-header">
<text class="modal-title">编辑分组</text>
<text class="modal-close" @click="closeGroupSelectModal"></text>
</view>
<view class="modal-content">
<view class="group-grid">
<view
v-for="group in stockGroups"
:key="group.id"
:class="['group-item', group.id === currentGroupId ? 'current-group' : '']"
@click="selectTargetGroup(group)"
>
<text class="group-name">{{ group.name }}</text>
</view>
<view class="group-item new-group" @click="createNewGroupInModal">
<text class="new-group-text">+ 新建分组</text>
</view>
</view>
</view>
<view class="modal-footer">
<button class="confirm-btn" @click="confirmMoveToGroup">确认</button>
</view>
</view>
</view>
</view> </view>
</template> </template>
<script> <script>
import { getUserStockGroupList, addUserStockGroup, getUserStockList } from '@/api/home/mySelections.js'
import { getUserStockGroupList, addUserStockGroup, getUserStockList, updateUserStockGroup } from '@/api/home/mySelections.js'
export default { export default {
data() { data() {
@ -97,7 +155,21 @@
// //
stockList: [], stockList: [],
// //
loading: false
loading: false,
//
isMultiSelectMode: false,
// ID
selectedStockIds: [],
//
showGroupSelectModal: false,
//
selectedTargetGroup: null
}
},
computed: {
//
isAllSelected() {
return this.stockList.length > 0 && this.selectedStockIds.length === this.stockList.length
} }
}, },
onLoad() { onLoad() {
@ -251,10 +323,178 @@
}) })
}, },
//
// -
onSecondButtonClick() { onSecondButtonClick() {
console.log('第二个按钮被点击')
//
this.isMultiSelectMode = !this.isMultiSelectMode
// 退
if (!this.isMultiSelectMode) {
this.selectedStockIds = []
}
console.log('多选模式:', this.isMultiSelectMode)
},
//
handleStockClick(stock) {
if (this.isMultiSelectMode) {
//
this.toggleStockSelection(stock.id)
} else {
//
console.log('点击股票:', stock)
}
},
//
toggleStockSelection(stockId) {
const index = this.selectedStockIds.indexOf(stockId)
if (index > -1) {
//
this.selectedStockIds.splice(index, 1)
} else {
//
this.selectedStockIds.push(stockId)
}
},
// /
toggleSelectAll() {
if (this.isAllSelected) {
//
this.selectedStockIds = []
} else {
//
this.selectedStockIds = this.stockList.map(stock => stock.id)
}
},
//
closeGroupSelectModal() {
this.showGroupSelectModal = false
this.selectedTargetGroup = null
},
//
selectTargetGroup(group) {
this.selectedTargetGroup = group
},
//
createNewGroupInModal() {
uni.showModal({
title: '创建分组',
content: '请输入分组名称',
editable: true,
placeholderText: '请输入分组名称',
success: (res) => {
if (res.confirm && res.content) {
this.createNewGroupAndSelect(res.content.trim())
}
}
})
},
//
async createNewGroupAndSelect(groupName) {
try {
uni.showLoading({
title: '创建中...'
})
const response = await addUserStockGroup(null, null, {
name: groupName
})
if (response.code === 200) {
uni.showToast({
title: '创建成功',
icon: 'success'
})
//
await this.loadStockGroups()
//
if (response.data && response.data.id) {
this.selectedTargetGroup = this.stockGroups.find(g => g.id === response.data.id)
}
} else {
uni.showToast({
title: response.message || '创建失败',
icon: 'none'
})
}
} catch (error) {
console.error('创建分组失败:', error)
uni.showToast({
title: '创建失败,请重试',
icon: 'none'
})
} finally {
uni.hideLoading()
}
},
//
confirmMoveToGroup() {
if (!this.selectedTargetGroup) {
uni.showToast({
title: '请选择目标分组',
icon: 'none'
})
return
}
if (this.selectedStockIds.length === 0) {
uni.showToast({
title: '请选择要移动的股票',
icon: 'none'
})
return
}
// API
this.moveStocksToGroup(this.selectedTargetGroup.id)
},
//
async moveStocksToGroup(targetGroupId) {
try {
uni.showLoading({
title: '移动中...'
})
// APIID
const promises = this.selectedStockIds.map(stockId => {
return updateUserStockGroup(null, null, {
stockId: stockId,
groupId: targetGroupId
})
})
await Promise.all(promises)
uni.showToast({
title: '移动成功',
icon: 'success'
})
//
this.closeGroupSelectModal()
// 退
this.isMultiSelectMode = false
this.selectedStockIds = []
//
this.loadStockList()
} catch (error) {
console.error('移动股票失败:', error)
uni.showToast({
title: '移动失败,请重试',
icon: 'none'
})
} finally {
uni.hideLoading()
}
} }
} }
} }
@ -471,4 +711,187 @@
.change.down { .change.down {
color: #34c759; color: #34c759;
} }
/* 复选框样式 */
.checkbox-container {
margin-right: 12px;
}
.checkbox {
width: 20px;
height: 20px;
border: 2px solid #ddd;
border-radius: 4px;
display: flex;
align-items: center;
justify-content: center;
background-color: #fff;
}
.checkbox.checked {
background-color: #ff3b30;
border-color: #ff3b30;
}
.checkbox-icon {
color: #fff;
font-size: 12px;
font-weight: bold;
}
/* 底部操作栏样式 */
.bottom-toolbar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background-color: #fff;
border-top: 1px solid #f0f0f0;
padding: 12px 16px;
display: flex;
align-items: center;
justify-content: space-between;
z-index: 1000;
}
.toolbar-left {
display: flex;
align-items: center;
gap: 16px;
}
.selected-count {
font-size: 14px;
color: #333;
}
.select-all-btn {
font-size: 14px;
color: #ff3b30;
padding: 4px 8px;
}
.toolbar-right {
display: flex;
align-items: center;
}
.add-to-group-btn {
background-color: #ff3b30;
color: #fff;
border: none;
border-radius: 6px;
padding: 8px 16px;
font-size: 14px;
}
.add-to-group-btn:disabled {
background-color: #ccc;
color: #999;
}
/* 弹窗样式 */
.modal-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
align-items: flex-end;
z-index: 1000;
}
.group-select-modal {
background-color: white;
border-radius: 20rpx 20rpx 0 0;
width: 100%;
max-height: 80vh;
overflow: hidden;
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 30rpx 40rpx;
border-bottom: 1px solid #f0f0f0;
}
.modal-title {
font-size: 36rpx;
font-weight: bold;
color: #333333;
}
.modal-close {
font-size: 40rpx;
color: #999999;
padding: 10rpx;
}
.modal-content {
padding: 40rpx;
max-height: 60vh;
overflow-y: auto;
}
.group-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 20rpx;
}
.group-item {
background-color: #f8f8f8;
border-radius: 16rpx;
padding: 30rpx 20rpx;
text-align: center;
border: 2rpx solid transparent;
transition: all 0.3s ease;
}
.group-item.current-group {
background-color: #fff2f0;
border-color: #ff4d4f;
}
.group-item:active {
background-color: #e6f7ff;
border-color: #1890ff;
}
.group-name {
font-size: 28rpx;
color: #333333;
font-weight: 500;
}
.group-item.new-group {
background-color: #fff;
border: 2rpx dashed #d9d9d9;
}
.new-group-text {
font-size: 28rpx;
color: #ff4d4f;
font-weight: 500;
}
.modal-footer {
padding: 30rpx 40rpx;
border-top: 1px solid #f0f0f0;
}
.confirm-btn {
width: 100%;
height: 88rpx;
background-color: #ff4d4f;
color: white;
border: none;
border-radius: 44rpx;
font-size: 32rpx;
font-weight: 500;
}
</style> </style>
Loading…
Cancel
Save