133 lines
3.3 KiB
Vue
133 lines
3.3 KiB
Vue
<template>
|
|
<div class="view-kv-table-cell">
|
|
<el-tag v-if="field.tagType" :type="field.tagType" size="small" class="view-kv-tag">{{
|
|
formatViewValue(field.value)
|
|
}}</el-tag>
|
|
<ul v-else-if="field.items?.length" class="view-plain-list">
|
|
<li v-for="(item, idx) in field.items" :key="idx">{{ item }}</li>
|
|
</ul>
|
|
<span v-else :class="{ 'money-display': field.money, 'danger-display': field.danger, 'muted-display': isMuted }">{{
|
|
formatViewValue(field.value)
|
|
}}</span>
|
|
<el-button
|
|
v-if="showMapBtn"
|
|
link
|
|
type="primary"
|
|
size="small"
|
|
class="view-kv-field-link"
|
|
title="在高德地图查看"
|
|
@click="openAmapLocation"
|
|
>
|
|
<el-icon><Location /></el-icon>
|
|
</el-button>
|
|
<el-button
|
|
v-if="showViewBtn"
|
|
link
|
|
type="primary"
|
|
size="small"
|
|
class="view-kv-field-link"
|
|
:title="viewBtnTitle"
|
|
@click="handleView"
|
|
>
|
|
<el-icon :size="16"><View /></el-icon>
|
|
</el-button>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { computed, inject } from 'vue'
|
|
import { Location, View } from '@element-plus/icons-vue'
|
|
import type { ViewField } from './types'
|
|
import { formatViewValue } from './types'
|
|
import { buildAmapLocationUrl } from '@/utils/amap/navigation'
|
|
|
|
const VIEW_KV_FIELD_VIEW_KEY = 'viewKvFieldView'
|
|
|
|
const props = defineProps<{
|
|
field: ViewField
|
|
}>()
|
|
|
|
const onFieldView = inject<((field: ViewField) => void) | undefined>(VIEW_KV_FIELD_VIEW_KEY)
|
|
|
|
const isMuted = computed(
|
|
() => !props.field.money && !props.field.danger && formatViewValue(props.field.value) === '—'
|
|
)
|
|
|
|
const showViewBtn = computed(() => {
|
|
if (!props.field.viewTarget || !props.field.viewId || !onFieldView) return false
|
|
if (props.field.viewTarget !== 'customer' && formatViewValue(props.field.value) === '—') {
|
|
return false
|
|
}
|
|
return true
|
|
})
|
|
|
|
const viewBtnTitle = computed(() => {
|
|
if (props.field.viewTarget === 'customer') return '查看客户'
|
|
if (props.field.viewTarget === 'opportunity') return '查看商机'
|
|
if (props.field.viewTarget === 'quote') return '查看报价单'
|
|
return '查看'
|
|
})
|
|
|
|
const amapLocationUrl = computed(() => {
|
|
if (!props.field.showMapLink) return null
|
|
return buildAmapLocationUrl({
|
|
lng: props.field.mapLng,
|
|
lat: props.field.mapLat,
|
|
name: props.field.mapName,
|
|
address: formatViewValue(props.field.value) === '—' ? undefined : String(props.field.value ?? '')
|
|
})
|
|
})
|
|
|
|
const showMapBtn = computed(() => Boolean(amapLocationUrl.value))
|
|
|
|
function handleView() {
|
|
onFieldView?.(props.field)
|
|
}
|
|
|
|
function openAmapLocation() {
|
|
const url = amapLocationUrl.value
|
|
if (!url) return
|
|
window.open(url, '_blank', 'noopener,noreferrer')
|
|
}
|
|
</script>
|
|
|
|
<style scoped lang="scss">
|
|
.view-kv-table-cell {
|
|
display: flex;
|
|
align-items: center;
|
|
flex-wrap: wrap;
|
|
gap: 6px;
|
|
}
|
|
|
|
.view-kv-tag {
|
|
font-weight: 600;
|
|
}
|
|
|
|
.view-kv-field-link {
|
|
margin: 0;
|
|
padding: 0 4px;
|
|
height: auto;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.view-plain-list {
|
|
margin: 0;
|
|
padding-left: 1.15em;
|
|
list-style: disc;
|
|
|
|
li + li {
|
|
margin-top: 4px;
|
|
}
|
|
}
|
|
|
|
.muted-display {
|
|
color: var(--text-muted, #64748b);
|
|
font-weight: 600;
|
|
}
|
|
|
|
.danger-display {
|
|
color: #dc2626;
|
|
font-weight: 600;
|
|
}
|
|
</style>
|