142 lines
5.4 KiB
TypeScript
142 lines
5.4 KiB
TypeScript
export interface DataEntry {
|
|
key: string
|
|
value: any
|
|
}
|
|
|
|
export interface ContractSegmentPackage {
|
|
version: number
|
|
exportedAt: string
|
|
packageType?: 'contract-segments'
|
|
project?: {
|
|
industry: string
|
|
}
|
|
storage?: {
|
|
localforageEntries: DataEntry[]
|
|
keyedEntries?: DataEntry[]
|
|
}
|
|
contracts: Array<{
|
|
id: string
|
|
name: string
|
|
order: number
|
|
createdAt: string
|
|
}>
|
|
projectIndustry?: string
|
|
localforageEntries?: DataEntry[]
|
|
keyedEntries?: DataEntry[]
|
|
pinia?: {
|
|
zxFwPricing?: {
|
|
contracts?: Record<string, unknown>
|
|
servicePricingStates?: Record<string, unknown>
|
|
htFeeMainStates?: Record<string, unknown>
|
|
htFeeMethodStates?: Record<string, unknown>
|
|
}
|
|
}
|
|
piniaState?: {
|
|
zxFwPricing?: {
|
|
contracts?: Record<string, unknown>
|
|
servicePricingStates?: Record<string, unknown>
|
|
htFeeMainStates?: Record<string, unknown>
|
|
htFeeMethodStates?: Record<string, unknown>
|
|
}
|
|
}
|
|
}
|
|
|
|
export const CONTRACT_SEGMENT_FILE_EXTENSION = '.htzw'
|
|
export const CONTRACT_SEGMENT_VERSION = 3
|
|
export const CONTRACT_KEY_PREFIX = 'ht-info-v3-'
|
|
export const SERVICE_KEY_PREFIX = 'zxFW-'
|
|
export const CONTRACT_CONSULT_FACTOR_KEY_PREFIX = 'ht-consult-category-factor-v1-'
|
|
export const CONTRACT_MAJOR_FACTOR_KEY_PREFIX = 'ht-major-factor-v1-'
|
|
export const PRICING_KEY_PREFIXES = ['tzGMF-', 'ydGMF-', 'gzlF-', 'hourlyPricing-', 'htExtraFee-'] as const
|
|
export const PROJECT_INFO_KEY = 'xm-base-info-v1'
|
|
export const PROJECT_SCALE_KEY = 'xm-info-v3'
|
|
export const SERVICE_PRICING_METHODS = ['investScale', 'landScale', 'workload', 'hourly'] as const
|
|
|
|
export const formatExportTimestamp = (date: Date): string => {
|
|
const yyyy = date.getFullYear()
|
|
const mm = String(date.getMonth() + 1).padStart(2, '0')
|
|
const dd = String(date.getDate()).padStart(2, '0')
|
|
const hh = String(date.getHours()).padStart(2, '0')
|
|
const mi = String(date.getMinutes()).padStart(2, '0')
|
|
return `${yyyy}${mm}${dd}-${hh}${mi}`
|
|
}
|
|
|
|
export const isRecord = (value: unknown): value is Record<string, unknown> =>
|
|
Boolean(value && typeof value === 'object' && !Array.isArray(value))
|
|
|
|
export const cloneJson = <T>(value: T): T => JSON.parse(JSON.stringify(value)) as T
|
|
|
|
export const normalizeDataEntries = (value: unknown): DataEntry[] => {
|
|
if (!Array.isArray(value)) return []
|
|
return value
|
|
.filter(item => item && typeof item === 'object' && typeof (item as DataEntry).key === 'string')
|
|
.map(item => ({
|
|
key: String((item as DataEntry).key),
|
|
value: (item as DataEntry).value
|
|
}))
|
|
}
|
|
|
|
export const normalizeContractSegmentPackage = (payload: ContractSegmentPackage) => ({
|
|
projectIndustry:
|
|
typeof payload.project?.industry === 'string' && payload.project.industry.trim()
|
|
? payload.project.industry.trim()
|
|
: (typeof payload.projectIndustry === 'string' ? payload.projectIndustry.trim() : ''),
|
|
localforageEntries: normalizeDataEntries(payload.storage?.localforageEntries ?? payload.localforageEntries),
|
|
keyedEntries: normalizeDataEntries(payload.storage?.keyedEntries ?? payload.keyedEntries),
|
|
piniaState: payload.pinia ?? payload.piniaState
|
|
})
|
|
|
|
export const isContractSegmentPackage = (value: unknown): value is ContractSegmentPackage => {
|
|
const payload = value as Partial<ContractSegmentPackage> | null
|
|
return Boolean(payload && typeof payload === 'object' && Array.isArray(payload.contracts))
|
|
}
|
|
|
|
export const isContractRelatedForageKey = (key: string, contractId: string) => {
|
|
if (key === `${CONTRACT_KEY_PREFIX}${contractId}`) return true
|
|
if (key === `${SERVICE_KEY_PREFIX}${contractId}`) return true
|
|
if (key === `${CONTRACT_CONSULT_FACTOR_KEY_PREFIX}${contractId}`) return true
|
|
if (key === `${CONTRACT_MAJOR_FACTOR_KEY_PREFIX}${contractId}`) return true
|
|
if (PRICING_KEY_PREFIXES.some(prefix => key.startsWith(`${prefix}${contractId}-`))) return true
|
|
return false
|
|
}
|
|
|
|
export const isContractRelatedKeyedStateKey = (key: string, contractId: string) => {
|
|
if (key === `ht-base-info-${contractId}`) return true
|
|
if (key.startsWith(`work-content-${contractId}-`)) return true
|
|
if (key.startsWith(`work-content-htExtraFee-${contractId}-`)) return true
|
|
return false
|
|
}
|
|
|
|
export const rewriteKeyWithContractId = (key: string, fromId: string, toId: string) => {
|
|
if (key === `${CONTRACT_KEY_PREFIX}${fromId}`) return `${CONTRACT_KEY_PREFIX}${toId}`
|
|
if (key === `${SERVICE_KEY_PREFIX}${fromId}`) return `${SERVICE_KEY_PREFIX}${toId}`
|
|
if (key === `${CONTRACT_CONSULT_FACTOR_KEY_PREFIX}${fromId}`) {
|
|
return `${CONTRACT_CONSULT_FACTOR_KEY_PREFIX}${toId}`
|
|
}
|
|
if (key === `${CONTRACT_MAJOR_FACTOR_KEY_PREFIX}${fromId}`) {
|
|
return `${CONTRACT_MAJOR_FACTOR_KEY_PREFIX}${toId}`
|
|
}
|
|
if (key === `ht-base-info-${fromId}`) return `ht-base-info-${toId}`
|
|
if (key.startsWith(`work-content-${fromId}-`)) {
|
|
return key.replace(`work-content-${fromId}-`, `work-content-${toId}-`)
|
|
}
|
|
if (key.startsWith(`work-content-htExtraFee-${fromId}-`)) {
|
|
return key.replace(`work-content-htExtraFee-${fromId}-`, `work-content-htExtraFee-${toId}-`)
|
|
}
|
|
for (const prefix of PRICING_KEY_PREFIXES) {
|
|
if (key.startsWith(`${prefix}${fromId}-`)) {
|
|
return key.replace(`${prefix}${fromId}-`, `${prefix}${toId}-`)
|
|
}
|
|
}
|
|
return key
|
|
}
|
|
|
|
export const generateContractId = (usedIds: Set<string>) => {
|
|
let nextId = ''
|
|
while (!nextId || usedIds.has(nextId)) {
|
|
nextId = `ct-${Date.now()}-${Math.random().toString(16).slice(2, 8)}`
|
|
}
|
|
usedIds.add(nextId)
|
|
return nextId
|
|
}
|