Browse Source

产品选择修复

milestone-20260212-日常优化2.0
ZhangYong 3 weeks ago
parent
commit
9adfe0f486
  1. 206
      src/components/MoneyManage/ProductSelect.vue

206
src/components/MoneyManage/ProductSelect.vue

@ -81,17 +81,48 @@
<div class="ai"> <div class="ai">
<div class="checktxt">{{ t('cash.other') }}</div> <div class="checktxt">{{ t('cash.other') }}</div>
<hr class="line"> <hr class="line">
<el-radio-group v-model="selectedValue">
<div v-for="ai in InfoFee" :key="ai" class="radio-wrapper">
<el-radio class="radio" :value="ai" @click="handleClick(ai)">
{{ ai }}
</el-radio>
<div v-if="showPanel&&ai==t('cash.HC')" class="cascader-panel" @click.stop>
<el-cascader-panel :options="cascaderOptions" :value="cascaderValue"
@change="handlePanelChange" />
<!-- Native implementation replacing el-radio-group -->
<div class="native-radio-group">
<div v-for="ai in InfoFee" :key="ai" class="radio-wrapper native-wrapper">
<div class="native-radio-item" @click="handleClick(ai)">
<span class="native-radio-input" :class="{ 'is-checked': selectedValue === ai }">
<span class="native-radio-inner"></span>
</span>
<span class="native-radio-label" :class="{ 'is-checked': selectedValue === ai }">{{ ai }}</span>
</div> </div>
</div> </div>
</el-radio-group>
<div class="native-radio-item" @click=" showPanel = !showPanel">
<span class="native-radio-input">
<span class="native-radio-inner"></span>
</span>
<span class="native-radio-label">{{ t('cash.HC')
}}</span>
<div v-if="showPanel" class="native-cascader-panel" @click.stop>
<div class="cascader-menu">
<div v-for="opt in cascaderOptions" :key="opt.value" class="cascader-node"
:class="{ 'is-active': activeCascaderOption?.value === opt.value }"
@mouseenter="activeCascaderOption = opt">
<span class="cascader-label">{{ opt.label }}</span>
<el-icon class="cascader-icon">
<ArrowRight />
</el-icon>
</div>
</div>
<div class="cascader-menu sub-menu" v-if="activeCascaderOption">
<div v-for="child in activeCascaderOption.children" :key="child.value" class="cascader-node"
@click="handlePanelChange([activeCascaderOption.value, child.value])">
<span class="cascader-label">{{ child.label }}</span>
</div>
</div>
</div>
</div>
</div>
</div>
<hr class="line">
<div class="confirm">
<el-button type="info" @click="cancelSelection">{{ t('common.cancel') }}</el-button>
<el-button type="primary" @click="confirmSelection">{{ t('common.confirm') }}</el-button>
</div> </div>
</div> </div>
</div> </div>
@ -100,7 +131,7 @@
</template> </template>
<script setup> <script setup>
import { ref, watch, onMounted, computed, onUnmounted, nextTick } from 'vue'; import { ref, watch, onMounted, computed, onUnmounted, nextTick } from 'vue';
import { ArrowDown } from '@element-plus/icons-vue';
import { ArrowDown, ArrowRight } from '@element-plus/icons-vue';
// //
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
@ -136,13 +167,20 @@ const props = defineProps({
const emit = defineEmits(['update:modelValue']) const emit = defineEmits(['update:modelValue'])
const selectedValue = ref('') const selectedValue = ref('')
const confirmSelection = () => {
emit('update:modelValue', selectedValue.value ? selectedValue.value : '');
console.log('更新父组件', selectedValue.value);
selectedItem.value = selectedValue.value || '';
isOpen.value = false
}
const cancelSelection = () => {
emit('update:modelValue', '');
console.log('点击了取消', '');
selectedItem.value = '';
isOpen.value = false
}
watch(selectedValue, (newVal) => {
emit('update:modelValue', newVal ? newVal : '');
console.log('更新父组件', newVal);
selectedItem.value = newVal || '';
});
const AIProduct = [ const AIProduct = [
@ -163,15 +201,13 @@ const superProduct = [
const InfoFee = [ const InfoFee = [
t('cash.staticInfoFee'), t('cash.staticInfoFee'),
t('cash.BGmember'), t('cash.BGmember'),
t('cash.HC')
] ]
const showPanel = ref(false) const showPanel = ref(false)
const activeCascaderOption = ref(null)
const handleClick = (ai) => { const handleClick = (ai) => {
if (ai == t('cash.HC')) {
showPanel.value = true
}
selectedValue.value = ai;
} }
const cascaderValue = ref([]) const cascaderValue = ref([])
const handlePanelChange = (val) => { const handlePanelChange = (val) => {
selectedValue.value = val[val.length - 1] selectedValue.value = val[val.length - 1]
@ -518,23 +554,15 @@ defineExpose({ resetSelect });
position: relative; position: relative;
display: inline-block; display: inline-block;
margin-right: 32px; margin-right: 32px;
.radio {
margin-right: 0;
}
.cascader-panel {
position: absolute;
top: -36px;
left: 100px;
z-index: 1000;
border: 1px solid #e6e6e6;
border-radius: 4px;
background: #E4F0FC;
margin-bottom: 10px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
} }
} }
.confirm {
width: 100%;
padding: 10px 0;
display: flex;
justify-content: center;
gap: 50px;
} }
.marketprodut { .marketprodut {
@ -591,4 +619,112 @@ defineExpose({ resetSelect });
} }
} }
} }
/* Native Radio Styles */
.native-radio-group {
display: inline-block;
}
.native-radio-item {
position: relative;
display: inline-flex;
align-items: center;
cursor: pointer;
margin-right: 0;
}
.native-radio-input {
white-space: nowrap;
cursor: pointer;
outline: none;
display: inline-flex;
position: relative;
vertical-align: middle;
width: 14px;
height: 14px;
background-color: #fff;
border: 1px solid #dcdfe6;
border-radius: 50%;
box-sizing: border-box;
margin-right: 8px;
&.is-checked {
border-color: #409eff;
background: #409eff;
.native-radio-inner {
width: 4px;
height: 4px;
border-radius: 50%;
background-color: #fff;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
}
}
.native-radio-label {
font-size: 14px;
color: #606266;
&.is-checked {
color: #409eff;
}
}
/* Native Cascader Styles */
.native-cascader-panel {
position: absolute;
top: -36px;
left: 100px;
/* Adjust as needed */
z-index: 1000;
background: #fff;
border: 1px solid #e4e7ed;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
border-radius: 4px;
display: flex;
max-height: 100px;
}
.cascader-menu {
min-width: 150px;
padding: 6px 0;
border-right: 1px solid #e4e7ed;
&:last-child {
border-right: none;
}
&.sub-menu {
background-color: #f5f7fa;
/* Slightly different bg for submenu */
overflow-y: auto;
height: 150px;
}
}
.cascader-node {
padding: 8px 15px;
display: flex;
align-items: center;
justify-content: space-between;
cursor: pointer;
font-size: 14px;
color: #606266;
&:hover,
&.is-active {
background-color: #f5f7fa;
color: #409eff;
}
.cascader-icon {
font-size: 12px;
margin-left: 10px;
color: #c0c4cc;
}
}
</style> </style>
Loading…
Cancel
Save