Files
xk-doctor-wx/subPackages/sub_salesperson/components/StoreInputPicker.vue
2026-06-18 14:09:38 +08:00

196 lines
6.9 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<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>