All checks were successful
Build and Deploy Front / deploy (push) Successful in 5m59s
侧栏改为 Cursor 式账户面板(仓库眼标预览、语言切换、假邮箱过滤),运单「更多」支持发货后四态变更且妥投成功仅可进入。 Co-authored-by: Cursor <cursoragent@cursor.com>
280 lines
6.5 KiB
Vue
280 lines
6.5 KiB
Vue
<script setup lang="ts">
|
||
import { computed, onMounted } from 'vue'
|
||
import { useI18n } from 'vue-i18n'
|
||
import { getWarehouseList } from '@/api/system/warehouse'
|
||
import { useCurrentWarehouseStore } from '@/store'
|
||
|
||
const props = withDefaults(
|
||
defineProps<{
|
||
variant?: 'navbar' | 'login' | 'sider'
|
||
/** 下拉位置;侧栏沉底用 rt */
|
||
dropdownPosition?: 'br' | 'bl' | 'tr' | 'tl' | 'rt' | 'rb'
|
||
/** 侧栏收起:窄宽展示缩略文案(无图标) */
|
||
compact?: boolean
|
||
/** 下拉触发;侧栏默认 click,顶栏 hover */
|
||
trigger?: 'hover' | 'click'
|
||
/** 侧栏展开:显示「发货仓库」语义前缀 */
|
||
showCaption?: boolean
|
||
contentClass?: string
|
||
}>(),
|
||
{
|
||
variant: 'navbar',
|
||
dropdownPosition: 'br',
|
||
compact: false,
|
||
trigger: undefined,
|
||
showCaption: false,
|
||
contentClass: '',
|
||
},
|
||
)
|
||
|
||
const { t } = useI18n()
|
||
const warehouseStore = useCurrentWarehouseStore()
|
||
|
||
const displayName = computed(
|
||
() =>
|
||
warehouseStore.warehouseName ||
|
||
t('nav.contactService.selectWarehouse'),
|
||
)
|
||
|
||
/** 收起时只露一字,避免无图标时空块 */
|
||
const labelText = computed(() => {
|
||
const name = displayName.value
|
||
if (props.variant === 'sider' && props.compact) {
|
||
return name.slice(0, 1) || '仓'
|
||
}
|
||
return name
|
||
})
|
||
|
||
const useDropdown = computed(() => props.variant === 'navbar' || props.variant === 'sider')
|
||
|
||
const dropdownTrigger = computed(() => {
|
||
if (props.trigger) return props.trigger
|
||
return props.variant === 'sider' ? 'click' : 'hover'
|
||
})
|
||
|
||
const showSiderCaption = computed(
|
||
() => props.showCaption && props.variant === 'sider' && !props.compact,
|
||
)
|
||
|
||
const contentClass = computed(() => props.contentClass || undefined)
|
||
|
||
const popupTranslate = computed<[number, number] | undefined>(() => {
|
||
const pos = props.dropdownPosition
|
||
return pos === 'tl' || pos === 'tr' ? [0, -6] : undefined
|
||
})
|
||
|
||
async function loadServiceDataList() {
|
||
try {
|
||
const { items } = await getWarehouseList({
|
||
page: 1,
|
||
pageSize: 100,
|
||
})
|
||
const list = (items ?? [])
|
||
.filter((row) => row.id != null)
|
||
.map((row) => ({
|
||
label: row.warehouseName || String(row.id),
|
||
value: Number(row.id),
|
||
}))
|
||
warehouseStore.setOptions(list)
|
||
} catch (error) {
|
||
console.error('Failed to load service warehouse list', error)
|
||
warehouseStore.setOptions([])
|
||
}
|
||
}
|
||
|
||
function onSelectWarehouse(id: number) {
|
||
warehouseStore.setWarehouseId(id)
|
||
}
|
||
|
||
onMounted(() => {
|
||
void loadServiceDataList()
|
||
})
|
||
</script>
|
||
|
||
<template>
|
||
<div
|
||
class="contact-service"
|
||
:class="[
|
||
`contact-service--${variant}`,
|
||
{ 'is-compact': compact },
|
||
]"
|
||
>
|
||
<a-dropdown
|
||
v-if="useDropdown"
|
||
:trigger="dropdownTrigger"
|
||
:position="dropdownPosition"
|
||
:content-class="contentClass"
|
||
:popup-translate="popupTranslate"
|
||
:popup-max-height="320"
|
||
>
|
||
<button
|
||
type="button"
|
||
class="contact-service__label"
|
||
:title="displayName"
|
||
:aria-label="`${t('nav.contactService.shipWarehouse')}: ${displayName}`"
|
||
>
|
||
<span v-if="showSiderCaption" class="contact-service__caption">
|
||
{{ t('nav.contactService.shipWarehouse') }}
|
||
</span>
|
||
<span class="contact-service__text">{{ labelText }}</span>
|
||
</button>
|
||
<template #content>
|
||
<a-doption
|
||
v-for="opt in warehouseStore.options"
|
||
:key="String(opt.value)"
|
||
:value="opt.value"
|
||
:selected="opt.value === warehouseStore.warehouseId"
|
||
@click="onSelectWarehouse(opt.value)"
|
||
>
|
||
{{ opt.label }}
|
||
</a-doption>
|
||
</template>
|
||
</a-dropdown>
|
||
|
||
<a-select
|
||
v-else
|
||
:model-value="warehouseStore.warehouseId"
|
||
class="contact-service__select"
|
||
:placeholder="t('nav.contactService.selectWarehouse')"
|
||
popup-container="body"
|
||
@change="(v: any) => warehouseStore.setWarehouseId(v)"
|
||
>
|
||
<a-option
|
||
v-for="opt in warehouseStore.options"
|
||
:key="String(opt.value)"
|
||
:value="opt.value"
|
||
>
|
||
{{ opt.label }}
|
||
</a-option>
|
||
</a-select>
|
||
</div>
|
||
</template>
|
||
|
||
<style lang="less" scoped>
|
||
.contact-service {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
flex-shrink: 0;
|
||
min-width: 0;
|
||
|
||
&__select {
|
||
min-width: 120px;
|
||
}
|
||
|
||
&__text {
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
&--navbar {
|
||
color: #fff;
|
||
|
||
.contact-service__label {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
max-width: 180px;
|
||
height: 28px;
|
||
padding: 0 8px;
|
||
border: none;
|
||
border-radius: 6px;
|
||
background: transparent;
|
||
font-size: 13px;
|
||
line-height: 28px;
|
||
color: #fff;
|
||
cursor: pointer;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
transition: background-color 0.15s ease, opacity 0.15s ease;
|
||
|
||
&:hover {
|
||
background-color: rgba(255, 255, 255, 0.12);
|
||
}
|
||
}
|
||
}
|
||
|
||
&--sider {
|
||
width: 100%;
|
||
|
||
.contact-service__label {
|
||
display: inline-flex;
|
||
flex-direction: row;
|
||
align-items: center;
|
||
gap: 4px;
|
||
width: 100%;
|
||
height: 30px;
|
||
min-height: 30px;
|
||
padding: 0 8px;
|
||
border: none;
|
||
border-radius: 6px;
|
||
background: rgba(255, 255, 255, 0.55);
|
||
font-size: 12px;
|
||
font-weight: 400;
|
||
color: var(--color-text-1);
|
||
cursor: pointer;
|
||
text-align: left;
|
||
transition: background-color 0.14s ease, color 0.14s ease;
|
||
|
||
&:hover {
|
||
background: rgba(255, 255, 255, 0.92);
|
||
color: var(--app-primary-color, rgb(var(--primary-6)));
|
||
}
|
||
}
|
||
|
||
.contact-service__caption {
|
||
flex-shrink: 0;
|
||
font-size: 11px;
|
||
font-weight: 500;
|
||
color: var(--color-text-3);
|
||
|
||
&::after {
|
||
content: '·';
|
||
margin-left: 4px;
|
||
color: var(--color-text-4, #c9cdd4);
|
||
}
|
||
}
|
||
|
||
.contact-service__text {
|
||
min-width: 0;
|
||
flex: 1;
|
||
line-height: 1.2;
|
||
}
|
||
|
||
&.is-compact .contact-service__label {
|
||
justify-content: center;
|
||
align-items: center;
|
||
gap: 0;
|
||
padding: 0;
|
||
min-width: 36px;
|
||
width: 36px;
|
||
height: 28px;
|
||
min-height: 28px;
|
||
background: transparent;
|
||
font-size: 14px;
|
||
font-weight: 400;
|
||
text-align: center;
|
||
|
||
&:hover {
|
||
background: rgba(255, 255, 255, 0.85);
|
||
}
|
||
}
|
||
|
||
&.is-compact .contact-service__text {
|
||
flex: none;
|
||
width: 100%;
|
||
text-align: center;
|
||
line-height: 1;
|
||
}
|
||
}
|
||
|
||
&--login {
|
||
:deep(.arco-select-view) {
|
||
min-width: 120px;
|
||
height: 32px;
|
||
border-radius: 16px;
|
||
}
|
||
}
|
||
}
|
||
</style>
|