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 {
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
}
// 查询会员用户列表

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 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 },
children: [
{
path: 'user/detail',
path: 'user/detail/:id',
name: 'MemberUserDetail',
meta: {
title: '会员详情',

View File

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

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>
</template>
<script lang="ts" setup>
defineComponent({
name: 'AccountInfo'
})
</script>
<style scoped lang="scss">
.cell-item {
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"
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>

View File

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

View File

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

View File

@ -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 } })
}
/** 初始化 **/