mirror of https://github.com/nocodb/nocodb
DarkPhoenix2704
9 months ago
4 changed files with 362 additions and 0 deletions
After Width: | Height: | Size: 433 B |
After Width: | Height: | Size: 547 B |
@ -0,0 +1,347 @@ |
|||||||
|
<script lang="ts" setup> |
||||||
|
import { |
||||||
|
type ColumnType, |
||||||
|
type LookupType, |
||||||
|
type RollupType, |
||||||
|
dateFormats, |
||||||
|
isCreatedOrLastModifiedByCol, |
||||||
|
isCreatedOrLastModifiedTimeCol, |
||||||
|
timeFormats, |
||||||
|
} from 'nocodb-sdk' |
||||||
|
import dayjs from 'dayjs' |
||||||
|
import { |
||||||
|
computed, |
||||||
|
isBoolean, |
||||||
|
isDate, |
||||||
|
isDateTime, |
||||||
|
isInt, |
||||||
|
parseProp, |
||||||
|
ref, |
||||||
|
storeToRefs, |
||||||
|
useAttachment, |
||||||
|
useBase, |
||||||
|
useMetas, |
||||||
|
} from '#imports' |
||||||
|
|
||||||
|
interface Props { |
||||||
|
column: ColumnType |
||||||
|
modelValue: any |
||||||
|
bold?: boolean |
||||||
|
italic?: boolean |
||||||
|
underline?: boolean |
||||||
|
} |
||||||
|
|
||||||
|
const props = defineProps<Props>() |
||||||
|
|
||||||
|
const meta = inject(MetaInj) |
||||||
|
|
||||||
|
const { metas } = useMetas() |
||||||
|
|
||||||
|
const column = toRef(props, 'column') |
||||||
|
|
||||||
|
const { sqlUis } = storeToRefs(useBase()) |
||||||
|
|
||||||
|
const basesStore = useBases() |
||||||
|
|
||||||
|
const { basesUser } = storeToRefs(basesStore) |
||||||
|
|
||||||
|
const { isXcdbBase, isMssql, isMysql } = useBase() |
||||||
|
|
||||||
|
const { getPossibleAttachmentSrc } = useAttachment() |
||||||
|
|
||||||
|
const sqlUi = ref(column.value?.source_id ? sqlUis.value[column.value?.source_id] : Object.values(sqlUis.value)[0]) |
||||||
|
|
||||||
|
const abstractType = computed(() => column.value && sqlUi.value.getAbstractType(column.value)) |
||||||
|
|
||||||
|
const getCheckBoxValue = (modelValue: any) => { |
||||||
|
return !modelValue && modelValue !== '0' && modelValue !== 0 && modelValue !== 'false' |
||||||
|
} |
||||||
|
|
||||||
|
const getMultiSelectValue = (modelValue: any, col: ColumnType): string => { |
||||||
|
return modelValue |
||||||
|
? Array.isArray(modelValue) |
||||||
|
? modelValue.join(', ') |
||||||
|
: modelValue.toString() |
||||||
|
: isMysql(col.source_id) |
||||||
|
? modelValue.toString().split(',').join(', ') |
||||||
|
: modelValue.split(', ') |
||||||
|
} |
||||||
|
|
||||||
|
const getDateValue = (modelValue: string | null | number, col: ColumnType, isSystemCol?: boolean) => { |
||||||
|
const dateFormat = !isSystemCol ? parseProp(col.meta)?.date_format ?? 'YYYY-MM-DD' : 'YYYY-MM-DD HH:mm:ss' |
||||||
|
if (!modelValue || !dayjs(modelValue).isValid()) { |
||||||
|
return 'Invalid Date' |
||||||
|
} else { |
||||||
|
return dayjs(/^\d+$/.test(String(modelValue)) ? +modelValue : modelValue).format(dateFormat) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const getYearValue = (modelValue: string | null) => { |
||||||
|
if (!modelValue) { |
||||||
|
return undefined |
||||||
|
} else if (!dayjs(modelValue).isValid()) { |
||||||
|
return 'Invalid Date' |
||||||
|
} else { |
||||||
|
return dayjs(modelValue.toString(), 'YYYY').format('YYYY') |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const getDateTimeValue = (modelValue: string | null, col: ColumnType) => { |
||||||
|
if (!modelValue || !dayjs(modelValue).isValid()) { |
||||||
|
return 'Invalid Date' |
||||||
|
} |
||||||
|
|
||||||
|
const dateFormat = parseProp(col?.meta)?.date_format ?? dateFormats[0] |
||||||
|
const timeFormat = parseProp(col?.meta)?.time_format ?? timeFormats[0] |
||||||
|
const dateTimeFormat = `${dateFormat} ${timeFormat}` |
||||||
|
|
||||||
|
const isXcDB = isXcdbBase(col.source_id) |
||||||
|
|
||||||
|
if (!isXcDB) { |
||||||
|
return dayjs(/^\d+$/.test(modelValue) ? +modelValue : modelValue, dateTimeFormat).format(dateTimeFormat) |
||||||
|
} |
||||||
|
|
||||||
|
if (isMssql(col.source_id)) { |
||||||
|
// e.g. 2023-04-29T11:41:53.000Z |
||||||
|
return dayjs(modelValue, dateTimeFormat).format(dateTimeFormat) |
||||||
|
} else { |
||||||
|
return dayjs(modelValue).utc().local().format(dateTimeFormat) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const getTimeValue = (modelValue: string | null) => { |
||||||
|
if (!modelValue) { |
||||||
|
return undefined |
||||||
|
} |
||||||
|
let dateTime = dayjs(modelValue) |
||||||
|
|
||||||
|
if (!dateTime.isValid()) { |
||||||
|
dateTime = dayjs(modelValue, 'HH:mm:ss') |
||||||
|
} |
||||||
|
if (!dateTime.isValid()) { |
||||||
|
dateTime = dayjs(`1999-01-01 ${modelValue}`) |
||||||
|
} |
||||||
|
if (!dateTime.isValid()) { |
||||||
|
return 'Invalid Date' |
||||||
|
} |
||||||
|
|
||||||
|
return dateTime.format('HH:mm') |
||||||
|
} |
||||||
|
|
||||||
|
const getDurationValue = (modelValue: string | null, col: ColumnType) => { |
||||||
|
const durationType = parseProp(col.meta)?.duration || 0 |
||||||
|
return convertMS2Duration(modelValue, durationType) |
||||||
|
} |
||||||
|
|
||||||
|
const getPercentValue = (modelValue: string | null) => { |
||||||
|
return modelValue ? `${modelValue}%` : undefined |
||||||
|
} |
||||||
|
|
||||||
|
const getCurrencyValue = (modelValue: string | number | null, col: ColumnType) => { |
||||||
|
const currencyMeta = { |
||||||
|
currency_locale: 'en-US', |
||||||
|
currency_code: 'USD', |
||||||
|
...parseProp(col.meta), |
||||||
|
} |
||||||
|
try { |
||||||
|
if (modelValue === null || modelValue === undefined || isNaN(modelValue)) { |
||||||
|
return modelValue |
||||||
|
} |
||||||
|
return new Intl.NumberFormat(currencyMeta.currency_locale || 'en-US', { |
||||||
|
style: 'currency', |
||||||
|
currency: currencyMeta.currency_code || 'USD', |
||||||
|
}).format(+modelValue) |
||||||
|
} catch (e) { |
||||||
|
return modelValue |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const getUserValue = (modelValue: string | string[] | null | Array<any>) => { |
||||||
|
if (!modelValue) { |
||||||
|
return 'Invalid User' |
||||||
|
} |
||||||
|
const baseUsers = meta?.value.base_id ? basesUser.value.get(meta?.value.base_id) || [] : [] |
||||||
|
|
||||||
|
if (typeof modelValue === 'string') { |
||||||
|
const idsOrMails = modelValue.split(',') |
||||||
|
|
||||||
|
return idsOrMails |
||||||
|
.map((idOrMail) => { |
||||||
|
const user = baseUsers.find((u) => u.id === idOrMail || u.email === idOrMail) |
||||||
|
return user ? user.display_name || user.email : idOrMail.id |
||||||
|
}) |
||||||
|
.join(', ') |
||||||
|
} else { |
||||||
|
if (Array.isArray(modelValue)) { |
||||||
|
return modelValue |
||||||
|
.map((idOrMail) => { |
||||||
|
const user = baseUsers.find((u) => u.id === idOrMail.id || u.email === idOrMail.email) |
||||||
|
return user ? user.display_name || user.email : idOrMail.id |
||||||
|
}) |
||||||
|
.join(', ') |
||||||
|
} else { |
||||||
|
return modelValue ? modelValue.display_name || modelValue.email : 'Invalid User' |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const getDecimalValue = (modelValue: string | null | number, col: ColumnType) => { |
||||||
|
if (!modelValue || isNaN(Number(modelValue))) { |
||||||
|
return 'Invalid Number' |
||||||
|
} |
||||||
|
const columnMeta = parseProp(col.meta) |
||||||
|
|
||||||
|
return Number(modelValue).toFixed(columnMeta?.precision ?? 1) |
||||||
|
} |
||||||
|
|
||||||
|
const getIntValue = (modelValue: string | null | number) => { |
||||||
|
if (!modelValue || isNaN(Number(modelValue))) { |
||||||
|
return 'Invalid Number' |
||||||
|
} |
||||||
|
return Number(modelValue) |
||||||
|
} |
||||||
|
|
||||||
|
const getTextAreaValue = (modelValue: string | null, col: ColumnType) => { |
||||||
|
const isRichMode = typeof col.meta === 'string' ? JSON.parse(col.meta).richMode : col.meta?.richMode |
||||||
|
if (isRichMode) { |
||||||
|
return modelValue?.replace(/[*_~\[\]]|<\/?[^>]+(>|$)/g, '') |
||||||
|
} |
||||||
|
return modelValue |
||||||
|
} |
||||||
|
|
||||||
|
const getRollupValue = (modelValue: string | null | number, col: ColumnType) => { |
||||||
|
const colOptions = col.colOptions as RollupType |
||||||
|
|
||||||
|
const fns = ['count', 'avg', 'sum', 'countDistinct', 'sumDistinct', 'avgDistinct'] |
||||||
|
if (fns.includes(colOptions.rollup_function!)) { |
||||||
|
return modelValue |
||||||
|
} else { |
||||||
|
const relationColumnOptions = colOptions.fk_relation_column_id |
||||||
|
? meta?.value.columns?.find((c) => c.id === colOptions.fk_relation_column_id)?.colOptions |
||||||
|
: null |
||||||
|
const relatedTableMeta = |
||||||
|
relationColumnOptions?.fk_related_model_id && metas.value?.[relationColumnOptions.fk_related_model_id as string] |
||||||
|
|
||||||
|
const childColumn = relatedTableMeta?.columns.find((c: ColumnType) => c.id === colOptions.fk_rollup_column_id) |
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-use-before-define |
||||||
|
return parseValue(modelValue, childColumn) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const getLookupValue = (modelValue: string | null | number | Array<any>, col: ColumnType) => { |
||||||
|
const colOptions = col.colOptions as LookupType |
||||||
|
const relationColumnOptions = colOptions.fk_relation_column_id |
||||||
|
? meta?.value.columns?.find((c) => c.id === colOptions.fk_relation_column_id)?.colOptions |
||||||
|
: null |
||||||
|
const relatedTableMeta = |
||||||
|
relationColumnOptions?.fk_related_model_id && metas.value?.[relationColumnOptions.fk_related_model_id as string] |
||||||
|
|
||||||
|
const childColumn = relatedTableMeta?.columns.find((c: ColumnType) => c.id === colOptions.fk_lookup_column_id) as |
||||||
|
| ColumnType |
||||||
|
| undefined |
||||||
|
|
||||||
|
if (Array.isArray(modelValue)) { |
||||||
|
return modelValue |
||||||
|
.map((v) => { |
||||||
|
// eslint-disable-next-line @typescript-eslint/no-use-before-define |
||||||
|
return parseValue(v, childColumn!) |
||||||
|
}) |
||||||
|
.join(', ') |
||||||
|
} |
||||||
|
// eslint-disable-next-line @typescript-eslint/no-use-before-define |
||||||
|
return parseValue(modelValue, childColumn!) |
||||||
|
} |
||||||
|
|
||||||
|
const getAttachmentValue = (modelValue: string | null | number | Array<any>) => { |
||||||
|
console.log(modelValue) |
||||||
|
if (Array.isArray(modelValue)) { |
||||||
|
return modelValue.map((v) => `${v.title} (${getPossibleAttachmentSrc(v).join(', ')})`).join(', ') |
||||||
|
} |
||||||
|
return modelValue |
||||||
|
} |
||||||
|
|
||||||
|
const parseValue = (value: any, col: ColumnType): string => { |
||||||
|
if (!value || !col) { |
||||||
|
return undefined |
||||||
|
} |
||||||
|
if (isGeoData(col)) { |
||||||
|
const [latitude, longitude] = ((value as string) || '').split(';') |
||||||
|
return latitude && longitude ? `${latitude}; ${longitude}` : 'Invalid location' |
||||||
|
} |
||||||
|
if (isTextArea(col)) { |
||||||
|
return getTextAreaValue(value, col) |
||||||
|
} |
||||||
|
if (isBoolean(col, abstractType)) { |
||||||
|
return getCheckBoxValue(value) ? 'Checked' : 'UnChecked' |
||||||
|
} |
||||||
|
if (isMultiSelect(col)) { |
||||||
|
return getMultiSelectValue(value, col) |
||||||
|
} |
||||||
|
if (isDate(col, abstractType)) { |
||||||
|
return getDateValue(value, col) |
||||||
|
} |
||||||
|
if (isYear(col, abstractType)) { |
||||||
|
return getYearValue(value) |
||||||
|
} |
||||||
|
if (isDateTime(col, abstractType)) { |
||||||
|
return getDateTimeValue(value, col) |
||||||
|
} |
||||||
|
if (isTime(col, abstractType)) { |
||||||
|
return getTimeValue(value) |
||||||
|
} |
||||||
|
if (isDuration(col)) { |
||||||
|
return getDurationValue(value, col) |
||||||
|
} |
||||||
|
if (isPercent(col)) { |
||||||
|
return getPercentValue(value) |
||||||
|
} |
||||||
|
if (isCurrency(col)) { |
||||||
|
return getCurrencyValue(value, col) |
||||||
|
} |
||||||
|
if (isUser(col)) { |
||||||
|
return getUserValue(value, col, false) |
||||||
|
} |
||||||
|
if (isDecimal(col)) { |
||||||
|
return getDecimalValue(value, col) |
||||||
|
} |
||||||
|
if (isInt(col, abstractType)) { |
||||||
|
return getIntValue(value) |
||||||
|
} |
||||||
|
if (isJSON(col)) { |
||||||
|
return JSON.stringify(value, null, 2) |
||||||
|
} |
||||||
|
if (isRollup(col)) { |
||||||
|
return getRollupValue(value, col) |
||||||
|
} |
||||||
|
if (isLookup(col)) { |
||||||
|
return getLookupValue(value, col) |
||||||
|
} |
||||||
|
if (isCreatedOrLastModifiedTimeCol(col)) { |
||||||
|
return getDateValue(value, col, true) |
||||||
|
} |
||||||
|
if (isCreatedOrLastModifiedByCol(col)) { |
||||||
|
return getUserValue(value) |
||||||
|
} |
||||||
|
if (isAttachment(col)) { |
||||||
|
return getAttachmentValue(value) |
||||||
|
} |
||||||
|
|
||||||
|
return value as unknown as string |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<template> |
||||||
|
<span |
||||||
|
:class="{ |
||||||
|
'font-bold': props.bold, |
||||||
|
'italic': props.italic, |
||||||
|
'underline': props.underline, |
||||||
|
}" |
||||||
|
data-testid="nc-calendar-cell" |
||||||
|
> |
||||||
|
{{ parseValue(props.modelValue, column) }} |
||||||
|
</span> |
||||||
|
</template> |
||||||
|
|
||||||
|
<style lang="scss" scoped></style> |
Loading…
Reference in new issue