소스 검색

Merge branch 'dev' of https://git.citupro.com/zhengnaiwen_citu/menduner into dev

lifanagju_citu 6 달 전
부모
커밋
d0054a9fc3

+ 0 - 3
components.d.ts

@@ -70,7 +70,4 @@ declare module 'vue' {
     VerifySlide: typeof import('./src/components/Verifition/Verify/VerifySlide.vue')['default']
     WangEditor: typeof import('./src/components/FormUI/wangEditor/index.vue')['default']
   }
-  export interface ComponentCustomProperties {
-    vLoading: typeof import('element-plus/es')['ElLoadingDirective']
-  }
 }

+ 7 - 0
src/api/Verifition.js

@@ -27,3 +27,10 @@ export const reqCheck = async (data) => {
     data
   })
 }
+
+export const sendError = async (data) => {
+  return await request.post({
+    url: '/app-api/menduner/system/error-record/create',
+    data
+  })
+}

+ 9 - 0
src/api/mall/user.js

@@ -0,0 +1,9 @@
+import request from '@/config/axios'
+
+// 获取订单分页
+export const getMallOrderPage = async (params) => {
+  return request.get({
+    url: '/app-api/trade/order/page',
+    params
+  })
+}

+ 69 - 1
src/config/axios/service.js

@@ -12,11 +12,12 @@ import { encryptionFun } from '@/utils/openEncryption'
 import { rewardEventTrackClick } from '@/api/integral'
 import errorCode from './errorCode'
 import { useI18n } from '@/hooks/web/useI18n'
+import { sendError } from '@/api/Verifition'
 
 // import { resetRouter } from '@/router'
 // import { deleteUserCache } from '@/hooks/web/useCache'
 
-
+const errorData = []
 
 const tenantEnable = import.meta.env.VITE_APP_TENANT_ENABLE
 const { result_code, base_url, request_timeout } = config
@@ -109,7 +110,25 @@ service.interceptors.request.use(
         ...config.data,
         ...config.params
       }
+      /**
+       * header
+       * params: { data, params, raw }
+       * content
+       */
       const header = encryptionFun({raw, body, appId: 'web_client', AppSecret: 'fa0fc0b5098b974b'})
+      const content = {
+        data: config.data,
+        params: config.params,
+        body,
+        raw,
+        config,
+        browserInfo: getBrowserInfo()
+      }
+      errorData.push({
+        time: header.timestamp,
+        url: config.url,
+        content
+      })
       Object.assign(config.headers, header)
     }
     
@@ -164,6 +183,7 @@ service.interceptors.response.use(
     const code = data.code || result_code
     // 获取错误信息
     const msg = data.msg || errorCode[code] || errorCode['default']
+    const _index = errorData.findIndex(e => e.url === config.url && e.time === +config.headers.timestamp)
     if (ignoreMsgs.indexOf(msg) !== -1) {
       // 如果是忽略的错误码,直接返回 msg 异常
       return Promise.reject(msg)
@@ -231,10 +251,19 @@ service.interceptors.response.use(
         // 未注册过的手机号将code码返回
         return Promise.reject(data)
       } else {
+        if (_index > -1) {
+          // 保存错误信息
+          sendError({ content: JSON.stringify(errorData[_index].content) })
+          // 移除
+          errorData.splice(_index, 1)
+        }
         Snackbar.error(msg)
       }
       return Promise.reject(msg)
     }
+    if (_index > -1) {
+      errorData.splice(_index, 1)
+    }
     // 请求成功后触发获取积分
     if (response.config.headers?.Authorization) {
       const url = getSuffixAfterPrefix(response.config.url)
@@ -306,4 +335,43 @@ const getIntegral = (url, store) => {
     }, 2000)
   })
 }
+
+// 获取浏览器信息
+function getBrowserInfo() {  
+  const ua = navigator.userAgent; // 获取用户代理字符串  
+  let browserName, fullVersion, majorVersion;  
+
+  // 检测浏览器  
+  if (ua.includes("Firefox")) {  
+      // Firefox 浏览器  
+      browserName = "Firefox";  
+      fullVersion = ua.split("Firefox/")[1].split(" ")[0];  
+  } else if (ua.includes("Chrome")) {  
+      // Chrome 浏览器  
+      browserName = "Chrome";  
+      fullVersion = ua.split("Chrome/")[1].split(" ")[0];  
+  } else if (ua.includes("Safari")) {  
+      // Safari 浏览器  
+      browserName = "Safari";  
+      fullVersion = ua.split("Version/")[1].split(" ")[0];  
+  } else if (ua.includes("MSIE") || ua.includes("Trident")) {  
+      // Internet Explorer  
+      browserName = "Internet Explorer";  
+      const version = ua.includes("MSIE") ? ua.split("MSIE ")[1] : ua.split("rv:")[1];  
+      fullVersion = version.split(";")[0];  
+  } else {  
+      browserName = "Unknown";  
+      fullVersion = "Unknown";  
+  }  
+
+  // 提取主要版本号  
+  majorVersion = parseInt(fullVersion.split('.')[0], 10);  
+
+  return {  
+      browserName,  
+      fullVersion,  
+      majorVersion,  
+      userAgent: ua,  
+  };  
+}  
 export { service }

+ 4 - 0
src/store/user.js

@@ -151,7 +151,11 @@ export const useUserStore = defineStore('user',
         this.userInfo = {}
         this.baseInfo = {}
         this.accountInfo = {}
+
+        // 商城模版数据不清楚缓存
+        const mallTemplate = localStorage.getItem('mallTemplate')
         localStorage.clear()
+        localStorage.setItem('mallTemplate', mallTemplate)
       },
       // 切换为招聘者
       async changeRole (res) {

+ 1 - 1
src/version.js

@@ -1,2 +1,2 @@
 // 版本号
-export const vue_version = 'v24.12.19.1226'
+export const vue_version = 'v24.12.19.1908'

+ 13 - 1
src/views/mall/components/navbar.vue

@@ -3,7 +3,7 @@
     <div class="default-width d-flex align-center justify-space-between">
       <div class="header-link">
         <span class="cursor-pointer" :class="{'active-route' : isActive('/mall')}" @click="router.push('/mall')">首页</span>
-        <span class="cursor-pointer mx-8" :class="{'active-route' : isActive('/mall/user', true)}" @click="router.push('/mall/user')">
+        <span class="cursor-pointer mx-8" :class="{'active-route' : isActive('/mall/user', true)}" @click="handleTo('/mall/user')">
           <v-icon>mdi-account-circle-outline</v-icon>
           我的
         </span>
@@ -35,13 +35,25 @@
 defineOptions({ name: 'formPage'})
 import { computed, ref } from 'vue'
 import { useRouter } from 'vue-router'
+import { getToken } from '@/utils/auth'
+import Snackbar from '@/plugins/snackbar'
 
+const emit = defineEmits(['login'])
 const router = useRouter()
 const isActive = computed(() => (path, hasChild) => {
   const currentPath = router.currentRoute.value.path
   return hasChild ? currentPath.includes(path) : currentPath === path
 })
 
+const handleTo = (path) => {
+  if (!getToken()) {
+    Snackbar.warning('请先登录')
+    emit('login', path)
+    return
+  }
+  router.push(path)
+}
+
 const inputVal = ref('')
 const handleSearch = () => {}
 </script>

+ 1 - 0
src/views/mall/home/components/hotGoods.vue

@@ -36,6 +36,7 @@ const router = useRouter()
 const goodList = ref([])
 const getGoodsList = async () => {
   const productCard = props.templateData?.home?.components.find(item => item.id === 'ProductCard')
+  if (!productCard) return
   const ids = productCard.property.spuIds
   if (!ids.length) return
   const data = await getProductByIds(ids)

+ 18 - 4
src/views/mall/home/index.vue

@@ -1,7 +1,7 @@
 <template>
   <div style="min-width: 1184px;" class="white-bgc">
     <!-- 导航栏 -->
-    <Navbar />
+    <Navbar @login="handleLogin" />
 
     <!-- 轮播图 -->
     <Carousel :templateData="template" class="mb-10" style="max-height: 594.5px;" />
@@ -21,7 +21,7 @@
 
 <script setup>
 defineOptions({ name: 'mall-home-index'})
-import { ref } from 'vue'
+import { ref, onMounted } from 'vue'
 import Navbar from '../components/navbar.vue'
 import Carousel from './components/carousel.vue'
 import HotGoods from './components/hotGoods.vue'
@@ -29,9 +29,15 @@ import PointExchange from '../pointExchange'
 import loginPage from '@/views/common/loginDialog.vue'
 import { useMallStore } from '@/store/mall'
 import { useUserStore } from '@/store/user'
+import Snackbar from '@/plugins/snackbar'
+import { useRouter } from 'vue-router'
+
+const router = useRouter()
 
 // 获取装修模版
-useMallStore().getMallDiyTemplate()
+onMounted(async () => {
+  await useMallStore().getMallDiyTemplate()
+})
 
 let template = ref(JSON.parse(localStorage.getItem('mallTemplate')) || {})
 useMallStore().$subscribe((mutation, state) => {
@@ -46,14 +52,22 @@ userStore.$subscribe((mutation, state) => {
 })
 
 const showLogin = ref(false)
-const handleLogin = () => {
+const returnUrl = ref('')
+const handleLogin = (path) => {
   showLogin.value = true // 打开快速登录弹窗
+  returnUrl.value = path
 }
 
 // 快速登录
 const loginSuccess = () => {
   showLogin.value = false
   Snackbar.success('登录成功')
+  if (returnUrl.value) {
+    router.push(returnUrl.value)
+    setTimeout(() => {
+      returnUrl.value = ''
+    }, 1000)
+  }
 }
 
 const loginClose = () => {

+ 6 - 6
src/views/mall/pointExchange/index.vue

@@ -3,9 +3,9 @@
     <div class="d-flex justify-space-between color-666">
       <div class="color-primary" style="font-size: 25px;">积分兑换</div>
       <div>
-        <span class="cursor-pointer active" @click="router.push('/recruit/personal/personalCenter/wallet')">当前账户积分:{{ point }}</span>
+        <span class="cursor-pointer active" @click="handleTo('/recruit/personal/personalCenter/wallet')">当前账户积分:{{ point }}</span>
         <span class="septal-line"></span>
-        <span class="cursor-pointer active" @click="handleToExchangeRecord">兑换记录</span>
+        <span class="cursor-pointer active" @click="handleTo('/mall/pointExchange/records')">兑换记录</span>
       </div>
     </div>
     <div class="goods-box mt-5">
@@ -169,14 +169,14 @@ const handleSubmit = async () =>{
   await useUserStore().getUserAccountInfo()
 }
 
-// 积分兑换记录
-const handleToExchangeRecord = () => {
+// 积分兑换记录、积分明细
+const handleTo = (path) => {
   if (!getToken()) {
     Snackbar.warning('请先登录')
-    emit('login')
+    emit('login', path)
     return
   }
-  router.push('/mall/pointExchange/records')
+  router.push(path)
 }
 
 </script>

+ 1 - 1
src/views/mall/user/index.vue

@@ -3,7 +3,7 @@
   <div class="d-flex parent default-width mb-5">
     <v-card class="left">
       <v-list color="primary">
-        <div class="text-center mb-3">
+        <div class="text-center my-3">
           <v-avatar :image="getUserAvatar(baseInfo?.avatar, baseInfo?.sex)" size="100"></v-avatar>
           <p class="mt-2 color-primary font-weight-bold">{{ baseInfo?.name }}</p>
         </div>

+ 89 - 2
src/views/mall/user/order/index.vue

@@ -1,11 +1,98 @@
 <template>
-  <div>order-index</div>
+  <div>
+    <v-tabs v-model="tab" align-tabs="start" color="primary" bg-color="#f7f8fa" @update:modelValue="getOrderPage">
+      <v-tab v-for="(val, i) in tabList" :key="i" :value="val.value">{{ val.title }}</v-tab>
+    </v-tabs>
+    <div v-if="orderList.length" class="mt-3">
+      <div v-for="val in orderList" :key="val.id" class="order-item mb-3">
+        <div class="order-item-header px-5">
+          <div style="width: 40%;">
+            <span>订单号:{{ val.no }}</span>
+            <span class="ml-5">{{ timesTampChange(val.createTime) }}</span>
+          </div>
+          <div class="text-end color-warning" style="flex: 1">
+            待发货
+          </div>
+        </div>
+        <div v-for="k in val.items" :key="k.id" class="order-item-goods px-3 pt-3">
+          <div class="d-flex">
+            <div style="width: 90px; height: 90px">
+              <v-img :src="k.picUrl"></v-img>
+            </div>
+            <div class="ml-5">
+              <p class="font-size-15">{{ k.spuName }}</p>
+              <p>
+                <span class="color-333">¥{{ fen2yuan(k.price) }}</span>
+                <span v-if="k.count" class="color-999 font-size-13 ml-1">x {{ k.count }}</span>
+              </p>
+            </div>
+          </div>
+          <v-divider class="mt-3"></v-divider>
+        </div>
+        <div class="text-end pa-3 font-size-13 color-666">共{{ val.productCount }}件商品,合计:¥{{ fen2yuan(val.payPrice) }}</div>
+      </div>
+    </div>
+    <Empty v-else :elevation="false" :message="tab === -1 ? '暂无订单' : '暂无' + tabList.find(e => e.value === tab).title + '订单'"></Empty>
+  </div>
 </template>
 
 <script setup>
 defineOptions({ name: 'mall-user-order-index'})
+import { ref } from 'vue'
+import { getMallOrderPage } from '@/api/mall/user'
+import { getDict } from '@/hooks/web/useDictionaries'
+import { timesTampChange } from '@/utils/date'
+import { fen2yuan } from '@/hooks/web/useGoods'
+
+const tab = ref(-1)
+const tabList = [
+  { title: '全部', value: -1 },
+  { title: '待付款', value: 0 },
+  { title: '待发货', value: 10 },
+  { title: '待收货', value: 20 },
+  { title: '待评价', value: 30 }
+]
+const total = ref(0)
+const queryParams = ref({
+  pageNo: 1,
+  pageSize: 10
+})
+
+// 获取订单列表
+const orderList = ref([])
+const getOrderPage = async () => {
+  queryParams.value.status = tab.value
+  if (tab.value === -1) delete queryParams.value.status
+  if (tab.value === 30) queryParams.value.commentStatus = false
+  const result = await getMallOrderPage(queryParams.value)
+  orderList.value = result.list
+  total.value = result.total
+}
+getOrderPage()
+
+const getDictData = async (dictType, value) => {
+  const { data } = await getDict(dictType)
+  console.log(data, 'dict-data')
+  const obj = data.find(e => e.value === value)
+  return obj.label
+}
+// console.log(getDictLabel('trade_order_status', 10), 'getDictLabel')
+
 </script>
 
 <style scoped lang="scss">
-
+.order-item {
+  border: 1px solid #dbdbdb;
+  &-header {
+    display: flex;
+    background-color: #f2f4f7;
+    height: 36px;
+    line-height: 36px;
+    font-size: 13px;
+    color: #666;
+  }
+  &-goods {
+    // border-bottom: 1px solid #dbdbdb;
+  }
+}
 </style>