fix(resume): remove shadowing local ResumeSectionCfg (use types.ts with edu kind)
This commit is contained in:
@@ -336,6 +336,8 @@ function openDb(dbPath) {
|
||||
d.exec('PRAGMA foreign_keys = ON;');
|
||||
preMigrateColumns(d);
|
||||
d.exec(fs.readFileSync(path.join(__dirname, '..', 'schema.sql'), 'utf8'));
|
||||
// 个人信息表兜底(确保任何挂载形态下都存在)
|
||||
d.exec("CREATE TABLE IF NOT EXISTS profile (id INTEGER PRIMARY KEY AUTOINCREMENT, uuid TEXT, content TEXT NOT NULL DEFAULT '{}', deleted_at TEXT, origin TEXT, hlc TEXT)");
|
||||
migrateSync(d);
|
||||
ensureBuiltin(d);
|
||||
alignBuiltinUuids(d);
|
||||
|
||||
+27
-21
@@ -1,4 +1,4 @@
|
||||
import type { FootprintRow, ProfileInfo, ResumeConfig } from './types';
|
||||
import type { FootprintRow, ProfileInfo, ResumeConfig, ResumeSectionCfg } from './types';
|
||||
|
||||
// ---------- 简历数据模型 v2 ----------
|
||||
|
||||
@@ -6,34 +6,33 @@ export interface ResumeItemCfg { title: string; subtitle?: string; date?: string
|
||||
|
||||
export interface ResumeSectionDef {
|
||||
key: string; defaultTitle: string;
|
||||
kind: 'info' | 'list' | 'text';
|
||||
kind: 'info' | 'edu' | 'list' | 'text';
|
||||
types?: string[]; // list 类:从哪些记录类型装配
|
||||
fixed?: boolean; // 不可删除/停用(基本信息、自我评价)
|
||||
fixed?: boolean; // 不可删除/停用
|
||||
}
|
||||
|
||||
export const RESUME_SECTION_DEFS: ResumeSectionDef[] = [
|
||||
{ key: 'info', defaultTitle: '基本信息', kind: 'info', fixed: true },
|
||||
{ key: 'education', defaultTitle: '教育背景', kind: 'list', types: ['学业'] },
|
||||
{ key: 'skills', defaultTitle: '技能证书', kind: 'list', types: ['证书技能'] },
|
||||
{ key: 'awards', defaultTitle: '荣誉奖项', kind: 'list', types: ['荣誉惩处'] },
|
||||
{ key: 'competition', defaultTitle: '竞赛经历', kind: 'list', types: ['竞赛'] },
|
||||
{ key: 'research', defaultTitle: '科研经历', kind: 'list', types: ['科研'] },
|
||||
{ key: 'practice', defaultTitle: '实践经历', kind: 'list', types: ['志愿公益', '实习实践', '学生工作'] },
|
||||
{ key: 'education', defaultTitle: '教育经历', kind: 'edu', fixed: true },
|
||||
{ key: 'skills', defaultTitle: '核心技能', kind: 'text' },
|
||||
{ key: 'projects', defaultTitle: '项目经历', kind: 'list', types: ['竞赛', '科研', '实习实践'] },
|
||||
{ key: 'certs', defaultTitle: '证书与荣誉', kind: 'list', types: ['荣誉惩处', '证书技能'] },
|
||||
{ key: 'campus', defaultTitle: '在校经历', kind: 'list', types: ['学生工作', '志愿公益'] },
|
||||
{ key: 'activity', defaultTitle: '文体活动', kind: 'list', types: ['文体活动'] },
|
||||
{ key: 'other', defaultTitle: '其他经历', kind: 'list' }, // 未归类的自定义类型 + 自定义条目
|
||||
{ key: 'other', defaultTitle: '其他经历', kind: 'list' },
|
||||
{ key: 'self', defaultTitle: '自我评价', kind: 'text', fixed: true },
|
||||
];
|
||||
|
||||
export interface ResumeSectionCfg {
|
||||
key: string;
|
||||
title: string;
|
||||
enabled: boolean;
|
||||
kind?: 'info' | 'list' | 'text';
|
||||
types?: string[];
|
||||
excluded?: number[]; // 隐藏的记录 id
|
||||
items?: ResumeItemCfg[]; // 自定义条目
|
||||
text?: string; // text 板块内容
|
||||
}
|
||||
// 首次使用种子内容(IT/网安方向示例,可自由修改)
|
||||
const SEED: Record<string, { text?: string; items?: { title: string; subtitle?: string; date?: string; desc?: string }[] }> = {
|
||||
skills: { text: '路由交换:熟悉TCP/IP协议栈与基础路由交换,掌握VLAN、链路聚合、MSTP、VRRP/VRRP6等园区网冗余技术,熟悉OSPF、RIP、BGP等动态路由协议,具备IPv4/IPv6双栈网络的规划与部署能力。\n网络安全:熟悉防火墙安全区域、ACL访问控制与安全策略配置,掌握NAPT、NAT Server、NAT64地址转换,了解GRE over IPsec隧道与防火墙双机热备。\n网络设备:熟悉华为交换机、路由器、防火墙CLI操作与配置,掌握GVRP、MSTP、VRRP、链路聚合及BFD联动快速收敛,熟悉Wireshark抓包分析。\n运维基础:熟悉RedHat、Ubuntu等Linux系统部署与日常维护,了解Docker、K8s、Prometheus等云原生运维工具。' },
|
||||
campus: { items: [
|
||||
{ title: '学校图书馆 勤工俭学固定岗', subtitle: '图书管理员', date: '2024.12 - 2026.7', desc: '负责图书上架、整理和维护,定时进行馆内安全巡检,协助读者检索和借阅服务,累计服务读者超2000人次,零服务投诉。这段经历培养了高度的责任意识与服务意识,锻炼了高效执行和多任务时间管理能力。' },
|
||||
{ title: '学院团总支学生会宣传部 干事', subtitle: '视觉设计', date: '2023.9 - 2024.9', desc: '独立完成学院活动海报、邀请函、KT板、易拉宝等40余份宣传物料设计,参与换届大会、迎新、毕业季等重大活动视觉设计与宣传品制作。负责报告厅后台多媒体设备控制,保障12场大型活动视觉呈现零失误,锻炼了应急处置能力与谨慎细致的工作态度。' },
|
||||
]},
|
||||
self: { text: '心态沉稳、抗压能力较好,遇到突发状况能冷静应对、稳住局面。做事有计划性,习惯提前预判风险并做好预案,追求稳妥与确定性,执行质量有保障,能在压力下保持稳定输出。责任心强,凡事有始有终,注重细节与条理,能在复杂环境中稳步推进工作,是一名可靠、值得信赖的执行者。' },
|
||||
};
|
||||
|
||||
|
||||
export type ResumeTemplate = 'classic' | 'tech' | 'minimal';
|
||||
|
||||
@@ -44,6 +43,9 @@ export function defaultResumeConfig(): ResumeConfig {
|
||||
fontScale: 1, density: 'normal', onePage: false,
|
||||
sections: RESUME_SECTION_DEFS.map(d => ({
|
||||
key: d.key, title: d.defaultTitle, enabled: true, kind: d.kind, types: d.types,
|
||||
...(d.key === 'skills' ? { text: SEED.skills.text } : {}),
|
||||
...(d.key === 'campus' ? { items: SEED.campus.items } : {}),
|
||||
...(d.key === 'self' ? { text: SEED.self.text } : {}),
|
||||
})),
|
||||
};
|
||||
}
|
||||
@@ -57,7 +59,11 @@ export function migrateResumeConfig(raw: unknown): ResumeConfig {
|
||||
const sections = def.sections.map(d => {
|
||||
const old = oldSections.find(o => o.key === d.key);
|
||||
const dd = RESUME_SECTION_DEFS.find(x => x.key === d.key);
|
||||
return { ...d, enabled: old?.enabled ?? true, title: old?.title ?? dd?.defaultTitle ?? d.title };
|
||||
const base: ResumeSectionCfg = { ...d, enabled: old?.enabled ?? true, title: old?.title ?? dd?.defaultTitle ?? d.title };
|
||||
if (d.key === 'skills' && !base.text) base.text = SEED.skills.text;
|
||||
if (d.key === 'campus' && !(base.items?.length)) base.items = SEED.campus.items;
|
||||
if (d.key === 'self' && !base.text) base.text = SEED.self.text;
|
||||
return base;
|
||||
});
|
||||
// v1 里用户新增的板块(不在默认定义中)→ 追加为自定义文本板块
|
||||
for (const o of oldSections) {
|
||||
|
||||
@@ -235,7 +235,7 @@ export interface GradesOverview {
|
||||
export interface ProfileInfo {
|
||||
name: string; gender: string; birth: string; nation: string; native: string;
|
||||
political: string; school: string; college: string; major: string;
|
||||
className: string; studentId: string; degree: string;
|
||||
className: string; studentId: string; degree: string; eduLength: string; eduStart: string; eduEnd: string; majorCourses: string;
|
||||
phone: string; email: string; homepage: string; photoUrl: string;
|
||||
selfIntro: string;
|
||||
}
|
||||
@@ -243,7 +243,7 @@ export interface ResumeItemCfg { title: string; subtitle?: string; date?: string
|
||||
|
||||
export interface ResumeSectionCfg {
|
||||
key: string; title: string; enabled: boolean;
|
||||
kind?: 'info' | 'list' | 'text';
|
||||
kind?: 'info' | 'edu' | 'list' | 'text';
|
||||
types?: string[];
|
||||
excluded?: number[];
|
||||
items?: ResumeItemCfg[];
|
||||
|
||||
@@ -8,7 +8,8 @@ import { Button, Dialog, Field, Input, Select, Textarea, useToast } from '@/comp
|
||||
const EMPTY: ProfileInfo = {
|
||||
name: '', gender: '', birth: '', nation: '', native: '', political: '',
|
||||
school: '', college: '', major: '', className: '', studentId: '', degree: '',
|
||||
phone: '', email: '', homepage: '', photoUrl: '', selfIntro: ''
|
||||
phone: '', email: '', homepage: '', photoUrl: '', selfIntro: '',
|
||||
eduLength: '', eduStart: '', eduEnd: '', majorCourses: ''
|
||||
};
|
||||
|
||||
const FIELD_GROUPS: { title: string; fields: { key: keyof ProfileInfo; label: string; type?: string; options?: string[] }[] }[] = [
|
||||
@@ -27,6 +28,12 @@ const FIELD_GROUPS: { title: string; fields: { key: keyof ProfileInfo; label: st
|
||||
{ key: 'className', label: '班级' },
|
||||
{ key: 'studentId', label: '学号' },
|
||||
{ key: 'degree', label: '学历层次', options: ['', '专科', '本科', '硕士研究生', '博士研究生'] },
|
||||
{ key: 'eduLength', label: '学制', options: ['', '两年', '三年', '四年', '五年'] },
|
||||
{ key: 'eduStart', label: '入学时间', type: 'month' },
|
||||
{ key: 'eduEnd', label: '毕业时间', type: 'month' },
|
||||
]},
|
||||
{ title: '主修课程', fields: [
|
||||
{ key: 'majorCourses', label: '主修课程' },
|
||||
]},
|
||||
{ title: '联系方式', fields: [
|
||||
{ key: 'phone', label: '手机' },
|
||||
|
||||
Reference in New Issue
Block a user