[{"data":1,"prerenderedAt":71},["ShallowReactive",2],{"project:accuhit-campaign-hub:zh-cn":3,"i-tabler:route":59,"i-tabler:database":63,"i-tabler:shield-check":65,"i-tabler:components":67,"i-tabler:login":69},{"slug":4,"name":5,"summary":6,"role":7,"updateNote":-1,"meta":8,"coverUrl":-1,"lang":23,"isFallback":24,"featuredRank":25,"badge":26,"lastActivity":18,"tapeNumber":27,"blocks":28},"accuhit-campaign-hub","活动页整合平台","把分散在各活动页、以传统 HTML 与 JS 编写的多个客户端项目，整合成基于 Vue 与 Vuetify 的单一应用。","前端工程师",{"origin":9,"categories":10,"tags":12,"released":18,"company":19,"period":20},"company",[11],"frontend",[13,14,15,16,17],"vue","typescript","vuetify","pinia","liff","2025-11-01","accuhit",{"from":21,"to":22},"2025-11","2026-01","zh-CN",false,3,null,5,[29,52],{"type":30,"items":31},"features",[32,36,40,44,48],{"title":33,"description":34,"icon":35},"多项目路由整合","将多个活动页整合到同一个应用，以路径区分。引流时只需处理各路径所需的数据，例如网址携带的参数。","tabler:route",{"title":37,"description":38,"icon":39},"配置的单一来源（SSOT）","把各项目不同的 UI 与配置汇总成单一来源，类型由配置本身推导，降低编写错误与维护成本。","tabler:database",{"title":41,"description":42,"icon":43},"类型约束的配置映射表","用映射表取代分散在各处的 switch 判断。新增方案时漏写任何配置，类型检查就会报错，未知的值则回退到默认值。","tabler:shield-check",{"title":45,"description":46,"icon":47},"统一的 UI","用 Vuetify 统一各活动页的界面，取代各自为政的样式。","tabler:components",{"title":49,"description":50,"icon":51},"LINE 登录与异常处理","通过 LIFF 对接 LINE 登录，统一处理加载流程与登录失效等异常情况。","tabler:login",{"type":53,"title":54,"problem":55,"solution":57},"challenge","活动页各自为政，改一处要动好几处",[56],"多个活动页各自用 HTML、JS 编写，UI 不统一。同类配置分散在各处，规则容易出现分歧，改一处要联动修改好几处。",[58],"整合成 Vue 的单一应用，以路径区分各项目。配置集中为单一来源，并用 TypeScript 约束，漏写或写错在类型检查时就会发现。",{"left":60,"top":60,"width":61,"height":61,"rotate":60,"vFlip":24,"hFlip":24,"body":62},0,24,"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M3 19a2 2 0 1 0 4 0a2 2 0 0 0-4 0M19 7a2 2 0 1 0 0-4a2 2 0 0 0 0 4m-8 12h5.5a3.5 3.5 0 0 0 0-7h-8a3.5 3.5 0 0 1 0-7H13\"\u002F>",{"left":60,"top":60,"width":61,"height":61,"rotate":60,"vFlip":24,"hFlip":24,"body":64},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Cpath d=\"M4 6a8 3 0 1 0 16 0A8 3 0 1 0 4 6\"\u002F>\u003Cpath d=\"M4 6v6a8 3 0 0 0 16 0V6\"\u002F>\u003Cpath d=\"M4 12v6a8 3 0 0 0 16 0v-6\"\u002F>\u003C\u002Fg>",{"left":60,"top":60,"width":61,"height":61,"rotate":60,"vFlip":24,"hFlip":24,"body":66},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M11.46 20.846A12 12 0 0 1 3.5 6A12 12 0 0 0 12 3a12 12 0 0 0 8.5 3a12 12 0 0 1-.09 7.06M15 19l2 2l4-4\"\u002F>",{"left":60,"top":60,"width":61,"height":61,"rotate":60,"vFlip":24,"hFlip":24,"body":68},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"m3 12l3 3l3-3l-3-3zm12 0l3 3l3-3l-3-3zM9 6l3 3l3-3l-3-3zm0 12l3 3l3-3l-3-3z\"\u002F>",{"left":60,"top":60,"width":61,"height":61,"rotate":60,"vFlip":24,"hFlip":24,"body":70},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Cpath d=\"M15 8V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h7a2 2 0 0 0 2-2v-2\"\u002F>\u003Cpath d=\"M21 12H8l3-3m0 6l-3-3\"\u002F>\u003C\u002Fg>",1793955809415]