Explorar el Código

Merge remote-tracking branch 'origin/dev' into owen_dev

owen hace 1 año
padre
commit
bce427f702

+ 15 - 0
src/api/member/address/index.ts

@@ -0,0 +1,15 @@
+import request from '@/config/axios'
+
+export interface AddressVO {
+  id: number
+  name: string
+  mobile: string
+  areaId: number
+  detailAddress: string
+  defaultStatus: boolean
+}
+
+// 查询用户收件地址列表
+export const getAddressList = async (params) => {
+  return await request.get({ url: `/member/address/list`, params })
+}

+ 10 - 29
src/api/member/user/index.ts

@@ -2,39 +2,20 @@ import request from '@/config/axios'
 
 export interface UserVO {
   id: number
-  mobile: string
-  password: string
-  status: number
-  registerIp: string
+  avatar: string | undefined
+  birthday: number | undefined
+  createTime: number | undefined
+  loginDate: number | undefined
   loginIp: string
-  loginDate: Date
-  nickname: string
-  avatar: string
-  name: string
-  sex: number
-  areaId: number
-  birthday: Date
   mark: string
-  createTime: Date
-}
-
-// TODO @梦:和 UserVO 搞成一个把。
-export interface UserBaseInfoVO {
-  id: number | undefined | null
   mobile: string
-  password: string | null | undefined
-  status: number
-  registerIp: string | null | undefined
-  loginIp: string | null | undefined
-  loginDate: Date | null | undefined
-  nickname: string | null | undefined
-  avatar: string | null | undefined
-  name: string | null | undefined
+  name: string | undefined
+  nickname: string | undefined
+  registerIp: string
   sex: number
-  areaId: number | null | undefined
-  birthday: Date | null | undefined
-  mark: string | null | undefined
-  createTime: Date | null | undefined
+  status: number
+  areaId: number | undefined
+  areaName: string | undefined
 }
 
 // 查询会员用户列表

+ 3 - 0
src/components/Card/index.ts

@@ -0,0 +1,3 @@
+import CardTitle from './src/CardTitle.vue'
+
+export { CardTitle }

+ 0 - 0
src/views/member/user/components/card-title.vue → src/components/Card/src/CardTitle.vue


+ 2 - 1
src/components/Descriptions/index.ts

@@ -1,3 +1,4 @@
 import Descriptions from './src/Descriptions.vue'
+import DescriptionsItemLabel from './src/DescriptionsItemLabel.vue'
 
-export { Descriptions }
+export { Descriptions, DescriptionsItemLabel }

+ 28 - 0
src/components/Descriptions/src/DescriptionsItemLabel.vue

@@ -0,0 +1,28 @@
+<script setup lang="ts">
+const { label } = defineProps({
+  label: {
+    type: String,
+    required: true
+  },
+  icon: {
+    type: String,
+    required: false
+  }
+})
+</script>
+
+<template>
+  <div class="cell-item">
+    <Icon :icon="icon" />
+    {{ label }}
+  </div>
+</template>
+
+<style scoped lang="scss">
+.cell-item {
+  display: inline;
+}
+.cell-item::after {
+  content: ':';
+}
+</style>

+ 1 - 1
src/router/modules/remaining.ts

@@ -434,7 +434,7 @@ const remainingRouter: AppRouteRecordRaw[] = [
     meta: { hidden: true },
     children: [
       {
-        path: 'user/detail',
+        path: 'user/detail/:id',
         name: 'MemberUserDetail',
         meta: {
           title: '会员详情',

+ 1 - 1
src/utils/formatTime.ts

@@ -11,7 +11,7 @@ import dayjs from 'dayjs'
  * @description format 季度 + 星期 + 几周:"YYYY-mm-dd HH:MM:SS WWW QQQQ ZZZ"
  * @returns 返回拼接后的时间字符串
  */
-export function formatDate(date: Date, format?: string): string {
+export function formatDate(date: Date | number, format?: string): string {
   // 日期不存在,则返回空
   if (!date) {
     return ''

+ 0 - 14
src/views/member/user/components/address-list.vue

@@ -1,14 +0,0 @@
-<script lang="ts">
-import { defineComponent } from 'vue'
-
-export default defineComponent({
-  name: 'AddressList'
-})
-</script>
-
-<!-- TODO @梦:可以读 address 表 -->
-<template>
-  <div>收货地址列表</div>
-</template>
-
-<style scoped lang="scss"></style>

+ 0 - 5
src/views/member/user/components/account-info.vue → src/views/member/user/detail/UserAccountInfo.vue

@@ -46,11 +46,6 @@
     </el-descriptions-item>
   </el-descriptions>
 </template>
-<script lang="ts" setup>
-defineComponent({
-  name: 'AccountInfo'
-})
-</script>
 <style scoped lang="scss">
 .cell-item {
   display: inline;

+ 54 - 0
src/views/member/user/detail/UserAddressList.vue

@@ -0,0 +1,54 @@
+<template>
+  <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
+    <el-table-column label="地址编号" align="center" prop="id" width="150px" />
+    <el-table-column label="收件人名称" align="center" prop="name" width="150px" />
+    <el-table-column label="手机号" align="center" prop="mobile" width="150px" />
+    <el-table-column label="地区编码" align="center" prop="areaId" width="150px" />
+    <el-table-column label="收件详细地址" align="center" prop="detailAddress" />
+    <el-table-column label="是否默认" align="center" prop="defaultStatus" width="150px">
+      <template #default="scope">
+        <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="Number(scope.row.defaultStatus)" />
+      </template>
+    </el-table-column>
+    <el-table-column
+      label="创建时间"
+      align="center"
+      prop="createTime"
+      :formatter="dateFormatter"
+      width="180px"
+    />
+  </el-table>
+</template>
+<script lang="ts" setup>
+import { DICT_TYPE } from '@/utils/dict'
+import { dateFormatter } from '@/utils/formatTime'
+import * as AddressApi from '@/api/member/address'
+
+const { userId }: { userId: number } = defineProps({
+  userId: {
+    type: Number,
+    required: true
+  }
+})
+
+const loading = ref(true) // 列表的加载中
+const total = ref(0) // 列表的总页数
+const list = ref([]) // 列表的数据
+
+/** 查询列表 */
+const getList = async () => {
+  loading.value = true
+  try {
+    list.value = await AddressApi.getAddressList({ userId })
+  } finally {
+    loading.value = false
+  }
+}
+
+/** 初始化 **/
+onMounted(() => {
+  getList()
+})
+</script>
+
+<style scoped lang="scss"></style>

+ 90 - 0
src/views/member/user/detail/UserBasicInfo.vue

@@ -0,0 +1,90 @@
+<template>
+  <el-card shadow="never">
+    <template #header>
+      <slot name="header"></slot>
+    </template>
+    <el-row>
+      <el-col :span="4">
+        <ElAvatar shape="square" :size="140" :src="user.avatar || undefined" />
+      </el-col>
+      <el-col :span="20">
+        <el-descriptions :column="2">
+          <el-descriptions-item>
+            <template #label>
+              <descriptions-item-label label="用户名" icon="ep:user" />
+            </template>
+            {{ user.name || '空' }}
+          </el-descriptions-item>
+          <el-descriptions-item>
+            <template #label>
+              <descriptions-item-label label="昵称" icon="ep:user" />
+            </template>
+            {{ user.nickname }}
+          </el-descriptions-item>
+          <el-descriptions-item label="手机号">
+            <template #label>
+              <descriptions-item-label label="手机号" icon="ep:phone" />
+            </template>
+            {{ user.mobile }}
+          </el-descriptions-item>
+          <el-descriptions-item>
+            <template #label>
+              <descriptions-item-label label="性别" icon="fa:mars-double" />
+            </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" />
+            </template>
+            {{ user.areaName }}
+          </el-descriptions-item>
+          <el-descriptions-item>
+            <template #label>
+              <descriptions-item-label label="注册 IP" icon="ep:position" />
+            </template>
+            {{ user.registerIp }}
+          </el-descriptions-item>
+          <el-descriptions-item>
+            <template #label>
+              <descriptions-item-label label="生日" icon="fa:birthday-cake" />
+            </template>
+            {{ user.birthday ? formatDate(user.birthday) : '空' }}
+          </el-descriptions-item>
+          <el-descriptions-item>
+            <template #label>
+              <descriptions-item-label label="注册时间" icon="ep:calendar" />
+            </template>
+            {{ user.createTime ? formatDate(user.createTime) : '空' }}
+          </el-descriptions-item>
+          <el-descriptions-item>
+            <template #label>
+              <descriptions-item-label label="最后登录时间" icon="ep:calendar" />
+            </template>
+            {{ user.loginDate ? formatDate(user.loginDate) : '空' }}
+          </el-descriptions-item>
+        </el-descriptions>
+      </el-col>
+    </el-row>
+  </el-card>
+</template>
+<script setup lang="ts">
+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 }: { user: UserApi.UserVO } = defineProps({
+  user: {
+    type: UserApi.UserVO,
+    required: true
+  }
+})
+</script>
+<style scoped lang="scss">
+.card-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+</style>

+ 4 - 8
src/views/member/user/components/point-list.vue → src/views/member/user/detail/UserPointList.vue

@@ -67,7 +67,6 @@
         :formatter="dateFormatter"
         width="180"
       />
-      <el-table-column label="用户" align="center" prop="nickname" width="200" />
       <el-table-column label="获得积分" align="center" prop="point" width="100">
         <template #default="scope">
           <el-tag v-if="scope.row.point > 0" class="ml-2" type="success" effect="dark">
@@ -101,8 +100,6 @@ import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
 import { dateFormatter } from '@/utils/formatTime'
 import * as RecordApi from '@/api//member/point/record'
 
-defineOptions({ name: 'PointList' })
-
 const loading = ref(true) // 列表的加载中
 const total = ref(0) // 列表的总页数
 const list = ref([]) // 列表的数据
@@ -112,7 +109,7 @@ const queryParams = reactive({
   bizType: undefined,
   title: null,
   createDate: [],
-  userId: null
+  userId: NaN
 })
 const queryFormRef = ref() // 搜索的表单
 
@@ -140,9 +137,8 @@ const resetQuery = () => {
   handleQuery()
 }
 
-// TODO @梦:改成 userId 哈
-const { memberId } = defineProps({
-  memberId: {
+const { userId } = defineProps({
+  userId: {
     type: Number,
     required: true
   }
@@ -150,7 +146,7 @@ const { memberId } = defineProps({
 
 /** 初始化 **/
 onMounted(() => {
-  queryParams.userId = memberId
+  queryParams.userId = userId
   getList()
 })
 </script>

+ 4 - 7
src/views/member/user/components/sign-list.vue → src/views/member/user/detail/UserSignList.vue

@@ -48,7 +48,6 @@
   <ContentWrap>
     <el-table v-loading="loading" :data="list">
       <el-table-column label="编号" align="center" prop="id" />
-      <el-table-column label="签到用户" align="center" prop="nickname" />
       <el-table-column
         label="签到天数"
         align="center"
@@ -84,14 +83,13 @@
 import { dateFormatter } from '@/utils/formatTime'
 import * as SignInRecordApi from '@/api/member/signin/record'
 
-defineOptions({ name: 'SignList' })
-
 const loading = ref(true) // 列表的加载中
 const total = ref(0) // 列表的总页数
 const list = ref([]) // 列表的数据
 const queryParams = reactive({
   pageNo: 1,
   pageSize: 10,
+  userId: NaN,
   nickname: null,
   day: null,
   createTime: []
@@ -122,9 +120,8 @@ const resetQuery = () => {
   handleQuery()
 }
 
-// TODO @梦:改成 userId 哈
-const { memberId } = defineProps({
-  memberId: {
+const { userId } = defineProps({
+  userId: {
     type: Number,
     required: true
   }
@@ -132,7 +129,7 @@ const { memberId } = defineProps({
 
 /** 初始化 **/
 onMounted(() => {
-  queryParams.userId = memberId
+  queryParams.userId = userId
   getList()
 })
 </script>

+ 38 - 159
src/views/member/user/detail/index.vue

@@ -1,220 +1,106 @@
 <template>
   <div v-loading="loading">
-    <el-row :gutter="10" class="detail-info-warp">
+    <el-row :gutter="10">
       <!-- 左上角:基本信息 -->
       <el-col :span="14" class="detail-info-item">
-        <el-card shadow="never">
+        <UserBasicInfo :user="user">
           <template #header>
             <div class="card-header">
-              <!-- TODO @梦:如果不要小蓝线,是不是直接用 el-card 自带的 title 即可? -->
               <CardTitle title="基本信息" />
-              <el-button
-                v-if="user.id"
-                type="primary"
-                size="small"
-                text
-                @click="openForm('update', user.id)"
-              >
+              <el-button type="primary" size="small" text @click="openForm('update')">
                 编辑
               </el-button>
             </div>
           </template>
-          <el-row>
-            <el-col :span="4">
-              <ElAvatar shape="square" :size="140" :src="user.avatar || undefined" />
-            </el-col>
-            <el-col :span="20">
-              <el-descriptions :column="2">
-                <el-descriptions-item>
-                  <template #label>
-                    <div class="cell-item">
-                      <Icon icon="ep:user" />
-                      用户名
-                    </div>
-                  </template>
-                  {{ user.name || '空' }}
-                </el-descriptions-item>
-                <el-descriptions-item>
-                  <template #label>
-                    <div class="cell-item">
-                      <Icon icon="ep:user" />
-                      昵称
-                    </div>
-                  </template>
-                  {{ user.nickname }}
-                </el-descriptions-item>
-                <el-descriptions-item label="手机号">
-                  <template #label>
-                    <div class="cell-item">
-                      <Icon icon="ep:phone" />
-                      手机号
-                    </div>
-                  </template>
-                  {{ user.mobile }}
-                </el-descriptions-item>
-                <el-descriptions-item>
-                  <template #label>
-                    <div class="cell-item">
-                      <Icon icon="fa:mars-double" />
-                      性别
-                    </div>
-                  </template>
-                  <dict-tag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="user.sex" />
-                </el-descriptions-item>
-                <el-descriptions-item>
-                  <template #label>
-                    <div class="cell-item">
-                      <Icon icon="ep:location" />
-                      所在地
-                    </div>
-                  </template>
-                  <!-- TODO @梦:这里后端返回的时候,要返回 areaName -->
-                  {{ user.areaId }}
-                </el-descriptions-item>
-                <el-descriptions-item>
-                  <template #label>
-                    <div class="cell-item">
-                      <Icon icon="ep:position" />
-                      注册 IP
-                    </div>
-                  </template>
-                  {{ user.registerIp }}
-                </el-descriptions-item>
-                <el-descriptions-item>
-                  <template #label>
-                    <div class="cell-item">
-                      <Icon icon="fa:birthday-cake" />
-                      生日
-                    </div>
-                  </template>
-                  {{ user.birthday ? formatDate(user.birthday) : '空' }}
-                </el-descriptions-item>
-                <el-descriptions-item>
-                  <template #label>
-                    <div class="cell-item">
-                      <Icon icon="ep:calendar" />
-                      注册时间
-                    </div>
-                  </template>
-                  {{ user.createTime ? formatDate(user.createTime) : '空' }}
-                </el-descriptions-item>
-                <el-descriptions-item>
-                  <template #label>
-                    <div class="cell-item">
-                      <Icon icon="ep:calendar" />
-                      最后登录时间
-                    </div>
-                  </template>
-                  {{ user.loginDate ? formatDate(user.loginDate) : '空' }}
-                </el-descriptions-item>
-              </el-descriptions>
-            </el-col>
-          </el-row>
-        </el-card>
+        </UserBasicInfo>
       </el-col>
-
       <!-- 右上角:账户信息 -->
       <el-col :span="10" class="detail-info-item">
         <el-card shadow="never">
           <template #header>
             <CardTitle title="账户信息" />
           </template>
-          <AccountInfo />
+          <UserAccountInfo />
         </el-card>
       </el-col>
-
       <!-- 下边:账户明细 -->
-      <!-- TODO 芋艿:【收货地址】【订单管理】【售后管理】【收藏记录】【优惠劵】 -->
+      <!-- TODO 芋艿:【订单管理】【售后管理】【收藏记录】【优惠劵】 -->
       <el-card header="账户明细" style="width: 100%; margin-top: 20px" shadow="never">
         <template #header>
           <CardTitle title="账户明细" />
         </template>
         <el-tabs v-model="activeName">
           <el-tab-pane label="积分" name="point">
-            <PointList v-if="user.id" :member-id="user.id" />
+            <UserPointList :user-id="id" />
           </el-tab-pane>
           <el-tab-pane label="签到" name="sign">
-            <SignList v-if="user.id" :member-id="user.id" />
+            <UserSignList :user-id="id" />
           </el-tab-pane>
           <el-tab-pane label="成长值" name="third">成长值(WIP)</el-tab-pane>
           <el-tab-pane label="余额" name="fourth">余额(WIP)</el-tab-pane>
+          <el-tab-pane label="收货地址" name="address">
+            <UserAddressList :user-id="id" />
+          </el-tab-pane>
+          <el-tab-pane label="订单管理" name="fourth">订单管理(WIP)</el-tab-pane>
+          <el-tab-pane label="售后管理" name="fourth">售后管理(WIP)</el-tab-pane>
+          <el-tab-pane label="收藏记录" name="fourth">收藏记录(WIP)</el-tab-pane>
+          <el-tab-pane label="优惠劵" name="fourth">优惠劵(WIP)</el-tab-pane>
         </el-tabs>
       </el-card>
     </el-row>
   </div>
 
   <!-- 表单弹窗:添加/修改 -->
-  <UserForm ref="formRef" @success="getUserData(user.id)" />
+  <UserForm ref="formRef" @success="getUserData(id)" />
 </template>
 <script setup lang="ts">
-// TODO @梦:组件对应的 vue,都大写
-import PointList from '@/views/member/user/components/point-list.vue'
-import SignList from '@/views/member/user/components/sign-list.vue'
-import CardTitle from '@/views/member/user/components/card-title.vue'
-// TODO @梦:参考别的模块,UserApi 这样去引用
-import { getUser, UserBaseInfoVO } from '@/api/member/user'
-import { formatDate } from '@/utils/formatTime'
-import { DICT_TYPE } from '@/utils/dict'
+import * as UserApi from '@/api/member/user'
+import { useTagsViewStore } from '@/store/modules/tagsView'
+import UserBasicInfo from './UserBasicInfo.vue'
 import UserForm from '@/views/member/user/UserForm.vue'
-// TODO @梦:把用户信息,也抽成一个组件,类似 AccountInfo
-import AccountInfo from '@/views/member/user/components/account-info.vue'
+import UserAccountInfo from './UserAccountInfo.vue'
+import UserAddressList from './UserAddressList.vue'
+import UserPointList from './UserPointList.vue'
+import UserSignList from './UserSignList.vue'
+import { CardTitle } from '@/components/Card/index'
 
 defineOptions({ name: 'MemberDetail' })
 
 const activeName = ref('point') // 账户明细 选中的 tabs
 const loading = ref(true) // 加载中
-let user = ref<UserBaseInfoVO>({
-  areaId: undefined,
-  avatar: undefined,
-  birthday: undefined,
-  createTime: undefined,
-  id: undefined,
-  loginDate: undefined,
-  loginIp: '',
-  mark: '',
-  mobile: '',
-  name: '',
-  nickname: '',
-  password: null,
-  registerIp: undefined,
-  sex: 0,
-  status: 0
-})
+let user = ref<UserApi.UserVO>({})
+
+/** 添加/修改操作 */
+const formRef = ref()
+const openForm = (type: string) => {
+  formRef.value.open(type, id)
+}
 
 /** 获得用户 */
 const getUserData = async (id: number) => {
   loading.value = true
   try {
-    user.value = await getUser(id)
+    user.value = await UserApi.getUser(id)
   } finally {
     loading.value = false
   }
 }
 
-/** 添加/修改操作 */
-const formRef = ref()
-const openForm = (type: string, id?: number) => {
-  formRef.value.open(type, id)
-}
-
 /** 初始化 */
+const { push, currentRoute } = useRouter() // 路由
+const { delView } = useTagsViewStore() // 视图操作
 const route = useRoute()
-const router = useRouter()
-// TODO @梦:改成 id 路径参数,而不是 query
-// TODO @梦:会员列表,把【详情】按钮加上哈
-const member_id = route.query.member_id as number
+const id = route.params.id as number
 onMounted(() => {
-  if (!member_id) {
-    // TODO
+  if (!id) {
     ElMessage.warning('参数错误,会员编号不能为空!')
-    router.back()
+    delView(unref(currentRoute))
     return
   }
-  getUserData(member_id)
+  getUserData(id)
 })
 </script>
 <style scoped lang="css">
-/** TODO 这 3 个 css 貌似没用? */
 .detail-info-item:first-child {
   padding-left: 0 !important;
 }
@@ -227,11 +113,4 @@ onMounted(() => {
   justify-content: space-between;
   align-items: center;
 }
-.cell-item {
-  display: inline;
-}
-/** TODO 下面 css 貌似没啥用? */
-.cell-item::after {
-  content: ':';
-}
 </style>

+ 6 - 6
src/views/member/user/index.vue

@@ -109,8 +109,9 @@
         :formatter="dateFormatter"
         width="180px"
       />
-      <el-table-column label="操作" align="center" width="140px" fixed="right">
+      <el-table-column label="操作" align="center" width="180px" fixed="right">
         <template #default="scope">
+          <el-button link type="primary" @click="openDetail(scope.row.id)">详情</el-button>
           <el-button
             link
             type="primary"
@@ -148,7 +149,6 @@
 <script setup lang="ts">
 import { dateFormatter } from '@/utils/formatTime'
 import * as UserApi from '@/api/member/user'
-import UserForm from './UserForm.vue'
 import { DICT_TYPE } from '@/utils/dict'
 import MemberTagSelect from '@/views/member/tag/components/MemberTagSelect.vue'
 import MemberLevelSelect from '@/views/member/level/components/MemberLevelSelect.vue'
@@ -198,10 +198,10 @@ const resetQuery = () => {
   handleQuery()
 }
 
-/** 添加/修改操作 */
-const formRef = ref()
-const openForm = (type: string, id?: number) => {
-  formRef.value.open(type, id)
+/** 打开会员详情 */
+const { push } = useRouter()
+const openDetail = (id: number) => {
+  push({ name: 'MemberUserDetail', params: { id } })
 }
 
 /** 初始化 **/