付费会员列表模块
This commit is contained in:
parent
2d9889af9f
commit
9191ca6c59
@ -0,0 +1,134 @@
|
|||||||
|
<template>
|
||||||
|
<Dialog title="修改用户余额" v-model="dialogVisible" width="600">
|
||||||
|
<el-form
|
||||||
|
ref="formRef"
|
||||||
|
:model="formData"
|
||||||
|
:rules="formRules"
|
||||||
|
label-width="100px"
|
||||||
|
v-loading="formLoading"
|
||||||
|
>
|
||||||
|
<el-form-item label="用户编号" prop="userId">
|
||||||
|
<el-input v-model="formData.userId" class="!w-240px" disabled />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="用户昵称" prop="nickname">
|
||||||
|
<el-input v-model="formData.nickname" class="!w-240px" disabled />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="变动前余额" prop="balance">
|
||||||
|
<el-input-number v-model="formData.balance" class="!w-240px" :precision="2" disabled />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="变动类型" prop="changeType">
|
||||||
|
<el-radio-group v-model="formData.changeType">
|
||||||
|
<el-radio :label="1">增加</el-radio>
|
||||||
|
<el-radio :label="-1">减少</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="变动余额" prop="changePoint">
|
||||||
|
<el-input-number v-model="formData.changePoint" class="!w-240px" :min="0" :precision="2" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="变动后余额">
|
||||||
|
<el-input-number v-model="pointResult" class="!w-240px" :precision="2" disabled />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
|
||||||
|
<el-button @click="dialogVisible = false">取 消</el-button>
|
||||||
|
</template>
|
||||||
|
</Dialog>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import * as UserApi from '@/api/pay/wallet/balance'
|
||||||
|
import * as UserApi2 from '@/api/member/user'
|
||||||
|
/** 修改用户余额表单 */
|
||||||
|
defineOptions({ name: 'UpdatePointForm' })
|
||||||
|
|
||||||
|
const { t } = useI18n() // 国际化
|
||||||
|
const message = useMessage() // 消息弹窗
|
||||||
|
|
||||||
|
const dialogVisible = ref(false) // 弹窗的是否展示
|
||||||
|
const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
|
||||||
|
const formData = ref({
|
||||||
|
id: undefined,
|
||||||
|
userId: undefined,
|
||||||
|
nickname: undefined,
|
||||||
|
balance: 0,
|
||||||
|
changePoint: 0,
|
||||||
|
changeType: 1
|
||||||
|
})
|
||||||
|
const formRules = reactive({
|
||||||
|
changePoint: [{ required: true, message: '变动余额不能为空', trigger: 'blur' }]
|
||||||
|
})
|
||||||
|
const formRef = ref() // 表单 Ref
|
||||||
|
|
||||||
|
/** 打开弹窗 */
|
||||||
|
const open = async (id?: number) => {
|
||||||
|
dialogVisible.value = true
|
||||||
|
resetForm()
|
||||||
|
// 修改时,设置数据
|
||||||
|
if (id) {
|
||||||
|
formLoading.value = true
|
||||||
|
try {
|
||||||
|
const param = { userId: id }
|
||||||
|
const wallet = await UserApi.getWallet(param)
|
||||||
|
formData.value = wallet
|
||||||
|
formData.value.balance = wallet.balance / 100.0;
|
||||||
|
const user = await UserApi2.getUser(id);
|
||||||
|
formData.value.nickname = user.nickname;
|
||||||
|
formData.value.changeType = 1 // 默认增加余额
|
||||||
|
formData.value.changePoint = 0 // 变动余额默认0
|
||||||
|
} finally {
|
||||||
|
formLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
defineExpose({ open }) // 提供 open 方法,用于打开弹窗
|
||||||
|
|
||||||
|
/** 提交表单 */
|
||||||
|
const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
|
||||||
|
const submitForm = async () => {
|
||||||
|
// 校验表单
|
||||||
|
if (!formRef) return
|
||||||
|
const valid = await formRef.value.validate()
|
||||||
|
if (!valid) return
|
||||||
|
|
||||||
|
if (formData.value.changePoint < 1) {
|
||||||
|
message.error('变动余额不能小于 1')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (pointResult.value < 0) {
|
||||||
|
message.error('变动后的余额不能小于 0')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提交请求
|
||||||
|
formLoading.value = true
|
||||||
|
try {
|
||||||
|
await UserApi.updateWalletBalance({
|
||||||
|
id: formData.value.id,
|
||||||
|
balance: formData.value.changePoint * formData.value.changeType
|
||||||
|
})
|
||||||
|
|
||||||
|
message.success(t('common.updateSuccess'))
|
||||||
|
dialogVisible.value = false
|
||||||
|
// 发送操作成功的事件
|
||||||
|
emit('success')
|
||||||
|
} finally {
|
||||||
|
formLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 重置表单 */
|
||||||
|
const resetForm = () => {
|
||||||
|
formData.value = {
|
||||||
|
id: undefined,
|
||||||
|
nickname: undefined,
|
||||||
|
balance: undefined,
|
||||||
|
reason: undefined
|
||||||
|
}
|
||||||
|
formRef.value?.resetFields()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 变动后的余额 */
|
||||||
|
const pointResult = computed(
|
||||||
|
() => formData.value.balance + formData.value.changePoint * formData.value.changeType
|
||||||
|
)
|
||||||
|
</script>
|
179
yudao-admin-vue3/src/views/mall/promotion/user/UserForm.vue
Normal file
179
yudao-admin-vue3/src/views/mall/promotion/user/UserForm.vue
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
<template>
|
||||||
|
<Dialog :title="dialogTitle" v-model="dialogVisible">
|
||||||
|
<el-form
|
||||||
|
ref="formRef"
|
||||||
|
:model="formData"
|
||||||
|
:rules="formRules"
|
||||||
|
label-width="100px"
|
||||||
|
v-loading="formLoading"
|
||||||
|
>
|
||||||
|
<el-form-item label="手机号" prop="mobile">
|
||||||
|
<el-input v-model="formData.mobile" placeholder="请输入手机号" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="状态" prop="status">
|
||||||
|
<el-radio-group v-model="formData.status">
|
||||||
|
<el-radio
|
||||||
|
v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
|
||||||
|
:key="dict.value"
|
||||||
|
:label="dict.value"
|
||||||
|
>
|
||||||
|
{{ dict.label }}
|
||||||
|
</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="用户昵称" prop="nickname">
|
||||||
|
<el-input v-model="formData.nickname" placeholder="请输入用户昵称" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="头像" prop="avatar">
|
||||||
|
<UploadImg v-model="formData.avatar" :limit="1" :is-show-tip="false" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="真实名字" prop="name">
|
||||||
|
<el-input v-model="formData.name" placeholder="请输入真实名字" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="用户性别" prop="sex">
|
||||||
|
<el-radio-group v-model="formData.sex">
|
||||||
|
<el-radio
|
||||||
|
v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)"
|
||||||
|
:key="dict.value"
|
||||||
|
:label="dict.value"
|
||||||
|
>
|
||||||
|
{{ dict.label }}
|
||||||
|
</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="出生日期" prop="birthday">
|
||||||
|
<el-date-picker
|
||||||
|
v-model="formData.birthday"
|
||||||
|
type="date"
|
||||||
|
value-format="x"
|
||||||
|
placeholder="选择出生日期"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="所在地" prop="areaId">
|
||||||
|
<el-tree-select
|
||||||
|
v-model="formData.areaId"
|
||||||
|
:data="areaList"
|
||||||
|
:props="defaultProps"
|
||||||
|
:render-after-expand="true"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="用户标签" prop="tagIds">
|
||||||
|
<MemberTagSelect v-model="formData.tagIds" show-add />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="用户分组" prop="groupId">
|
||||||
|
<MemberGroupSelect v-model="formData.groupId" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="会员备注" prop="mark">
|
||||||
|
<el-input type="textarea" v-model="formData.mark" placeholder="请输入会员备注" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
|
||||||
|
<el-button @click="dialogVisible = false">取 消</el-button>
|
||||||
|
</template>
|
||||||
|
</Dialog>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
|
||||||
|
import * as UserApi from '@/api/member/user'
|
||||||
|
import * as AreaApi from '@/api/system/area'
|
||||||
|
import { defaultProps } from '@/utils/tree'
|
||||||
|
import MemberTagSelect from '@/views/member/tag/components/MemberTagSelect.vue'
|
||||||
|
import MemberGroupSelect from '@/views/member/group/components/MemberGroupSelect.vue'
|
||||||
|
|
||||||
|
const { t } = useI18n() // 国际化
|
||||||
|
const message = useMessage() // 消息弹窗
|
||||||
|
|
||||||
|
const dialogVisible = ref(false) // 弹窗的是否展示
|
||||||
|
const dialogTitle = ref('') // 弹窗的标题
|
||||||
|
const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
|
||||||
|
const formType = ref('') // 表单的类型:create - 新增;update - 修改
|
||||||
|
const formData = ref({
|
||||||
|
id: undefined,
|
||||||
|
mobile: undefined,
|
||||||
|
password: undefined,
|
||||||
|
status: undefined,
|
||||||
|
nickname: undefined,
|
||||||
|
avatar: undefined,
|
||||||
|
name: undefined,
|
||||||
|
sex: undefined,
|
||||||
|
areaId: undefined,
|
||||||
|
birthday: undefined,
|
||||||
|
mark: undefined,
|
||||||
|
tagIds: [],
|
||||||
|
groupId: undefined
|
||||||
|
})
|
||||||
|
const formRules = reactive({
|
||||||
|
mobile: [{ required: true, message: '手机号不能为空', trigger: 'blur' }],
|
||||||
|
status: [{ required: true, message: '状态不能为空', trigger: 'blur' }]
|
||||||
|
})
|
||||||
|
const formRef = ref() // 表单 Ref
|
||||||
|
const areaList = ref([]) // 地区列表
|
||||||
|
|
||||||
|
/** 打开弹窗 */
|
||||||
|
const open = async (type: string, id?: number) => {
|
||||||
|
dialogVisible.value = true
|
||||||
|
dialogTitle.value = t('action.' + type)
|
||||||
|
formType.value = type
|
||||||
|
resetForm()
|
||||||
|
// 修改时,设置数据
|
||||||
|
if (id) {
|
||||||
|
formLoading.value = true
|
||||||
|
try {
|
||||||
|
formData.value = await UserApi.getUser(id)
|
||||||
|
} finally {
|
||||||
|
formLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 获得地区列表
|
||||||
|
areaList.value = await AreaApi.getAreaTree()
|
||||||
|
}
|
||||||
|
defineExpose({ open }) // 提供 open 方法,用于打开弹窗
|
||||||
|
|
||||||
|
/** 提交表单 */
|
||||||
|
const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
|
||||||
|
const submitForm = async () => {
|
||||||
|
// 校验表单
|
||||||
|
if (!formRef) return
|
||||||
|
const valid = await formRef.value.validate()
|
||||||
|
if (!valid) return
|
||||||
|
// 提交请求
|
||||||
|
formLoading.value = true
|
||||||
|
try {
|
||||||
|
const data = formData.value as unknown as UserApi.UserVO
|
||||||
|
if (formType.value === 'create') {
|
||||||
|
// 说明:目前暂时没有新增操作。如果自己业务需要,可以进行扩展
|
||||||
|
// await UserApi.createUser(data)
|
||||||
|
message.success(t('common.createSuccess'))
|
||||||
|
} else {
|
||||||
|
await UserApi.updateUser(data)
|
||||||
|
message.success(t('common.updateSuccess'))
|
||||||
|
}
|
||||||
|
dialogVisible.value = false
|
||||||
|
// 发送操作成功的事件
|
||||||
|
emit('success')
|
||||||
|
} finally {
|
||||||
|
formLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 重置表单 */
|
||||||
|
const resetForm = () => {
|
||||||
|
formData.value = {
|
||||||
|
id: undefined,
|
||||||
|
mobile: undefined,
|
||||||
|
password: undefined,
|
||||||
|
status: undefined,
|
||||||
|
nickname: undefined,
|
||||||
|
avatar: undefined,
|
||||||
|
name: undefined,
|
||||||
|
sex: undefined,
|
||||||
|
areaId: undefined,
|
||||||
|
birthday: undefined,
|
||||||
|
mark: undefined,
|
||||||
|
tagIds: [],
|
||||||
|
groupId: undefined
|
||||||
|
}
|
||||||
|
formRef.value?.resetFields()
|
||||||
|
}
|
||||||
|
</script>
|
@ -0,0 +1,101 @@
|
|||||||
|
<template>
|
||||||
|
<Dialog title="修改用户等级" v-model="dialogVisible" width="600">
|
||||||
|
<el-form
|
||||||
|
ref="formRef"
|
||||||
|
:model="formData"
|
||||||
|
:rules="formRules"
|
||||||
|
label-width="100px"
|
||||||
|
v-loading="formLoading"
|
||||||
|
>
|
||||||
|
<el-form-item label="用户编号" prop="id">
|
||||||
|
<el-input v-model="formData.id" placeholder="请输入用户昵称" class="!w-240px" disabled />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="用户昵称" prop="nickname">
|
||||||
|
<el-input
|
||||||
|
v-model="formData.nickname"
|
||||||
|
placeholder="请输入用户昵称"
|
||||||
|
class="!w-240px"
|
||||||
|
disabled
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="用户等级" prop="levelId">
|
||||||
|
<MemberLevelSelect v-model="formData.levelId" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="修改原因" prop="reason">
|
||||||
|
<el-input type="textarea" v-model="formData.reason" placeholder="请输入修改原因" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
|
||||||
|
<el-button @click="dialogVisible = false">取 消</el-button>
|
||||||
|
</template>
|
||||||
|
</Dialog>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import * as UserApi from '@/api/member/user'
|
||||||
|
import MemberLevelSelect from '@/views/member/level/components/MemberLevelSelect.vue'
|
||||||
|
|
||||||
|
const { t } = useI18n() // 国际化
|
||||||
|
const message = useMessage() // 消息弹窗
|
||||||
|
|
||||||
|
const dialogVisible = ref(false) // 弹窗的是否展示
|
||||||
|
const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
|
||||||
|
const formData = ref({
|
||||||
|
id: undefined,
|
||||||
|
nickname: undefined,
|
||||||
|
levelId: undefined,
|
||||||
|
reason: undefined
|
||||||
|
})
|
||||||
|
const formRules = reactive({
|
||||||
|
reason: [{ required: true, message: '修改原因不能为空', trigger: 'blur' }]
|
||||||
|
})
|
||||||
|
const formRef = ref() // 表单 Ref
|
||||||
|
|
||||||
|
/** 打开弹窗 */
|
||||||
|
const open = async (id?: number) => {
|
||||||
|
dialogVisible.value = true
|
||||||
|
resetForm()
|
||||||
|
// 修改时,设置数据
|
||||||
|
if (id) {
|
||||||
|
formLoading.value = true
|
||||||
|
try {
|
||||||
|
formData.value = await UserApi.getUser(id)
|
||||||
|
} finally {
|
||||||
|
formLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
defineExpose({ open }) // 提供 open 方法,用于打开弹窗
|
||||||
|
|
||||||
|
/** 提交表单 */
|
||||||
|
const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
|
||||||
|
const submitForm = async () => {
|
||||||
|
// 校验表单
|
||||||
|
if (!formRef) return
|
||||||
|
const valid = await formRef.value.validate()
|
||||||
|
if (!valid) return
|
||||||
|
// 提交请求
|
||||||
|
formLoading.value = true
|
||||||
|
try {
|
||||||
|
await UserApi.updateUserLevel(formData.value)
|
||||||
|
|
||||||
|
message.success(t('common.updateSuccess'))
|
||||||
|
dialogVisible.value = false
|
||||||
|
// 发送操作成功的事件
|
||||||
|
emit('success')
|
||||||
|
} finally {
|
||||||
|
formLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 重置表单 */
|
||||||
|
const resetForm = () => {
|
||||||
|
formData.value = {
|
||||||
|
id: undefined,
|
||||||
|
nickname: undefined,
|
||||||
|
levelId: undefined,
|
||||||
|
reason: undefined
|
||||||
|
}
|
||||||
|
formRef.value?.resetFields()
|
||||||
|
}
|
||||||
|
</script>
|
@ -0,0 +1,128 @@
|
|||||||
|
<template>
|
||||||
|
<Dialog title="修改用户积分" v-model="dialogVisible" width="600">
|
||||||
|
<el-form
|
||||||
|
ref="formRef"
|
||||||
|
:model="formData"
|
||||||
|
:rules="formRules"
|
||||||
|
label-width="100px"
|
||||||
|
v-loading="formLoading"
|
||||||
|
>
|
||||||
|
<el-form-item label="用户编号" prop="id">
|
||||||
|
<el-input v-model="formData.id" class="!w-240px" disabled />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="用户昵称" prop="nickname">
|
||||||
|
<el-input v-model="formData.nickname" class="!w-240px" disabled />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="变动前积分" prop="point">
|
||||||
|
<el-input-number v-model="formData.point" class="!w-240px" disabled />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="变动类型" prop="changeType">
|
||||||
|
<el-radio-group v-model="formData.changeType">
|
||||||
|
<el-radio :label="1">增加</el-radio>
|
||||||
|
<el-radio :label="-1">减少</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="变动积分" prop="changePoint">
|
||||||
|
<el-input-number v-model="formData.changePoint" class="!w-240px" :min="0" :precision="0" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="变动后积分">
|
||||||
|
<el-input-number v-model="pointResult" class="!w-240px" disabled />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
|
||||||
|
<el-button @click="dialogVisible = false">取 消</el-button>
|
||||||
|
</template>
|
||||||
|
</Dialog>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import * as UserApi from '@/api/member/user'
|
||||||
|
|
||||||
|
/** 修改用户积分表单 */
|
||||||
|
defineOptions({ name: 'UpdatePointForm' })
|
||||||
|
|
||||||
|
const { t } = useI18n() // 国际化
|
||||||
|
const message = useMessage() // 消息弹窗
|
||||||
|
|
||||||
|
const dialogVisible = ref(false) // 弹窗的是否展示
|
||||||
|
const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
|
||||||
|
const formData = ref({
|
||||||
|
id: undefined,
|
||||||
|
nickname: undefined,
|
||||||
|
point: 0,
|
||||||
|
changePoint: 0,
|
||||||
|
changeType: 1
|
||||||
|
})
|
||||||
|
const formRules = reactive({
|
||||||
|
changePoint: [{ required: true, message: '变动积分不能为空', trigger: 'blur' }]
|
||||||
|
})
|
||||||
|
const formRef = ref() // 表单 Ref
|
||||||
|
|
||||||
|
/** 打开弹窗 */
|
||||||
|
const open = async (id?: number) => {
|
||||||
|
dialogVisible.value = true
|
||||||
|
resetForm()
|
||||||
|
// 修改时,设置数据
|
||||||
|
if (id) {
|
||||||
|
formLoading.value = true
|
||||||
|
try {
|
||||||
|
formData.value = await UserApi.getUser(id)
|
||||||
|
formData.value.changeType = 1 // 默认增加积分
|
||||||
|
formData.value.changePoint = 0 // 变动积分默认0
|
||||||
|
} finally {
|
||||||
|
formLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
defineExpose({ open }) // 提供 open 方法,用于打开弹窗
|
||||||
|
|
||||||
|
/** 提交表单 */
|
||||||
|
const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
|
||||||
|
const submitForm = async () => {
|
||||||
|
// 校验表单
|
||||||
|
if (!formRef) return
|
||||||
|
const valid = await formRef.value.validate()
|
||||||
|
if (!valid) return
|
||||||
|
|
||||||
|
if (formData.value.changePoint < 1) {
|
||||||
|
message.error('变动积分不能小于 1')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (pointResult.value < 0) {
|
||||||
|
message.error('变动后的积分不能小于 0')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提交请求
|
||||||
|
formLoading.value = true
|
||||||
|
try {
|
||||||
|
await UserApi.updateUserPoint({
|
||||||
|
id: formData.value.id,
|
||||||
|
point: formData.value.changePoint * formData.value.changeType
|
||||||
|
})
|
||||||
|
|
||||||
|
message.success(t('common.updateSuccess'))
|
||||||
|
dialogVisible.value = false
|
||||||
|
// 发送操作成功的事件
|
||||||
|
emit('success')
|
||||||
|
} finally {
|
||||||
|
formLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 重置表单 */
|
||||||
|
const resetForm = () => {
|
||||||
|
formData.value = {
|
||||||
|
id: undefined,
|
||||||
|
nickname: undefined,
|
||||||
|
levelId: undefined,
|
||||||
|
reason: undefined
|
||||||
|
}
|
||||||
|
formRef.value?.resetFields()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 变动后的积分 */
|
||||||
|
const pointResult = computed(
|
||||||
|
() => formData.value.point + formData.value.changePoint * formData.value.changeType
|
||||||
|
)
|
||||||
|
</script>
|
@ -0,0 +1,14 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent } from 'vue'
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'BalanceList'
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- TODO @芋艿:未来实现,等周建的 -->
|
||||||
|
<template>
|
||||||
|
<div>余额列表</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped lang="scss"></style>
|
@ -0,0 +1,87 @@
|
|||||||
|
<template>
|
||||||
|
<el-descriptions :column="2">
|
||||||
|
<el-descriptions-item>
|
||||||
|
<template #label>
|
||||||
|
<descriptions-item-label label=" 等级 " icon="svg-icon:member_level" />
|
||||||
|
</template>
|
||||||
|
{{ user.levelName || '无' }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item>
|
||||||
|
<template #label>
|
||||||
|
<descriptions-item-label label=" 成长值 " icon="ep:suitcase" />
|
||||||
|
</template>
|
||||||
|
{{ user.experience || 0 }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item>
|
||||||
|
<template #label>
|
||||||
|
<descriptions-item-label label=" 当前积分 " icon="ep:coin" />
|
||||||
|
</template>
|
||||||
|
{{ user.point || 0 }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item>
|
||||||
|
<template #label>
|
||||||
|
<descriptions-item-label label=" 总积分 " icon="ep:coin" />
|
||||||
|
</template>
|
||||||
|
{{ user.totalPoint || 0 }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item>
|
||||||
|
<template #label>
|
||||||
|
<descriptions-item-label label=" 当前余额 " icon="svg-icon:member_balance" />
|
||||||
|
</template>
|
||||||
|
{{ fenToYuan(wallet.balance || 0) }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item>
|
||||||
|
<template #label>
|
||||||
|
<descriptions-item-label label=" 支出金额 " icon="svg-icon:member_expenditure_balance" />
|
||||||
|
</template>
|
||||||
|
{{ fenToYuan(wallet.totalExpense || 0) }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item>
|
||||||
|
<template #label>
|
||||||
|
<descriptions-item-label label=" 充值金额 " icon="svg-icon:member_recharge_balance" />
|
||||||
|
</template>
|
||||||
|
{{ fenToYuan(wallet.totalRecharge || 0) }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
</el-descriptions>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { DescriptionsItemLabel } from '@/components/Descriptions'
|
||||||
|
import * as UserApi from '@/api/member/user'
|
||||||
|
import * as WalletApi from '@/api/pay/wallet/balance'
|
||||||
|
import { UserTypeEnum } from '@/utils/constants'
|
||||||
|
import { fenToYuan } from '@/utils'
|
||||||
|
|
||||||
|
const props = defineProps<{ user: UserApi.UserVO }>() // 用户信息
|
||||||
|
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 (!props.user.id) {
|
||||||
|
wallet.value = WALLET_INIT_DATA
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const params = { userId: props.user.id }
|
||||||
|
wallet.value = (await WalletApi.getWallet(params)) || WALLET_INIT_DATA
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 监听用户编号变化 */
|
||||||
|
watch(
|
||||||
|
() => props.user.id,
|
||||||
|
() => getUserWallet(),
|
||||||
|
{ immediate: true }
|
||||||
|
)
|
||||||
|
</script>
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.cell-item {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cell-item::after {
|
||||||
|
content: ':';
|
||||||
|
}
|
||||||
|
</style>
|
@ -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>
|
@ -0,0 +1,85 @@
|
|||||||
|
<template>
|
||||||
|
<el-card shadow="never">
|
||||||
|
<template #header>
|
||||||
|
<slot name="header"></slot>
|
||||||
|
</template>
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="4">
|
||||||
|
<ElAvatar shape="circle" :size="100" :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 } = defineProps<{ user: UserApi.UserVO }>()
|
||||||
|
</script>
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.card-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,125 @@
|
|||||||
|
<template>
|
||||||
|
<ContentWrap>
|
||||||
|
<!-- 搜索工作栏 -->
|
||||||
|
<el-form
|
||||||
|
class="-mb-15px"
|
||||||
|
:model="queryParams"
|
||||||
|
ref="queryFormRef"
|
||||||
|
:inline="true"
|
||||||
|
label-width="85px"
|
||||||
|
>
|
||||||
|
<el-form-item label="用户类型" prop="level">
|
||||||
|
<el-radio-group v-model="queryParams.level" @change="handleQuery">
|
||||||
|
<el-radio-button checked>全部</el-radio-button>
|
||||||
|
<el-radio-button label="1">一级推广人</el-radio-button>
|
||||||
|
<el-radio-button label="2">二级推广人</el-radio-button>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="绑定时间" prop="bindUserTime">
|
||||||
|
<el-date-picker
|
||||||
|
v-model="queryParams.bindUserTime"
|
||||||
|
value-format="YYYY-MM-DD HH:mm:ss"
|
||||||
|
type="daterange"
|
||||||
|
start-placeholder="开始日期"
|
||||||
|
end-placeholder="结束日期"
|
||||||
|
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
|
||||||
|
class="!w-240px"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
|
||||||
|
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</ContentWrap>
|
||||||
|
|
||||||
|
<!-- 列表 -->
|
||||||
|
<ContentWrap>
|
||||||
|
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
|
||||||
|
<el-table-column label="用户编号" align="center" prop="id" min-width="80px" />
|
||||||
|
<el-table-column label="头像" align="center" prop="avatar" width="70px">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-avatar :src="scope.row.avatar" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="昵称" align="center" prop="nickname" min-width="80px" />
|
||||||
|
<el-table-column label="等级" align="center" prop="level" min-width="80px">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-tag v-if="scope.row.bindUserId === bindUserId">一级</el-tag>
|
||||||
|
<el-tag v-else>二级</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column
|
||||||
|
label="绑定时间"
|
||||||
|
align="center"
|
||||||
|
prop="bindUserTime"
|
||||||
|
:formatter="dateFormatter"
|
||||||
|
width="170px"
|
||||||
|
/>
|
||||||
|
</el-table>
|
||||||
|
<!-- 分页 -->
|
||||||
|
<Pagination
|
||||||
|
:total="total"
|
||||||
|
v-model:page="queryParams.pageNo"
|
||||||
|
v-model:limit="queryParams.pageSize"
|
||||||
|
@pagination="getList"
|
||||||
|
/>
|
||||||
|
</ContentWrap>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { dateFormatter } from '@/utils/formatTime'
|
||||||
|
import * as BrokerageUserApi from '@/api/mall/trade/brokerage/user'
|
||||||
|
|
||||||
|
/** 推广人列表 */
|
||||||
|
defineOptions({ name: 'UserBrokerageList' })
|
||||||
|
|
||||||
|
const { bindUserId }: { bindUserId: number } = defineProps({
|
||||||
|
bindUserId: {
|
||||||
|
type: Number,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
}) //用户编号
|
||||||
|
|
||||||
|
const loading = ref(true) // 列表的加载中
|
||||||
|
const total = ref(0) // 列表的总页数
|
||||||
|
const list = ref([]) // 列表的数据
|
||||||
|
const queryParams = reactive({
|
||||||
|
pageNo: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
bindUserId: null,
|
||||||
|
level: '',
|
||||||
|
bindUserTime: []
|
||||||
|
})
|
||||||
|
const queryFormRef = ref() // 搜索的表单
|
||||||
|
|
||||||
|
/** 查询列表 */
|
||||||
|
const getList = async () => {
|
||||||
|
loading.value = true
|
||||||
|
try {
|
||||||
|
queryParams.bindUserId = bindUserId
|
||||||
|
const data = await BrokerageUserApi.getBrokerageUserPage(queryParams)
|
||||||
|
list.value = data.list
|
||||||
|
total.value = data.total
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 搜索按钮操作 */
|
||||||
|
const handleQuery = () => {
|
||||||
|
queryParams.pageNo = 1
|
||||||
|
getList()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 重置按钮操作 */
|
||||||
|
const resetQuery = () => {
|
||||||
|
queryFormRef.value?.resetFields()
|
||||||
|
handleQuery()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 初始化 **/
|
||||||
|
onMounted(() => {
|
||||||
|
getList()
|
||||||
|
})
|
||||||
|
</script>
|
@ -0,0 +1,190 @@
|
|||||||
|
<template>
|
||||||
|
<!-- 搜索工作栏 -->
|
||||||
|
<ContentWrap>
|
||||||
|
<el-form
|
||||||
|
ref="queryFormRef"
|
||||||
|
:inline="true"
|
||||||
|
:model="queryParams"
|
||||||
|
class="-mb-15px"
|
||||||
|
label-width="68px"
|
||||||
|
>
|
||||||
|
<el-form-item label="创建时间" prop="createTime">
|
||||||
|
<el-date-picker
|
||||||
|
v-model="queryParams.createTime"
|
||||||
|
value-format="YYYY-MM-DD HH:mm:ss"
|
||||||
|
type="daterange"
|
||||||
|
start-placeholder="开始日期"
|
||||||
|
end-placeholder="结束日期"
|
||||||
|
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
|
||||||
|
class="!w-240px"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button @click="handleQuery"> <Icon icon="ep:search" class="mr-5px" />搜索 </el-button>
|
||||||
|
<el-button @click="resetQuery"> <Icon icon="ep:refresh" class="mr-5px" />重置 </el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</ContentWrap>
|
||||||
|
|
||||||
|
<ContentWrap>
|
||||||
|
<!-- Tab 选项:真正的内容在 Lab -->
|
||||||
|
<el-tabs v-model="activeTab" type="card" @tab-change="onTabChange">
|
||||||
|
<el-tab-pane
|
||||||
|
v-for="tab in statusTabs"
|
||||||
|
:key="tab.value"
|
||||||
|
:label="tab.label"
|
||||||
|
:name="tab.value"
|
||||||
|
/>
|
||||||
|
</el-tabs>
|
||||||
|
|
||||||
|
<!-- 列表 -->
|
||||||
|
<el-table v-loading="loading" :data="list">
|
||||||
|
<el-table-column label="优惠劵" align="center" prop="name" />
|
||||||
|
<el-table-column label="优惠券类型" align="center" prop="discountType">
|
||||||
|
<template #default="scope">
|
||||||
|
<dict-tag :type="DICT_TYPE.PROMOTION_DISCOUNT_TYPE" :value="scope.row.discountType" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="领取方式" align="center" prop="takeType">
|
||||||
|
<template #default="scope">
|
||||||
|
<dict-tag :type="DICT_TYPE.PROMOTION_COUPON_TAKE_TYPE" :value="scope.row.takeType" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="状态" align="center" prop="status">
|
||||||
|
<template #default="scope">
|
||||||
|
<dict-tag :type="DICT_TYPE.PROMOTION_COUPON_STATUS" :value="scope.row.status" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column
|
||||||
|
label="领取时间"
|
||||||
|
align="center"
|
||||||
|
prop="createTime"
|
||||||
|
:formatter="dateFormatter"
|
||||||
|
width="180"
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
label="使用时间"
|
||||||
|
align="center"
|
||||||
|
prop="useTime"
|
||||||
|
:formatter="dateFormatter"
|
||||||
|
width="180"
|
||||||
|
/>
|
||||||
|
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-button
|
||||||
|
v-hasPermi="['promotion:coupon:delete']"
|
||||||
|
type="danger"
|
||||||
|
link
|
||||||
|
@click="handleDelete(scope.row.id)"
|
||||||
|
>
|
||||||
|
回收
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<!-- 分页 -->
|
||||||
|
<Pagination
|
||||||
|
v-model:limit="queryParams.pageSize"
|
||||||
|
v-model:page="queryParams.pageNo"
|
||||||
|
:total="total"
|
||||||
|
@pagination="getList"
|
||||||
|
/>
|
||||||
|
</ContentWrap>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts" name="UserCouponList">
|
||||||
|
import { deleteCoupon, getCouponPage } from '@/api/mall/promotion/coupon/coupon'
|
||||||
|
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
|
||||||
|
import { dateFormatter } from '@/utils/formatTime'
|
||||||
|
|
||||||
|
defineOptions({ name: 'UserCouponList' })
|
||||||
|
|
||||||
|
const { userId }: { userId: number } = defineProps({
|
||||||
|
userId: {
|
||||||
|
type: Number,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
}) //用户编号
|
||||||
|
|
||||||
|
const message = useMessage() // 消息弹窗
|
||||||
|
|
||||||
|
const loading = ref(true) // 列表的加载中
|
||||||
|
const total = ref(0) // 列表的总页数
|
||||||
|
const list = ref([]) // 字典表格数据
|
||||||
|
// 查询参数
|
||||||
|
const queryParams = reactive({
|
||||||
|
pageNo: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
createTime: [],
|
||||||
|
status: undefined,
|
||||||
|
userIds: undefined
|
||||||
|
})
|
||||||
|
const queryFormRef = ref() // 搜索的表单
|
||||||
|
|
||||||
|
const activeTab = ref('all') // Tab 筛选
|
||||||
|
const statusTabs = reactive([
|
||||||
|
{
|
||||||
|
label: '全部',
|
||||||
|
value: 'all'
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
/** 查询列表 */
|
||||||
|
const getList = async () => {
|
||||||
|
loading.value = true
|
||||||
|
// 执行查询
|
||||||
|
try {
|
||||||
|
queryParams.userIds = userId
|
||||||
|
const data = await getCouponPage(queryParams)
|
||||||
|
list.value = data.list
|
||||||
|
total.value = data.total
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 搜索按钮操作 */
|
||||||
|
const handleQuery = () => {
|
||||||
|
queryParams.pageNo = 1
|
||||||
|
getList()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 重置按钮操作 */
|
||||||
|
const resetQuery = () => {
|
||||||
|
queryFormRef.value?.resetFields()
|
||||||
|
handleQuery()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 删除按钮操作 */
|
||||||
|
const handleDelete = async (id: number) => {
|
||||||
|
try {
|
||||||
|
// 二次确认
|
||||||
|
await message.confirm(
|
||||||
|
'回收将会收回会员领取的待使用的优惠券,已使用的将无法回收,确定要回收所选优惠券吗?'
|
||||||
|
)
|
||||||
|
// 发起删除
|
||||||
|
await deleteCoupon(id)
|
||||||
|
message.notifySuccess('回收成功')
|
||||||
|
// 重新加载列表
|
||||||
|
await getList()
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** tab 切换 */
|
||||||
|
const onTabChange = (tabName) => {
|
||||||
|
queryParams.status = tabName === 'all' ? undefined : tabName
|
||||||
|
getList()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 初始化 **/
|
||||||
|
onMounted(() => {
|
||||||
|
getList()
|
||||||
|
// 设置 statuses 过滤
|
||||||
|
for (const dict of getIntDictOptions(DICT_TYPE.PROMOTION_COUPON_STATUS)) {
|
||||||
|
statusTabs.push({
|
||||||
|
label: dict.label,
|
||||||
|
value: dict.value as string
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
@ -0,0 +1,158 @@
|
|||||||
|
<template>
|
||||||
|
<ContentWrap>
|
||||||
|
<!-- 搜索工作栏 -->
|
||||||
|
<el-form
|
||||||
|
class="-mb-15px"
|
||||||
|
:model="queryParams"
|
||||||
|
ref="queryFormRef"
|
||||||
|
:inline="true"
|
||||||
|
label-width="68px"
|
||||||
|
>
|
||||||
|
<el-form-item label="业务类型" prop="bizType">
|
||||||
|
<el-select
|
||||||
|
v-model="queryParams.bizType"
|
||||||
|
placeholder="请选择业务类型"
|
||||||
|
clearable
|
||||||
|
class="!w-240px"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="dict in getIntDictOptions(DICT_TYPE.MEMBER_EXPERIENCE_BIZ_TYPE)"
|
||||||
|
:key="dict.value"
|
||||||
|
:label="dict.label"
|
||||||
|
:value="dict.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="标题" prop="title">
|
||||||
|
<el-input
|
||||||
|
v-model="queryParams.title"
|
||||||
|
placeholder="请输入标题"
|
||||||
|
clearable
|
||||||
|
@keyup.enter="handleQuery"
|
||||||
|
class="!w-240px"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="创建时间" prop="createTime">
|
||||||
|
<el-date-picker
|
||||||
|
v-model="queryParams.createTime"
|
||||||
|
value-format="YYYY-MM-DD HH:mm:ss"
|
||||||
|
type="daterange"
|
||||||
|
start-placeholder="开始日期"
|
||||||
|
end-placeholder="结束日期"
|
||||||
|
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
|
||||||
|
class="!w-240px"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
|
||||||
|
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</ContentWrap>
|
||||||
|
|
||||||
|
<!-- 列表 -->
|
||||||
|
<ContentWrap>
|
||||||
|
<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="createTime"
|
||||||
|
:formatter="dateFormatter"
|
||||||
|
/>
|
||||||
|
<el-table-column label="经验" align="center" prop="experience" width="150px">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-tag v-if="scope.row.experience > 0" class="ml-2" type="success" effect="dark">
|
||||||
|
+{{ scope.row.experience }}
|
||||||
|
</el-tag>
|
||||||
|
<el-tag v-else class="ml-2" type="danger" effect="dark">
|
||||||
|
{{ scope.row.experience }}
|
||||||
|
</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="总经验" align="center" prop="totalExperience" width="150px">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-tag class="ml-2" effect="dark">
|
||||||
|
{{ scope.row.totalExperience }}
|
||||||
|
</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="标题" align="center" prop="title" width="150px" />
|
||||||
|
<el-table-column label="描述" align="center" prop="description" />
|
||||||
|
<el-table-column label="业务编号" align="center" prop="bizId" width="150px" />
|
||||||
|
<el-table-column label="业务类型" align="center" prop="bizType" width="150px">
|
||||||
|
<!-- TODO 芋艿:此处应创建对应的字典 -->
|
||||||
|
<template #default="scope">
|
||||||
|
<dict-tag :type="DICT_TYPE.MEMBER_EXPERIENCE_BIZ_TYPE" :value="scope.row.bizType" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<!-- 分页 -->
|
||||||
|
<Pagination
|
||||||
|
:total="total"
|
||||||
|
v-model:page="queryParams.pageNo"
|
||||||
|
v-model:limit="queryParams.pageSize"
|
||||||
|
@pagination="getList"
|
||||||
|
/>
|
||||||
|
</ContentWrap>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { dateFormatter } from '@/utils/formatTime'
|
||||||
|
import * as ExperienceRecordApi from '@/api/member/experience-record/index'
|
||||||
|
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
|
||||||
|
|
||||||
|
defineOptions({ name: 'UserExperienceRecordList' })
|
||||||
|
|
||||||
|
const loading = ref(true) // 列表的加载中
|
||||||
|
const total = ref(0) // 列表的总页数
|
||||||
|
const list = ref([]) // 列表的数据
|
||||||
|
const queryParams = reactive({
|
||||||
|
pageNo: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
userId: null,
|
||||||
|
bizId: null,
|
||||||
|
bizType: null,
|
||||||
|
title: null,
|
||||||
|
description: null,
|
||||||
|
experience: null,
|
||||||
|
totalExperience: null,
|
||||||
|
createTime: []
|
||||||
|
})
|
||||||
|
const queryFormRef = ref() // 搜索的表单
|
||||||
|
/** 查询列表 */
|
||||||
|
const getList = async () => {
|
||||||
|
loading.value = true
|
||||||
|
try {
|
||||||
|
const data = await ExperienceRecordApi.getExperienceRecordPage(queryParams)
|
||||||
|
list.value = data.list
|
||||||
|
total.value = data.total
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 搜索按钮操作 */
|
||||||
|
const handleQuery = () => {
|
||||||
|
queryParams.pageNo = 1
|
||||||
|
getList()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 重置按钮操作 */
|
||||||
|
const resetQuery = () => {
|
||||||
|
queryFormRef.value.resetFields()
|
||||||
|
handleQuery()
|
||||||
|
}
|
||||||
|
|
||||||
|
const { userId } = defineProps({
|
||||||
|
userId: {
|
||||||
|
type: Number,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
/** 初始化 **/
|
||||||
|
onMounted(() => {
|
||||||
|
queryParams.userId = userId
|
||||||
|
getList()
|
||||||
|
})
|
||||||
|
</script>
|
@ -0,0 +1,96 @@
|
|||||||
|
<template>
|
||||||
|
<!-- 列表 -->
|
||||||
|
<ContentWrap>
|
||||||
|
<el-table v-loading="loading" :data="list">
|
||||||
|
<el-table-column key="id" align="center" label="商品编号" width="180" prop="id" />
|
||||||
|
<el-table-column label="商品图" min-width="80">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-image :src="row.picUrl" class="h-30px w-30px" @click="imagePreview(row.picUrl)" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column :show-overflow-tooltip="true" label="商品名称" min-width="300" prop="name" />
|
||||||
|
<el-table-column align="center" label="商品售价" min-width="90" prop="price">
|
||||||
|
<template #default="{ row }"> {{ floatToFixed2(row.price) }}元</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column align="center" label="销量" min-width="90" prop="salesCount" />
|
||||||
|
<el-table-column
|
||||||
|
:formatter="dateFormatter"
|
||||||
|
align="center"
|
||||||
|
label="收藏时间"
|
||||||
|
prop="createTime"
|
||||||
|
width="180"
|
||||||
|
/>
|
||||||
|
<el-table-column align="center" label="状态" min-width="80">
|
||||||
|
<template #default="scope">
|
||||||
|
<dict-tag :type="DICT_TYPE.PRODUCT_SPU_STATUS" :value="scope.row.status" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<!-- 分页 -->
|
||||||
|
<Pagination
|
||||||
|
:total="total"
|
||||||
|
v-model:page="queryParams.pageNo"
|
||||||
|
v-model:limit="queryParams.pageSize"
|
||||||
|
@pagination="getList"
|
||||||
|
/>
|
||||||
|
</ContentWrap>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { DICT_TYPE } from '@/utils/dict'
|
||||||
|
import { dateFormatter } from '@/utils/formatTime'
|
||||||
|
import * as FavoriteApi from '@/api/mall/product/favorite'
|
||||||
|
import { floatToFixed2 } from '@/utils'
|
||||||
|
|
||||||
|
const message = useMessage() // 消息弹窗
|
||||||
|
const { t } = useI18n() // 国际化
|
||||||
|
|
||||||
|
const loading = ref(true) // 列表的加载中
|
||||||
|
const total = ref(0) // 列表的总页数
|
||||||
|
const list = ref([]) // 列表的数据
|
||||||
|
const queryParams = reactive({
|
||||||
|
pageNo: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
name: null,
|
||||||
|
createTime: [],
|
||||||
|
userId: NaN
|
||||||
|
})
|
||||||
|
const queryFormRef = ref() // 搜索的表单
|
||||||
|
|
||||||
|
/** 查询列表 */
|
||||||
|
const getList = async () => {
|
||||||
|
loading.value = true
|
||||||
|
try {
|
||||||
|
const data = await FavoriteApi.getFavoritePage(queryParams)
|
||||||
|
list.value = data.list
|
||||||
|
total.value = data.total
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 搜索按钮操作 */
|
||||||
|
const handleQuery = () => {
|
||||||
|
queryParams.pageNo = 1
|
||||||
|
getList()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 重置按钮操作 */
|
||||||
|
const resetQuery = () => {
|
||||||
|
queryFormRef.value.resetFields()
|
||||||
|
handleQuery()
|
||||||
|
}
|
||||||
|
|
||||||
|
const { userId } = defineProps({
|
||||||
|
userId: {
|
||||||
|
type: Number,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
/** 初始化 **/
|
||||||
|
onMounted(() => {
|
||||||
|
queryParams.userId = userId
|
||||||
|
getList()
|
||||||
|
})
|
||||||
|
</script>
|
@ -0,0 +1,279 @@
|
|||||||
|
<template>
|
||||||
|
<!-- 搜索 -->
|
||||||
|
<ContentWrap>
|
||||||
|
<el-form
|
||||||
|
ref="queryFormRef"
|
||||||
|
:inline="true"
|
||||||
|
:model="queryParams"
|
||||||
|
class="-mb-15px"
|
||||||
|
label-width="68px"
|
||||||
|
>
|
||||||
|
<el-form-item label="订单状态" prop="status">
|
||||||
|
<el-select v-model="queryParams.status" class="!w-280px" clearable placeholder="全部">
|
||||||
|
<el-option
|
||||||
|
v-for="dict in getIntDictOptions(DICT_TYPE.TRADE_ORDER_STATUS)"
|
||||||
|
:key="dict.value"
|
||||||
|
:label="dict.label"
|
||||||
|
:value="dict.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="支付方式" prop="payChannelCode">
|
||||||
|
<el-select
|
||||||
|
v-model="queryParams.payChannelCode"
|
||||||
|
class="!w-280px"
|
||||||
|
clearable
|
||||||
|
placeholder="全部"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="dict in getStrDictOptions(DICT_TYPE.PAY_CHANNEL_CODE)"
|
||||||
|
:key="dict.value"
|
||||||
|
:label="dict.label"
|
||||||
|
:value="dict.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="创建时间" prop="createTime">
|
||||||
|
<el-date-picker
|
||||||
|
v-model="queryParams.createTime"
|
||||||
|
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
|
||||||
|
class="!w-280px"
|
||||||
|
end-placeholder="自定义时间"
|
||||||
|
start-placeholder="自定义时间"
|
||||||
|
type="daterange"
|
||||||
|
value-format="YYYY-MM-DD HH:mm:ss"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="订单来源" prop="terminal">
|
||||||
|
<el-select v-model="queryParams.terminal" class="!w-280px" clearable placeholder="全部">
|
||||||
|
<el-option
|
||||||
|
v-for="dict in getIntDictOptions(DICT_TYPE.TERMINAL)"
|
||||||
|
:key="dict.value"
|
||||||
|
:label="dict.label"
|
||||||
|
:value="dict.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="订单类型" prop="type">
|
||||||
|
<el-select v-model="queryParams.type" class="!w-280px" clearable placeholder="全部">
|
||||||
|
<el-option
|
||||||
|
v-for="dict in getIntDictOptions(DICT_TYPE.TRADE_ORDER_TYPE)"
|
||||||
|
:key="dict.value"
|
||||||
|
:label="dict.label"
|
||||||
|
:value="dict.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="配送方式" prop="deliveryType">
|
||||||
|
<el-select v-model="queryParams.deliveryType" class="!w-280px" clearable placeholder="全部">
|
||||||
|
<el-option
|
||||||
|
v-for="dict in getIntDictOptions(DICT_TYPE.TRADE_DELIVERY_TYPE)"
|
||||||
|
:key="dict.value"
|
||||||
|
:label="dict.label"
|
||||||
|
:value="dict.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
v-if="queryParams.deliveryType === DeliveryTypeEnum.EXPRESS.type"
|
||||||
|
label="快递公司"
|
||||||
|
prop="logisticsId"
|
||||||
|
>
|
||||||
|
<el-select v-model="queryParams.logisticsId" class="!w-280px" clearable placeholder="全部">
|
||||||
|
<el-option
|
||||||
|
v-for="item in deliveryExpressList"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.name"
|
||||||
|
:value="item.id"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
v-if="queryParams.deliveryType === DeliveryTypeEnum.PICK_UP.type"
|
||||||
|
label="自提门店"
|
||||||
|
prop="pickUpStoreId"
|
||||||
|
>
|
||||||
|
<el-select
|
||||||
|
v-model="queryParams.pickUpStoreId"
|
||||||
|
class="!w-280px"
|
||||||
|
clearable
|
||||||
|
multiple
|
||||||
|
placeholder="全部"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in pickUpStoreList"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.name"
|
||||||
|
:value="item.id"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
v-if="queryParams.deliveryType === DeliveryTypeEnum.PICK_UP.type"
|
||||||
|
label="核销码"
|
||||||
|
prop="pickUpVerifyCode"
|
||||||
|
>
|
||||||
|
<el-input
|
||||||
|
v-model="queryParams.pickUpVerifyCode"
|
||||||
|
class="!w-280px"
|
||||||
|
clearable
|
||||||
|
placeholder="请输入自提核销码"
|
||||||
|
@keyup.enter="handleQuery"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="聚合搜索">
|
||||||
|
<el-input
|
||||||
|
v-show="true"
|
||||||
|
v-model="queryParams[queryType.queryParam]"
|
||||||
|
class="!w-280px"
|
||||||
|
clearable
|
||||||
|
placeholder="请输入"
|
||||||
|
>
|
||||||
|
<template #prepend>
|
||||||
|
<el-select
|
||||||
|
v-model="queryType.queryParam"
|
||||||
|
class="!w-110px"
|
||||||
|
clearable
|
||||||
|
placeholder="全部"
|
||||||
|
@change="inputChangeSelect"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="dict in dynamicSearchList"
|
||||||
|
:key="dict.value"
|
||||||
|
:label="dict.label"
|
||||||
|
:value="dict.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button @click="handleQuery">
|
||||||
|
<Icon class="mr-5px" icon="ep:search" />
|
||||||
|
搜索
|
||||||
|
</el-button>
|
||||||
|
<el-button @click="resetQuery">
|
||||||
|
<Icon class="mr-5px" icon="ep:refresh" />
|
||||||
|
重置
|
||||||
|
</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</ContentWrap>
|
||||||
|
|
||||||
|
<!-- 列表 -->
|
||||||
|
<ContentWrap>
|
||||||
|
<!-- 添加 row-key="id" 解决列数据中的 table#header 数据不刷新的问题 -->
|
||||||
|
<el-table v-loading="loading" :data="list" row-key="id">
|
||||||
|
<OrderTableColumn :list="list" :pick-up-store-list="pickUpStoreList">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-button link type="primary" @click="openDetail(row.id)">
|
||||||
|
<Icon icon="ep:notification" />
|
||||||
|
详情
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</OrderTableColumn>
|
||||||
|
</el-table>
|
||||||
|
<!-- 分页 -->
|
||||||
|
<Pagination
|
||||||
|
v-model:limit="queryParams.pageSize"
|
||||||
|
v-model:page="queryParams.pageNo"
|
||||||
|
:total="total"
|
||||||
|
@pagination="getList"
|
||||||
|
/>
|
||||||
|
</ContentWrap>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import * as OrderApi from '@/api/mall/trade/order/index'
|
||||||
|
import { DICT_TYPE, getIntDictOptions, getStrDictOptions } from '@/utils/dict'
|
||||||
|
import * as PickUpStoreApi from '@/api/mall/trade/delivery/pickUpStore'
|
||||||
|
import * as DeliveryExpressApi from '@/api/mall/trade/delivery/express'
|
||||||
|
import { FormInstance } from 'element-plus'
|
||||||
|
import { OrderTableColumn } from '@/views/mall/trade/order/components'
|
||||||
|
import { DeliveryTypeEnum } from '@/utils/constants'
|
||||||
|
|
||||||
|
const { push } = useRouter() // 路由跳转
|
||||||
|
|
||||||
|
const { userId } = defineProps<{
|
||||||
|
userId: number
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const loading = ref(true) // 列表的加载中
|
||||||
|
const total = ref(0) // 列表的总页数
|
||||||
|
const list = ref([]) // 列表的数据
|
||||||
|
const pickUpStoreList = ref<PickUpStoreApi.DeliveryPickUpStoreVO[]>([]) // 自提门店精简列表
|
||||||
|
const deliveryExpressList = ref<DeliveryExpressApi.DeliveryExpressVO[]>([]) // 物流公司
|
||||||
|
const queryFormRef = ref<FormInstance>() // 搜索的表单
|
||||||
|
// 表单搜索
|
||||||
|
const queryParams = ref({
|
||||||
|
pageNo: 1, // 页数
|
||||||
|
pageSize: 10, // 每页显示数量
|
||||||
|
userId: userId,
|
||||||
|
status: undefined, // 订单状态
|
||||||
|
payChannelCode: undefined, // 支付方式
|
||||||
|
createTime: undefined, // 创建时间
|
||||||
|
terminal: undefined, // 订单来源
|
||||||
|
type: undefined, // 订单类型
|
||||||
|
deliveryType: undefined, // 配送方式
|
||||||
|
logisticsId: undefined, // 快递公司
|
||||||
|
pickUpStoreId: undefined, // 自提门店
|
||||||
|
pickUpVerifyCode: undefined // 自提核销码
|
||||||
|
})
|
||||||
|
const queryType = reactive({ queryParam: '' }) // 订单搜索类型 queryParam
|
||||||
|
|
||||||
|
// 订单聚合搜索 select 类型配置(动态搜索)
|
||||||
|
const dynamicSearchList = ref([
|
||||||
|
{ value: 'no', label: '订单号' },
|
||||||
|
{ value: 'userNickname', label: '用户昵称' },
|
||||||
|
{ value: 'userMobile', label: '用户电话' }
|
||||||
|
])
|
||||||
|
/**
|
||||||
|
* 聚合搜索切换查询对象时触发
|
||||||
|
* @param val
|
||||||
|
*/
|
||||||
|
const inputChangeSelect = (val: string) => {
|
||||||
|
dynamicSearchList.value
|
||||||
|
.filter((item) => item.value !== val)
|
||||||
|
?.forEach((item1) => {
|
||||||
|
// 清除集合搜索无用属性
|
||||||
|
if (queryParams.value.hasOwnProperty(item1.value)) {
|
||||||
|
delete queryParams.value[item1.value]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 搜索按钮操作 */
|
||||||
|
const handleQuery = async () => {
|
||||||
|
queryParams.value.pageNo = 1
|
||||||
|
await getList()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 重置按钮操作 */
|
||||||
|
const resetQuery = () => {
|
||||||
|
queryFormRef.value?.resetFields()
|
||||||
|
queryParams.value.userId = userId
|
||||||
|
handleQuery()
|
||||||
|
}
|
||||||
|
/** 查询列表 */
|
||||||
|
const getList = async () => {
|
||||||
|
loading.value = true
|
||||||
|
try {
|
||||||
|
const data = await OrderApi.getOrderPage(queryParams.value)
|
||||||
|
list.value = data.list
|
||||||
|
total.value = data.total
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 查看订单详情 */
|
||||||
|
const openDetail = (id: number) => {
|
||||||
|
push({ name: 'TradeOrderDetail', params: { id } })
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 初始化 **/
|
||||||
|
onMounted(async () => {
|
||||||
|
await getList()
|
||||||
|
pickUpStoreList.value = await PickUpStoreApi.getListAllSimple()
|
||||||
|
deliveryExpressList.value = await DeliveryExpressApi.getSimpleDeliveryExpressList()
|
||||||
|
})
|
||||||
|
</script>
|
@ -0,0 +1,152 @@
|
|||||||
|
<template>
|
||||||
|
<ContentWrap>
|
||||||
|
<!-- 搜索工作栏 -->
|
||||||
|
<el-form
|
||||||
|
class="-mb-15px"
|
||||||
|
:model="queryParams"
|
||||||
|
ref="queryFormRef"
|
||||||
|
:inline="true"
|
||||||
|
label-width="68px"
|
||||||
|
>
|
||||||
|
<el-form-item label="业务类型" prop="bizType">
|
||||||
|
<el-select
|
||||||
|
v-model="queryParams.bizType"
|
||||||
|
placeholder="请选择业务类型"
|
||||||
|
clearable
|
||||||
|
class="!w-240px"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="dict in getIntDictOptions(DICT_TYPE.MEMBER_POINT_BIZ_TYPE)"
|
||||||
|
:key="dict.value"
|
||||||
|
:label="dict.label"
|
||||||
|
:value="dict.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="积分标题" prop="title">
|
||||||
|
<el-input
|
||||||
|
v-model="queryParams.title"
|
||||||
|
placeholder="请输入积分标题"
|
||||||
|
clearable
|
||||||
|
@keyup.enter="handleQuery"
|
||||||
|
class="!w-240px"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="获得时间" prop="createDate">
|
||||||
|
<el-date-picker
|
||||||
|
v-model="queryParams.createDate"
|
||||||
|
value-format="YYYY-MM-DD HH:mm:ss"
|
||||||
|
type="daterange"
|
||||||
|
start-placeholder="开始日期"
|
||||||
|
end-placeholder="结束日期"
|
||||||
|
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
|
||||||
|
class="!w-240px"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button @click="handleQuery">
|
||||||
|
<Icon icon="ep:search" class="mr-5px" />
|
||||||
|
搜索
|
||||||
|
</el-button>
|
||||||
|
<el-button @click="resetQuery">
|
||||||
|
<Icon icon="ep:refresh" class="mr-5px" />
|
||||||
|
重置
|
||||||
|
</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</ContentWrap>
|
||||||
|
|
||||||
|
<!-- 列表 -->
|
||||||
|
<ContentWrap>
|
||||||
|
<el-table v-loading="loading" :data="list">
|
||||||
|
<el-table-column label="编号" align="center" prop="id" width="180" />
|
||||||
|
<el-table-column
|
||||||
|
label="获得时间"
|
||||||
|
align="center"
|
||||||
|
prop="createTime"
|
||||||
|
:formatter="dateFormatter"
|
||||||
|
width="180"
|
||||||
|
/>
|
||||||
|
<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">
|
||||||
|
+{{ scope.row.point }}
|
||||||
|
</el-tag>
|
||||||
|
<el-tag v-else class="ml-2" type="danger" effect="dark"> {{ scope.row.point }} </el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="总积分" align="center" prop="totalPoint" width="100" />
|
||||||
|
<el-table-column label="标题" align="center" prop="title" />
|
||||||
|
<el-table-column label="描述" align="center" prop="description" />
|
||||||
|
<el-table-column label="业务编码" align="center" prop="bizId" />
|
||||||
|
<el-table-column label="业务类型" align="center" prop="bizType">
|
||||||
|
<template #default="scope">
|
||||||
|
<dict-tag :type="DICT_TYPE.MEMBER_POINT_BIZ_TYPE" :value="scope.row.bizType" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<!-- 分页 -->
|
||||||
|
<Pagination
|
||||||
|
:total="total"
|
||||||
|
v-model:page="queryParams.pageNo"
|
||||||
|
v-model:limit="queryParams.pageSize"
|
||||||
|
@pagination="getList"
|
||||||
|
/>
|
||||||
|
</ContentWrap>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
|
||||||
|
import { dateFormatter } from '@/utils/formatTime'
|
||||||
|
import * as RecordApi from '@/api//member/point/record'
|
||||||
|
|
||||||
|
const loading = ref(true) // 列表的加载中
|
||||||
|
const total = ref(0) // 列表的总页数
|
||||||
|
const list = ref([]) // 列表的数据
|
||||||
|
const queryParams = reactive({
|
||||||
|
pageNo: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
bizType: undefined,
|
||||||
|
title: null,
|
||||||
|
createDate: [],
|
||||||
|
userId: NaN
|
||||||
|
})
|
||||||
|
const queryFormRef = ref() // 搜索的表单
|
||||||
|
|
||||||
|
/** 查询列表 */
|
||||||
|
const getList = async () => {
|
||||||
|
loading.value = true
|
||||||
|
try {
|
||||||
|
const data = await RecordApi.getRecordPage(queryParams)
|
||||||
|
list.value = data.list
|
||||||
|
total.value = data.total
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 搜索按钮操作 */
|
||||||
|
const handleQuery = () => {
|
||||||
|
queryParams.pageNo = 1
|
||||||
|
getList()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 重置按钮操作 */
|
||||||
|
const resetQuery = () => {
|
||||||
|
queryFormRef.value.resetFields()
|
||||||
|
handleQuery()
|
||||||
|
}
|
||||||
|
|
||||||
|
const { userId } = defineProps({
|
||||||
|
userId: {
|
||||||
|
type: Number,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
/** 初始化 **/
|
||||||
|
onMounted(() => {
|
||||||
|
queryParams.userId = userId
|
||||||
|
getList()
|
||||||
|
})
|
||||||
|
</script>
|
@ -0,0 +1,135 @@
|
|||||||
|
<template>
|
||||||
|
<ContentWrap>
|
||||||
|
<!-- 搜索工作栏 -->
|
||||||
|
<el-form
|
||||||
|
class="-mb-15px"
|
||||||
|
:model="queryParams"
|
||||||
|
ref="queryFormRef"
|
||||||
|
:inline="true"
|
||||||
|
label-width="68px"
|
||||||
|
>
|
||||||
|
<el-form-item label="签到用户" prop="nickname">
|
||||||
|
<el-input
|
||||||
|
v-model="queryParams.nickname"
|
||||||
|
placeholder="请输入签到用户"
|
||||||
|
clearable
|
||||||
|
@keyup.enter="handleQuery"
|
||||||
|
class="!w-240px"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="签到天数" prop="day">
|
||||||
|
<el-input
|
||||||
|
v-model="queryParams.day"
|
||||||
|
placeholder="请输入签到天数"
|
||||||
|
clearable
|
||||||
|
@keyup.enter="handleQuery"
|
||||||
|
class="!w-240px"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="签到时间" prop="createTime">
|
||||||
|
<el-date-picker
|
||||||
|
v-model="queryParams.createTime"
|
||||||
|
value-format="YYYY-MM-DD HH:mm:ss"
|
||||||
|
type="daterange"
|
||||||
|
start-placeholder="开始日期"
|
||||||
|
end-placeholder="结束日期"
|
||||||
|
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
|
||||||
|
class="!w-240px"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
|
||||||
|
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</ContentWrap>
|
||||||
|
|
||||||
|
<!-- 列表 -->
|
||||||
|
<ContentWrap>
|
||||||
|
<el-table v-loading="loading" :data="list">
|
||||||
|
<el-table-column label="编号" align="center" prop="id" />
|
||||||
|
<el-table-column
|
||||||
|
label="签到天数"
|
||||||
|
align="center"
|
||||||
|
prop="day"
|
||||||
|
:formatter="(_, __, cellValue) => ['第', cellValue, '天'].join(' ')"
|
||||||
|
/>
|
||||||
|
<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">
|
||||||
|
+{{ scope.row.point }}
|
||||||
|
</el-tag>
|
||||||
|
<el-tag v-else class="ml-2" type="danger" effect="dark"> {{ scope.row.point }} </el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column
|
||||||
|
label="签到时间"
|
||||||
|
align="center"
|
||||||
|
prop="createTime"
|
||||||
|
:formatter="dateFormatter"
|
||||||
|
/>
|
||||||
|
</el-table>
|
||||||
|
<!-- 分页 -->
|
||||||
|
<Pagination
|
||||||
|
:total="total"
|
||||||
|
v-model:page="queryParams.pageNo"
|
||||||
|
v-model:limit="queryParams.pageSize"
|
||||||
|
@pagination="getList"
|
||||||
|
/>
|
||||||
|
</ContentWrap>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { dateFormatter } from '@/utils/formatTime'
|
||||||
|
import * as SignInRecordApi from '@/api/member/signin/record'
|
||||||
|
|
||||||
|
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: []
|
||||||
|
})
|
||||||
|
const queryFormRef = ref() // 搜索的表单
|
||||||
|
|
||||||
|
/** 查询列表 */
|
||||||
|
const getList = async () => {
|
||||||
|
loading.value = true
|
||||||
|
try {
|
||||||
|
const data = await SignInRecordApi.getSignInRecordPage(queryParams)
|
||||||
|
list.value = data.list
|
||||||
|
total.value = data.total
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 搜索按钮操作 */
|
||||||
|
const handleQuery = () => {
|
||||||
|
queryParams.pageNo = 1
|
||||||
|
getList()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 重置按钮操作 */
|
||||||
|
const resetQuery = () => {
|
||||||
|
queryFormRef.value.resetFields()
|
||||||
|
handleQuery()
|
||||||
|
}
|
||||||
|
|
||||||
|
const { userId } = defineProps({
|
||||||
|
userId: {
|
||||||
|
type: Number,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
/** 初始化 **/
|
||||||
|
onMounted(() => {
|
||||||
|
queryParams.userId = userId
|
||||||
|
getList()
|
||||||
|
})
|
||||||
|
</script>
|
135
yudao-admin-vue3/src/views/mall/promotion/user/detail/index.vue
Normal file
135
yudao-admin-vue3/src/views/mall/promotion/user/detail/index.vue
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
<template>
|
||||||
|
<div v-loading="loading">
|
||||||
|
<el-row :gutter="10">
|
||||||
|
<!-- 左上角:基本信息 -->
|
||||||
|
<el-col :span="14" class="detail-info-item">
|
||||||
|
<UserBasicInfo :user="user">
|
||||||
|
<template #header>
|
||||||
|
<div class="card-header">
|
||||||
|
<CardTitle title="基本信息" />
|
||||||
|
<el-button type="primary" size="small" text @click="openForm('update')">
|
||||||
|
编辑
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</UserBasicInfo>
|
||||||
|
</el-col>
|
||||||
|
<!-- 右上角:账户信息 -->
|
||||||
|
<el-col :span="10" class="detail-info-item">
|
||||||
|
<el-card shadow="never" class="h-full">
|
||||||
|
<template #header>
|
||||||
|
<CardTitle title="账户信息" />
|
||||||
|
</template>
|
||||||
|
<UserAccountInfo :user="user" />
|
||||||
|
</el-card>
|
||||||
|
</el-col>
|
||||||
|
<!-- 下边:账户明细 -->
|
||||||
|
<!-- TODO 芋艿:【订单管理】【售后管理】【收藏记录】-->
|
||||||
|
<el-card header="账户明细" style="width: 100%; margin-top: 20px" shadow="never">
|
||||||
|
<template #header>
|
||||||
|
<CardTitle title="账户明细" />
|
||||||
|
</template>
|
||||||
|
<el-tabs>
|
||||||
|
<el-tab-pane label="积分">
|
||||||
|
<UserPointList :user-id="id" />
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane label="签到" lazy>
|
||||||
|
<UserSignList :user-id="id" />
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane label="成长值" lazy>
|
||||||
|
<UserExperienceRecordList :user-id="id" />
|
||||||
|
</el-tab-pane>
|
||||||
|
<!-- TODO @jason:增加一个余额变化; -->
|
||||||
|
<el-tab-pane label="余额" lazy>余额(WIP)</el-tab-pane>
|
||||||
|
<el-tab-pane label="收货地址" lazy>
|
||||||
|
<UserAddressList :user-id="id" />
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane label="订单管理" lazy>
|
||||||
|
<UserOrderList :user-id="id" />
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane label="售后管理" lazy>售后管理(WIP)</el-tab-pane>
|
||||||
|
<el-tab-pane label="收藏记录" lazy>
|
||||||
|
<UserFavoriteList :user-id="id" />
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane label="优惠劵" lazy>
|
||||||
|
<UserCouponList :user-id="id" />
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane label="推广用户" lazy>
|
||||||
|
<UserBrokerageList :bind-user-id="id" />
|
||||||
|
</el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
</el-card>
|
||||||
|
</el-row>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 表单弹窗:添加/修改 -->
|
||||||
|
<UserForm ref="formRef" @success="getUserData(id)" />
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import * as UserApi from '@/api/member/user'
|
||||||
|
import { useTagsViewStore } from '@/store/modules/tagsView'
|
||||||
|
import UserForm from '@/views/member/user/UserForm.vue'
|
||||||
|
import UserAccountInfo from './UserAccountInfo.vue'
|
||||||
|
import UserAddressList from './UserAddressList.vue'
|
||||||
|
import UserBasicInfo from './UserBasicInfo.vue'
|
||||||
|
import UserBrokerageList from './UserBrokerageList.vue'
|
||||||
|
import UserCouponList from './UserCouponList.vue'
|
||||||
|
import UserExperienceRecordList from './UserExperienceRecordList.vue'
|
||||||
|
import UserOrderList from './UserOrderList.vue'
|
||||||
|
import UserPointList from './UserPointList.vue'
|
||||||
|
import UserSignList from './UserSignList.vue'
|
||||||
|
import UserFavoriteList from './UserFavoriteList.vue'
|
||||||
|
import { CardTitle } from '@/components/Card/index'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
|
||||||
|
defineOptions({ name: 'MemberDetail' })
|
||||||
|
|
||||||
|
const loading = ref(true) // 加载中
|
||||||
|
const user = ref<UserApi.UserVO>({} as 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 UserApi.getUser(id)
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 初始化 */
|
||||||
|
const { currentRoute } = useRouter() // 路由
|
||||||
|
const { delView } = useTagsViewStore() // 视图操作
|
||||||
|
const route = useRoute()
|
||||||
|
const id = Number(route.params.id)
|
||||||
|
onMounted(() => {
|
||||||
|
if (!id) {
|
||||||
|
ElMessage.warning('参数错误,会员编号不能为空!')
|
||||||
|
delView(unref(currentRoute))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
getUserData(id)
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
<style scoped lang="css">
|
||||||
|
.detail-info-item:first-child {
|
||||||
|
padding-left: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* first-child 不生效有没有大佬给看下q.q */
|
||||||
|
.detail-info-item:nth-child(2) {
|
||||||
|
padding-right: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
</style>
|
319
yudao-admin-vue3/src/views/mall/promotion/user/index.vue
Normal file
319
yudao-admin-vue3/src/views/mall/promotion/user/index.vue
Normal file
@ -0,0 +1,319 @@
|
|||||||
|
<template>
|
||||||
|
<doc-alert title="会员用户、标签、分组" url="https://doc.iocoder.cn/member/user/" />
|
||||||
|
|
||||||
|
<ContentWrap>
|
||||||
|
<!-- 搜索工作栏 -->
|
||||||
|
<el-form
|
||||||
|
ref="queryFormRef"
|
||||||
|
:inline="true"
|
||||||
|
:model="queryParams"
|
||||||
|
class="-mb-15px"
|
||||||
|
label-width="68px"
|
||||||
|
>
|
||||||
|
<el-form-item label="用户昵称" prop="nickname">
|
||||||
|
<el-input
|
||||||
|
v-model="queryParams.nickname"
|
||||||
|
class="!w-240px"
|
||||||
|
clearable
|
||||||
|
placeholder="请输入用户昵称"
|
||||||
|
@keyup.enter="handleQuery"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="手机号" prop="mobile">
|
||||||
|
<el-input
|
||||||
|
v-model="queryParams.mobile"
|
||||||
|
class="!w-240px"
|
||||||
|
clearable
|
||||||
|
placeholder="请输入手机号"
|
||||||
|
@keyup.enter="handleQuery"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="注册时间" prop="createTime">
|
||||||
|
<el-date-picker
|
||||||
|
v-model="queryParams.createTime"
|
||||||
|
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
|
||||||
|
class="!w-240px"
|
||||||
|
end-placeholder="结束日期"
|
||||||
|
start-placeholder="开始日期"
|
||||||
|
type="daterange"
|
||||||
|
value-format="YYYY-MM-DD HH:mm:ss"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="登录时间" prop="loginDate">
|
||||||
|
<el-date-picker
|
||||||
|
v-model="queryParams.loginDate"
|
||||||
|
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
|
||||||
|
class="!w-240px"
|
||||||
|
end-placeholder="结束日期"
|
||||||
|
start-placeholder="开始日期"
|
||||||
|
type="daterange"
|
||||||
|
value-format="YYYY-MM-DD HH:mm:ss"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="用户标签" prop="tagIds">
|
||||||
|
<MemberTagSelect v-model="queryParams.tagIds" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="用户等级" prop="levelId">
|
||||||
|
<MemberLevelSelect v-model="queryParams.levelId" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="用户分组" prop="groupId">
|
||||||
|
<MemberGroupSelect v-model="queryParams.groupId" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button @click="handleQuery">
|
||||||
|
<Icon class="mr-5px" icon="ep:search" />
|
||||||
|
搜索
|
||||||
|
</el-button>
|
||||||
|
<el-button @click="resetQuery">
|
||||||
|
<Icon class="mr-5px" icon="ep:refresh" />
|
||||||
|
重置
|
||||||
|
</el-button>
|
||||||
|
<el-button v-hasPermi="['promotion:coupon:send']" @click="openCoupon">发送优惠券</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</ContentWrap>
|
||||||
|
|
||||||
|
<!-- 列表 -->
|
||||||
|
<ContentWrap>
|
||||||
|
<el-table
|
||||||
|
v-loading="loading"
|
||||||
|
:data="list"
|
||||||
|
:show-overflow-tooltip="true"
|
||||||
|
:stripe="true"
|
||||||
|
@selection-change="handleSelectionChange"
|
||||||
|
>
|
||||||
|
<el-table-column type="selection" width="55" />
|
||||||
|
<el-table-column align="center" label="用户编号" prop="id" width="120px" />
|
||||||
|
<el-table-column align="center" label="头像" prop="avatar" width="80px">
|
||||||
|
<template #default="scope">
|
||||||
|
<img :src="scope.row.avatar" style="width: 40px" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column align="center" label="手机号" prop="mobile" width="120px" />
|
||||||
|
<el-table-column align="center" label="昵称" prop="nickname" width="80px" />
|
||||||
|
<el-table-column align="center" label="等级" prop="levelName" width="100px" />
|
||||||
|
<el-table-column align="center" label="分组" prop="groupName" width="100px" />
|
||||||
|
<el-table-column
|
||||||
|
:show-overflow-tooltip="false"
|
||||||
|
align="center"
|
||||||
|
label="用户标签"
|
||||||
|
prop="tagNames"
|
||||||
|
>
|
||||||
|
<template #default="scope">
|
||||||
|
<el-tag v-for="(tagName, index) in scope.row.tagNames" :key="index" class="mr-5px">
|
||||||
|
{{ tagName }}
|
||||||
|
</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column align="center" label="积分" prop="point" width="100px" />
|
||||||
|
<el-table-column align="center" label="余额" prop="balance" width="100px" />
|
||||||
|
<el-table-column align="center" label="状态" prop="status" width="100px">
|
||||||
|
<template #default="scope">
|
||||||
|
<dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column
|
||||||
|
:formatter="dateFormatter"
|
||||||
|
align="center"
|
||||||
|
label="登录时间"
|
||||||
|
prop="loginDate"
|
||||||
|
width="180px"
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
:formatter="dateFormatter"
|
||||||
|
align="center"
|
||||||
|
label="注册时间"
|
||||||
|
prop="createTime"
|
||||||
|
width="180px"
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
:show-overflow-tooltip="false"
|
||||||
|
align="center"
|
||||||
|
fixed="right"
|
||||||
|
label="操作"
|
||||||
|
width="100px"
|
||||||
|
>
|
||||||
|
<template #default="scope">
|
||||||
|
<div class="flex items-center justify-center">
|
||||||
|
<el-button link type="primary" @click="openDetail(scope.row.id)">详情</el-button>
|
||||||
|
<el-dropdown
|
||||||
|
v-hasPermi="[
|
||||||
|
'member:user:update',
|
||||||
|
'member:user:update-level',
|
||||||
|
'member:user:update-point',
|
||||||
|
'member:user:update-balance'
|
||||||
|
]"
|
||||||
|
@command="(command) => handleCommand(command, scope.row)"
|
||||||
|
>
|
||||||
|
<el-button link type="primary">
|
||||||
|
<Icon icon="ep:d-arrow-right" />
|
||||||
|
更多
|
||||||
|
</el-button>
|
||||||
|
<template #dropdown>
|
||||||
|
<el-dropdown-menu>
|
||||||
|
<el-dropdown-item
|
||||||
|
v-if="checkPermi(['member:user:update'])"
|
||||||
|
command="handleUpdate"
|
||||||
|
>
|
||||||
|
编辑
|
||||||
|
</el-dropdown-item>
|
||||||
|
<el-dropdown-item
|
||||||
|
v-if="checkPermi(['member:user:update-level'])"
|
||||||
|
command="handleUpdateLevel"
|
||||||
|
>
|
||||||
|
修改等级
|
||||||
|
</el-dropdown-item>
|
||||||
|
<el-dropdown-item
|
||||||
|
v-if="checkPermi(['member:user:update-point'])"
|
||||||
|
command="handleUpdatePoint"
|
||||||
|
>
|
||||||
|
修改积分
|
||||||
|
</el-dropdown-item>
|
||||||
|
<el-dropdown-item
|
||||||
|
v-if="checkPermi(['member:user:update-balance'])"
|
||||||
|
command="handleUpdateBlance"
|
||||||
|
>
|
||||||
|
修改余额
|
||||||
|
</el-dropdown-item>
|
||||||
|
</el-dropdown-menu>
|
||||||
|
</template>
|
||||||
|
</el-dropdown>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<!-- 分页 -->
|
||||||
|
<Pagination
|
||||||
|
v-model:limit="queryParams.pageSize"
|
||||||
|
v-model:page="queryParams.pageNo"
|
||||||
|
:total="total"
|
||||||
|
@pagination="getList"
|
||||||
|
/>
|
||||||
|
</ContentWrap>
|
||||||
|
|
||||||
|
<!-- 表单弹窗:添加/修改 -->
|
||||||
|
<UserForm ref="formRef" @success="getList" />
|
||||||
|
<!-- 修改用户等级弹窗 -->
|
||||||
|
<UserLevelUpdateForm ref="updateLevelFormRef" @success="getList" />
|
||||||
|
<!-- 修改用户积分弹窗 -->
|
||||||
|
<UserPointUpdateForm ref="updatePointFormRef" @success="getList" />
|
||||||
|
<!-- 修改用户余额弹窗 -->
|
||||||
|
<UserBalanceUpdateForm ref="updateBalanceFormRef" @success="getList" />
|
||||||
|
<!-- 发送优惠券弹窗 -->
|
||||||
|
<CouponSendForm ref="couponSendFormRef" />
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { dateFormatter } from '@/utils/formatTime'
|
||||||
|
import * as UserApi from '@/api/member/user'
|
||||||
|
import { DICT_TYPE } from '@/utils/dict'
|
||||||
|
import UserForm from './UserForm.vue'
|
||||||
|
import MemberTagSelect from '@/views/member/tag/components/MemberTagSelect.vue'
|
||||||
|
import MemberLevelSelect from '@/views/member/level/components/MemberLevelSelect.vue'
|
||||||
|
import MemberGroupSelect from '@/views/member/group/components/MemberGroupSelect.vue'
|
||||||
|
import UserLevelUpdateForm from './UserLevelUpdateForm.vue'
|
||||||
|
import UserPointUpdateForm from './UserPointUpdateForm.vue'
|
||||||
|
import UserBalanceUpdateForm from './UserBalanceUpdateForm.vue'
|
||||||
|
import { CouponSendForm } from '@/views/mall/promotion/coupon/components'
|
||||||
|
import { checkPermi } from '@/utils/permission'
|
||||||
|
|
||||||
|
defineOptions({ name: 'MemberUser' })
|
||||||
|
|
||||||
|
const message = useMessage() // 消息弹窗
|
||||||
|
|
||||||
|
const loading = ref(true) // 列表的加载中
|
||||||
|
const total = ref(0) // 列表的总页数
|
||||||
|
const list = ref([]) // 列表的数据
|
||||||
|
const queryParams = reactive({
|
||||||
|
pageNo: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
nickname: null,
|
||||||
|
mobile: null,
|
||||||
|
loginDate: [],
|
||||||
|
createTime: [],
|
||||||
|
tagIds: [],
|
||||||
|
levelId: null,
|
||||||
|
groupId: null,
|
||||||
|
isPaidMember: 1
|
||||||
|
})
|
||||||
|
const queryFormRef = ref() // 搜索的表单
|
||||||
|
const updateLevelFormRef = ref() // 修改会员等级表单
|
||||||
|
const updatePointFormRef = ref() // 修改会员积分表单
|
||||||
|
const updateBalanceFormRef = ref() // 修改会员余额表单
|
||||||
|
const selectedIds = ref<number[]>([]) // 表格的选中 ID 数组
|
||||||
|
|
||||||
|
/** 查询列表 */
|
||||||
|
const getList = async () => {
|
||||||
|
loading.value = true
|
||||||
|
try {
|
||||||
|
const data = await UserApi.getUserPage(queryParams)
|
||||||
|
list.value = data.list
|
||||||
|
total.value = data.total
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 搜索按钮操作 */
|
||||||
|
const handleQuery = () => {
|
||||||
|
queryParams.pageNo = 1
|
||||||
|
getList()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 重置按钮操作 */
|
||||||
|
const resetQuery = () => {
|
||||||
|
queryFormRef.value.resetFields()
|
||||||
|
handleQuery()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 打开会员详情 */
|
||||||
|
const { push } = useRouter()
|
||||||
|
const openDetail = (id: number) => {
|
||||||
|
push({ name: 'MemberUserDetail', params: { id } })
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 添加/修改操作 */
|
||||||
|
const formRef = ref()
|
||||||
|
const openForm = (type: string, id?: number) => {
|
||||||
|
formRef.value.open(type, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 表格选中事件 */
|
||||||
|
const handleSelectionChange = (rows: UserApi.UserVO[]) => {
|
||||||
|
selectedIds.value = rows.map((row) => row.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 发送优惠券 */
|
||||||
|
const couponSendFormRef = ref()
|
||||||
|
const openCoupon = () => {
|
||||||
|
if (selectedIds.value.length === 0) {
|
||||||
|
message.warning('请选择要发送优惠券的用户')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
couponSendFormRef.value.open(selectedIds.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 操作分发 */
|
||||||
|
const handleCommand = (command: string, row: UserApi.UserVO) => {
|
||||||
|
switch (command) {
|
||||||
|
case 'handleUpdate':
|
||||||
|
openForm('update', row.id)
|
||||||
|
break
|
||||||
|
case 'handleUpdateLevel':
|
||||||
|
updateLevelFormRef.value.open(row.id)
|
||||||
|
break
|
||||||
|
case 'handleUpdatePoint':
|
||||||
|
updatePointFormRef.value.open(row.id)
|
||||||
|
break
|
||||||
|
case 'handleUpdateBlance':
|
||||||
|
updateBalanceFormRef.value.open(row.id)
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 初始化 **/
|
||||||
|
onMounted(() => {
|
||||||
|
getList()
|
||||||
|
})
|
||||||
|
</script>
|
@ -84,7 +84,7 @@ public class MemberUserController {
|
|||||||
@Operation(summary = "更新会员用户余额")
|
@Operation(summary = "更新会员用户余额")
|
||||||
@PreAuthorize("@ss.hasPermission('member:user:update-balance')")
|
@PreAuthorize("@ss.hasPermission('member:user:update-balance')")
|
||||||
public CommonResult<Boolean> updateUserBalance(@Valid @RequestBody Long id) {
|
public CommonResult<Boolean> updateUserBalance(@Valid @RequestBody Long id) {
|
||||||
// todo @jason:增加一个【修改余额】
|
// 这个功能加在了pay模块里
|
||||||
return success(true);
|
return success(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,6 +41,8 @@ public class MemberUserPageReqVO extends PageParam {
|
|||||||
@Schema(description = "用户分组编号", example = "1")
|
@Schema(description = "用户分组编号", example = "1")
|
||||||
private Long groupId;
|
private Long groupId;
|
||||||
|
|
||||||
|
@Schema(description = "是否付费会员", example = "1")
|
||||||
|
private Integer isPaidMember;
|
||||||
// TODO 芋艿:注册用户类型;
|
// TODO 芋艿:注册用户类型;
|
||||||
|
|
||||||
// TODO 芋艿:登录用户类型;
|
// TODO 芋艿:登录用户类型;
|
||||||
|
@ -142,4 +142,8 @@ public class MemberUserDO extends TenantBaseDO {
|
|||||||
*/
|
*/
|
||||||
private Long groupId;
|
private Long groupId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否付费会员(0:不是 1:是)
|
||||||
|
*/
|
||||||
|
private Integer isPaidMember;
|
||||||
}
|
}
|
||||||
|
@ -47,6 +47,7 @@ public interface MemberUserMapper extends BaseMapperX<MemberUserDO> {
|
|||||||
.betweenIfPresent(MemberUserDO::getCreateTime, reqVO.getCreateTime())
|
.betweenIfPresent(MemberUserDO::getCreateTime, reqVO.getCreateTime())
|
||||||
.eqIfPresent(MemberUserDO::getLevelId, reqVO.getLevelId())
|
.eqIfPresent(MemberUserDO::getLevelId, reqVO.getLevelId())
|
||||||
.eqIfPresent(MemberUserDO::getGroupId, reqVO.getGroupId())
|
.eqIfPresent(MemberUserDO::getGroupId, reqVO.getGroupId())
|
||||||
|
.eqIfPresent(MemberUserDO::getIsPaidMember, reqVO.getIsPaidMember())
|
||||||
.apply(StrUtil.isNotEmpty(tagIdSql), tagIdSql)
|
.apply(StrUtil.isNotEmpty(tagIdSql), tagIdSql)
|
||||||
.orderByDesc(MemberUserDO::getId));
|
.orderByDesc(MemberUserDO::getId));
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
|||||||
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||||
|
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||||
import cn.iocoder.yudao.module.member.controller.admin.user.vo.MemberUserPageReqVO;
|
import cn.iocoder.yudao.module.member.controller.admin.user.vo.MemberUserPageReqVO;
|
||||||
import cn.iocoder.yudao.module.member.controller.admin.user.vo.MemberUserUpdateReqVO;
|
import cn.iocoder.yudao.module.member.controller.admin.user.vo.MemberUserUpdateReqVO;
|
||||||
import cn.iocoder.yudao.module.member.controller.app.user.vo.*;
|
import cn.iocoder.yudao.module.member.controller.app.user.vo.*;
|
||||||
@ -284,10 +285,14 @@ public class MemberUserServiceImpl implements MemberUserService {
|
|||||||
public void updateUserLevel(Long id, Long levelId, Integer experience) {
|
public void updateUserLevel(Long id, Long levelId, Integer experience) {
|
||||||
// 0 代表无等级:防止UpdateById时,会被过滤掉的问题
|
// 0 代表无等级:防止UpdateById时,会被过滤掉的问题
|
||||||
levelId = ObjectUtil.defaultIfNull(levelId, 0L);
|
levelId = ObjectUtil.defaultIfNull(levelId, 0L);
|
||||||
memberUserMapper.updateById(new MemberUserDO()
|
MemberUserDO memberUserDO = new MemberUserDO().setId(id).setLevelId(levelId).setExperience(experience);
|
||||||
.setId(id)
|
// 暂时这样设计:如果等级为0则设置付费会员状态为0,否则则设置为付费会员状态(1)
|
||||||
.setLevelId(levelId).setExperience(experience)
|
if (levelId == 0){
|
||||||
);
|
memberUserDO.setIsPaidMember(0);
|
||||||
|
}else{
|
||||||
|
memberUserDO.setIsPaidMember(1);
|
||||||
|
}
|
||||||
|
memberUserMapper.updateById(memberUserDO);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
Loading…
Reference in New Issue
Block a user