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

This commit is contained in:
owen 2023-08-26 07:31:38 +08:00
commit bce427f702
16 changed files with 256 additions and 231 deletions

View File

@ -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 })
}

View File

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

View File

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

View File

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

View File

@ -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>

View File

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

View File

@ -11,7 +11,7 @@ import dayjs from 'dayjs'
* @description format + + "YYYY-mm-dd HH:MM:SS WWW QQQQ ZZZ" * @description format + + "YYYY-mm-dd HH:MM:SS WWW QQQQ ZZZ"
* @returns * @returns
*/ */
export function formatDate(date: Date, format?: string): string { export function formatDate(date: Date | number, format?: string): string {
// 日期不存在,则返回空 // 日期不存在,则返回空
if (!date) { if (!date) {
return '' return ''

View File

@ -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>

View File

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

View File

@ -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>

View File

@ -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>

View File

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

View File

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

View File

@ -1,220 +1,106 @@
<template> <template>
<div v-loading="loading"> <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-col :span="14" class="detail-info-item">
<el-card shadow="never"> <UserBasicInfo :user="user">
<template #header> <template #header>
<div class="card-header"> <div class="card-header">
<!-- TODO @如果不要小蓝线是不是直接用 el-card 自带的 title 即可 -->
<CardTitle title="基本信息" /> <CardTitle title="基本信息" />
<el-button <el-button type="primary" size="small" text @click="openForm('update')">
v-if="user.id"
type="primary"
size="small"
text
@click="openForm('update', user.id)"
>
编辑 编辑
</el-button> </el-button>
</div> </div>
</template> </template>
<el-row> </UserBasicInfo>
<el-col :span="4">
<ElAvatar shape="square" :size="140" :src="user.avatar || undefined" />
</el-col> </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>
</el-col>
<!-- 右上角账户信息 --> <!-- 右上角账户信息 -->
<el-col :span="10" class="detail-info-item"> <el-col :span="10" class="detail-info-item">
<el-card shadow="never"> <el-card shadow="never">
<template #header> <template #header>
<CardTitle title="账户信息" /> <CardTitle title="账户信息" />
</template> </template>
<AccountInfo /> <UserAccountInfo />
</el-card> </el-card>
</el-col> </el-col>
<!-- 下边账户明细 --> <!-- 下边账户明细 -->
<!-- TODO 芋艿收货地址订单管理售后管理收藏记录优惠劵 --> <!-- TODO 芋艿订单管理售后管理收藏记录优惠劵 -->
<el-card header="账户明细" style="width: 100%; margin-top: 20px" shadow="never"> <el-card header="账户明细" style="width: 100%; margin-top: 20px" shadow="never">
<template #header> <template #header>
<CardTitle title="账户明细" /> <CardTitle title="账户明细" />
</template> </template>
<el-tabs v-model="activeName"> <el-tabs v-model="activeName">
<el-tab-pane label="积分" name="point"> <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>
<el-tab-pane label="签到" name="sign"> <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>
<el-tab-pane label="成长值" name="third">成长值(WIP)</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="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-tabs>
</el-card> </el-card>
</el-row> </el-row>
</div> </div>
<!-- 表单弹窗添加/修改 --> <!-- 表单弹窗添加/修改 -->
<UserForm ref="formRef" @success="getUserData(user.id)" /> <UserForm ref="formRef" @success="getUserData(id)" />
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
// TODO @ vue import * as UserApi from '@/api/member/user'
import PointList from '@/views/member/user/components/point-list.vue' import { useTagsViewStore } from '@/store/modules/tagsView'
import SignList from '@/views/member/user/components/sign-list.vue' import UserBasicInfo from './UserBasicInfo.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 UserForm from '@/views/member/user/UserForm.vue' import UserForm from '@/views/member/user/UserForm.vue'
// TODO @ AccountInfo import UserAccountInfo from './UserAccountInfo.vue'
import AccountInfo from '@/views/member/user/components/account-info.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' }) defineOptions({ name: 'MemberDetail' })
const activeName = ref('point') // tabs const activeName = ref('point') // tabs
const loading = ref(true) // const loading = ref(true) //
let user = ref<UserBaseInfoVO>({ let user = ref<UserApi.UserVO>({})
areaId: undefined,
avatar: undefined, /** 添加/修改操作 */
birthday: undefined, const formRef = ref()
createTime: undefined, const openForm = (type: string) => {
id: undefined, formRef.value.open(type, id)
loginDate: undefined, }
loginIp: '',
mark: '',
mobile: '',
name: '',
nickname: '',
password: null,
registerIp: undefined,
sex: 0,
status: 0
})
/** 获得用户 */ /** 获得用户 */
const getUserData = async (id: number) => { const getUserData = async (id: number) => {
loading.value = true loading.value = true
try { try {
user.value = await getUser(id) user.value = await UserApi.getUser(id)
} finally { } finally {
loading.value = false 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 route = useRoute()
const router = useRouter() const id = route.params.id as number
// TODO @ id query
// TODO @
const member_id = route.query.member_id as number
onMounted(() => { onMounted(() => {
if (!member_id) { if (!id) {
// TODO
ElMessage.warning('参数错误,会员编号不能为空!') ElMessage.warning('参数错误,会员编号不能为空!')
router.back() delView(unref(currentRoute))
return return
} }
getUserData(member_id) getUserData(id)
}) })
</script> </script>
<style scoped lang="css"> <style scoped lang="css">
/** TODO 这 3 个 css 貌似没用? */
.detail-info-item:first-child { .detail-info-item:first-child {
padding-left: 0 !important; padding-left: 0 !important;
} }
@ -227,11 +113,4 @@ onMounted(() => {
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
} }
.cell-item {
display: inline;
}
/** TODO 下面 css 貌似没啥用? */
.cell-item::after {
content: ':';
}
</style> </style>

View File

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