tangning hai 1 semana
pai
achega
dc641c7a49

+ 3 - 0
src/App.vue

@@ -1,7 +1,10 @@
 <script setup lang="ts">
 import '@/assets/style/iconfont.css'
+import { useUserStore } from '@/stores/user'
 import { RouterView } from 'vue-router'
 import { onMounted } from 'vue'
+const useUser = useUserStore()
+useUser.getInfo()
 onMounted(() => {
   window.onresize = () => {
     console.log('window.onresize');

+ 70 - 0
src/api/user.ts

@@ -0,0 +1,70 @@
+import { request } from "@/utils/request";
+export const getUserInfo = () => {
+  return request({
+    url: "/ucenter/user/getUserInfo",
+    method: "post",
+    config: {
+      timeout: 10000,
+      headers: {
+        "Content-Type": "application/json;charset=UTF-8",
+      },
+    },
+  });
+};
+
+export const openPay = (data) => {
+    return request({
+      url: "/service/pay/openPay",
+      method: "post",
+      data,
+      config: {
+        timeout: 10000,
+        headers: {
+            "Content-Type": "application/json;charset=UTF-8",
+        },
+      },
+    });
+  };
+
+  export const wxLogin = (data:logonParam) => {
+    return request({
+      url: "/service/pay/wxLogin",
+      method: "get",
+      data,
+      config: {
+        timeout: 10000,
+        headers: {
+            "Content-Type": "application/json;charset=UTF-8",
+        },
+      },
+    });
+  };
+  
+export const getOrderInfo = (orderSn:string) => {
+    return request({
+      url: `/service/pay/order/info/${orderSn}`,
+      method: "get",
+      config: {
+        timeout: 10000,
+        loading: true,//隐藏进度条
+        headers: {
+            "Content-Type": "application/json;charset=UTF-8",
+        },
+      },
+    });
+  };
+
+export const queryOrderStatus = (data) => {
+    return request({
+      url: `/ucenter/user/order/queryOrderStatus`,
+      method: "post",
+      data,
+      config: {
+        timeout: 10000,
+        loading: true,//隐藏进度条
+        headers: {
+            "Content-Type": "application/json;charset=UTF-8",
+        },
+      },
+    });
+  };

BIN=BIN
src/assets/images/footer/shopbtn-en.gif


BIN=BIN
src/assets/images/footer/shopbtn.gif


BIN=BIN
src/assets/images/home/France@2x.jpg


BIN=BIN
src/assets/images/home/Germany@2x.jpg


BIN=BIN
src/assets/images/home/USA@2x.jpg


BIN=BIN
src/assets/images/home/china@2x.png


+ 5 - 2
src/assets/main.css

@@ -42,7 +42,10 @@ a,
 }
 
 .contentPage{
-  max-width: 1366px;
+  /* max-width: 1316px;
+  margin: 0 auto;
+  min-width: 1200px; */
+  width: 1316px;
+  padding: 0 20px;
   margin: 0 auto;
-  min-width: 1200px;
 }

+ 40 - 1
src/components/pc/data.ts

@@ -1,4 +1,7 @@
 
+import zh from '@/assets/images/home/china@2x.png'
+import en from '@/assets/images/home/USA@2x.jpg'
+
 export const pcFooter = (t:any) => {
   return [
   {
@@ -77,4 +80,40 @@ export const pcFooter = (t:any) => {
     ]
   }
 ]
-}
+}
+export const pcHeader = (t:any) => {
+  return [
+        { text: t('manage.sceneAdmin.sdsg'), link: '/mall/meta' },
+        { text: t('header.Mega'), link: '/mall/mega' },
+        { text: t('header.kankanMinion'), link: '/mall/kankanMinion' },
+        { text: t('header.mallPro'), link: '/mall/kankanPro' },
+        { text: t('header.mallPeijian'), link: '/mall/zhijia',items: [
+          {
+            text: t('header.tripod'),
+            link: '/mall/zhijia'
+          },
+          {
+            text: t('header.USBdrive'),
+            link: '/mall/USBdrive'
+          },
+          {
+            text: t('header.Battery'),
+            link: '/mall/Battery'
+          },
+        ] },
+        { text: t('header.addService'), link: '/mall/member' }
+      ]
+}
+
+export const languageList = [
+  {
+        name: '简体中文',
+        img: zh,
+        value: 'zh' 
+  },
+  {
+        name: 'English',
+        img: en,
+        value: 'en' 
+  }
+]

+ 397 - 10
src/components/pc/header.vue

@@ -1,28 +1,415 @@
 <script setup lang="ts">
+import { ref, computed } from 'vue'
+import { useRouter, useRoute } from 'vue-router'
 import { useI18n } from 'vue-i18n'
 import logoCn from '@/assets/images/logoCn.png'
 import logoEn from '@/assets/images/logoEn.png'
+import shopbtn from '@/assets/images/footer/shopbtn.gif'
+import shopbtnEn from '@/assets/images/footer/shopbtn-en.gif'
+import { useUserStore } from '@/stores/user'
+import { pcHeader, languageList } from './data'
+const router = useRouter();
 //得到i18n的locale
-const { locale } = useI18n();
+const userStore = useUserStore()
+const info = computed(() => userStore.getUserInfo)
+const isLogin = computed(() => userStore.isLogin)
+const { locale:langauge, t } = useI18n();
+const navs = pcHeader(t)
+const languageObj = computed(() => languageList.find(item => item.value === langauge.value) || {})
+console.log('languageObj', info.value, userStore)
 </script>
 
 <template>
-  <div class="header">
-    <div class="logo contentPage">
+    <div class="header-layout">
+    <div class="headercontainer clear flex justify-between items-center">
       <img :src="locale === 'zh' ? logoCn : logoEn" alt="logo">
+      <div class="menu">
+        <div
+          class="list"
+          ref="list"
+        >
+          <a
+            v-for="nav in navs"
+            :key="nav.text"
+            :class="{active: hoverCp === nav.cp}"
+            class="header-item"
+            :style="{'margin-right': langauge==='en' ? '30px' : '48px'}"
+            @click="toNav(nav)"
+          >{{nav.text}}
+            <ul class="child-list" v-if="nav.items">
+              <li class="" v-for="(item, index) in nav.items" :key="index" @click.stop="toNav(item)">
+                {{ item.text }}
+              </li>
+            </ul>
+          </a>
+          
+        </div>
+      </div>
+      <div class="ctrl">
+        <div class="shop-btn" @click="router.push({name: 'mallMeta'})" v-if="!isShop">
+          <img :src="langauge==='en' ? shopbtnEn : shopbtn" alt="" srcset="">
+        </div>
+        <div class="language-w">
+          <div class="list">
+            <a class="header-item">
+              <p class="guoqi" :style="{'background-image': `url(${languageObj.img})`}">{{ languageObj.name }}</p>
+              <ul class="child-list">
+                <li v-for="item in languageList" :key="item.name" :style="{'background-image': `url(${item.img})`}" @click="changeLanguage(item.value)">{{ item.name }}</li>
+              </ul>
+            </a>
+          </div>
+        </div>
+        <div class="user" @click="router.push('/login/login')" v-if="!isLogin"></div>
+        <div v-else-if="info" class="user-w">
+          <div class="user avatar" :class="{vip: info.incrementNum}" :style="{'background-image': `url(${info.head})`}" @click="router.push('/information')">
+          <div class="member-icon" @click.stop="router.push({name: 'member'})" v-if="info.incrementNum"></div>
+          </div>
+          <div class="list">
+              <a class="header-item" @click="router.push('/information')">
+                <ul class="child-list">
+                  <li @click="router.push('/information')">{{ t('header.myaccount') }}</li>
+                  <li @click.stop="handleLogout">{{ t('header.logout') }}</li>
+                </ul>
+              </a>
+            </div>
+        </div>
+        <div class="cart" @click="handleCartClick">
+          <h-icon type="xingouwuche" class="icon" />
+          <span v-if="cartCount">{{cartCount}}</span>
+        </div>
+      </div>
     </div>
   </div>
+  <!-- <div class="header">
+    <div class="logo contentPage">
+      <img :src="locale === 'zh' ? logoCn : logoEn" alt="logo">
+    </div>
+  </div> -->
 </template>
+
 <style lang="less" scoped>
-.header{
+.language-w {
+  .header-item {
+    margin-right: 20px !important;
+    display: inline-block;
+    p {
+      color: #323233;
+      font-size: 14px;
+      font-weight: normal;
+      padding-left: 28px;
+      background: url(~@/assets/images/home/China.png) no-repeat left center;
+      background-size: 20px 14px;
+    }
+  }
+  .child-list {
+    background: #fff;
+    li {
+      color: #323233;
+      font-size: 14px;
+      font-weight: normal;
+      padding: 0 13px 0 40px;
+      background: url(~@/assets/images/home/China.png) no-repeat 13px center;
+      background-size: 20px 14px;
+    }
+  }
+}
+
+.header-layout {
+  // $mc: .5s cubic-bezier(.77, 0, .175, 1);
+  // $ts: all $mc;
+  background-color: #fff;
+  color: #fff;
+  justify-content: space-between;
+  color: #323233;
   height: 80px;
-  background: #FFFFFF;
-  box-shadow: 0px 3px 6px 0px rgba(0,0,0,0.1);
-  border-radius: 0px 0px 0px 0px;
-  opacity: 1;
-  .logo{
+  box-shadow:0px 3px 6px rgba(0,0,0,0.1);
+  .headercontainer {
+    height: 100%;
+    width: 1316px;
+    padding: 0 20px;
+    margin: 0 auto;
+  }
+  .child-layout {
+    position: absolute;
+    top: 100%;
+    max-height: 0;
+    left: 0;
+    right: 0;
+    // transition: max-height $mc;
+    overflow: hidden;
+    box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
+    .silp {
+      position: absolute;
+      width: 1px;
+      height: 100%;
+      background-color: #ededed;
+      z-index: 2;
+    }
+  }
+
+  .logo-layout {
+    text-align: center;
+    text-align: left;
+    margin-right: 52px;
+    float: left;
+    height: 100%;
+    .logo {
+      position: relative;
+      width: 150px;
+      height: 100%;
+      display: inline-block;
+      color: #fff;
+    }
+  }
+
+  .menu {
+    float: left;
+    min-width: 600px;
+
+    .lang {
+      box-sizing: border-box;
+      text-align: center;
+      padding-right: 10px;
+
+      a {
+        display: inline-block;
+        font-size: 16px;
+        font-weight: bold;
+        margin-left: 5px;
+        color: #727272;
+        transition: color 0.2s ease;
+        &:hover{
+          color: #fff;
+        }
+      }
+
+      .active{
+        color: #fff;
+      }
+    }
+
+    
+  }
+  .list {
+      justify-content: space-between;
+      height: 100%;
+      a {
+        display: inline-block;
+        // padding: 30px 47px 25px 0;
+        margin-right: 48px;
+        line-height: 80px;
+        font-size: 16px;
+        text-decoration: none;
+        font-weight: bold;
+        position: relative;
+        transition: color 0.3s ease;
+
+        &::before {
+          z-index: 2;
+        }
+
+        &.active {
+          color: #727272;
+
+          &::after {
+            border-top-color: #727272;
+            transform: translateY(-50%) scale(1.3);
+          }
+
+          &::before {
+            transform: translateY(-50%) scale(0.7);
+            border-top-color: #000;
+          }
+        }
+
+      }
+    }
+  .ctrl {
+    align-items: center;
+    font-size: 16px;
+    &>div {
+      display: inline-block;
+      vertical-align: middle;
+    }
+    .shop-btn {
+      margin-right: 25px;
+      cursor: pointer;
+      
+      height: 34px;
+      line-height: 34px;
+      text-align: center;
+      font-weight: 400;
+      height: 34px;
+      background: linear-gradient(180deg, #1EDAE5 1%, #069199 100%);
+      border-radius: 17px;
+      color: #FFFFFF;
+        
+  img {
+    height: 34px;
+  }
+    }
+    .country {
+      width: 20px;
+      height: 21px;
+      display: inline-block;
+      background: url(~@/assets/images/home/China.png) no-repeat center center;
+      vertical-align: middle;
+    }
+    .language-w {
+      // padding: 0 30px  0 10px;
+    }
+    .language {
+      margin: 0 15px 0 0;
+      color: #8F8F8F;
+      cursor: pointer;
+      vertical-align: middle;
+      font-size: 16px;
+      font-weight: 600;
+      &.is-active {
+        color: #323233;
+      }
+    }
+    .user {
+      width: 20px;
+      height: 20px;
+      background: url(~@/assets/images/home/account-icon.png) no-repeat center center;
+      cursor: pointer;
+      background-size: cover;
+      &.avatar {
+        width: 34px;
+        height: 34px;
+        border: 1px solid #EFEFEF;
+        border-radius: 50%;
+        position: relative;
+        &.vip {
+          border-color: #D8AF7C;
+        }
+      }
+      
+      .member-icon {
+        width: 12px;
+        height: 12px;
+        background: url(~@/assets/images/refactor/usercenter/avatar_vip.png) no-repeat center center;
+        background-size: cover;
+        position: absolute;
+        right: -2px;
+        bottom: 0;
+      }
+    }
+    .cart {
+      color: #323233;
+      margin-left: 18px;
+      cursor: pointer;
+      position: relative;
+      .icon {
+        font-size: 26px;
+      }
+      span {
+        display: block;
+        position: absolute;
+        left: 9px;
+        top: 0;
+        font-size: 12px;
+        line-height: 16px;
+        text-align: center;
+        font-weight: bold;
+        color: #FFFFFF;
+        line-height: 14px;
+
+        height: 16px;
+        min-width: 16px;
+        padding: 0 2px;
+        background: linear-gradient(135deg, #696D75 0%, #3C3F41 100%);
+        border-radius: 4px;
+      }
+    }
+  }
+
+}
+.header-item:hover {
+  position: relative;
+  .child-list {
+    display: block;
+  }
+}
+.child-list {
+  position: absolute;
+  // width: 112px;
+  box-shadow: 0px -2px 6px rgba(113,113,113,0.16);
+  margin-top: -10px;
+  left: 50%;
+  transform: translateX(-50%);
+  z-index: 1;
+  display: none;
+  transition: all linear 0.5s;
+  padding-top: 6px;
+  white-space: nowrap;
+  
+  background: #fff;
+  &::before {
+    position: absolute;
+    display: block;
+    top: -5px;
+    left: 50%;
+    margin-left: -2px;
+    width: 0;
+    height: 0px;
+    content: '';
+    background: #fff;
+    border-style: solid;
+    border-width: 4px;
+    border-color: #fff #fff transparent transparent;
+    transform: rotate(-45deg);
+    box-shadow: 1px -1px 0px rgba(113,113,113,0.16);
+    z-index: 1;
+  }
+  li {
+    height: 48px;
+    line-height: 48px;
+    font-size: 16px;
+    text-align: center;
+    position: relative;
+    background: #fff;
+    z-index: 2;
+    width: 100%;
+    padding: 0 25px;
+    &:hover {
+      background-color: #EBEBEB;
+    }
+  }
+}
+.list {
+  &:hover {
+    .header-item {
+      color: #909090;
+    }
+  }
+  .header-item:hover {
+    position: relative;
+    color: #323233;
+    transition: 0s;
+    .child-list {
+      display: block;
+    }
+  }
+}
+.user-w {
+  .list {
+    position: absolute;
     height: 100%;
-    padding: 17px 0;
+    top: 0;
+    .header-item {
+      display: block;
+      width: 32px;
+      padding-top: 80px;
+    }
   }
 }
+@media screen and (max-width: 1600px){
+}
+
+@media screen and (max-width: 1450px){
+}
+
 </style>
+

+ 56 - 0
src/i18n/modules/zh/header.js

@@ -0,0 +1,56 @@
+export default {
+        "core_product": "核心产品",
+        "solutions": "行业解决方案",
+        "solutionsText": "四维时代致力于人工智能三维数字化技术<br/>的研究和应用",
+        "kankan_space": "经典案例",
+        "core_tech": "核心技术",
+        "service": "服务支持",
+        "about": "关于我们",
+        "online_shop": "商城",
+        "foreign": "中德合作",
+        "solutionsHouse": "房产营销",
+        "solutionsExi": "智慧城市",
+        "solutionsSubject": "博物馆",
+        "solutionsShop": "VR购物",
+        "solutionsSec": "刑侦消防",
+        "serviceApp": "App 下载",
+        "joinUs": "加入我们",
+        "serviceUse": "使用教程",
+        "serviceBaoxiu": "售后服务",
+        "serviceVideo": "视频教程",
+        "aboutNews": "新闻中心",
+        "aboutAgent": "成为经销商",
+        "aboutCompany": "公司介绍",
+        "mallPro": "四维看看",
+        "kankanMinion": "四维看见",
+        "Mega": "四维深时",
+        "mallPeijian": "精选配件",
+        "tripod": "三脚架套装",
+        "USBdrive": "U盘",
+        "Battery": "电池",
+        "addService": "会员权益",
+        "corePruductItemPro": "四维看看",
+        "corePruductItemSxz": "四维 • 随心装",
+        "footer": {
+            "bannerTitle": "四维看看,让空间讲故事",
+            "find": "发现精彩",
+            "saleEmail": "销售合作",
+            "meitiEmail": "媒体采访",
+            "phone": "联系电话",
+            "find4D": "探索四维",
+            "kankan": "四维时代",
+            "zhongde": "中德人工智能研究院",
+            "moku": "四维模库",
+            "workTime": "周一至周五 9:00-18:30"
+        },
+        "moreName": {
+            "1": "装修家装",
+            "2": "商圈",
+            "3": "线上会展",
+            "4": "地下管网",
+            "5": "BIM"
+        },
+        myaccount: '我的账号',
+        logout: '退出登录'
+
+    }

+ 0 - 0
src/i18n/modules/zh/home.js


+ 81 - 0
src/i18n/modules/zh/manage.js

@@ -0,0 +1,81 @@
+export default {
+        "information": {
+            "uploadTip": "图片大小不能大于",
+            "editInformation": "修改信息",
+            "editAddressLinkText": "修改地址",
+            "editInfo": "修改账号信息",
+            "gotoPay": "购买权益",
+            "memberDevice": "权益相机",
+            "expiredDownload": "剩余下载",
+            "takePhotos": "拍摄场景",
+            "defaultAddress": "默认收货地址",
+            "informationOverview": "账户概览",
+            "uploadAvatar": "上传头像",
+            "uploadAvatarTips": "推荐分辨率为:512*512px,<br/>允许JPG、PNG格式,小于1MB",
+            "userName": "账号",
+            "nickName": "昵称",
+            "email": "邮箱",
+            "cameraCount": "相机数量",
+            "memberCount": "权益数量",
+            "tai": "台",
+            "ci": "次",
+            "ge": "个",
+            "tai1": "(台)",
+            "ci1": "(次)",
+            "ge1": "(个)",
+            "editAddress": {
+                "editAddress": "修改收货地址",
+                "country": "国家/地区",
+                "province": "省",
+                "city": "市",
+                "qu": "区",
+                "addressDetail": "详细地址",
+                "receiver": "收件人",
+                "receiverPhone": "手机号码",
+                "internationalCity": "城市",
+                "internationalProvince": "州/省/地区"
+            },
+            "changePassword": {
+                "changePassword": "修改密码",
+                "verCode": "验证码",
+                "newPassword": "新密码",
+                "confirmNewPassword": "确认密码"
+            },
+            "memberTable": {
+                "deviceMember": "会员权益",
+                "bindDeviceNum": "授权相机{num}台",
+                "snInputPlaceHolder": "搜索相机S/N码",
+                "searchNoData": "抱歉,没有找到相关信息。",
+                "nodataPre": "请先购买会员权益",
+                "nodataGoBuy": "购买权益",
+                "isExpired": "已过期"
+            },
+            "nameArr": {
+                "information": "账号信息",
+                "scene": "场景管理",
+                "order": "我的订单",
+                "device": "我的相机",
+                "consumption": "消费记录",
+                "change": "修改密码",
+                "logout": "退出登录",
+                "products": "应用中心"
+            },
+            "deviceSettings": [
+                {
+                    "name": "security",
+                    "items": [
+                        {
+                            "name": "场景管理",
+                            "to": {
+                                "name": "scene"
+                            }
+                        },
+                        {
+                            "name": "退出登录",
+                            "to": "logout"
+                        }
+                    ]
+                }
+            ]
+        },
+    }

+ 130 - 0
src/i18n/modules/zh/toast.js

@@ -0,0 +1,130 @@
+export default {
+  '1': '获取订单信息失败',
+  '2': '获取支付二维码失败',
+  '3': '正在跳转至paypal支付链接,请稍等',
+  '4': '信息填写不能为空',
+  '5': '开票成功',
+  '6': '开票成功',
+  '7': '不能为空',
+  '8': '请输入正确的邮箱地址',
+  '9': '提交成功',
+  '10': '联系信息不正确,请修改',
+  '11': '系统繁忙,请稍后再试',
+  '12': '您的信息已收到,我们会尽快与您联系',
+  '13': '获取相机详情失败',
+  '14': '无法删除最后的商品',
+  '15': '确定删除吗?',
+  '16': '请同意条款',
+  '17': '请先保存发票信息',
+  '18': '请先保存收货信息',
+  '19': '请完善收货信息',
+  '20': '请完善发票信息',
+  '21': '请输入18位的税务登记号',
+  '22': '请输入正确的手机号码',
+  '23': '注册成功,是否立刻登录?',
+  '24': '密码修改成功,请重新登录',
+  '25': '没有找到相应的记录',
+  '26': '确定要解绑当前相机吗?',
+  '27': '上传的图片类型不正确,请重新上传',
+  '28': '您的云端容量已用完,请删除其他场景或扩容, 以保证足够的容量。',
+  '29': '账号不合法',
+  '30': '请重新登录',
+  '31': '密码位数不能少于8位',
+  '32': '密码修改成功',
+  '33': '解绑成功',
+  '34': '失败',
+  '35': '昵称不能为空',
+  '36': '上传的图片类型不正确,请重新上传',
+  '37': '删除成功',
+  '38': '删除失败',
+  '39': '商品加入购物车成功',
+  '40': '请登录您的用户账号,再进行充值续费。',
+  '41': '去登录',
+  '42': '暂不支持降级套餐,您可进行续费或升级套餐。',
+  '43': '请绑定用户账号后,进行充值扩容。',
+  '44': '分配成功',
+  '45': '已取消协作',
+  '46': '解除成功',
+  '3001': '缺少必要参数',
+  '3002': '访问异常!',
+  '3003': '非法访问!',
+  '3004': '请重新登录',
+  '3005': '验证码错误',
+  '3006': '验证码错误',
+  '3007': '昵称已存在',
+  '3008': '该账号已被注册',
+  '3009': '两次输入的密码不一致',
+  '3010': '昵称长度在2-11位之间',
+  '3011': '密码必须包含英文大小写、数字,长度8-16个字符',
+  '3012': '昵称包含敏感词',
+  '3013': '手机号码格式错误',
+  '3014': '账号或密码不正确',
+  '3015': '用户不存在',
+  '3016': '您没有权限,请联系管理员',
+  '3017': '空文件',
+  '3018': '需要上传或使用的文件不存在',
+  '3019': '邮箱格式不正确',
+  '3020': '邮箱地址已存在',
+  '3021': '账号不存在,请核对后重新输入',
+  '3022': '该场景已添加协作者,请先取消协作后再添加',
+  '3023': '手机验证码获取验证码次数过多,请明天再试',
+  '3024': '不能将场景协作给自己',
+  '3025': '不能将相机分配给自己',
+  '3026': '有部分场景已存在协作者,请先取消协作后再添加。',
+  '3030': '当前会员权益不存在',
+  '3031': '当前会员权益已绑定相机,请先解除绑定',
+  '3032': '当前相机已被授权,请选择其它相机。',
+  '3037': '当前场景不支持该操作。',
+  '4007': '用户名不存在',
+  '4010': '绑定的相机不存在',
+  '4011': '相机已经被绑定',
+  '4012': '账号或密码错误',
+  '4021': '已开票',
+  '5001': 'modeldata.json为空',
+  '5002': 'order值为空',
+  '5003': 'guideSid或order值为空',
+  '5004': 'guideSid或guideName值为空',
+  '5005': '场景为空',
+  '5006': '余额不足',
+  '5007': '非八目场景',
+  '5008': '该场景已经被封存,无法删除',
+  '5009': '场景被删除',
+  '5010': '场景不属于该相机',
+  '5011': '创建',
+  '5012': '数据不正常',
+  '5013': '场景对应的用户名为空',
+  '5014': '该用户无权操作该场景',
+  '5015': '该场景不属于当前登录账号',
+  '5016': '热点外链场景不对',
+  '5030': '同级文件夹名称不能重复',
+  '5038': '生成 obj 失败,请重算场景。',
+  '5051': '无法将上级目录移动到下级目录',
+  '6001': '物理地址重复',
+  '6002': '退充值超过了充值总额',
+  '6003': '该相机未被绑定,请前往 我的相机 先绑定相机后再进行授权',
+  '6004': '表示相机的点数超过了10万',
+  '6005': '会员权益不可授权非本账号相机',
+  '6006': '不支持重复绑定',
+  '6008': '云容量不足,无法复制。',
+  '6009': 'data.fdage文件不存在',
+  '6010': '该SN码已被绑定',
+  '6012': '相机未绑定用户',
+  '6013': '必须输入需迁相机所绑定用户的验证码',
+  '6014': '必须输入目标相机所绑定用户的验证码',
+  '6015': '该相机已添加协作者,请先取消协作后再添加',
+  '6016': '有部分相机已存在协作者,请先取消协作后再添加。',
+  '6028': 'xxxxx',
+  '7001': '标题包含敏感词',
+  '7002': '内容包含敏感词',
+  '7019': '场景升级中,请勿重复升级',
+  '8001': '订单不存在',
+  '8002': '支付失败',
+  '8016': '场景使用中,无法删除,请稍候。',
+  '400002': '当前场景不支持该操作。',
+  '400003': '数据生成失败!',
+  '400013': '该功能需要使用场景原始数据,需要较长时间等待。如需继续使用,请联系客服。',
+  '400014': '原始数据不存在。',
+  '400015': '数据资源冲突,请稍候重试。',
+  '400016': '数据生成失败!'
+
+}

+ 7 - 134
src/i18n/zh.js

@@ -1,141 +1,14 @@
+import header from './modules/zh/header.js';
+import manage from './modules/zh/manage.js';
+import toast from './modules/zh/toast.js';
+
 export default {
     confirm: {
         text: '确认'
     },
-    manage: {
-        "information": {
-            "uploadTip": "图片大小不能大于",
-            "editInformation": "修改信息",
-            "editAddressLinkText": "修改地址",
-            "editInfo": "修改账号信息",
-            "gotoPay": "购买权益",
-            "memberDevice": "权益相机",
-            "expiredDownload": "剩余下载",
-            "takePhotos": "拍摄场景",
-            "defaultAddress": "默认收货地址",
-            "informationOverview": "账户概览",
-            "uploadAvatar": "上传头像",
-            "uploadAvatarTips": "推荐分辨率为:512*512px,<br/>允许JPG、PNG格式,小于1MB",
-            "userName": "账号",
-            "nickName": "昵称",
-            "email": "邮箱",
-            "cameraCount": "相机数量",
-            "memberCount": "权益数量",
-            "tai": "台",
-            "ci": "次",
-            "ge": "个",
-            "tai1": "(台)",
-            "ci1": "(次)",
-            "ge1": "(个)",
-            "editAddress": {
-                "editAddress": "修改收货地址",
-                "country": "国家/地区",
-                "province": "省",
-                "city": "市",
-                "qu": "区",
-                "addressDetail": "详细地址",
-                "receiver": "收件人",
-                "receiverPhone": "手机号码",
-                "internationalCity": "城市",
-                "internationalProvince": "州/省/地区"
-            },
-            "changePassword": {
-                "changePassword": "修改密码",
-                "verCode": "验证码",
-                "newPassword": "新密码",
-                "confirmNewPassword": "确认密码"
-            },
-            "memberTable": {
-                "deviceMember": "会员权益",
-                "bindDeviceNum": "授权相机{num}台",
-                "snInputPlaceHolder": "搜索相机S/N码",
-                "searchNoData": "抱歉,没有找到相关信息。",
-                "nodataPre": "请先购买会员权益",
-                "nodataGoBuy": "购买权益",
-                "isExpired": "已过期"
-            },
-            "nameArr": {
-                "information": "账号信息",
-                "scene": "场景管理",
-                "order": "我的订单",
-                "device": "我的相机",
-                "consumption": "消费记录",
-                "change": "修改密码",
-                "logout": "退出登录",
-                "products": "应用中心"
-            },
-            "deviceSettings": [
-                {
-                    "name": "security",
-                    "items": [
-                        {
-                            "name": "场景管理",
-                            "to": {
-                                "name": "scene"
-                            }
-                        },
-                        {
-                            "name": "退出登录",
-                            "to": "logout"
-                        }
-                    ]
-                }
-            ]
-        },
-    },
-    header: {
-        "core_product": "核心产品",
-        "solutions": "行业解决方案",
-        "solutionsText": "四维时代致力于人工智能三维数字化技术<br/>的研究和应用",
-        "kankan_space": "经典案例",
-        "core_tech": "核心技术",
-        "service": "服务支持",
-        "about": "关于我们",
-        "online_shop": "商城",
-        "foreign": "中德合作",
-        "solutionsHouse": "房产营销",
-        "solutionsExi": "智慧城市",
-        "solutionsSubject": "博物馆",
-        "solutionsShop": "VR购物",
-        "solutionsSec": "刑侦消防",
-        "serviceApp": "App 下载",
-        "joinUs": "加入我们",
-        "serviceUse": "使用教程",
-        "serviceBaoxiu": "售后服务",
-        "serviceVideo": "视频教程",
-        "aboutNews": "新闻中心",
-        "aboutAgent": "成为经销商",
-        "aboutCompany": "公司介绍",
-        "mallPro": "四维看看",
-        "kankanMinion": "四维看见",
-        "Mega": "四维深时",
-        "mallPeijian": "精选配件",
-        "tripod": "三脚架套装",
-        "USBdrive": "U盘",
-        "Battery": "电池",
-        "addService": "会员权益",
-        "corePruductItemPro": "四维看看",
-        "corePruductItemSxz": "四维 • 随心装",
-        "footer": {
-            "bannerTitle": "四维看看,让空间讲故事",
-            "find": "发现精彩",
-            "saleEmail": "销售合作",
-            "meitiEmail": "媒体采访",
-            "phone": "联系电话",
-            "find4D": "探索四维",
-            "kankan": "四维时代",
-            "zhongde": "中德人工智能研究院",
-            "moku": "四维模库",
-            "workTime": "周一至周五 9:00-18:30"
-        },
-        "moreName": {
-            "1": "装修家装",
-            "2": "商圈",
-            "3": "线上会展",
-            "4": "地下管网",
-            "5": "BIM"
-        }
-    },
+    manage,
+    header,
+    toast,
     payInfo: {
         payErr: '支付异常',
         payfail: '支付失败',

+ 15 - 15
src/router/pcRoute.ts

@@ -1,48 +1,48 @@
-const pc = () => import('../components/pc/index.vue')
-const pcHome = () => import('../views/pc/index.vue')
-const information = () => import('../views/pc/information/index.vue')
-const scene = () => import('../views/pc/scene/index.vue')
-const order = () => import('../views/pc/order/index.vue')
-const device = () => import('../views/pc/device/index.vue')
-const appProduct = () => import('../views/pc/appProduct/index.vue')
+const Pc = () => import('../components/pc/index.vue')
+const PcHome = () => import('../views/pc/index.vue')
+const Information = () => import('../views/pc/information/index.vue')
+const Scene = () => import('../views/pc/scene/index.vue')
+const Order = () => import('../views/pc/order/index.vue')
+const Device = () => import('../views/pc/device/index.vue')
+const AppProduct = () => import('../views/pc/appProduct/index.vue')
 const routesP = [{
   path: '/',
-  name: 'Pc',
+  name: 'pc',
   redirect: '/',
-  component: pc,
+  component: Pc,
   children: [{
     path: '/',
     name: 'index',
-    component: pcHome
+    component: PcHome
   }, {
     name: 'information',
     path: '/information',
-    component: information,
+    component: Information,
     meta: { hideFooterFind: false, requireAuth: true }
   },
   {
     name: 'scene',
     path: '/scene',
-    component: scene,
+    component: Scene,
     meta: { hideFooterFind: false, requireAuth: true }
   },
   {
     name: 'order',
     path: '/order',
-    component: order,
+    component: Order,
     meta: { hideFooterFind: false, requireAuth: true }
 
   },
   {
     name: 'device',
     path: '/device',
-    component: device,
+    component: Device,
     meta: { hideFooterFind: false, requireAuth: true }
   },
   {
     name: 'appProduct',
     path: '/appProduct',
-    component: appProduct,
+    component: AppProduct,
     meta: { hideFooterFind: false, requireAuth: true }
   }]
 

+ 16 - 2
src/stores/user.ts

@@ -1,13 +1,17 @@
 import { defineStore } from 'pinia';
+import { getUserInfo } from '@/api/user'
 // defineStore 方法有两个参数,第一个参数是模块化名字(也就相当于身份证一样,不能重复)
 
 // 第二个参数是选项,对象里面有三个属性,相比于vuex 少了一个 mutations.
 export const useUserStore = defineStore('user', {
   state(){  // 存放的就是模块的变量
     return {
-      token: localStorage.getItem('token'),
+      token: localStorage.getItem('token') || 'eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMzYzMTI2MjkyNiIsImxvZ2luVHlwZSI6InVzZXIiLCJ1c2VyTmFtZSI6IjEzNjMxMjYyOTI2IiwiaWF0IjoxNzU4ODU2MzkzLCJqdGkiOiI3MmY0NWYwMC1iOTFkLTQ1ZGItYWIzZS1iOGNlNGVhNDNkMTMifQ.PG85Q044plwHvak1aRGgKXYYsH1hXhueKK1X-2Q65Lo',
       openId: localStorage.getItem('openId'),
-      isEur: window.location.hostname.includes('eur'),
+      isLogin: false,
+      info: {
+
+      },
     }
   },
   getters:{ // 相当于vue里面的计算属性,可以缓存数据
@@ -16,12 +20,22 @@ export const useUserStore = defineStore('user', {
     },
     getOpenId(state){
       return state.openId || localStorage.getItem('openId')
+    },
+    getUserInfo(state){
+      return state.info || localStorage.getItem('info')
     }
   },
   actions:{ // 可以通过actions 方法,改变 state 里面的值。
     setUserOpenId(value:string){
       this.openId = value
       localStorage.setItem('openId', value,)
+    },
+    async getInfo(){
+      let infoRes = await getUserInfo()
+      console.log('infoRes', infoRes)
+      this.info = infoRes
+      this.isLogin = true
+
     }
   }
 })

+ 27 - 8
src/utils/api.js

@@ -1,9 +1,14 @@
 import axios from "axios";
+import { useUserStore } from '@/stores/user'
+import i18n from '@/i18n/index.js'
 import { ElLoading, ElMessage } from "element-plus";
 let current = (localStorage && localStorage.getItem('language')) || 'zh'
 let token = (localStorage && localStorage.getItem('token')) || 'eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxNTkxNTgxNjA0MSIsImxvZ2luVHlwZSI6InVzZXIiLCJ1c2VyTmFtZSI6IjE1OTE1ODE2MDQxIiwiaWF0IjoxNjgxODAzNzY1LCJqdGkiOiJhMDU4M2EwZS01M2EzLTQ1YTUtOTI1ZS1kZDgzYzU5Y2Y5MGMifQ.bdu5jqbSxSlo9LH4w_uPEuP67DUJk6w5Yqnu633OtQI'
 // request是一个axios实例,每一个实例你都可以单独定制它的baseURL,超时时间,请求头和一些其他配置项。
 const baseUrl = import.meta.env.VITE_BASE_URL; //接口统一域名
+let store = null
+const timeZone = new Date().getTimezoneOffset()
+const lang = i18n.global.locale;
 const instance = axios.create({
     baseURL: baseUrl,
     // timeout: 60 * 1000, //设置超时
@@ -11,9 +16,9 @@ const instance = axios.create({
         "Content-Type": "application/json;charset=UTF-8;",
         "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
         ".AspNetCore.Culture": "c=zh-Hans|uic=zh-Hans",
-        token:token,
+        token: token,
         current,
-        lang:current,
+        lang: current,
     },
 });
 
@@ -42,8 +47,14 @@ const hideLoading = () => {
 //请求拦截器
 instance.interceptors.request.use(
     (config) => {
-        console.log('config',config.loading,'if',config.loading != true)
-        if(!config.loading){
+        if (!store) store = useUserStore()
+        console.log('config', config.loading, 'if', store)
+        token = store.token
+        if (token) {
+            // 判断是否存在token,如果存在的话,则每个http header都加上token
+            config.headers.token = token //请求头加上token
+        }
+        if (!config.loading) {
             showLoading();
         }
         // 每次发送请求之前判断是否存在token,如果存在,则统一在http请求的header都加上token,不用每次请求都手动添加了
@@ -61,10 +72,18 @@ instance.interceptors.request.use(
 //响应拦截器
 instance.interceptors.response.use(
     (response) => {
+        console.log('response', i18n, response.data)
+        let t = i18n.global.t;
+        let code = Number(response.data.code)
+
         hideLoading();
-        if (response.data.code !== 200) {
-            ElMessage.error(response.data.message);
-            return  Promise.reject(response.data)
+        if(code == 3004){
+            ElMessage.error(t(`toast.${code}`) || response.data.message);
+            throw response.data.msg || response.data.message;
+            // window.location.href = '/#/login/login?from=%2F'
+        }else if (code !== 200 && code !== 0) {
+            ElMessage.error(t(`toast.${code}`) || response.data.message);
+            return Promise.reject(response.data)
             // router.push("/");
         }
         else return response.data?.data;
@@ -75,7 +94,7 @@ instance.interceptors.response.use(
         let message = "";
         if (error.response && error.response.status) {
             const status = error.response.status;
-            console.log('Error',error.response)
+            console.log('Error', error.response)
             switch (status) {
                 case 400:
                     message = "请求错误";

+ 2 - 2
src/views/mobile/vite.config.ts

@@ -44,12 +44,12 @@ export default defineConfig({
   server: {
     proxy: {
       '/service': {
-        target: 'https://testeur.4dkankan.com/',
+        target: 'https://test.4dkankan.com/',
         changeOrigin: true,
         // rewrite: (path) => path.replace(/^\/api/, '')
       },
       '/ucenter': {
-        target: 'https://testeur.4dkankan.com/',
+        target: 'https://test.4dkankan.com/',
         changeOrigin: true,
         // rewrite: (path) => path.replace(/^\/api/, '')
       }

+ 2 - 1
src/views/pc/device/index.vue

@@ -12,7 +12,8 @@ const userStore = useUserStore();
 const isEur = userStore.isEur
 </script>
 <template>
-  <div class="pcPage">mobilePage
+  <div class="pcPage">
+      <h-icon class="icon" type="sousuo" />
   </div>
 </template>
 

+ 2 - 2
vite.config.ts

@@ -46,12 +46,12 @@ export default defineConfig({
   server: {
     proxy: {
       '/service': {
-        target: 'https://testeur.4dkankan.com/',
+        target: 'https://test.4dkankan.com/',
         changeOrigin: true,
         // rewrite: (path) => path.replace(/^\/api/, '')
       },
       '/ucenter': {
-        target: 'https://testeur.4dkankan.com/',
+        target: 'https://test.4dkankan.com/',
         changeOrigin: true,
         // rewrite: (path) => path.replace(/^\/api/, '')
       }