interpreter-admin/composables/useRateCalculation.ts
Mars Developer 51f8d95bf9 first commit
2025-06-26 11:24:11 +08:00

366 lines
9.2 KiB
TypeScript

// 费率计算和管理的组合函数
import { ref, computed } from 'vue'
import { useSupabase } from './useSupabase'
// 服务类型费率配置
export interface ServiceRate {
id: string
service_type: string
service_name: string
base_price: number // 基础价格
price_per_minute?: number // 按分钟计费
price_per_word?: number // 按字数计费
price_per_page?: number // 按页数计费
urgency_multiplier: {
normal: number
urgent: number
very_urgent: number
}
language_pair_multiplier: {
[key: string]: number // 语言对费率倍数
}
currency: string
created_at: string
updated_at: string
}
// 订单费用计算结果
export interface CostCalculation {
baseCost: number
urgencyMultiplier: number
languageMultiplier: number
totalCost: number
breakdown: {
basePrice: number
urgencyFee: number
languageFee: number
estimatedDuration?: number
estimatedWords?: number
}
}
export const useRateCalculation = () => {
const { supabase } = useSupabase()
// 默认费率配置
const defaultRates = ref<ServiceRate[]>([
{
id: 'voice-call',
service_type: 'voice',
service_name: '语音通话',
base_price: 50,
price_per_minute: 2.5,
urgency_multiplier: {
normal: 1.0,
urgent: 1.5,
very_urgent: 2.0
},
language_pair_multiplier: {
'zh-en': 1.0,
'zh-ja': 1.2,
'zh-ko': 1.2,
'zh-fr': 1.3,
'zh-de': 1.3,
'zh-es': 1.2,
'zh-ru': 1.4,
'en-ja': 1.3,
'en-ko': 1.3,
'en-fr': 1.2,
'en-de': 1.2,
'en-es': 1.1,
'en-ru': 1.4
},
currency: 'CNY',
created_at: new Date().toISOString(),
updated_at: new Date().toISOString()
},
{
id: 'video-call',
service_type: 'video',
service_name: '视频通话',
base_price: 80,
price_per_minute: 4.0,
urgency_multiplier: {
normal: 1.0,
urgent: 1.5,
very_urgent: 2.0
},
language_pair_multiplier: {
'zh-en': 1.0,
'zh-ja': 1.2,
'zh-ko': 1.2,
'zh-fr': 1.3,
'zh-de': 1.3,
'zh-es': 1.2,
'zh-ru': 1.4
},
currency: 'CNY',
created_at: new Date().toISOString(),
updated_at: new Date().toISOString()
},
{
id: 'document-translation',
service_type: 'document',
service_name: '文档翻译',
base_price: 100,
price_per_word: 0.15,
urgency_multiplier: {
normal: 1.0,
urgent: 1.3,
very_urgent: 1.8
},
language_pair_multiplier: {
'zh-en': 1.0,
'zh-ja': 1.2,
'zh-ko': 1.2,
'zh-fr': 1.3,
'zh-de': 1.3,
'zh-es': 1.2,
'zh-ru': 1.4
},
currency: 'CNY',
created_at: new Date().toISOString(),
updated_at: new Date().toISOString()
},
{
id: 'interpretation',
service_type: 'interpretation',
service_name: '口译服务',
base_price: 200,
price_per_minute: 8.0,
urgency_multiplier: {
normal: 1.0,
urgent: 1.6,
very_urgent: 2.2
},
language_pair_multiplier: {
'zh-en': 1.0,
'zh-ja': 1.3,
'zh-ko': 1.3,
'zh-fr': 1.4,
'zh-de': 1.4,
'zh-es': 1.3,
'zh-ru': 1.5
},
currency: 'CNY',
created_at: new Date().toISOString(),
updated_at: new Date().toISOString()
},
{
id: 'localization',
service_type: 'localization',
service_name: '本地化',
base_price: 300,
price_per_word: 0.25,
urgency_multiplier: {
normal: 1.0,
urgent: 1.4,
very_urgent: 1.9
},
language_pair_multiplier: {
'zh-en': 1.0,
'zh-ja': 1.3,
'zh-ko': 1.3,
'zh-fr': 1.4,
'zh-de': 1.4,
'zh-es': 1.3,
'zh-ru': 1.5
},
currency: 'CNY',
created_at: new Date().toISOString(),
updated_at: new Date().toISOString()
},
{
id: 'proofreading',
service_type: 'proofreading',
service_name: '校对服务',
base_price: 80,
price_per_word: 0.08,
urgency_multiplier: {
normal: 1.0,
urgent: 1.3,
very_urgent: 1.7
},
language_pair_multiplier: {
'zh-en': 1.0,
'zh-ja': 1.1,
'zh-ko': 1.1,
'zh-fr': 1.2,
'zh-de': 1.2,
'zh-es': 1.1,
'zh-ru': 1.3
},
currency: 'CNY',
created_at: new Date().toISOString(),
updated_at: new Date().toISOString()
}
])
// 当前费率配置
const serviceRates = ref<ServiceRate[]>([])
const loading = ref(false)
const error = ref<string | null>(null)
// 从数据库加载费率配置
const loadRates = async () => {
loading.value = true
error.value = null
try {
const { data, error: dbError } = await supabase
.from('service_rates')
.select('*')
.order('service_type')
if (dbError) {
console.warn('从数据库加载费率失败,使用默认费率:', dbError.message)
serviceRates.value = [...defaultRates.value]
} else {
serviceRates.value = data || [...defaultRates.value]
}
} catch (err) {
console.warn('费率加载错误,使用默认费率:', err)
serviceRates.value = [...defaultRates.value]
error.value = '费率加载失败,使用默认配置'
} finally {
loading.value = false
}
}
// 保存费率配置到数据库
const saveRates = async (rates: ServiceRate[]) => {
loading.value = true
error.value = null
try {
// 先删除现有费率
await supabase.from('service_rates').delete().neq('id', '')
// 插入新费率
const { data, error: dbError } = await supabase
.from('service_rates')
.insert(rates.map(rate => ({
...rate,
updated_at: new Date().toISOString()
})))
if (dbError) throw dbError
serviceRates.value = [...rates]
return { success: true, data }
} catch (err) {
console.error('保存费率失败:', err)
error.value = '保存费率失败'
return { success: false, error: err }
} finally {
loading.value = false
}
}
// 获取指定服务类型的费率
const getRateByServiceType = (serviceType: string): ServiceRate | null => {
return serviceRates.value.find(rate => rate.service_type === serviceType) || null
}
// 计算订单费用
const calculateOrderCost = (
serviceType: string,
sourceLanguage: string,
targetLanguage: string,
urgency: 'normal' | 'urgent' | 'very_urgent' = 'normal',
estimatedDuration?: number, // 分钟
estimatedWords?: number, // 字数
estimatedPages?: number // 页数
): CostCalculation => {
const rate = getRateByServiceType(serviceType)
if (!rate) {
throw new Error(`未找到服务类型 ${serviceType} 的费率配置`)
}
// 基础价格
let baseCost = rate.base_price
// 根据服务类型计算额外费用
if (rate.price_per_minute && estimatedDuration) {
baseCost += rate.price_per_minute * estimatedDuration
}
if (rate.price_per_word && estimatedWords) {
baseCost += rate.price_per_word * estimatedWords
}
if (rate.price_per_page && estimatedPages) {
baseCost += rate.price_per_page * estimatedPages
}
// 紧急程度倍数
const urgencyMultiplier = rate.urgency_multiplier[urgency] || 1.0
// 语言对倍数
const languagePair = `${sourceLanguage}-${targetLanguage}`
const languageMultiplier = rate.language_pair_multiplier[languagePair] || 1.0
// 计算最终费用
const urgencyFee = baseCost * (urgencyMultiplier - 1)
const languageFee = baseCost * (languageMultiplier - 1)
const totalCost = baseCost * urgencyMultiplier * languageMultiplier
return {
baseCost,
urgencyMultiplier,
languageMultiplier,
totalCost: Math.round(totalCost * 100) / 100, // 保留两位小数
breakdown: {
basePrice: baseCost,
urgencyFee: Math.round(urgencyFee * 100) / 100,
languageFee: Math.round(languageFee * 100) / 100,
estimatedDuration,
estimatedWords
}
}
}
// 获取服务类型选项
const serviceTypeOptions = computed(() => {
return serviceRates.value.map(rate => ({
value: rate.service_type,
label: rate.service_name,
basePrice: rate.base_price
}))
})
// 获取所有语言对的费率倍数
const getLanguagePairMultipliers = (serviceType: string) => {
const rate = getRateByServiceType(serviceType)
return rate ? rate.language_pair_multiplier : {}
}
// 初始化费率配置
const initializeRates = async () => {
await loadRates()
// 如果数据库中没有费率配置,则保存默认配置
if (serviceRates.value.length === 0) {
await saveRates(defaultRates.value)
}
}
return {
// 数据
serviceRates: readonly(serviceRates),
loading: readonly(loading),
error: readonly(error),
// 计算属性
serviceTypeOptions,
// 方法
loadRates,
saveRates,
getRateByServiceType,
calculateOrderCost,
getLanguagePairMultipliers,
initializeRates
}
}