ry_app/pages/BrandSelector/BrandSelector.vue

184 lines
3.7 KiB
Vue
Raw Normal View History

2026-01-22 21:27:11 +08:00
<template>
<view v-if="visible" class="brand-selector-overlay" @click="handleClose">
<view class="brand-selector-container" @click.stop>
<!-- 头部 -->
<view class="selector-header">
<view class="header-left" @click="handleClose">
<text class="close-icon">×</text>
</view>
<view class="header-title">选择品牌</view>
<view class="header-right" @click="handleConfirm">
<text class="confirm-btn">完成</text>
</view>
</view>
<!-- 搜索框 -->
<view class="search-box">
<input
class="search-input"
type="text"
placeholder="搜索品牌名称"
v-model="searchKeyword"
/>
</view>
<!-- 品牌列表 -->
<view class="brand-list">
<view
class="brand-item"
:class="{active: selectedBrand === item.name}"
v-for="item in filteredBrandList"
:key="item.name"
@click="selectBrand(item.name)"
>
{{ item.name }}
</view>
</view>
<!-- 品牌管理入口 -->
<view class="brand-management" @click="handleToBrandManagement">
<text class="management-text">品牌管理</text>
</view>
</view>
</view>
</template>
<script>
export default {
name: 'BrandSelector',
props: {
visible: {
type: Boolean,
default: false
},
defaultValue: {
type: String,
default: '默认品牌'
},
brandList: {
type: Array,
default: () => [{ name: '默认品牌' }]
}
},
data() {
return {
selectedBrand: this.defaultValue,
searchKeyword: ''
}
},
watch: {
defaultValue(newVal) {
this.selectedBrand = newVal
}
},
computed: {
filteredBrandList() {
if (!this.searchKeyword) return this.brandList
return this.brandList.filter(item =>
item.name.includes(this.searchKeyword)
)
}
},
methods: {
selectBrand(brandName) {
this.selectedBrand = brandName
},
handleConfirm() {
this.$emit('confirm', this.selectedBrand)
this.handleClose()
},
handleClose() {
this.$emit('close')
},
handleToBrandManagement() {
this.$emit('toBrandManagement')
}
}
}
</script>
<style lang="scss" scoped>
.brand-selector-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
display: flex;
align-items: flex-end;
z-index: 999;
}
.brand-selector-container {
width: 100%;
background: #fff;
border-radius: 16rpx 16rpx 0 0;
max-height: 80vh;
display: flex;
flex-direction: column;
}
.selector-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 30rpx;
border-bottom: 1rpx solid #f0f0f0;
.close-icon {
font-size: 36rpx;
color: #666;
}
.header-title {
font-size: 32rpx;
font-weight: 500;
color: #333;
}
.confirm-btn {
font-size: 30rpx;
color: #E62429;
}
}
.search-box {
padding: 20rpx 30rpx;
.search-input {
width: 100%;
padding: 20rpx;
background: #f5f5f5;
border-radius: 8rpx;
font-size: 28rpx;
}
}
.brand-list {
flex: 1;
overflow-y: auto;
.brand-item {
padding: 30rpx;
border-bottom: 1rpx solid #f0f0f0;
font-size: 30rpx;
color: #333;
position: relative;
&.active {
color: #E62429;
&::after {
content: "✓";
position: absolute;
right: 30rpx;
top: 50%;
transform: translateY(-50%);
font-size: 28rpx;
}
}
}
}
.brand-management {
padding: 30rpx;
text-align: center;
color: #1677FF;
font-size: 28rpx;
border-top: 1rpx solid #f0f0f0;
}
</style>