export const BUDGET_ONTOLOGY_FIELDS = [ { key: 'budget_period', label: '预算周期', scope: 'budget_header', required: true, aliases: ['预算周期', '预算期间', '年度', '季度', '月份'] }, { key: 'department', label: '所属部门', scope: 'budget_header', required: true, aliases: ['所属部门', '预算部门', '部门'] }, { key: 'cost_center', label: '成本中心', scope: 'budget_header', required: true, aliases: ['成本中心', '成本中心编码'] }, { key: 'budget_owner', label: '预算负责人', scope: 'budget_header', required: true, aliases: ['预算负责人', '负责人', '编制人'] }, { key: 'budget_version', label: '预算版本', scope: 'budget_header', required: true, aliases: ['预算版本', '版本'] }, { key: 'budget_status', label: '预算状态', scope: 'budget_header', required: true, aliases: ['预算状态', '状态'] }, { key: 'budget_description', label: '预算说明', scope: 'budget_header', required: false, aliases: ['预算说明', '编制说明', '说明'] }, { key: 'budget_subject', label: '预算科目', scope: 'budget_detail', required: true, aliases: ['预算科目', '费用类型', '费用科目'] }, { key: 'budget_amount', label: '预算金额', scope: 'budget_detail', required: true, aliases: ['预算金额', '预算额度', '预算总额'] }, { key: 'reserved_amount', label: '已占用', scope: 'budget_execution', required: false, aliases: ['已占用', '已预占', '占用金额'] }, { key: 'consumed_amount', label: '已发生', scope: 'budget_execution', required: false, aliases: ['已发生', '已核销', '已消耗', '已使用'] }, { key: 'available_amount', label: '剩余可用', scope: 'budget_execution', required: false, aliases: ['剩余可用', '可用余额', '剩余预算', '可用预算'] }, { key: 'warning_threshold', label: '预警线', scope: 'budget_control', required: true, aliases: ['预警线', '预警阈值', '预算预警'] }, { key: 'control_action', label: '控制动作', scope: 'budget_control', required: true, aliases: ['控制动作', '管控动作', '超预算控制'] }, { key: 'budget_remark', label: '备注', scope: 'budget_detail', required: false, aliases: ['备注', '说明'] } ] export const BUDGET_FIELD_KEYS = Object.freeze( BUDGET_ONTOLOGY_FIELDS.reduce((result, field) => { result[field.key] = field.key return result }, {}) ) export const BUDGET_STATUS_OPTIONS = ['编制中', '已发布', '已冻结'] export const BUDGET_WARNING_OPTIONS = ['60%', '70%', '80%', '90%'] export const BUDGET_CONTROL_ACTION_OPTIONS = ['正常', '提醒', '管控'] export const BUDGET_YEAR_OPTIONS = ['2026', '2027', '2028'] export const BUDGET_QUARTER_OPTIONS = ['Q1', 'Q2', 'Q3', 'Q4'] export const BUDGET_EXPENSE_TYPE_OPTIONS = Object.freeze([ { value: 'travel', label: '差旅' }, { value: 'hotel', label: '住宿费' }, { value: 'transport', label: '交通费' }, { value: 'meal', label: '招待费' }, { value: 'meeting', label: '会务费' }, { value: 'marketing', label: '市场推广费' }, { value: 'office', label: '办公用品' }, { value: 'training', label: '培训费' }, { value: 'software', label: '软件服务费' }, { value: 'communication', label: '通信' }, { value: 'welfare', label: '福利费' } ]) const BUDGET_EXPENSE_TYPE_BY_CODE = Object.freeze( BUDGET_EXPENSE_TYPE_OPTIONS.reduce((result, item) => { result[item.value] = item return result }, {}) ) export const BUDGET_VISIBLE_EXPENSE_TYPE_CODES = Object.freeze([ 'travel', 'communication', 'meal', 'office' ]) export const BUDGET_VISIBLE_EXPENSE_TYPE_OPTIONS = Object.freeze( BUDGET_VISIBLE_EXPENSE_TYPE_CODES.map((code) => BUDGET_EXPENSE_TYPE_BY_CODE[code]).filter(Boolean) ) export function resolveBudgetExpenseTypeLabel(code, fallback = '') { return BUDGET_EXPENSE_TYPE_BY_CODE[String(code || '').trim()]?.label || fallback } export function formatBudgetPeriod(year, quarter) { const normalizedYear = String(year || '').replace(/[^\d]/g, '') || '2026' const normalizedQuarter = BUDGET_QUARTER_OPTIONS.includes(String(quarter || '').trim()) ? String(quarter || '').trim() : BUDGET_QUARTER_OPTIONS[0] return `${normalizedYear}年${normalizedQuarter}` } export function buildBudgetOntologyContext({ form = {}, rows = [], departments = [] } = {}) { const department = departments.find((item) => item.code === form.departmentCode) || {} const budgetYear = String(form.budgetYear || '').replace(/[^\d]/g, '') || String(form.budgetPeriod || '').replace(/[^\d]/g, '').slice(0, 4) || '2026' const budgetQuarter = BUDGET_QUARTER_OPTIONS.includes(String(form.budgetQuarter || '').trim()) ? String(form.budgetQuarter || '').trim() : BUDGET_QUARTER_OPTIONS[0] const budgetPeriod = form.budgetYear || form.budgetQuarter ? formatBudgetPeriod(budgetYear, budgetQuarter) : form.budgetPeriod || formatBudgetPeriod(budgetYear, budgetQuarter) return { document_type: 'budget_plan', entry_source: 'budget_center', conversation_scenario: 'budget', budget_fields: BUDGET_ONTOLOGY_FIELDS, budget_header: { budget_period: budgetPeriod, budget_year: budgetYear, budget_quarter: budgetQuarter, department: department.name || '', department_code: form.departmentCode || '', cost_center: form.costCenter || department.costCenter || '', budget_owner: form.budgetOwner || '', budget_version: form.budgetVersion || '', budget_status: form.budgetStatus || '', budget_description: form.budgetDescription || '' }, budget_details: rows.map((row) => { const code = String(row.budgetSubjectCode || '').trim() const option = BUDGET_EXPENSE_TYPE_BY_CODE[code] const label = option?.label || row.budgetSubject || '' return { budget_subject: label, budget_subject_code: option?.value || code, expense_type: option?.value || code, expense_type_label: label, budget_amount: row.budgetAmount || '', warning_threshold: row.warningThreshold || '', control_action: row.controlAction || '', budget_remark: row.budgetRemark || '' } }) } }