196 lines
6.9 KiB
Vue
196 lines
6.9 KiB
Vue
<template>
|
||
<view class="picker-wrap">
|
||
<view class="store-input-picker" @click="openDrawer">
|
||
<text :class="summary ? 'summary-text' : 'placeholder-text'">{{ summary || placeholder }}</text>
|
||
<u-icon v-if="!disabled" name="arrow-right" color="#c0c4cc" size="28"></u-icon>
|
||
</view>
|
||
|
||
<drawer-page-container v-model="show" title="选择关联门店">
|
||
<view class="drawer-body">
|
||
<view class="tab-wrap">
|
||
<u-subsection
|
||
:list="tabLabels"
|
||
:current="activeTab"
|
||
active-color="#6acdbb"
|
||
@change="onTabChange"
|
||
/>
|
||
</view>
|
||
<scroll-view scroll-y class="card-scroll">
|
||
<template v-if="activeTab === 0">
|
||
<view v-if="loading" class="empty">加载中...</view>
|
||
<view v-else-if="!options.length" class="empty">暂无预填诊所</view>
|
||
<view
|
||
v-for="item in options"
|
||
:key="item.id"
|
||
class="store-card"
|
||
:class="{ active: innerInputIds.includes(item.id) }"
|
||
@click="toggleInput(item.id)"
|
||
>
|
||
<view class="card-head">
|
||
<text class="card-name">{{ item.name || '-' }}</text>
|
||
<text class="card-status" :class="'s' + item.status">{{ item.status_text }}</text>
|
||
</view>
|
||
<text class="card-mobile">{{ item.mobile || '-' }}</text>
|
||
<text v-if="innerInputIds.includes(item.id)" class="card-check">已选</text>
|
||
</view>
|
||
</template>
|
||
<template v-else>
|
||
<view v-if="formalLoading" class="empty">加载中...</view>
|
||
<view v-else-if="!formalOptions.length" class="empty">暂无正式诊所</view>
|
||
<view
|
||
v-for="item in formalOptions"
|
||
:key="item.id"
|
||
class="store-card"
|
||
:class="{ active: innerStoreIds.includes(item.id) }"
|
||
@click="toggleStore(item.id)"
|
||
>
|
||
<view class="card-head">
|
||
<text class="card-name">{{ item.name || '-' }}</text>
|
||
</view>
|
||
<text v-if="innerStoreIds.includes(item.id)" class="card-check">已选</text>
|
||
</view>
|
||
</template>
|
||
</scroll-view>
|
||
<view class="drawer-footer">
|
||
<u-button type="primary" :custom-style="primaryStyle" @click="confirm">
|
||
确定({{ totalSelected }})
|
||
</u-button>
|
||
</view>
|
||
</view>
|
||
</drawer-page-container>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
import DrawerPageContainer from '@/subPackages/sub_salesperson/components/DrawerPageContainer.vue'
|
||
|
||
export default {
|
||
name: 'StoreInputPicker',
|
||
components: { DrawerPageContainer },
|
||
props: {
|
||
value: { type: Array, default: () => [] },
|
||
storeIds: { type: Array, default: () => [] },
|
||
options: { type: Array, default: () => [] },
|
||
formalOptions: { type: Array, default: () => [] },
|
||
loading: { type: Boolean, default: false },
|
||
formalLoading: { type: Boolean, default: false },
|
||
disabled: { type: Boolean, default: false },
|
||
placeholder: { type: String, default: '请选择关联门店' },
|
||
defaultStoreInputId: { type: [Number, String], default: 0 },
|
||
},
|
||
data() {
|
||
return {
|
||
show: false,
|
||
activeTab: 0,
|
||
innerInputIds: [],
|
||
innerStoreIds: [],
|
||
tabLabels: ['预填诊所', '正式诊所'],
|
||
primaryStyle: {
|
||
backgroundColor: '#6acdbb',
|
||
color: '#ffffff',
|
||
borderColor: '#6acdbb',
|
||
},
|
||
}
|
||
},
|
||
computed: {
|
||
totalSelected() {
|
||
return this.innerInputIds.length + this.innerStoreIds.length
|
||
},
|
||
summary() {
|
||
const inputNames = this.options
|
||
.filter((o) => this.value.includes(o.id))
|
||
.map((o) => o.name)
|
||
const storeNames = this.formalOptions
|
||
.filter((o) => this.storeIds.includes(o.id))
|
||
.map((o) => o.name)
|
||
const names = [...inputNames, ...storeNames]
|
||
if (names.length) return names.join('、')
|
||
const total = this.value.length + this.storeIds.length
|
||
if (total > 0) return `已选 ${total} 个门店`
|
||
return ''
|
||
},
|
||
},
|
||
watch: {
|
||
defaultStoreInputId: {
|
||
immediate: true,
|
||
handler(id) {
|
||
const n = Number(id || 0)
|
||
if (n > 0 && !this.value.includes(n)) {
|
||
this.$emit('input', [n])
|
||
}
|
||
},
|
||
},
|
||
},
|
||
methods: {
|
||
openDrawer() {
|
||
if (this.disabled) return
|
||
this.innerInputIds = [...this.value]
|
||
this.innerStoreIds = [...this.storeIds]
|
||
const preset = Number(this.defaultStoreInputId || 0)
|
||
if (preset > 0 && !this.innerInputIds.includes(preset)) {
|
||
this.innerInputIds.push(preset)
|
||
}
|
||
this.activeTab = 0
|
||
this.show = true
|
||
},
|
||
onTabChange(index) {
|
||
this.activeTab = index
|
||
},
|
||
toggleInput(id) {
|
||
const idx = this.innerInputIds.indexOf(id)
|
||
if (idx === -1) this.innerInputIds.push(id)
|
||
else this.innerInputIds.splice(idx, 1)
|
||
},
|
||
toggleStore(id) {
|
||
const idx = this.innerStoreIds.indexOf(id)
|
||
if (idx === -1) this.innerStoreIds.push(id)
|
||
else this.innerStoreIds.splice(idx, 1)
|
||
},
|
||
confirm() {
|
||
if (!this.innerInputIds.length && !this.innerStoreIds.length) {
|
||
uni.showToast({ title: '请选择关联门店', icon: 'none' })
|
||
return
|
||
}
|
||
this.$emit('input', [...this.innerInputIds])
|
||
this.$emit('update:storeIds', [...this.innerStoreIds])
|
||
this.show = false
|
||
},
|
||
},
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
.picker-wrap { width: 100%; }
|
||
.store-input-picker {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
width: 100%;
|
||
min-height: 72rpx;
|
||
}
|
||
.summary-text { font-size: 28rpx; color: #303133; flex: 1; }
|
||
.placeholder-text { font-size: 28rpx; color: #c0c4cc; flex: 1; }
|
||
.drawer-body { display: flex; flex-direction: column; max-height: 70vh; }
|
||
.tab-wrap { padding: 16rpx 24rpx 0; flex-shrink: 0; }
|
||
.card-scroll { flex: 1; max-height: 52vh; padding: 16rpx 24rpx; box-sizing: border-box; }
|
||
.store-card {
|
||
background: #f7f8fa;
|
||
border-radius: 16rpx;
|
||
padding: 24rpx;
|
||
margin-bottom: 16rpx;
|
||
border: 2rpx solid transparent;
|
||
position: relative;
|
||
}
|
||
.store-card.active { border-color: #6acdbb; background: rgba(106, 205, 187, 0.08); }
|
||
.card-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 8rpx; }
|
||
.card-name { font-size: 30rpx; font-weight: 600; color: #1d2129; flex: 1; }
|
||
.card-status { font-size: 22rpx; padding: 4rpx 12rpx; border-radius: 8rpx; }
|
||
.s0 { color: #ff7d00; background: rgba(255, 125, 0, 0.1); }
|
||
.s1 { color: #00b42a; background: rgba(0, 180, 42, 0.1); }
|
||
.s2 { color: #f53f3f; background: rgba(245, 63, 63, 0.1); }
|
||
.card-mobile { font-size: 26rpx; color: #86909c; }
|
||
.card-check { position: absolute; right: 24rpx; bottom: 24rpx; font-size: 24rpx; color: #6acdbb; font-weight: 600; }
|
||
.empty { text-align: center; color: #86909c; padding: 80rpx 0; font-size: 28rpx; }
|
||
.drawer-footer { padding: 16rpx 24rpx 32rpx; flex-shrink: 0; }
|
||
</style>
|