Selaa lähdekoodia

【功能完善】商城: 客服会员信息

puhui999 9 kuukautta sitten
vanhempi
sitoutus
fdee8d8628

+ 54 - 0
src/views/mall/promotion/kefu/components/member/MemberInfo.vue

@@ -25,6 +25,21 @@
       </div>
     </el-header>
     <el-main class="kefu-content">
+      <div v-if="!isEmpty(conversation)" v-loading="loading">
+        <!-- 基本信息 -->
+        <UserBasicInfo v-if="activeTab === '会员信息'" :user="user" mode="kefu">
+          <template #header>
+            <CardTitle title="基本信息" />
+          </template>
+        </UserBasicInfo>
+        <!-- 账户信息 -->
+        <el-card v-if="activeTab === '会员信息'" class="h-full" shadow="never">
+          <template #header>
+            <CardTitle title="账户信息" />
+          </template>
+          <UserAccountInfo :column="1" :user="user" :wallet="wallet" />
+        </el-card>
+      </div>
       <div v-show="!isEmpty(conversation)">
         <el-scrollbar ref="scrollbarRef" always @scroll="handleScroll">
           <!-- 最近浏览 -->
@@ -45,11 +60,17 @@ import { KeFuConversationRespVO } from '@/api/mall/promotion/kefu/conversation'
 import { isEmpty } from '@/utils/is'
 import { debounce } from 'lodash-es'
 import { ElScrollbar as ElScrollbarType } from 'element-plus/es/components/scrollbar/index'
+import { CardTitle } from '@/components/Card'
+import UserBasicInfo from '@/views/member/user/detail/UserBasicInfo.vue'
+import UserAccountInfo from '@/views/member/user/detail/UserAccountInfo.vue'
+import * as UserApi from '@/api/member/user'
+import * as WalletApi from '@/api/pay/wallet/balance'
 
 defineOptions({ name: 'MemberBrowsingHistory' })
 
 const activeTab = ref('会员信息')
 const tabActivation = computed(() => (tab: string) => activeTab.value === tab)
+
 /** tab 切换 */
 const productBrowsingHistoryRef = ref<InstanceType<typeof ProductBrowsingHistory>>()
 const orderBrowsingHistoryRef = ref<InstanceType<typeof OrderBrowsingHistory>>()
@@ -63,6 +84,8 @@ const handleClick = async (tab: string) => {
 const getHistoryList = async () => {
   switch (activeTab.value) {
     case '会员信息':
+      await getUserData()
+      await getUserWallet()
       break
     case '最近浏览':
       await productBrowsingHistoryRef.value?.getHistoryList(conversation.value)
@@ -110,6 +133,37 @@ const handleScroll = debounce(() => {
     loadMore()
   }
 }, 200)
+
+/* 用户钱包相关信息 */
+const WALLET_INIT_DATA = {
+  balance: 0,
+  totalExpense: 0,
+  totalRecharge: 0
+} as WalletApi.WalletVO // 钱包初始化数据
+const wallet = ref<WalletApi.WalletVO>(WALLET_INIT_DATA) // 钱包信息
+
+/** 查询用户钱包信息 */
+const getUserWallet = async () => {
+  if (!conversation.value.userId) {
+    wallet.value = WALLET_INIT_DATA
+    return
+  }
+  const params = { userId: conversation.value.userId }
+  wallet.value = (await WalletApi.getWallet(params)) || WALLET_INIT_DATA
+}
+
+const loading = ref(true) // 加载中
+const user = ref<UserApi.UserVO>({} as UserApi.UserVO)
+
+/** 获得用户 */
+const getUserData = async () => {
+  loading.value = true
+  try {
+    user.value = await UserApi.getUser(conversation.value.userId)
+  } finally {
+    loading.value = false
+  }
+}
 </script>
 
 <style lang="scss" scoped>

+ 4 - 2
src/views/member/user/detail/UserAccountInfo.vue

@@ -1,5 +1,5 @@
 <template>
-  <el-descriptions :column="2">
+  <el-descriptions :column="column">
     <el-descriptions-item>
       <template #label>
         <descriptions-item-label icon="svg-icon:member_level" label=" 等级 " />
@@ -50,7 +50,9 @@ import * as UserApi from '@/api/member/user'
 import * as WalletApi from '@/api/pay/wallet/balance'
 import { fenToYuan } from '@/utils'
 
-defineProps<{ user: UserApi.UserVO; wallet: WalletApi.WalletVO }>() // 用户信息
+withDefaults(defineProps<{ user: UserApi.UserVO; wallet: WalletApi.WalletVO; column?: number }>(), {
+  column: 2
+}) // 用户信息
 </script>
 <style lang="scss" scoped>
 .cell-item {

+ 78 - 17
src/views/member/user/detail/UserBasicInfo.vue

@@ -3,80 +3,141 @@
     <template #header>
       <slot name="header"></slot>
     </template>
-    <el-row>
+    <el-row v-if="mode === 'member'">
       <el-col :span="4">
-        <ElAvatar shape="square" :size="140" :src="user.avatar || undefined" />
+        <ElAvatar :size="140" :src="user.avatar || undefined" shape="square" />
       </el-col>
       <el-col :span="20">
         <el-descriptions :column="2">
           <el-descriptions-item>
             <template #label>
-              <descriptions-item-label label="用户名" icon="ep:user" />
+              <descriptions-item-label icon="ep:user" label="用户名" />
             </template>
             {{ user.name || '空' }}
           </el-descriptions-item>
           <el-descriptions-item>
             <template #label>
-              <descriptions-item-label label="昵称" icon="ep:user" />
+              <descriptions-item-label icon="ep:user" label="昵称" />
             </template>
             {{ user.nickname }}
           </el-descriptions-item>
           <el-descriptions-item label="手机号">
             <template #label>
-              <descriptions-item-label label="手机号" icon="ep:phone" />
+              <descriptions-item-label icon="ep:phone" label="手机号" />
             </template>
             {{ user.mobile }}
           </el-descriptions-item>
           <el-descriptions-item>
             <template #label>
-              <descriptions-item-label label="性别" icon="fa:mars-double" />
+              <descriptions-item-label icon="fa:mars-double" label="性别" />
             </template>
             <dict-tag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="user.sex" />
           </el-descriptions-item>
           <el-descriptions-item>
             <template #label>
-              <descriptions-item-label label="所在地" icon="ep:location" />
+              <descriptions-item-label icon="ep:location" label="所在地" />
             </template>
             {{ user.areaName }}
           </el-descriptions-item>
           <el-descriptions-item>
             <template #label>
-              <descriptions-item-label label="注册 IP" icon="ep:position" />
+              <descriptions-item-label icon="ep:position" label="注册 IP" />
             </template>
             {{ user.registerIp }}
           </el-descriptions-item>
           <el-descriptions-item>
             <template #label>
-              <descriptions-item-label label="生日" icon="fa:birthday-cake" />
+              <descriptions-item-label icon="fa:birthday-cake" label="生日" />
             </template>
-            {{ user.birthday ? formatDate(user.birthday) : '空' }}
+            {{ user.birthday ? formatDate(user.birthday as any) : '空' }}
           </el-descriptions-item>
           <el-descriptions-item>
             <template #label>
-              <descriptions-item-label label="注册时间" icon="ep:calendar" />
+              <descriptions-item-label icon="ep:calendar" label="注册时间" />
             </template>
-            {{ user.createTime ? formatDate(user.createTime) : '空' }}
+            {{ user.createTime ? formatDate(user.createTime as any) : '空' }}
           </el-descriptions-item>
           <el-descriptions-item>
             <template #label>
-              <descriptions-item-label label="最后登录时间" icon="ep:calendar" />
+              <descriptions-item-label icon="ep:calendar" label="最后登录时间" />
             </template>
-            {{ user.loginDate ? formatDate(user.loginDate) : '空' }}
+            {{ user.loginDate ? formatDate(user.loginDate as any) : '空' }}
           </el-descriptions-item>
         </el-descriptions>
       </el-col>
     </el-row>
+    <template v-if="mode === 'kefu'">
+      <ElAvatar :size="140" :src="user.avatar || undefined" shape="square" />
+      <el-descriptions :column="1">
+        <el-descriptions-item>
+          <template #label>
+            <descriptions-item-label icon="ep:user" label="用户名" />
+          </template>
+          {{ user.name || '空' }}
+        </el-descriptions-item>
+        <el-descriptions-item>
+          <template #label>
+            <descriptions-item-label icon="ep:user" label="昵称" />
+          </template>
+          {{ user.nickname }}
+        </el-descriptions-item>
+        <el-descriptions-item label="手机号">
+          <template #label>
+            <descriptions-item-label icon="ep:phone" label="手机号" />
+          </template>
+          {{ user.mobile }}
+        </el-descriptions-item>
+        <el-descriptions-item>
+          <template #label>
+            <descriptions-item-label icon="fa:mars-double" label="性别" />
+          </template>
+          <dict-tag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="user.sex" />
+        </el-descriptions-item>
+        <el-descriptions-item>
+          <template #label>
+            <descriptions-item-label icon="ep:location" label="所在地" />
+          </template>
+          {{ user.areaName }}
+        </el-descriptions-item>
+        <el-descriptions-item>
+          <template #label>
+            <descriptions-item-label icon="ep:position" label="注册 IP" />
+          </template>
+          {{ user.registerIp }}
+        </el-descriptions-item>
+        <el-descriptions-item>
+          <template #label>
+            <descriptions-item-label icon="fa:birthday-cake" label="生日" />
+          </template>
+          {{ user.birthday ? formatDate(user.birthday as any) : '空' }}
+        </el-descriptions-item>
+        <el-descriptions-item>
+          <template #label>
+            <descriptions-item-label icon="ep:calendar" label="注册时间" />
+          </template>
+          {{ user.createTime ? formatDate(user.createTime as any) : '空' }}
+        </el-descriptions-item>
+        <el-descriptions-item>
+          <template #label>
+            <descriptions-item-label icon="ep:calendar" label="最后登录时间" />
+          </template>
+          {{ user.loginDate ? formatDate(user.loginDate as any) : '空' }}
+        </el-descriptions-item>
+      </el-descriptions>
+    </template>
   </el-card>
 </template>
-<script setup lang="ts">
+<script lang="ts" setup>
 import { DICT_TYPE } from '@/utils/dict'
 import { formatDate } from '@/utils/formatTime'
 import * as UserApi from '@/api/member/user'
 import { DescriptionsItemLabel } from '@/components/Descriptions/index'
 
-const { user } = defineProps<{ user: UserApi.UserVO }>()
+withDefaults(defineProps<{ user: UserApi.UserVO; mode?: string }>(), {
+  mode: 'member'
+})
 </script>
-<style scoped lang="scss">
+<style lang="scss" scoped>
 .card-header {
   display: flex;
   justify-content: space-between;