Amadeus's blog Amadeus's blog
首页
  • 前端文章

    • JavaScript
    • Vue
    • TypeScript
    • 前端工程化
  • 学习笔记

    • 《JavaScript教程》笔记
    • 《ES6 教程》笔记
    • 《Vue》笔记
    • 《TypeScript 从零实现 axios》
    • 小程序笔记
  • HTML
  • CSS
  • stylus
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • 口语
  • 音标
  • 语法
  • 简单
  • 中等
  • 困难
  • 20年10月
  • 20年11月
  • 20年12月
  • 21年01月
  • 21年02月
  • 21年03月
  • 21年04月
  • 21年05月
  • 21年06月
  • 21年07月
  • 21年08月
  • 21年09月
  • 21年10月
  • 21年11月
  • 21年12月
  • 22年01月
  • 22年02月
  • 22年03月
  • 22年04月
  • 22年05月
  • 22年06月
  • 22年07月
  • 22年08月
  • 22年09月
  • 21年3月
  • 知识笔记
  • 22年5月
  • 22年8月
  • 22年9月
  • 学习
  • 书法
  • 面试
  • 音乐
  • 驾照
  • 深度强化学习
  • 心情杂货
  • 友情链接
关于
  • 网站
  • 资源
  • Vue资源
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Amadeus

起风了,唯有努力生存!
首页
  • 前端文章

    • JavaScript
    • Vue
    • TypeScript
    • 前端工程化
  • 学习笔记

    • 《JavaScript教程》笔记
    • 《ES6 教程》笔记
    • 《Vue》笔记
    • 《TypeScript 从零实现 axios》
    • 小程序笔记
  • HTML
  • CSS
  • stylus
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • 口语
  • 音标
  • 语法
  • 简单
  • 中等
  • 困难
  • 20年10月
  • 20年11月
  • 20年12月
  • 21年01月
  • 21年02月
  • 21年03月
  • 21年04月
  • 21年05月
  • 21年06月
  • 21年07月
  • 21年08月
  • 21年09月
  • 21年10月
  • 21年11月
  • 21年12月
  • 22年01月
  • 22年02月
  • 22年03月
  • 22年04月
  • 22年05月
  • 22年06月
  • 22年07月
  • 22年08月
  • 22年09月
  • 21年3月
  • 知识笔记
  • 22年5月
  • 22年8月
  • 22年9月
  • 学习
  • 书法
  • 面试
  • 音乐
  • 驾照
  • 深度强化学习
  • 心情杂货
  • 友情链接
关于
  • 网站
  • 资源
  • Vue资源
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • TypeScript笔记

  • 前端工程化

  • 面试

  • 小程序

  • Vue3源码解析

  • 设计模式

  • NestJS笔记

  • JavaScript文章

  • Vue文章

  • 学习笔记

  • 温州LW公司项目总结

    • 公司C端官网项目
      • 公司B端项目
    • 前端
    • 温州LW公司项目总结
    Amadeus
    2026-03-11
    目录

    公司C端官网项目

    # 项目主要框架

    vue 2.5.17 vue-router 3.0.1 vuex 3.0.1 element-ui 2.15.14 axios 0.18.0 @vue/cli-service 3.2.0

    # 首屏加载优化

    # 2k\4k\5k屏幕适配

    定义$breakpoints端点数组和respondTo混合器,封装冗余的媒体查询,实际使用的时候直接使用 @include respondTo('lg',‘xl’) 即可,可以省去冗长的@media表达式,对于不同断点相同的样式不再需要重复书写,具体代码如下:

    $breakpoints:(
        "xs": (320px, 480px),
        "sm": (481px, 768px),
        "md": (769px, 1024px),
        "lg": (1025px, 1440px),
        "xl": (1441px, 2000px),
        "2k": (2001px, 3770px),
        "4k": (3771px, 5119px),
        "5k": (5120px, 99999px)
    );
    
    @mixin respondTo($breaknames){
        @each $breakname in $breaknames {
            $bp: map-get($breakpoints, $breakname);
            @if type-of($bp == 'list') {
                $min: nth($bp, 1);
                $max: nth($bp, 2);
                @media (min-width: $min) and (max-width: $max) {
                    @content;
                }
            }
            @else {
                @media (min-width: $bp) {
                    @content;
                }
            }
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    .wrapper {
      min-width: 1400px;
      @include respondTo('lg') {
        width: 1290px !important;
        min-width: 1290px !important;
      }
      @include respondTo(xl) {
        width: 1440px !important;
      }
      @include respondTo('2k') {
        width: 1920px !important;
      }
      @include respondTo('4k') {
        width: 2880px !important;
      }
      @include respondTo('5k') {
        width: 3840px !important;
      }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19

    媒体查询更多适用于不同设备间展示布局有较大变化的情况。除非不同断点间的元素不不是等比缩放的,需要一定调整才使用。 如果是按视口宽度百分比缩放的,不建议使用,可能会导致很多类名下都会有大量的针对不同断点的混入,难以维护,使用rem、vw之类的可能会更好,不同平台之间的兼容性也会更好,px这个单位不同设备间展示的效果都有较大差异。

    # 移动端、PC端多端适配及访问设备检测

    # 多语言

    // setup/i18n-setup.js
    import Vue from 'vue'
    import VueI18n from 'vue-i18n'
    import messages from '@/lang/en_US.js'
    import axios from 'axios'
    Vue.use(VueI18n)
    // 追踪已加载的语言文件
    export const loadedLanguages = ['en_US']
    // 将语言代码转换为文件名格式
    export const getLanguageFile = (locale) => {
      // 从完整的 locale (如 'zh-CN') 中提取基础语言代码 ('zh')
      const baseLanguage = locale.split('-')[0]
      // 根据你的文件命名规则返回对应的文件名
      switch(baseLanguage) {
        case 'en': return 'en_US'  // 英语
        case 'ja': return 'ja_JP'  // 日语
        case 'zh': return 'zh_CN'  // 中文(简体)
        default: return baseLanguage
      }
    }
    // 获取浏览器语言和地区
    const getBrowserLocale = () => {
      const browserLang = navigator.language || navigator.userLanguage
      // 返回完整的语言-地区代码,如 'zh-CN', 'en-US'
      return browserLang
    }
    const savedLocale = localStorage.getItem('selectedLocale') || getBrowserLocale() || 'en-US'
    const languageFile = getLanguageFile(savedLocale)
    const loadInitialLanguage = async () => {
      if (languageFile !== 'en_US') {
        try {
          const messages = await import(/* webpackChunkName: "lang-[request]" */ `@/lang/${languageFile}.js`)
          i18n.setLocaleMessage(languageFile, messages.default)
          loadedLanguages.push(languageFile)
        } catch (error) {
          console.error(`Could not load initial language ${languageFile}:`, error)
        }
      }
    }
    export const i18n = new VueI18n({
      locale: languageFile,
      fallbackLocale: 'en_US',
      messages: {
        en_US: messages
      },
      silentTranslationWarn: true,
      // 添加自定义 modifier
      modifiers: {
        lowercase: str => str.toLowerCase(),
        uppercase: str => str.toUpperCase(),
        capitalize: str => str.charAt(0).toUpperCase() + str.slice(1)
      },
      missing: (locale, key) => {
        // 当找不到翻译时,尝试用小写key再次查找
        const messages = i18n.messages[locale]
        const lowerKey = key.toLowerCase()
        for (let k in messages) {
          if (k.toLowerCase() === lowerKey) {
            return messages[k]
          }
        }
        return key
      }
    })
    export function setI18nLanguage(locale) {
      const languageFile = getLanguageFile(locale)
      i18n.locale = languageFile
      axios.defaults.headers.common['Accept-Language'] = locale
      document.querySelector('html').setAttribute('lang', locale)
      localStorage.setItem('selectedLocale', locale)
      return languageFile
    }
    export async function loadLanguageAsync(locale) {
      const langFile = getLanguageFile(locale)
      // 如果语言已经加载
      if (i18n.locale === langFile) {
        return Promise.resolve(setI18nLanguage(locale))
      }
      // 如果语言还没有加载
      if (!loadedLanguages.includes(langFile)) {
        try {
          const messages = await import(/* webpackChunkName: "lang-[request]" */ `@/lang/${langFile}.js`)
          i18n.setLocaleMessage(langFile, messages.default)
          loadedLanguages.push(langFile)
          return setI18nLanguage(locale)
        } catch (error) {
          console.error(`Failed to load language ${langFile}:`, error)
          return Promise.reject(error)
        }
      }
      return Promise.resolve(setI18nLanguage(locale))
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    // store/modules/lang.js
    import { loadLanguageAsync, getLanguageFile, setI18nLanguage, loadedLanguages, i18n } from '@/setup/i18n-setup'
    const state = {
      currentLang: localStorage.getItem('selectedLocale') || 'en-US'
    }
    const mutations = {
      SET_LANG(state, lang) {
        state.currentLang = lang
      }
    }
    const actions = {
      async changeLang({ commit }, locale) {
        const languageFile = getLanguageFile(locale)
        if (!loadedLanguages.includes(languageFile)) {
          const messages = await import(/* webpackChunkName: "lang-[request]" */ `@/lang/${languageFile}.js`)
          i18n.setLocaleMessage(languageFile, messages.default)
          loadedLanguages.push(languageFile)
        }
        setI18nLanguage(locale)
        commit('SET_LANG', locale)
      }
    }
    const getters = {
      currentLang: state => state.currentLang
    }
    export default {
      namespaced: true,
      state,
      mutations,
      actions,
      getters
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    // lang/zh_CN.js
    export default {
      "Condition": "\u6761\u4ef6",
      "SMART HOME SCENE": "\u667a\u80fd\u5bb6\u5c45\u573a\u666f",
      "Smart Scenarios of Human Body Sensor": "\u4eba\u4f53\u4f20\u611f\u5668\u7684\u667a\u80fd\u573a\u666f",
      'Smart Applications': '智能应用',
      'Product Series': '产品系列',
      'Technical Support': '技术支持',
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    // main.js
    import store from './store' // vuex配置
    // 初始化时加载保存的语言
    store.dispatch('lang/changeLang', store.state.lang.currentLang)
    
    1
    2
    3
    4
    <script>
    import { mapGetters, mapActions } from 'vuex'
    export default {
      data() {
    	selectedLang: '',
      },
      created() {
        this.selectedLang = localStorage.getItem('selectedLocale') || this.$i18n.locale || 'en'
      },
      computed: {
        ...mapGetters('lang', ['currentLang'])
      },
      methods: {
         ...mapActions('lang', ['changeLang']),
    	 handleLangChange(langCode) {
          this.selectedLang = langCode;
          this.changeLang(langCode);
          this.isDropdownVisible = false;
        },
        getCurrentLangName() {
          const currentLang = this.langList.find(lang => lang.code === this.selectedLang);
          return currentLang ? currentLang.name : 'Language';
        },
      }
    }
    </script>
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26

    # 实际效果与原型对比分析组件

    <template>
      <div>
        <!-- 设计稿覆盖层 - 跟随页面滚动 -->
        <div v-if="showDesignBackground && designDraftPath" class="design-overlay">
          <img :src="designDraftPath" alt="设计稿" class="design-image">
        </div>
        <!-- 设计稿切换按钮 - 始终显示,用于调试 -->
        <div class="design-toggle" @click="toggleDesignBackground">
          <span class="toggle-text">
            {{ showDesignBackground ? '隐藏设计稿' : '显示设计稿' }}
            <br>
            <small style="font-size: 10px; opacity: 0.7;">
              {{ designDraftPath || '无设计稿' }}
            </small>
          </span>
        </div>
      </div>
    </template>
    <script>
    import { getDesignDraftPath } from '@/config/designDrafts'
    export default {
      name: 'DesignOverlay',
      data() {
        return {
          showDesignBackground: false
        }
      },
      computed: {
        // 从配置文件获取设计稿路径
        designDraftPath() {
          // 构建完整的路径,包括查询参数
          const fullPath = this.$route.path + (this.$route.query && Object.keys(this.$route.query).length > 0
            ? '?' + new URLSearchParams(this.$route.query).toString()
            : '')
          const path = getDesignDraftPath(fullPath)
          console.log('当前路径:', this.$route.path, '查询参数:', this.$route.query, '完整路径:', fullPath, '设计稿路径:', path)
          return path
        }
      },
      mounted() {
        // 从本地存储读取设计稿显示状态
        const savedState = localStorage.getItem('showDesignBackground')
        if (savedState !== null) {
          this.showDesignBackground = JSON.parse(savedState)
        }
        console.log('DesignOverlay 组件已挂载,当前路径:', this.$route.path)
      },
      methods: {
        toggleDesignBackground() {
          this.showDesignBackground = !this.showDesignBackground
          // 保存状态到本地存储
          localStorage.setItem('showDesignBackground', JSON.stringify(this.showDesignBackground))
          console.log('切换设计稿显示状态:', this.showDesignBackground)
        }
      }
    }
    </script>
    <style scoped lang="scss">
    // 设计稿覆盖层 - 跟随页面滚动
    .design-overlay {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%; // 使用100%而不是100vw,避免包含滚动条宽度
      min-height: 100vh; // 确保覆盖整个页面高度
      z-index: 9998; // 比切换按钮低一层,但比网站内容高
      pointer-events: none; // 不阻止用户交互
      opacity: 0.8;
      .design-image {
        width: 100%;
        height: 100%;
        object-fit: contain; // 保持设计稿完整显示
        object-position: top center;
      }
    }
    // 设计稿切换按钮样式 - 保持固定定位
    .design-toggle {
      position: fixed;
      top: 20px;
      right: 20px;
      z-index: 9999; // 确保按钮在最顶层
      background: #323232;
      color: white;
      padding: 10px 15px;
      border-radius: 5px;
      cursor: pointer;
      font-size: 14px;
      font-weight: 500;
      box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
      transition: all 0.3s ease;
      user-select: none;
      pointer-events: auto; // 确保按钮可以点击
      &:hover {
        background: #555;
        transform: translateY(-2px);
        box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);
      }
      .toggle-text {
        white-space: nowrap;
        line-height: 1.2;
      }
    }
    // 响应式调整
    @media (max-width: 768px) {
      .design-toggle {
        top: 10px;
        right: 10px;
        padding: 8px 12px;
        font-size: 12px;
      }
    }
    </style>
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    // App.vue
    <template>
      <div id="app">
        <router-view />
        <!-- 全局设计稿覆盖层 - 只在开发环境且在特定的开发路由下显示 -->
        <DesignOverlay v-if="isDevelopment && $route.path.includes('/story')" /> 
      </div>
    </template>
    <script>
    import DesignOverlay from '@/components/DesignOverlay.vue'
    export default {
      name: "App",
      components: {
        DesignOverlay
      },
      computed: {
        isDevelopment () {
          return process.env.NODE_ENV === 'development'
        }
      },
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    // config/designDrafts.js
    // 设计稿配置文件
    export const designDrafts = {
      '/': '/img/design_drafts/home.png',
      '/story': '/img/design_drafts/story.jpg',
      // 带参数的路径配置
      '/function?type=electronic_types': '/img/design_drafts/function#type=electronic_types.png',
      '/panel?activePanel=0': '/img/design_drafts/panel#activePanel=0.jpg',
    }
    // 获取当前页面的设计稿路径
    export function getDesignDraftPath(routePath) {
      console.log(`正在查找设计稿: ${routePath}`)
      // 首先尝试精确匹配
      if (designDrafts[routePath]) {
        console.log(`精确匹配成功: ${routePath} -> ${designDrafts[routePath]}`)
        return designDrafts[routePath]
      }
      // 如果精确匹配失败,尝试智能匹配
      // 解析路径和查询参数
      const [pathname, search] = routePath.split('?')
      const queryParams = new URLSearchParams(search || '')
      console.log(`解析路径: pathname=${pathname}, search=${search}`)
      // 构建可能的匹配键
      const possibleKeys = []
      // 1. 基础路径
      possibleKeys.push(pathname)
      // 2. 带查询参数的完整路径
      if (search) {
        possibleKeys.push(routePath)
      }
      // 3. 通用查询参数匹配:尝试所有可能的查询参数组合
      if (search && queryParams.size > 0) {
        // 构建所有可能的查询参数组合
        const paramEntries = Array.from(queryParams.entries())
        // 尝试单个参数
        paramEntries.forEach(([key, value]) => {
          possibleKeys.push(`${pathname}?${key}=${value}`)
        })
        // 尝试多个参数组合(按原始顺序)
        if (paramEntries.length > 1) {
          const sortedParams = new URLSearchParams()
          paramEntries.forEach(([key, value]) => {
            sortedParams.append(key, value)
          })
          possibleKeys.push(`${pathname}?${sortedParams.toString()}`)
        }
      }
      console.log(`尝试匹配的键:`, possibleKeys)
      // 查找匹配的设计稿
      for (const key of possibleKeys) {
        if (designDrafts[key]) {
          console.log(`设计稿匹配成功: ${routePath} -> ${key} -> ${designDrafts[key]}`)
          return designDrafts[key]
        }
      }
      console.log(`未找到设计稿: ${routePath}`)
      return null
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58

    # SEO

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="utf-8">
        <meta name="title" content="Home page">
        <meta name="description" content="XXX is known around the world as a leader in smart home devices that include electric switches and sockets." />
        <meta name="keywords" content="XXX,XXX touch switch,XXX socket,smart switch,app control switch,led indicate switch,light switch,wall socket"/>
        <!-- Twitter Cards -->
        <meta property="twitter:url" content="https://www.xxx.com" />
        <meta name="twitter:title" content="Home page  -- XXX experts in electric switches" />
        <meta name="twitter:description" content="XXX is known around the world as a leader in smart home devices that include electric switches and sockets." />
        <meta name="twitter:site" content="https://www.xxx.com" />
        <meta name="twitter:card" content="summary_large_image" />
        <meta name="twitter:image" content="" />
        <!-- Facebook Open Graph -->
        <meta property="og:url" content="https://www.xxx.com" />
        <meta property="og:title" content="Home page  -- XXX experts in electric switches" />
        <meta property="og:description" content="XXX is known around the world as a leader in smart home devices that include electric switches and sockets." />
        <meta property="og:image" content="" />
        <meta property="og:type" content="website" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
        <link rel="icon" href="<%= BASE_URL %>favicon.ico">
        <title>XXX</title>
        <!-- End Google Tag Manager -->
        <!-- 生产环境使用 CDN -->
        <!-- <% if (process.env.NODE_ENV === 'production') { %>
          <link rel="stylesheet" href="https://unpkg.com/[email protected]/lib/theme-chalk/index.css">
          <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/lib/style.min.css">
        <% } %> -->
        <!-- Google tag (gtag.js) -->
        <script async src="https://www.googletagmanager.com/gtag/js?id=G-XXX"></script>
        <script>
          window.dataLayer = window.dataLayer || [];
          function gtag(){dataLayer.push(arguments);}
          gtag('js', new Date());
          gtag('config', 'G-XXX');
        </script>
        <!-- 添加结构化数据 -->
        <script type="application/ld+json">
        [
    
          {
    
            "@context": "https://schema.org",
    
            "@type": "Organization",
    
            "url": "https://www.xxx.com",
    
            "logo": "https://www.xxx.com/favicon.ico",
    
            "name": "XXX"
    
          },
    
          {
    
            "@context": "https://schema.org",
    
            "@type": "WebSite",
    
            "url": "https://www.xxx.com",
    
            "name": "XXX",
    
            "potentialAction": {
    
              "@type": "SearchAction",
    
              "target": {
    
                "@type": "EntryPoint",
    
                "urlTemplate": "https://www.xxx.com/search?q={search_term_string}"
    
              },
    
              "query-input": "required name=search_term_string"
    
            }
    
          },
    
          {
    
            "@context": "https://schema.org",
    
            "@type": "FAQPage",
    
            "mainEntity": [{
    
              "@type": "Question",
    
              "name": "What is XXX Function?",
    
              "acceptedAnswer": {
    
                "@type": "Answer",
    
                "text": "Explore our smart home functions including touch switches, sockets, and smart control systems",
    
                "url": "https://www.xxx.com/function"
    
              }
    
            }, {
    
              "@type": "Question",
    
              "name": "What is XXX Story?",
    
              "acceptedAnswer": {
    
                "@type": "Answer",
    
                "text": "Learn about XXX's history, development and our commitment to smart home innovation",
    
                "url": "https://www.xxx.com/story"
    
              }
    
            }, {
    
              "@type": "Question",
    
              "name": "How to Contact XXX?",
    
              "acceptedAnswer": {
    
                "@type": "Answer",
    
                "text": "Get in touch with XXX team for business cooperation or technical support through our contact page",
    
                "url": "https://www.xxx.com/contact"
    
              }
    
            }]
    
          },
    
          {
    
            "@context": "https://schema.org",
    
            "@type": "ItemList",
    
            "itemListElement": [
    
              {
    
                "@type": "ListItem",
    
                "position": 1,
    
                "item": {
    
                  "@type": "Article",
    
                  "name": "Smart Home Functions",
    
                  "headline": "Explore XXX Smart Home Solutions",
    
                  "description": "Discover our innovative smart home solutions including touch switches, smart sockets, and intelligent control systems for modern living",
    
                  "url": "https://www.xxx.com/function",
    
                  "image": {
    
                    "@type": "ImageObject",
    
                    "url": "https://www.xxx.com/img/contact_1.png",
    
                    "width": 1200,
    
                    "height": 630
    
                  },
    
                  "author": {
    
                    "@type": "Organization",
    
                    "name": "XXX",
    
                    "url": "https://www.xxx.com"
    
                  },
    
                  "publisher": {
    
                    "@type": "Organization",
    
                    "name": "XXX",
    
                    "logo": {
    
                      "@type": "ImageObject",
    
                      "url": "https://www.xxx.com/favicon.ico"
    
                    }
    
                  },
    
                  "datePublished": "2025-01-01T00:00:00+08:00",
    
                  "dateModified": "2025-03-21T00:00:00+08:00"
    
                }
    
              },
    
              {
    
                "@type": "ListItem",
    
                "position": 2,
    
                "item": {
    
                  "@type": "Article",
    
                  "name": "XXX Story",
    
                  "headline": "Our Journey of Innovation",
    
                  "description": "From our founding principles to becoming a global leader in smart home technology - explore the XXX story of continuous innovation and growth",
    
                  "url": "https://www.xxx.com/story",
    
                  "image": {
    
                    "@type": "ImageObject",
    
                    "url": "https://www.xxx.com/img/contact_3.png",
    
                    "width": 1200,
    
                    "height": 630
    
                  },
    
                  "author": {
    
                    "@type": "Organization",
    
                    "name": "XXX",
    
                    "url": "https://www.xxx.com"
    
                  },
    
                  "publisher": {
    
                    "@type": "Organization",
    
                    "name": "XXX",
    
                    "logo": {
    
                      "@type": "ImageObject",
    
                      "url": "https://www.xxx.com/favicon.ico"
    
                    }
    
                  },
    
                  "datePublished": "2025-01-01T00:00:00+08:00",
    
                  "dateModified": "2025-03-21T00:00:00+08:00"
    
                }
    
              },
    
              {
    
                "@type": "ListItem",
    
                "position": 3,
    
                "item": {
    
                  "@type": "Article",
    
                  "name": "Contact XXX",
    
                  "headline": "Get in Touch with XXX",
    
                  "description": "Connect with XXX for business opportunities, technical support, or customer service. Your smart home journey starts here",
    
                  "url": "https://www.xxx.com/contact",
    
                  "image": {
    
                    "@type": "ImageObject",
    
                    "url": "https://www.xxx.com/img/contact_4.png",
    
                    "width": 1200,
    
                    "height": 630
    
                  },
    
                  "author": {
    
                    "@type": "Organization",
    
                    "name": "XXX",
    
                    "url": "https://www.xxx.com"
    
                  },
    
                  "publisher": {
    
                    "@type": "Organization",
    
                    "name": "XXX",
    
                    "logo": {
    
                      "@type": "ImageObject",
    
                      "url": "https://www.xxx.com/favicon.ico"
    
                    }
    
                  },
    
                  "datePublished": "2025-01-01T00:00:00+08:00",
    
                  "dateModified": "2025-03-21T00:00:00+08:00"
    
                }
    
              }
    
            ]
    
          }
    
        ]
        </script>
      </head>
      <body>
        <noscript>
          <strong>We're sorry but vue_template doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
        </noscript>
        <div id="app"></div>
        <!-- built files will be auto injected -->
        <!-- End Google Tag Manager (noscript) -->
        <!-- 生产环境使用 CDN -->
        <!-- <% if (process.env.NODE_ENV === 'production') { %>
          <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js"></script>
          <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue-router.min.js"></script>
          <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vuex.min.js"></script>
          <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/axios.min.js"></script>
          <script src="https://unpkg.com/[email protected]/lib/index.js"></script>
          <script src="https://cdn.jsdelivr.net/npm/[email protected]/lib/index.js"></script>
          <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue-i18n.min.js"></script>
        <% } %> -->
        <!-- <script async src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.5.207/pdf.min.js" data-body="true"></script> -->
      </body>
    </html>
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
    350
    351
    352
    353
    354
    355
    356
    357
    358
    359
    360
    361
    362
    363
    364
    365
    366
    367
    368
    369

    # 预渲染

    编辑 (opens new window)
    装机笔记
    公司B端项目

    ← 装机笔记 公司B端项目→

    最近更新
    01
    公司B端项目
    03-11
    02
    简历
    03-09
    03
    Blog环境更新测试
    03-09
    更多文章>
    Theme by Vdoing | Copyright © 2020-2026 Amadeus | MIT License
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式