2 Commits
fd791b6f6a
...
58b4e1c618
Author | SHA1 | Message | Date |
---|---|---|---|
|
58b4e1c618 |
产品选择组件
|
2 days ago |
|
3d98845145 |
新增付款币种组件
|
2 days ago |
3 changed files with 508 additions and 22 deletions
-
336src/components/MoneyManage/CurrencySelect.vue
-
121src/components/MoneyManage/ProductSelect.vue
-
55src/views/moneyManage/receiveDetail/receiveDetail.vue
@ -0,0 +1,336 @@ |
|||||
|
<template> |
||||
|
<div class="dropdown" ref="dropdownRef"> |
||||
|
<!-- 下拉框触发器 --> |
||||
|
<div class="dropdown-toggle" @click="toggleMenu" :class="{ 'active': isOpen }"> |
||||
|
<span class="placeholder" :style="{ color: selectedItem ? '#333' : '#A8ABB2' }"> |
||||
|
{{ selectedItem || placeholder }} |
||||
|
</span> |
||||
|
<span class="arrow"> |
||||
|
<el-icon> |
||||
|
<ArrowDown /> |
||||
|
</el-icon> |
||||
|
</span> |
||||
|
</div> |
||||
|
|
||||
|
<!-- 下拉菜单 --> |
||||
|
<div class="dropdown-menu" v-if="isOpen"> |
||||
|
<!-- 搜索框 --> |
||||
|
<div class="search"> |
||||
|
<input type="text" v-model="searchData" class="search-input" placeholder="查询" @focus="handleSearchFocus" |
||||
|
@blur="handleSearchBlur"> |
||||
|
<el-icon v-show="!searchData" class="search-icon"> |
||||
|
<Search /> |
||||
|
</el-icon> |
||||
|
<el-icon class="clear-icon" v-if="searchData" @click="clearSearch"> |
||||
|
<CircleClose /> |
||||
|
</el-icon> |
||||
|
</div> |
||||
|
|
||||
|
<!-- 选项区域:按钮样式 --> |
||||
|
<div class="menuContent"> |
||||
|
<button class="dropdown-item" v-for="(item, index) in filteredItems" :key="index" @click="handleSelect(item)" |
||||
|
:class="{ 'selected': selectedItem === item }"> |
||||
|
{{ item }} |
||||
|
</button> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script setup> |
||||
|
import { ref, computed, watchEffect, onMounted } from 'vue'; |
||||
|
|
||||
|
const searchData = ref('') |
||||
|
const isOpen = ref(false) |
||||
|
const selectedItem = ref('') |
||||
|
const dropdownRef = ref(null) |
||||
|
|
||||
|
const props = defineProps({ |
||||
|
items: { |
||||
|
type: Array, |
||||
|
required: true, |
||||
|
default: () => [] |
||||
|
}, |
||||
|
placeholder: { |
||||
|
type: String, |
||||
|
default: '请选择支付方式' |
||||
|
}, |
||||
|
modelValue: { |
||||
|
type: String, |
||||
|
default: '' |
||||
|
} |
||||
|
}) |
||||
|
|
||||
|
const emit = defineEmits(['update:modelValue', 'change']) |
||||
|
|
||||
|
// 切换下拉菜单 |
||||
|
const toggleMenu = () => { |
||||
|
isOpen.value = !isOpen.value |
||||
|
searchData.value = '' |
||||
|
} |
||||
|
|
||||
|
// 清除搜索 |
||||
|
const clearSearch = () => { |
||||
|
searchData.value = '' |
||||
|
} |
||||
|
|
||||
|
// 选择选项 |
||||
|
const handleSelect = (item) => { |
||||
|
selectedItem.value = item |
||||
|
isOpen.value = false |
||||
|
emit('update:modelValue', item) |
||||
|
emit('change', item) |
||||
|
} |
||||
|
|
||||
|
// 点击外部关闭菜单 |
||||
|
const handleClickOutside = (event) => { |
||||
|
if (dropdownRef.value && !dropdownRef.value.contains(event.target)) { |
||||
|
isOpen.value = false |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 监听搜索框的焦点和失焦事件 |
||||
|
const handleSearchFocus = () => { |
||||
|
// 可以在这里添加额外的逻辑 |
||||
|
} |
||||
|
|
||||
|
const handleSearchBlur = () => { |
||||
|
// 可以在这里添加额外的逻辑 |
||||
|
} |
||||
|
|
||||
|
// 搜索过滤 |
||||
|
const filteredItems = computed(() => { |
||||
|
if (!searchData.value) return props.items |
||||
|
return props.items.filter(item => |
||||
|
item.toLowerCase().includes(searchData.value.toLowerCase()) |
||||
|
) |
||||
|
}) |
||||
|
|
||||
|
// 挂载/卸载事件 |
||||
|
onMounted(() => { |
||||
|
document.addEventListener('click', handleClickOutside) |
||||
|
return () => { |
||||
|
document.removeEventListener('click', handleClickOutside) |
||||
|
} |
||||
|
}) |
||||
|
|
||||
|
// 监听外部值变化 |
||||
|
watchEffect(() => { |
||||
|
selectedItem.value = props.modelValue |
||||
|
}) |
||||
|
</script> |
||||
|
<style scoped lang="scss"> |
||||
|
// 下拉容器 |
||||
|
.dropdown { |
||||
|
position: relative; |
||||
|
width: 268px; |
||||
|
font-family: 'Arial', sans-serif; |
||||
|
} |
||||
|
|
||||
|
// 触发器:控制展开/收起 |
||||
|
.dropdown-toggle { |
||||
|
border: 1px solid #e5e7eb; |
||||
|
padding: 4px 12px; |
||||
|
/* 调整内边距以匹配按钮高度 */ |
||||
|
height: 23px; |
||||
|
/* 调整高度以匹配按钮 */ |
||||
|
cursor: pointer; |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
align-items: center; |
||||
|
background-color: #fff; |
||||
|
border-radius: 6px; |
||||
|
transition: all 0.3s ease; |
||||
|
|
||||
|
.placeholder { |
||||
|
flex: 1; |
||||
|
font-size: 14px; |
||||
|
line-height: 18px; |
||||
|
color: #A8ABB2; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 展开状态:边框+阴影高亮 |
||||
|
.dropdown-toggle.active { |
||||
|
border-color: #678BFF; |
||||
|
box-shadow: 0 0 0 2px rgba(103, 139, 255, 0.1); |
||||
|
} |
||||
|
|
||||
|
// 箭头图标:展开时旋转 |
||||
|
.arrow { |
||||
|
margin-left: 8px; |
||||
|
color: #999; |
||||
|
transition: transform 0.3s ease; |
||||
|
} |
||||
|
|
||||
|
.dropdown-toggle.active .arrow { |
||||
|
transform: rotate(180deg); |
||||
|
} |
||||
|
|
||||
|
// 下拉菜单主体 |
||||
|
.dropdown-menu { |
||||
|
position: absolute; |
||||
|
top: 100%; // 紧贴触发器下方 |
||||
|
left: 0; |
||||
|
width: 100%; |
||||
|
border: 1px solid #678BFF; |
||||
|
max-height: 300px; |
||||
|
background-color: #fff; |
||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); |
||||
|
border-radius: 0 0 8px 8px; // 仅底部两侧圆角 |
||||
|
z-index: 1000; |
||||
|
margin-top: 15px; // 关键:不要有上外边距,尖角要紧贴触发器 |
||||
|
overflow: visible; |
||||
|
|
||||
|
|
||||
|
&::before { |
||||
|
content: ""; |
||||
|
position: absolute; |
||||
|
top: -8px; |
||||
|
left: 50%; |
||||
|
transform: translateX(-50%) scaleY(0.5); |
||||
|
width: 30px; |
||||
|
height: 16px; |
||||
|
background: #fff; |
||||
|
clip-path: polygon(0 100%, 100% 100%, 50% 0); |
||||
|
z-index: 1001; |
||||
|
border: none; |
||||
|
/* 移除原来的边框 */ |
||||
|
} |
||||
|
|
||||
|
&::after { |
||||
|
content: ""; |
||||
|
position: absolute; |
||||
|
top: -9px; |
||||
|
/* 比 ::before 往下一点,制造边框效果 */ |
||||
|
left: 50%; |
||||
|
transform: translateX(-50%) scaleY(0.5); |
||||
|
width: 30px; |
||||
|
height: 16px; |
||||
|
background: #678BFF; |
||||
|
clip-path: polygon(0 100%, 100% 100%, 50% 0); |
||||
|
z-index: 1000; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 搜索框区域 |
||||
|
.search { |
||||
|
position: sticky; |
||||
|
top: 0; |
||||
|
background-color: #FFFFFF; |
||||
|
z-index: 1002; |
||||
|
padding: 10px 14px 0px 10px; |
||||
|
} |
||||
|
|
||||
|
// 搜索输入框:浅灰背景 + 图标定位 |
||||
|
.search-input { |
||||
|
width: 100%; |
||||
|
height: 27px; |
||||
|
padding: 0 12px 0 5px; |
||||
|
/* 左侧留出图标空间 */ |
||||
|
border: 1px solid #dcdfe6; |
||||
|
border-radius: 10px; |
||||
|
box-sizing: border-box; |
||||
|
background-color: #f8f9fa; |
||||
|
/* 浅灰背景匹配参考图 */ |
||||
|
outline: none; |
||||
|
font-size: 12px; |
||||
|
transition: border-color 0.3s ease; |
||||
|
|
||||
|
&::placeholder { |
||||
|
color: #909399; |
||||
|
} |
||||
|
|
||||
|
&:hover { |
||||
|
border-color: #c0c4cc; |
||||
|
} |
||||
|
|
||||
|
&:focus { |
||||
|
border-color: #678BFF; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 搜索图标:左侧定位 |
||||
|
.search-icon { |
||||
|
position: absolute; |
||||
|
top: 62%; |
||||
|
left: 50px; |
||||
|
transform: translateY(-50%); |
||||
|
color: #909399; |
||||
|
z-index: 1003; |
||||
|
} |
||||
|
|
||||
|
// 清除图标:右侧定位 + hover效果 |
||||
|
.clear-icon { |
||||
|
position: absolute; |
||||
|
top: 62%; |
||||
|
right: 20px; |
||||
|
transform: translateY(-50%); |
||||
|
color: #909399; |
||||
|
cursor: pointer; |
||||
|
z-index: 1003; |
||||
|
|
||||
|
&:hover { |
||||
|
color: #606266; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 选项容器:调整滚动区域高度 |
||||
|
.menuContent { |
||||
|
max-height: 200px; |
||||
|
/* 减去搜索框高度和尖角高度 */ |
||||
|
overflow-y: auto; |
||||
|
padding: 8px; |
||||
|
padding: 10px 14px 12px 10px; |
||||
|
} |
||||
|
|
||||
|
// 选项按钮:无边框 + hover/选中效果 |
||||
|
.dropdown-item { |
||||
|
width: 100%; |
||||
|
height: 27px; |
||||
|
padding: 5px 12px 5px 5px; |
||||
|
text-align: center; |
||||
|
cursor: pointer; |
||||
|
border: none; |
||||
|
border-radius: 10px; |
||||
|
background-color: #fff; |
||||
|
font-size: 12px; |
||||
|
font-style: normal; |
||||
|
font-weight: 700; |
||||
|
line-height: 20px; |
||||
|
margin: 5px 0; |
||||
|
color: #040A2D; |
||||
|
transition: all 0.2s ease; |
||||
|
|
||||
|
&:hover { |
||||
|
background-color: #F3FAFE; |
||||
|
/* hover浅灰 */ |
||||
|
} |
||||
|
|
||||
|
&.selected { |
||||
|
background-color: #E5EBFE; |
||||
|
/* 选中浅蓝 */ |
||||
|
color: #2741DE; |
||||
|
/* 选中文字蓝色 */ |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 可选:滚动条美化(与原风格一致) |
||||
|
.menuContent::-webkit-scrollbar { |
||||
|
width: 6px; |
||||
|
} |
||||
|
|
||||
|
.menuContent::-webkit-scrollbar-track { |
||||
|
background: #f1f1f1; |
||||
|
border-radius: 3px; |
||||
|
} |
||||
|
|
||||
|
.menuContent::-webkit-scrollbar-thumb { |
||||
|
background: #c0c4cc; |
||||
|
border-radius: 3px; |
||||
|
|
||||
|
&:hover { |
||||
|
background: #909399; |
||||
|
} |
||||
|
} |
||||
|
</style> |
@ -0,0 +1,121 @@ |
|||||
|
<template> |
||||
|
<div class="productContent"> |
||||
|
<div class="selectBox" @click="handelMenu" :class="{ 'active': isOpen }"> |
||||
|
<span class="placeholder" :style="{ color: selectedItem ? '#333' : '#A8ABB2' }"> |
||||
|
{{ selectedItem || placeholder }} |
||||
|
</span> |
||||
|
<span class="arrow"> |
||||
|
<el-icon> |
||||
|
<ArrowDown /> |
||||
|
</el-icon> |
||||
|
</span> |
||||
|
</div> |
||||
|
|
||||
|
<div class="menu" v-show="isOpen"> |
||||
|
<div class="coin"> |
||||
|
<div class="coinselect"> |
||||
|
coin1 |
||||
|
<span class="coin-arrow"> |
||||
|
<el-icon> |
||||
|
<ArrowDown /> |
||||
|
</el-icon> |
||||
|
</span> |
||||
|
</div> |
||||
|
<div class="coinoption"> |
||||
|
coIn2 |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="product"> |
||||
|
22 |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</template> |
||||
|
<script setup> |
||||
|
import { ref, computed, watchEffect, onMounted } from 'vue'; |
||||
|
const searchData = ref('') |
||||
|
const isOpen = ref(false) |
||||
|
const selectedItem = ref('') |
||||
|
const dropdownRef = ref(null) |
||||
|
const placeholder = ref('请选择产品') |
||||
|
|
||||
|
const handelMenu = () => { |
||||
|
isOpen.value = !isOpen.value |
||||
|
} |
||||
|
</script> |
||||
|
<style scoped lang="scss"> |
||||
|
.productContent { |
||||
|
position: relative; |
||||
|
width: 268px; |
||||
|
font-family: 'Arial', sans-serif; |
||||
|
} |
||||
|
|
||||
|
.selectBox { |
||||
|
border: 1px solid #e5e7eb; |
||||
|
padding: 4px 12px; |
||||
|
/* 调整内边距以匹配按钮高度 */ |
||||
|
height: 23px; |
||||
|
/* 调整高度以匹配按钮 */ |
||||
|
cursor: pointer; |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
align-items: center; |
||||
|
background-color: #fff; |
||||
|
border-radius: 6px; |
||||
|
transition: all 0.3s ease; |
||||
|
|
||||
|
.placeholder { |
||||
|
flex: 1; |
||||
|
font-size: 14px; |
||||
|
line-height: 18px; |
||||
|
color: #A8ABB2; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 箭头图标:展开时旋转 |
||||
|
.arrow { |
||||
|
margin-left: 8px; |
||||
|
color: #999; |
||||
|
transition: transform 0.3s ease; |
||||
|
} |
||||
|
|
||||
|
.selectBox.active .arrow { |
||||
|
transform: rotate(180deg); |
||||
|
} |
||||
|
|
||||
|
.menu { |
||||
|
position: absolute; |
||||
|
top: 100%; // 紧贴触发器下方 |
||||
|
left: 0; |
||||
|
width: 130%; |
||||
|
max-height: 600px; |
||||
|
display: flex; |
||||
|
padding: 10px; |
||||
|
flex-direction: column; |
||||
|
align-items: flex-start; |
||||
|
gap: 10px; |
||||
|
flex-shrink: 0; |
||||
|
border-radius: 8px; |
||||
|
background: #E4F0FC; |
||||
|
box-shadow: 0 0 4px 0 #00000040; |
||||
|
z-index: 100; |
||||
|
|
||||
|
|
||||
|
.coin { |
||||
|
width: 100%; |
||||
|
|
||||
|
.coinselect { |
||||
|
width: 100px; |
||||
|
height: 30px; |
||||
|
border: 1px solid #175BE5; |
||||
|
padding: 5px 0 5px 12px; |
||||
|
display: flex; |
||||
|
|
||||
|
.coin-arrow { |
||||
|
margin-top: 8px; |
||||
|
color: #111; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</style> |
Write
Preview
Loading…
Cancel
Save
Reference in new issue