mirror of
https://github.com/nocodb/nocodb.git
synced 2026-05-01 13:36:52 +00:00
159 lines
4.3 KiB
Vue
159 lines
4.3 KiB
Vue
<script setup lang="ts">
|
|
import { ColumnHelper, UITypes, ncIsNaN } from 'nocodb-sdk'
|
|
interface Props {
|
|
modelValue?: number | string | null
|
|
localEditEnabled?: boolean
|
|
}
|
|
|
|
const props = defineProps<Props>()
|
|
|
|
const emits = defineEmits(['update:localEditEnabled'])
|
|
|
|
const column = inject(ColumnInj)!
|
|
|
|
const readOnly = inject(ReadonlyInj, ref(false))
|
|
|
|
const isExpandedFormOpen = inject(IsExpandedFormOpenInj, ref(false))
|
|
|
|
const isUnderLookup = inject(IsUnderLookupInj, ref(false))
|
|
|
|
const isUnderLTAR = inject(IsUnderLTARInj, ref(false))
|
|
|
|
const isGrid = inject(IsGridInj, ref(false))
|
|
|
|
const isLinkRecordDropdown = inject(IsLinkRecordDropdownInj, ref(false))
|
|
|
|
const localEditEnabled = useVModel(props, 'localEditEnabled', emits, { defaultValue: false })
|
|
|
|
const expandedEditEnabled = ref(false)
|
|
|
|
const percentMeta = computed(() => {
|
|
return {
|
|
...ColumnHelper.getColumnDefaultMeta(UITypes.Percent),
|
|
...parseProp(column?.value?.meta),
|
|
is_progress: isUnderLookup.value && !isLinkRecordDropdown.value ? false : parseProp(column?.value?.meta).is_progress ?? false,
|
|
}
|
|
})
|
|
|
|
const percentValue = computed(() => {
|
|
return !ncIsNull(props.modelValue) && !ncIsUndefined(props.modelValue) && !ncIsNaN(props.modelValue)
|
|
? `${formatPercentage(Number(props.modelValue), percentMeta.value.precision ?? 2)}`
|
|
: props.modelValue
|
|
})
|
|
|
|
const percentValueNumber = computed(() => {
|
|
if (props.modelValue && props.modelValue !== '' && !ncIsNaN(props.modelValue)) {
|
|
return Number(props.modelValue)
|
|
}
|
|
return 0
|
|
})
|
|
|
|
const onWrapperFocus = () => {
|
|
if (readOnly.value) return
|
|
|
|
localEditEnabled.value = true
|
|
}
|
|
|
|
const onMouseover = () => {
|
|
expandedEditEnabled.value = true
|
|
}
|
|
|
|
const onMouseleave = () => {
|
|
expandedEditEnabled.value = false
|
|
}
|
|
|
|
const progressPercent = computed(() => {
|
|
if (
|
|
(isExpandedFormOpen.value ? !expandedEditEnabled.value : true) &&
|
|
!!percentMeta.value.is_progress &&
|
|
!ncIsNull(props.modelValue) &&
|
|
!ncIsUndefined(props.modelValue) &&
|
|
!isUnderLookup.value
|
|
) {
|
|
return Number(parseFloat(props.modelValue!.toString()).toFixed(2))
|
|
}
|
|
|
|
return null
|
|
})
|
|
|
|
const showAsProgres = computed(
|
|
() => percentMeta.value.is_progress && (isLinkRecordDropdown.value || (!isUnderLTAR.value && !isUnderLookup.value)),
|
|
)
|
|
|
|
const showInput = computed(() => !readOnly.value && (!isGrid.value || isExpandedFormOpen.value))
|
|
</script>
|
|
|
|
<template>
|
|
<div
|
|
v-if="showAsProgres"
|
|
class="nc-cell-field percent-progress w-full py-1 flex"
|
|
:style="{
|
|
...(isExpandedFormOpen && !isLinkRecordDropdown && { height: '100%' }),
|
|
...(isLinkRecordDropdown && { height: '16px' }),
|
|
}"
|
|
>
|
|
<div
|
|
class="w-full min-w-[100px]"
|
|
style="min-height: 4px"
|
|
@mouseover="onMouseover"
|
|
@mouseleave="onMouseleave"
|
|
@focus="onWrapperFocus"
|
|
@click="onWrapperFocus"
|
|
>
|
|
<CellPercentProgressBar
|
|
:percentage="percentValueNumber"
|
|
:is-show-number="isExpandedFormOpen"
|
|
:precision="percentMeta.precision"
|
|
>
|
|
<template v-if="showInput" #default>
|
|
<input
|
|
class="w-full !border-none !outline-none focus:ring-0 min-h-[10px]"
|
|
:value="modelValue"
|
|
@click="onWrapperFocus"
|
|
@focus="onWrapperFocus"
|
|
/>
|
|
</template>
|
|
</CellPercentProgressBar>
|
|
</div>
|
|
</div>
|
|
<div
|
|
v-else
|
|
:tabindex="readOnly ? -1 : 0"
|
|
class="nc-filter-value-select w-full focus:outline-transparent relative z-3"
|
|
:class="readOnly ? 'cursor-not-allowed pointer-events-none' : ''"
|
|
@mouseover="onMouseover"
|
|
@mouseleave="onMouseleave"
|
|
@focus="onWrapperFocus"
|
|
@click="onWrapperFocus"
|
|
>
|
|
<div v-if="progressPercent !== null" class="px-2">
|
|
<a-progress
|
|
:percent="progressPercent"
|
|
size="small"
|
|
status="normal"
|
|
stroke-color="var(--nc-content-brand)"
|
|
trail-color="var(--nc-bg-brand-inverted)"
|
|
:show-info="false"
|
|
/>
|
|
</div>
|
|
<!-- nbsp to keep height even if percentValue is zero length -->
|
|
<span v-else class="nc-cell-field">{{ percentValue ? percentValue : ' ' }} </span>
|
|
</div>
|
|
</template>
|
|
|
|
<style lang="scss">
|
|
.nc-cell:has(.progress-container) {
|
|
height: 100% !important;
|
|
}
|
|
</style>
|
|
|
|
<style lang="scss" scoped>
|
|
td.align-middle .percent-progress {
|
|
align-items: center;
|
|
}
|
|
td.align-top .percent-progress {
|
|
align-items: center;
|
|
height: 16px;
|
|
}
|
|
</style>
|