cxw #32

Merged
root merged 11 commits from cxw into master 2024-10-08 18:17:38 +08:00
152 changed files with 10712 additions and 240 deletions

View File

@ -24,7 +24,7 @@ steps: # 定义流水线执行步骤,这些步骤将顺序执行
port: 22 # 远程连接端口 port: 22 # 远程连接端口
command_timeout: 5m # 远程执行命令超时时间 command_timeout: 10m # 远程执行命令超时时间
script: script:
- cd /root/allLikeMall - cd /root/allLikeMall
@ -60,7 +60,7 @@ steps: # 定义流水线执行步骤,这些步骤将顺序执行
port: 22 # 远程连接端口 port: 22 # 远程连接端口
command_timeout: 5m # 远程执行命令超时时间 command_timeout: 10m # 远程执行命令超时时间
script: script:
# - ls # - ls

View File

@ -0,0 +1,43 @@
import request from '@/config/axios'
// 会员卡档案 VO
export interface CardBaseVO {
id: number // 档案编号
cardNum: string // 卡号
scret: string // 卡密
parentId: number // 上级id
subId: number // 下级id
}
// 会员卡档案 API
export const CardBaseApi = {
// 查询会员卡档案分页
getCardBasePage: async (params: any) => {
return await request.get({ url: `/mall/card-base/page`, params })
},
// 查询会员卡档案详情
getCardBase: async (id: number) => {
return await request.get({ url: `/mall/card-base/get?id=` + id })
},
// 新增会员卡档案
createCardBase: async (data: CardBaseVO) => {
return await request.post({ url: `/mall/card-base/create`, data })
},
// 修改会员卡档案
updateCardBase: async (data: CardBaseVO) => {
return await request.put({ url: `/mall/card-base/update`, data })
},
// 删除会员卡档案
deleteCardBase: async (id: number) => {
return await request.delete({ url: `/mall/card-base/delete?id=` + id })
},
// 导出会员卡档案 Excel
exportCardBase: async (params) => {
return await request.download({ url: `/mall/card-base/export-excel`, params })
},
}

View File

@ -0,0 +1,43 @@
import request from '@/config/axios'
// 发卡记录 VO
export interface CardLogVO {
id: number // 编号
nickName: string // 会员昵称
phone: string // 手机号
countNumber: number // 数量
cardSection: number // 区间
}
// 发卡记录 API
export const CardLogApi = {
// 查询发卡记录分页
getCardLogPage: async (params: any) => {
return await request.get({ url: `/send/card-log/page`, params })
},
// 查询发卡记录详情
getCardLog: async (id: number) => {
return await request.get({ url: `/send/card-log/get?id=` + id })
},
// 新增发卡记录
createCardLog: async (data: CardLogVO) => {
return await request.post({ url: `/send/card-log/create`, data })
},
// 修改发卡记录
updateCardLog: async (data: CardLogVO) => {
return await request.put({ url: `/send/card-log/update`, data })
},
// 删除发卡记录
deleteCardLog: async (id: number) => {
return await request.delete({ url: `/send/card-log/delete?id=` + id })
},
// 导出发卡记录 Excel
exportCardLog: async (params) => {
return await request.download({ url: `/send/card-log/export-excel`, params })
},
}

View File

@ -0,0 +1,44 @@
import request from '@/config/axios'
// 会员卡 VO
export interface CardVO {
id: number // 会员卡编号
parentId: number // 上级用户id
subId: number // 下级用户id
cardNumber: string // 会员卡号
isActivate: number // 是否已激活0未激活 1已激活
activateTime: number // 激活时间
}
// 会员卡 API
export const CardApi = {
// 查询会员卡分页
getCardPage: async (params: any) => {
return await request.get({ url: `/club/card/page`, params })
},
// 查询会员卡详情
getCard: async (id: number) => {
return await request.get({ url: `/club/card/get?id=` + id })
},
// 新增会员卡
createCard: async (data: CardVO) => {
return await request.post({ url: `/club/card/create`, data })
},
// 修改会员卡
updateCard: async (data: CardVO) => {
return await request.put({ url: `/club/card/update`, data })
},
// 删除会员卡
deleteCard: async (id: number) => {
return await request.delete({ url: `/club/card/delete?id=` + id })
},
// 导出会员卡 Excel
exportCard: async (params) => {
return await request.download({ url: `/club/card/export-excel`, params })
},
}

View File

@ -0,0 +1,45 @@
import request from '@/config/axios'
// 权益通知 VO
export interface InterestVO {
id: number // 权益编号
title: string // 权益标题
goodsName: string // 商品名称
desc: string // 权益描述
isUsed: string // 权益次数
equity: string // 权益内容
notice: string // 须知内容
}
// 权益通知 API
export const InterestApi = {
// 查询权益通知分页
getInterestPage: async (params: any) => {
return await request.get({ url: `/notice/interest/page`, params })
},
// 查询权益通知详情
getInterest: async (id: number) => {
return await request.get({ url: `/notice/interest/get?id=` + id })
},
// 新增权益通知
createInterest: async (data: InterestVO) => {
return await request.post({ url: `/notice/interest/create`, data })
},
// 修改权益通知
updateInterest: async (data: InterestVO) => {
return await request.put({ url: `/notice/interest/update`, data })
},
// 删除权益通知
deleteInterest: async (id: number) => {
return await request.delete({ url: `/notice/interest/delete?id=` + id })
},
// 导出权益通知 Excel
exportInterest: async (params) => {
return await request.download({ url: `/notice/interest/export-excel`, params })
},
}

View File

@ -0,0 +1,48 @@
import request from '@/config/axios'
// 付费会员权益 VO
export interface PaidMemberBenefitVO {
id: number // 编号
name: string // 名称
iconUrl: string // 图标地址
intro: string // 描述
status: boolean // 状态:(默认)0隐藏 1显示
sort: number // 排序
}
// 付费会员权益 API
export const PaidMemberBenefitApi = {
// 查询付费会员权益分页
getPaidMemberBenefitPage: async (params: any) => {
return await request.get({ url: `/paidmemberbenefit/paid-member-benefit/page`, params })
},
// 查询付费会员权益详情
getPaidMemberBenefit: async (id: number) => {
return await request.get({ url: `/paidmemberbenefit/paid-member-benefit/get?id=` + id })
},
// 新增付费会员权益
createPaidMemberBenefit: async (data: PaidMemberBenefitVO) => {
return await request.post({ url: `/paidmemberbenefit/paid-member-benefit/create`, data })
},
// 修改付费会员权益
updatePaidMemberBenefit: async (data: PaidMemberBenefitVO) => {
return await request.put({ url: `/paidmemberbenefit/paid-member-benefit/update`, data })
},
// 修改会员权益状态
updatePaidMemberBenefitStatus: async (data: any) => {
return await request.put({ url: `/paidmemberbenefit/paid-member-benefit/updateStatus`, data})
},
// 删除付费会员权益
deletePaidMemberBenefit: async (id: number) => {
return await request.delete({ url: `/paidmemberbenefit/paid-member-benefit/delete?id=` + id })
},
// 导出付费会员权益 Excel
exportPaidMemberBenefit: async (params) => {
return await request.download({ url: `/paidmemberbenefit/paid-member-benefit/export-excel`, params })
},
}

View File

@ -27,5 +27,5 @@ export const getWalletPage = async (params) => {
// 修改会员钱包余额 // 修改会员钱包余额
export const updateWalletBalance = async (data: any) => { export const updateWalletBalance = async (data: any) => {
return await request.post({ url: `/pay/wallet/update`, data }) return await request.put({ url: `/pay/wallet/update-balance`, data })
} }

View File

@ -0,0 +1,45 @@
import request from '@/config/axios'
// 会员卡划拨 VO
export interface TransferVO {
id: number // 编号
cardNumber: string // 会员卡号
assignorId: number // 合伙人
transfereeId: number // 会员
assignorPhone: string // 合伙人电话
transfereePhone: string // 会员电话
status: number // 状态
}
// 会员卡划拨 API
export const TransferApi = {
// 查询会员卡划拨分页
getTransferPage: async (params: any) => {
return await request.get({ url: `/card/transfer/page`, params })
},
// 查询会员卡划拨详情
getTransfer: async (id: number) => {
return await request.get({ url: `/card/transfer/get?id=` + id })
},
// 新增会员卡划拨
createTransfer: async (data: TransferVO) => {
return await request.post({ url: `/card/transfer/create`, data })
},
// 修改会员卡划拨
updateTransfer: async (data: TransferVO) => {
return await request.put({ url: `/card/transfer/update`, data })
},
// 删除会员卡划拨
deleteTransfer: async (id: number) => {
return await request.delete({ url: `/card/transfer/delete?id=` + id })
},
// 导出会员卡划拨 Excel
exportTransfer: async (params) => {
return await request.download({ url: `/card/transfer/export-excel`, params })
}
}

View File

@ -0,0 +1,45 @@
import request from '@/config/axios'
// 会员卡划拨记录 VO
export interface TransferLogVO {
id: number // 划拨id
cardNumber: string // 会员卡号
assignorId: number // 发起人
transfereeId: number // 划拨人
assignorPhone: string // 发起人手机
transfereePhone: string // 划拨人手机
status: number // 状态
}
// 会员卡划拨记录 API
export const TransferLogApi = {
// 查询会员卡划拨记录分页
getTransferLogPage: async (params: any) => {
return await request.get({ url: `/card/transfer-log/page`, params })
},
// 查询会员卡划拨记录详情
getTransferLog: async (id: number) => {
return await request.get({ url: `/card/transfer-log/get?id=` + id })
},
// 新增会员卡划拨记录
createTransferLog: async (data: TransferLogVO) => {
return await request.post({ url: `/card/transfer-log/create`, data })
},
// 修改会员卡划拨记录
updateTransferLog: async (data: TransferLogVO) => {
return await request.put({ url: `/card/transfer-log/update`, data })
},
// 删除会员卡划拨记录
deleteTransferLog: async (id: number) => {
return await request.delete({ url: `/card/transfer-log/delete?id=` + id })
},
// 导出会员卡划拨记录 Excel
exportTransferLog: async (params) => {
return await request.download({ url: `/card/transfer-log/export-excel`, params })
},
}

View File

@ -227,6 +227,7 @@ export enum DICT_TYPE {
PROMOTION_BARGAIN_RECORD_STATUS = 'promotion_bargain_record_status', // 砍价记录的状态 PROMOTION_BARGAIN_RECORD_STATUS = 'promotion_bargain_record_status', // 砍价记录的状态
PROMOTION_COMBINATION_RECORD_STATUS = 'promotion_combination_record_status', // 拼团记录的状态 PROMOTION_COMBINATION_RECORD_STATUS = 'promotion_combination_record_status', // 拼团记录的状态
PROMOTION_BANNER_POSITION = 'promotion_banner_position', // banner 定位 PROMOTION_BANNER_POSITION = 'promotion_banner_position', // banner 定位
MEMBER_BENEFIT_STATUS = 'member_benefit_status', // 会员权益状态
// ========== CRM - 客户管理模块 ========== // ========== CRM - 客户管理模块 ==========
CRM_AUDIT_STATUS = 'crm_audit_status', // CRM 审批状态 CRM_AUDIT_STATUS = 'crm_audit_status', // CRM 审批状态
@ -257,5 +258,7 @@ export enum DICT_TYPE {
AI_WRITE_LANGUAGE = 'ai_write_language', // AI 写作语言 AI_WRITE_LANGUAGE = 'ai_write_language', // AI 写作语言
// ========== 通用模块 ========== // ========== 通用模块 ==========
ZERO_OR_ONE = 'zero_or_one' ZERO_OR_ONE = 'zero_or_one',
IS_ACTIVATE = 'is_activate',
CARD_STATUS = 'card_status'
} }

View File

@ -0,0 +1,117 @@
<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="nickName">
<el-input v-model="formData.nickName" placeholder="请输入合伙人手机号" />
</el-form-item>
<el-form-item label="手机号" prop="phone">
<el-input v-model="formData.phone" placeholder="请输入手机号" />
</el-form-item>
<el-form-item label="会员卡号" prop="cardNumber">
<el-input v-model="formData.cardNumber" placeholder="请输入会员卡号" />
</el-form-item>
<el-form-item label="激活状态" prop="isActivate">
<el-radio-group v-model="formData.isActivate">
<el-radio
v-for="dict in getIntDictOptions(DICT_TYPE.IS_ACTIVATE)"
:key="dict.value"
:label="dict.value"
>
{{ dict.label }}
</el-radio>
</el-radio-group>
</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 { getIntDictOptions, DICT_TYPE } from '@/utils/dict'
import { CardApi, CardVO } from '@/api/club/clubCard'
/** 会员卡 表单 */
defineOptions({ name: 'CardForm' })
const { t } = useI18n() //
const message = useMessage() //
const dialogVisible = ref(false) //
const dialogTitle = ref('') //
const formLoading = ref(false) // 12
const formType = ref('') // create - update -
const formData = ref({
id: undefined,
nickName: undefined,
phone: undefined,
cardNumber: undefined,
isActivate: undefined,
activateTime: undefined,
})
const formRules = reactive({
})
const formRef = ref() // 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 CardApi.getCard(id)
} finally {
formLoading.value = false
}
}
}
defineExpose({ open }) // open
/** 提交表单 */
const emit = defineEmits(['success']) // success
const submitForm = async () => {
//
await formRef.value.validate()
//
formLoading.value = true
try {
const data = formData.value as unknown as CardVO
if (formType.value === 'create') {
await CardApi.createCard(data)
message.success(t('common.createSuccess'))
} else {
await CardApi.updateCard(data)
message.success(t('common.updateSuccess'))
}
dialogVisible.value = false
//
emit('success')
} finally {
formLoading.value = false
}
}
/** 重置表单 */
const resetForm = () => {
formData.value = {
id: undefined,
nickName: undefined,
phone: undefined,
cardNumber: undefined,
isActivate: undefined,
activateTime: undefined,
}
formRef.value?.resetFields()
}
</script>

View File

@ -0,0 +1,237 @@
<template>
<ContentWrap>
<!-- 搜索工作栏 -->
<el-form
class="-mb-15px"
:model="queryParams"
ref="queryFormRef"
:inline="true"
label-width="100px"
>
<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="phone">
<el-input
v-model="queryParams.phone"
placeholder="请输入领取人手机号"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="会员卡号" prop="cardNumber">
<el-input
v-model="queryParams.cardNumber"
placeholder="请输入会员卡号"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="激活状态" prop="isActivate">
<el-select
v-model="queryParams.isActivate"
placeholder="请选择激活状态"
clearable
class="!w-240px"
>
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.IS_ACTIVATE)"
: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"
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-button-->
<!-- type="primary"-->
<!-- plain-->
<!-- @click="openForm('create')"-->
<!-- v-hasPermi="['club:card:create']"-->
<!-- >-->
<!-- <Icon icon="ep:plus" class="mr-5px" /> 新增-->
<!-- </el-button>-->
<el-button
type="success"
plain
@click="handleExport"
:loading="exportLoading"
v-hasPermi="['club:card:export']"
>
<Icon icon="ep:download" 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" />
<el-table-column label="会员卡号" align="center" prop="cardNumber" />
<el-table-column label="合伙人姓名" align="center" prop="parentName" />
<el-table-column label="合伙人手机" align="center" prop="nickName" />
<el-table-column label="领取人手机" align="center" prop="phone" />
<el-table-column label="领取人姓名" align="center" prop="subName" />
<el-table-column label="激活状态" align="center" prop="isActivate">
<template #default="scope">
<dict-tag :type="DICT_TYPE.IS_ACTIVATE" :value="scope.row.isActivate" />
</template>
</el-table-column>
<el-table-column
label="领取时间"
align="center"
prop="activateTime"
:formatter="dateFormatter"
width="180px"
/>
<!-- <el-table-column label="操作" align="center">-->
<!-- <template #default="scope">-->
<!--&lt;!&ndash; <el-button&ndash;&gt;-->
<!--&lt;!&ndash; link&ndash;&gt;-->
<!--&lt;!&ndash; type="primary"&ndash;&gt;-->
<!--&lt;!&ndash; @click="openForm('update', scope.row.id)"&ndash;&gt;-->
<!--&lt;!&ndash; v-hasPermi="['club:card:update']"&ndash;&gt;-->
<!--&lt;!&ndash; >&ndash;&gt;-->
<!--&lt;!&ndash; 编辑&ndash;&gt;-->
<!--&lt;!&ndash; </el-button>&ndash;&gt;-->
<!-- <el-button-->
<!-- link-->
<!-- type="danger"-->
<!-- @click="handleDelete(scope.row.id)"-->
<!-- v-hasPermi="['club:card:delete']"-->
<!-- >-->
<!-- 删除-->
<!-- </el-button>-->
<!-- </template>-->
<!-- </el-table-column>-->
</el-table>
<!-- 分页 -->
<Pagination
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</ContentWrap>
<!-- 表单弹窗添加/修改 -->
<CardForm ref="formRef" @success="getList" />
</template>
<script setup lang="ts">
import { getIntDictOptions, DICT_TYPE } from '@/utils/dict'
import { dateFormatter } from '@/utils/formatTime'
import download from '@/utils/download'
import { CardApi, CardVO } from '@/api/club/clubCard'
import CardForm from './CardForm.vue'
/** 会员卡 列表 */
defineOptions({ name: 'ClubCard' })
const message = useMessage() //
const { t } = useI18n() //
const loading = ref(true) //
const list = ref<CardVO[]>([]) //
const total = ref(0) //
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
nickName: undefined,
phone: undefined,
cardNumber: undefined,
parentName: undefined,
subName: undefined,
isActivate: undefined,
activateTime: undefined,
createTime: [],
})
const queryFormRef = ref() //
const exportLoading = ref(false) //
/** 查询列表 */
const getList = async () => {
loading.value = true
try {
const data = await CardApi.getCardPage(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 formRef = ref()
const openForm = (type: string, id?: number) => {
formRef.value.open(type, id)
}
/** 删除按钮操作 */
const handleDelete = async (id: number) => {
try {
//
await message.delConfirm()
//
await CardApi.deleteCard(id)
message.success(t('common.delSuccess'))
//
await getList()
} catch {}
}
/** 导出按钮操作 */
const handleExport = async () => {
try {
//
await message.exportConfirm()
//
exportLoading.value = true
const data = await CardApi.exportCard(queryParams)
console.log(data,'data')
download.excel(data, '会员卡.xls')
} catch {
} finally {
exportLoading.value = false
}
}
/** 初始化 **/
onMounted(() => {
getList()
})
</script>

View File

@ -0,0 +1,182 @@
<template>
<Dialog title="会员卡列表" v-model="dialogVisible">
<ContentWrap>
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
<el-table-column label="编号" align="center" prop="id" />
<el-table-column label="会员卡号" align="center" prop="cardNumber" />
<!-- <el-table-column label="昵称" align="center" prop="nickName" />-->
<!-- <el-table-column label="合伙人" align="center" prop="nickName" />-->
<el-table-column label="领取人" align="center" prop="phone" />
<el-table-column label="激活状态" align="center" prop="isActivate">
<template #default="scope">
<dict-tag :type="DICT_TYPE.IS_ACTIVATE" :value="scope.row.isActivate" />
</template>
</el-table-column>
<el-table-column
label="领取时间"
align="center"
prop="activateTime"
:formatter="dateFormatter"
width="180px"
/>
<el-table-column label="操作" align="center">
<template #default="scope">
<!-- <el-button-->
<!-- link-->
<!-- type="primary"-->
<!-- @click="openForm('update', scope.row.id)"-->
<!-- v-hasPermi="['club:card:update']"-->
<!-- >-->
<!-- 编辑-->
<!-- </el-button>-->
<el-button
link
type="danger"
@click="handleDelete(scope.row.id)"
v-hasPermi="['club:card:delete']"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
<Pagination
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</ContentWrap>
<!-- <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 { CardLogApi, CardLogVO } from '@/api/cardlog'
import {CardApi, CardVO} from "@/api/club/clubCard";
import { getIntDictOptions, DICT_TYPE } from '@/utils/dict'
import { dateFormatter } from '@/utils/formatTime'
/** 发卡记录 表单 */
defineOptions({ name: 'CardLogForm' })
const { t } = useI18n() //
const message = useMessage() //
const loading = ref(false) //
const list = ref<CardVO[]>([]) //
const total = ref(0) //
const dialogVisible = ref(false) //
const dialogTitle = ref('') //
const formLoading = ref(false) // 12
const formType = ref('') // create - update -
const formData = ref({
id: undefined,
nickName: undefined,
phone: undefined,
countNumber: undefined,
})
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
nickName: undefined,
phone: undefined,
cardNumber: undefined,
isActivate: undefined,
activateTime: undefined,
createTime: [],
})
const formRules = reactive({
})
const formRef = ref() // Ref
/** 查询列表 */
const getList = async () => {
loading.value = true
try {
const data = await CardApi.getCardPage(queryParams)
list.value = data.list
total.value = data.total
} finally {
loading.value = false
}
}
/** 会员卡删除按钮操作 */
const handleDelete = async (id: number) => {
try {
//
await message.delConfirm()
//
let st = await CardApi.deleteCard(id)
// message.success(t('common.delSuccess'))
if (st){
message.success(t('common.delSuccess'))
}else {
message.error("删除失败,状态不是未激活")
}
//
await getList()
} catch {}
}
/** 打开弹窗 */
const openCardList = async (phone: String) => {
dialogVisible.value = true
// dialogTitle.value = t('action.' + type)
// formType.value = type
resetForm()
//
formLoading.value = true
try {
// formData.value = await CardLogApi.getCardLog(id)
queryParams.nickName = phone
const data = await CardApi.getCardPage(queryParams)
list.value = data.list
total.value = data.total
} finally {
formLoading.value = false
}
}
defineExpose({ openCardList }) // open
/** 提交表单 */
const emit = defineEmits(['success']) // success
const submitForm = async () => {
//
await formRef.value.validate()
//
formLoading.value = true
try {
const data = formData.value as unknown as CardLogVO
if (formType.value === 'create') {
await CardLogApi.createCardLog(data)
message.success(t('common.createSuccess'))
} else {
await CardLogApi.updateCardLog(data)
message.success(t('common.updateSuccess'))
}
dialogVisible.value = false
//
emit('success')
} finally {
formLoading.value = false
}
}
/** 重置表单 */
const resetForm = () => {
formData.value = {
id: undefined,
nickName: undefined,
phone: undefined,
cardNumber: undefined,
isActivate: undefined,
activateTime: undefined,
}
formRef.value?.resetFields()
}
</script>

View File

@ -0,0 +1,104 @@
<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="nickName">
<el-input v-model="formData.nickName" placeholder="请输入会员昵称" />
</el-form-item>
<el-form-item label="手机号" prop="phone">
<el-input v-model="formData.phone" placeholder="请输入手机号" />
</el-form-item>
<el-form-item label="数量" prop="countNumber">
<el-input v-model="formData.countNumber" placeholder="请输入数量" />
</el-form-item>
<el-form-item label="卡号区间" prop="cardSection">
<el-input v-model="formData.cardSection" 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 { CardLogApi, CardLogVO } from '@/api/cardlog'
/** 发卡记录 表单 */
defineOptions({ name: 'CardLogForm' })
const { t } = useI18n() //
const message = useMessage() //
const dialogVisible = ref(false) //
const dialogTitle = ref('') //
const formLoading = ref(false) // 12
const formType = ref('') // create - update -
const formData = ref({
id: undefined,
nickName: undefined,
phone: undefined,
countNumber: undefined,
})
const formRules = reactive({
})
const formRef = ref() // 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 CardLogApi.getCardLog(id)
} finally {
formLoading.value = false
}
}
}
defineExpose({ open }) // open
/** 提交表单 */
const emit = defineEmits(['success']) // success
const submitForm = async () => {
//
await formRef.value.validate()
//
formLoading.value = true
try {
const data = formData.value as unknown as CardLogVO
if (formType.value === 'create') {
await CardLogApi.createCardLog(data)
message.success(t('common.createSuccess'))
} else {
await CardLogApi.updateCardLog(data)
message.success(t('common.updateSuccess'))
}
dialogVisible.value = false
//
emit('success')
} finally {
formLoading.value = false
}
}
/** 重置表单 */
const resetForm = () => {
formData.value = {
id: undefined,
nickName: undefined,
phone: undefined,
countNumber: undefined,
}
formRef.value?.resetFields()
}
</script>

View File

@ -0,0 +1,235 @@
<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="phone">
<el-input
v-model="queryParams.phone"
placeholder="请输入手机号"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="数量" prop="countNumber">
<el-input
v-model="queryParams.countNumber"
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-button-->
<!-- type="primary"-->
<!-- plain-->
<!-- @click="openForm('create')"-->
<!-- v-hasPermi="['send:card-log:create']"-->
<!-- >-->
<!-- <Icon icon="ep:plus" class="mr-5px" /> 新增-->
<!-- </el-button>-->
<el-button
type="success"
plain
@click="handleExport"
:loading="exportLoading"
v-hasPermi="['send:card-log:export']"
>
<Icon icon="ep:download" 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" />
<el-table-column label="合伙人昵称" align="center" prop="nickName" />
<el-table-column label="手机号" align="center" prop="phone" />
<el-table-column label="数量" align="center" prop="countNumber" />
<!-- <el-table-column label="卡号区间" align="center" prop="cardSection" @click="toCards" />-->
<el-table-column prop="cardSection" label="卡号区间" >
<template #default="scope">
<div @click="toCards(scope.row.phone)">{{scope.row.cardSection}}</div>
</template>
</el-table-column>
<el-table-column
label="发卡时间"
align="center"
prop="createTime"
:formatter="dateFormatter"
width="180px"
/>
<!-- <el-table-column label="操作" align="center">-->
<!-- <template #default="scope">-->
<!-- <el-button-->
<!-- link-->
<!-- type="primary"-->
<!-- @click="openForm('update', scope.row.id)"-->
<!-- v-hasPermi="['send:card-log:update']"-->
<!-- >-->
<!-- 编辑-->
<!-- </el-button>-->
<!-- <el-button-->
<!-- link-->
<!-- type="danger"-->
<!-- @click="handleDelete(scope.row.id)"-->
<!-- v-hasPermi="['send:card-log:delete']"-->
<!-- >-->
<!-- 删除-->
<!-- </el-button>-->
<!-- </template>-->
<!-- </el-table-column>-->
</el-table>
<!-- 分页 -->
<Pagination
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</ContentWrap>
<!-- 表单弹窗添加/修改 -->
<CardLogForm ref="formRef" @success="getList" />
<CardList ref="cardListFormRef" @success="getList" />
</template>
<script setup lang="ts">
import { dateFormatter } from '@/utils/formatTime'
import download from '@/utils/download'
import { CardLogApi, CardLogVO } from '@/api/cardlog'
import { CardApi, CardVO } from '@/api/club/clubCard'
import CardLogForm from './CardLogForm.vue'
import CardList from './CardList.vue'
/** 发卡记录 列表 */
defineOptions({ name: 'CardLog' })
const message = useMessage() //
const { t } = useI18n() //
const loading = ref(true) //
const list = ref<CardLogVO[]>([]) //
const total = ref(0) //
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
nickName: undefined,
phone: undefined,
countNumber: undefined,
cardSection: undefined,
createTime: [],
})
const queryParamsByCardList = reactive({
pageNo: 1,
pageSize: 10,
nickName: undefined,
phone: undefined,
cardNumber: undefined,
isActivate: undefined,
createTime: [],
})
const queryFormRef = ref() //
const exportLoading = ref(false) //
/** 查询列表 */
const getList = async () => {
loading.value = true
try {
const data = await CardLogApi.getCardLogPage(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 formRef = ref()
const openForm = (type: string, id?: number) => {
formRef.value.open(type, id)
}
/** 删除按钮操作 */
const handleDelete = async (id: number) => {
try {
//
await message.delConfirm()
//
await CardLogApi.deleteCardLog(id)
message.success(t('common.delSuccess'))
//
await getList()
} catch {}
}
/** 会员卡列表 */
const cardListFormRef = ref()
const toCards = async (phone: String) => {
cardListFormRef.value.openCardList(phone)
}
/** 导出按钮操作 */
const handleExport = async () => {
try {
//
await message.exportConfirm()
//
exportLoading.value = true
const data = await CardLogApi.exportCardLog(queryParams)
download.excel(data, '发卡记录.xls')
} catch {
} finally {
exportLoading.value = false
}
}
/** 初始化 **/
onMounted(() => {
getList()
})
</script>

View File

@ -0,0 +1,117 @@
<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="title">
<el-input v-model="formData.title" placeholder="请输入权益标题" />
</el-form-item>
<el-form-item label="权益次数" prop="title">
<el-input v-model="formData.isUsed" placeholder="请输入权益次数" />
</el-form-item>
<el-form-item label="商品名称" prop="goodsName">
<el-input v-model="formData.goodsName" placeholder="请输入商品名称" />
</el-form-item>
<el-form-item label="权益描述" prop="description">
<Editor v-model="formData.description" height="150px" />
</el-form-item>
<el-form-item label="权益内容" prop="equity">
<Editor v-model="formData.equity" height="150px" />
</el-form-item>
<el-form-item label="须知内容" prop="notice">
<Editor v-model="formData.notice" height="150px" />
</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 { InterestApi, InterestVO } from '@/api/interest'
/** 权益通知 表单 */
defineOptions({ name: 'InterestForm' })
const { t } = useI18n() //
const message = useMessage() //
const dialogVisible = ref(false) //
const dialogTitle = ref('') //
const formLoading = ref(false) // 12
const formType = ref('') // create - update -
const formData = ref({
id: undefined,
title: undefined,
goodsName: undefined,
description: undefined,
isUsed: undefined,
equity: undefined,
notice: undefined,
})
const formRules = reactive({
})
const formRef = ref() // 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 InterestApi.getInterest(id)
} finally {
formLoading.value = false
}
}
}
defineExpose({ open }) // open
/** 提交表单 */
const emit = defineEmits(['success']) // success
const submitForm = async () => {
//
await formRef.value.validate()
//
formLoading.value = true
try {
const data = formData.value as unknown as InterestVO
if (formType.value === 'create') {
console.log(data,'data')
await InterestApi.createInterest(data)
message.success(t('common.createSuccess'))
} else {
await InterestApi.updateInterest(data)
message.success(t('common.updateSuccess'))
}
dialogVisible.value = false
//
emit('success')
} finally {
formLoading.value = false
}
}
/** 重置表单 */
const resetForm = () => {
formData.value = {
id: undefined,
title: undefined,
goodsName: undefined,
description: undefined,
isUsed: undefined,
equity: undefined,
notice: undefined,
}
formRef.value?.resetFields()
}
</script>

View File

@ -0,0 +1,197 @@
<template>
<ContentWrap>
<!-- 搜索工作栏 -->
<el-form
class="-mb-15px"
:model="queryParams"
ref="queryFormRef"
:inline="true"
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 label="权益标题" prop="title">
<el-input
v-model="queryParams.title"
placeholder="请输入权益标题"
clearable
@keyup.enter="handleQuery"
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-button
type="primary"
plain
@click="openForm('create')"
v-hasPermi="['notice:interest:create']"
>
<Icon icon="ep:plus" class="mr-5px" /> 新增
</el-button>
<el-button
type="success"
plain
@click="handleExport"
:loading="exportLoading"
v-hasPermi="['notice:interest:export']"
>
<Icon icon="ep:download" 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" />
<el-table-column label="权益标题" align="center" prop="title" />
<el-table-column label="权益描述" align="center" prop="description" />
<el-table-column label="权益内容" align="center" prop="equity" />
<el-table-column label="须知内容" align="center" prop="notice" />
<el-table-column label="权益次数" align="center" prop="isUsed" />
<el-table-column label="商品名称" align="center" prop="goodsName" />
<el-table-column
label="创建时间"
align="center"
prop="createTime"
:formatter="dateFormatter"
width="180px"
/>
<el-table-column label="操作" align="center">
<template #default="scope">
<el-button
link
type="primary"
@click="openForm('update', scope.row.id)"
v-hasPermi="['notice:interest:update']"
>
编辑
</el-button>
<el-button
link
type="danger"
@click="handleDelete(scope.row.id)"
v-hasPermi="['notice:interest:delete']"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<Pagination
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</ContentWrap>
<!-- 表单弹窗添加/修改 -->
<InterestForm ref="formRef" @success="getList" />
</template>
<script setup lang="ts">
import { dateFormatter } from '@/utils/formatTime'
import download from '@/utils/download'
import { InterestApi, InterestVO } from '@/api/interest'
import InterestForm from './InterestForm.vue'
/** 权益通知 列表 */
defineOptions({ name: 'Interest' })
const message = useMessage() //
const { t } = useI18n() //
const loading = ref(true) //
const list = ref<InterestVO[]>([]) //
const total = ref(0) //
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
createTime: [],
title: undefined,
goodsName: undefined,
description: undefined,
equity: undefined,
isUsed: undefined,
notice: undefined,
})
const queryFormRef = ref() //
const exportLoading = ref(false) //
/** 查询列表 */
const getList = async () => {
loading.value = true
try {
const data = await InterestApi.getInterestPage(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 formRef = ref()
const openForm = (type: string, id?: number) => {
formRef.value.open(type, id)
}
/** 删除按钮操作 */
const handleDelete = async (id: number) => {
try {
//
await message.delConfirm()
//
await InterestApi.deleteInterest(id)
message.success(t('common.delSuccess'))
//
await getList()
} catch {}
}
/** 导出按钮操作 */
const handleExport = async () => {
try {
//
await message.exportConfirm()
//
exportLoading.value = true
const data = await InterestApi.exportInterest(queryParams)
download.excel(data, '权益通知.xls')
} catch {
} finally {
exportLoading.value = false
}
}
/** 初始化 **/
onMounted(() => {
getList()
})
</script>

View File

@ -0,0 +1,151 @@
<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="name">
<el-input v-model="formData.name" placeholder="请输入名称" />
</el-form-item>
<el-form-item label="图标" prop="iconUrl">
<UploadImg v-model="formData.iconUrl" :limit="1" :is-show-tip="false" />
</el-form-item>
<el-form-item label="描述" prop="intro">
<el-input v-model="formData.intro" placeholder="请输入描述" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="formData.status" class="!w-240px" placeholder="请选择" clearable>
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.MEMBER_BENEFIT_STATUS)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item label="会员等级" prop="levelIdList">
<el-checkbox-group v-model="formData.levelIdList">
<el-checkbox
v-for="dict in memberLevelList"
:key="dict.id"
:label="dict.id"
>
{{ dict.name }}
</el-checkbox>
</el-checkbox-group>
</el-form-item>
<el-form-item label="排序" prop="sort">
<el-input v-model="formData.sort" 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 { PaidMemberBenefitApi, PaidMemberBenefitVO } from '@/api/mall/promotion/memberbenefit'
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
import * as LevelApi from '@/api/member/level'
/** 付费会员权益 表单 */
defineOptions({ name: 'PaidMemberBenefitForm' })
const { t } = useI18n() //
const message = useMessage() //
const dialogVisible = ref(false) //
const dialogTitle = ref('') //
const formLoading = ref(false) // 12
const formType = ref('') // create - update -
const formData = ref({
id: undefined,
name: undefined,
iconUrl: undefined,
intro: undefined,
status: undefined,
sort: undefined,
levelIdList: []
})
const formRules = reactive({
name: [{ required: true, message: '名称不能为空', trigger: 'blur' }],
iconUrl: [{ required: true, message: '图标地址不能为空', trigger: 'blur' }],
status: [{ required: true, message: '状态', trigger: 'blur' }],
sort: [{ required: true, message: '排序不能为空', trigger: 'blur' }],
})
const formRef = ref() // Ref
const memberLevelList = 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 PaidMemberBenefitApi.getPaidMemberBenefit(id)
} finally {
formLoading.value = false
}
}
}
defineExpose({ open }) // open
/**查询等级列表 */
const getMemberLevelList = async () => {
const queryLevelParams = reactive({
status: 0
})
const resultData = await LevelApi.getLevelList(queryLevelParams)
memberLevelList.value = resultData
}
/** 提交表单 */
const emit = defineEmits(['success']) // success
const submitForm = async () => {
//
await formRef.value.validate()
//
formLoading.value = true
try {
const data = formData.value as unknown as PaidMemberBenefitVO
if (formType.value === 'create') {
await PaidMemberBenefitApi.createPaidMemberBenefit(data)
message.success(t('common.createSuccess'))
} else {
await PaidMemberBenefitApi.updatePaidMemberBenefit(data)
message.success(t('common.updateSuccess'))
}
dialogVisible.value = false
//
emit('success')
} finally {
formLoading.value = false
}
}
/** 重置表单 */
const resetForm = () => {
formData.value = {
id: undefined,
name: undefined,
iconUrl: undefined,
intro: undefined,
status: undefined,
sort: undefined,
}
formRef.value?.resetFields()
}
/** 初始化 **/
onMounted(() => {
getMemberLevelList()
})
</script>

View File

@ -0,0 +1,289 @@
<template>
<ContentWrap>
<!-- 搜索工作栏 -->
<el-form
class="-mb-15px"
:model="queryParams"
ref="queryFormRef"
:inline="true"
label-width="68px"
>
<el-form-item label="名称" prop="name">
<el-input
v-model="queryParams.name"
placeholder="请输入名称"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<!-- <el-form-item label="图标地址" prop="iconUrl">
<el-input
v-model="queryParams.iconUrl"
placeholder="请输入图标地址"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item> -->
<!-- <el-form-item label="描述" prop="intro">
<el-input
v-model="queryParams.intro"
placeholder="请输入描述"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item> -->
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" class="!w-240px" placeholder="请选择" clearable>
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.MEMBER_BENEFIT_STATUS)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item label="会员等级" prop="levelId">
<el-select v-model="queryParams.levelId" class="!w-240px" placeholder="请选择" clearable>
<el-option
v-for="dict in memberLevelList"
:key="dict.id"
:label="dict.name"
:value="dict.id"
/>
</el-select>
</el-form-item>
<!-- <el-form-item label="排序" prop="sort">
<el-input
v-model="queryParams.sort"
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-button
type="primary"
plain
@click="openForm('create')"
v-hasPermi="['paidmemberbenefit:paid-member-benefit:create']"
>
<Icon icon="ep:plus" class="mr-5px" /> 新增
</el-button>
<el-button
type="success"
plain
@click="handleExport"
:loading="exportLoading"
v-hasPermi="['paidmemberbenefit:paid-member-benefit:export']"
>
<Icon icon="ep:download" 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" />
<el-table-column label="名称" align="center" prop="name" />
<el-table-column align="center" label="图标" prop="avatar" width="80px">
<template #default="scope">
<img :src="scope.row.iconUrl" style="width: 40px" />
</template>
</el-table-column>
<el-table-column label="描述" align="center" prop="intro" />
<el-table-column align="center" label="状态" min-width="80">
<template #default="{ row }">
<el-switch
v-model="row.status"
:active-value="1"
:inactive-value="0"
active-text="显示"
inactive-text="隐藏"
inline-prompt
@click="handleStatusChange(row)"
/>
</template>
</el-table-column>
<el-table-column label="排序" align="center" prop="sort" />
<el-table-column
label="创建时间"
align="center"
prop="createTime"
:formatter="dateFormatter"
width="180px"
/>
<el-table-column label="操作" align="center">
<template #default="scope">
<el-button
link
type="primary"
@click="openForm('update', scope.row.id)"
v-hasPermi="['paidmemberbenefit:paid-member-benefit:update']"
>
编辑
</el-button>
<el-button
link
type="danger"
@click="handleDelete(scope.row.id)"
v-hasPermi="['paidmemberbenefit:paid-member-benefit:delete']"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<Pagination
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</ContentWrap>
<!-- 表单弹窗添加/修改 -->
<PaidMemberBenefitForm ref="formRef" @success="getList" />
</template>
<script setup lang="ts">
import { dateFormatter } from '@/utils/formatTime'
import download from '@/utils/download'
import { PaidMemberBenefitApi, PaidMemberBenefitVO } from '@/api/mall/promotion/memberbenefit'
import PaidMemberBenefitForm from './PaidMemberBenefitForm.vue'
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
import { ProductSpuStatusEnum } from '@/utils/constants'
import * as LevelApi from '@/api/member/level'
/** 付费会员权益 列表 */
defineOptions({ name: 'PaidMemberBenefit' })
const message = useMessage() //
const { t } = useI18n() //
const loading = ref(true) //
const list = ref<PaidMemberBenefitVO[]>([]) //
const total = ref(0) //
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
name: undefined,
iconUrl: undefined,
intro: undefined,
status: undefined,
sort: undefined,
createTime: [],
levelId: undefined
})
const memberLevelList = ref() //
const queryFormRef = ref() //
const exportLoading = ref(false) //
/** 查询列表 */
const getList = async () => {
loading.value = true
try {
const data = await PaidMemberBenefitApi.getPaidMemberBenefitPage(queryParams)
list.value = data.list
total.value = data.total
} finally {
loading.value = false
}
}
/**查询等级列表 */
const getMemberLevelList = async () => {
const queryLevelParams = reactive({
status: 0
})
const resultData = await LevelApi.getLevelList(queryLevelParams)
memberLevelList.value = resultData
}
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.pageNo = 1
getList()
}
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value.resetFields()
handleQuery()
}
/** 添加/修改操作 */
const formRef = ref()
const openForm = (type: string, id?: number) => {
formRef.value.open(type, id)
}
/** 删除按钮操作 */
const handleDelete = async (id: number) => {
try {
//
await message.delConfirm()
//
await PaidMemberBenefitApi.deletePaidMemberBenefit(id)
message.success(t('common.delSuccess'))
//
await getList()
} catch {}
}
/** 导出按钮操作 */
const handleExport = async () => {
try {
//
await message.exportConfirm()
//
exportLoading.value = true
const data = await PaidMemberBenefitApi.exportPaidMemberBenefit(queryParams)
download.excel(data, '付费会员权益.xls')
} catch {
} finally {
exportLoading.value = false
}
}
/** 初始化 **/
onMounted(() => {
getMemberLevelList()
getList()
})
/** 更新显示/隐藏状态 */
const handleStatusChange = async (row: any) => {
try {
//
const text = row.status ? '显示' : '隐藏'
await message.confirm(`确认要${text}"${row.name}"吗?`)
//
await PaidMemberBenefitApi.updatePaidMemberBenefitStatus({id: row.id, status: row.status })
message.success(text + '成功')
//
await getList()
} catch {
row.status =
row.status === ProductSpuStatusEnum.DISABLE.status
? ProductSpuStatusEnum.ENABLE.status
: ProductSpuStatusEnum.DISABLE.status
}
}
</script>

View File

@ -1,117 +1,135 @@
<template> <template>
<Dialog :title="dialogTitle" v-model="dialogVisible"> <Dialog :title="dialogTitle" v-model="dialogVisible">
<el-form ref="formRef" :model="formData" :rules="formRules" label-width="120px" v-loading="formLoading"> <el-form
<el-form-item label="秒杀时段名称" prop="name"> ref="formRef"
<el-input v-model="formData.name" placeholder="请输入秒杀时段名称" /> :model="formData"
</el-form-item> :rules="formRules"
<el-form-item label="开始时间点" prop="startTime"> label-width="120px"
<el-time-picker v-model="formData.startTime" value-format="HH:mm" format="HH:mm" v-loading="formLoading"
placeholder="选择开始时间点" /> >
</el-form-item> <el-form-item label="秒杀时段名称" prop="name">
<el-form-item label="结束时间点" prop="endTime"> <el-input v-model="formData.name" placeholder="请输入秒杀时段名称" />
<el-time-picker v-model="formData.endTime" value-format="HH:mm" format="HH:mm" placeholder="选择结束时间点" /> </el-form-item>
</el-form-item> <el-form-item label="开始时间点" prop="startTime">
<el-form-item label="秒杀轮播图" prop="sliderPicUrls"> <el-time-picker
<UploadImgs v-model="formData.sliderPicUrls" placeholder="请输入秒杀轮播图" /> v-model="formData.startTime"
</el-form-item> value-format="HH:mm"
<el-form-item label="活动状态" prop="status"> format="HH:mm"
<el-radio-group v-model="formData.status"> placeholder="选择开始时间点"
<el-radio v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" :key="dict.value" />
:label="dict.value"> </el-form-item>
{{ dict.label }} <el-form-item label="结束时间点" prop="endTime">
</el-radio> <el-time-picker
</el-radio-group> v-model="formData.endTime"
</el-form-item> value-format="HH:mm"
</el-form> format="HH:mm"
<template #footer> placeholder="选择结束时间点"
<el-button @click="submitForm" type="primary" :disabled="formLoading"> </el-button> />
<el-button @click="dialogVisible = false"> </el-button> </el-form-item>
</template> <el-form-item label="秒杀轮播图" prop="sliderPicUrls">
</Dialog> <UploadImgs v-model="formData.sliderPicUrls" 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>
<template #footer>
<el-button @click="submitForm" type="primary" :disabled="formLoading"> </el-button>
<el-button @click="dialogVisible = false"> </el-button>
</template>
</Dialog>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { getIntDictOptions, DICT_TYPE } from '@/utils/dict' import { getIntDictOptions, DICT_TYPE } from '@/utils/dict'
import { SeckillConfigApi, SeckillConfigVO } from '@/api/mall/promotion/seckill/seckillConfig.ts' import { SeckillConfigApi, SeckillConfigVO } from '@/api/mall/promotion/seckill/seckillConfig.ts'
import { CommonStatusEnum } from '@/utils/constants' import { CommonStatusEnum } from '@/utils/constants'
/** 秒杀时段 表单 */ /** 秒杀时段 表单 */
defineOptions({ name: 'SeckillConfigForm' }) defineOptions({ name: 'SeckillConfigForm' })
const { t } = useI18n() // const { t } = useI18n() //
const message = useMessage() // const message = useMessage() //
const dialogVisible = ref(false) // const dialogVisible = ref(false) //
const dialogTitle = ref('') // const dialogTitle = ref('') //
const formLoading = ref(false) // 12 const formLoading = ref(false) // 12
const formType = ref('') // create - update - const formType = ref('') // create - update -
const formData = ref({ const formData = ref({
id: undefined, id: undefined,
name: undefined, name: undefined,
startTime: undefined, startTime: undefined,
endTime: undefined, endTime: undefined,
sliderPicUrls: undefined, sliderPicUrls: undefined,
status: undefined status: undefined
}) })
const formRules = reactive({ const formRules = reactive({
name: [{ required: true, message: '秒杀时段名称不能为空', trigger: 'blur' }], name: [{ required: true, message: '秒杀时段名称不能为空', trigger: 'blur' }],
startTime: [{ required: true, message: '开始时间点不能为空', trigger: 'blur' }], startTime: [{ required: true, message: '开始时间点不能为空', trigger: 'blur' }],
endTime: [{ required: true, message: '结束时间点不能为空', trigger: 'blur' }], endTime: [{ required: true, message: '结束时间点不能为空', trigger: 'blur' }],
status: [{ required: true, message: '活动状态不能为空', trigger: 'blur' }] status: [{ required: true, message: '活动状态不能为空', trigger: 'blur' }]
}) })
const formRef = ref() // Ref const formRef = ref() // Ref
/** 打开弹窗 */ /** 打开弹窗 */
const open = async (type : string, id ?: number) => { const open = async (type: string, id?: number) => {
dialogVisible.value = true dialogVisible.value = true
dialogTitle.value = t('action.' + type) dialogTitle.value = t('action.' + type)
formType.value = type formType.value = type
resetForm() resetForm()
// //
if (id) { if (id) {
formLoading.value = true formLoading.value = true
try { try {
formData.value = await SeckillConfigApi.getSeckillConfig(id) formData.value = await SeckillConfigApi.getSeckillConfig(id)
} finally { } finally {
formLoading.value = false formLoading.value = false
} }
} }
} }
defineExpose({ open }) // open defineExpose({ open }) // open
/** 提交表单 */ /** 提交表单 */
const emit = defineEmits(['success']) // success const emit = defineEmits(['success']) // success
const submitForm = async () => { const submitForm = async () => {
// //
await formRef.value.validate() await formRef.value.validate()
// //
formLoading.value = true formLoading.value = true
try { try {
const data = formData.value as unknown as SeckillConfigVO const data = formData.value as unknown as SeckillConfigVO
if (formType.value === 'create') { if (formType.value === 'create') {
await SeckillConfigApi.createSeckillConfig(data) await SeckillConfigApi.createSeckillConfig(data)
message.success(t('common.createSuccess')) message.success(t('common.createSuccess'))
} else { } else {
await SeckillConfigApi.updateSeckillConfig(data) await SeckillConfigApi.updateSeckillConfig(data)
message.success(t('common.updateSuccess')) message.success(t('common.updateSuccess'))
} }
dialogVisible.value = false dialogVisible.value = false
// //
emit('success') emit('success')
} finally { } finally {
formLoading.value = false formLoading.value = false
} }
} }
/** 重置表单 */ /** 重置表单 */
const resetForm = () => { const resetForm = () => {
formData.value = { formData.value = {
id: undefined, id: undefined,
name: undefined, name: undefined,
startTime: undefined, startTime: undefined,
endTime: undefined, endTime: undefined,
sliderPicUrls: [], sliderPicUrls: [],
status: CommonStatusEnum.ENABLE status: CommonStatusEnum.ENABLE
} }
formRef.value?.resetFields() formRef.value?.resetFields()
} }
</script> </script>

View File

@ -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) // 12
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>

View 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) // 12
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>

View File

@ -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) // 12
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>

View File

@ -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) // 12
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>

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View 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,
activate: 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>

View File

@ -0,0 +1,106 @@
<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="cardNum">
<el-input v-model="formData.cardNum" placeholder="请输入卡号" />
</el-form-item>
<el-form-item label="卡密" prop="scret">
<el-input v-model="formData.scret" placeholder="请输入卡密" />
</el-form-item>
<!-- <el-form-item label="上级id" prop="parentId">-->
<!-- <el-input v-model="formData.parentId" placeholder="请输入上级id" />-->
<!-- </el-form-item>-->
<!-- <el-form-item label="下级id" prop="subId">-->
<!-- <el-input v-model="formData.subId" placeholder="请输入下级id" />-->
<!-- </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 { CardBaseApi, CardBaseVO } from '@/api/cardbase'
/** 会员卡档案 表单 */
defineOptions({ name: 'CardBaseForm' })
const { t } = useI18n() //
const message = useMessage() //
const dialogVisible = ref(false) //
const dialogTitle = ref('') //
const formLoading = ref(false) // 12
const formType = ref('') // create - update -
const formData = ref({
id: undefined,
cardNum: undefined,
scret: undefined,
parentId: undefined,
subId: undefined,
})
const formRules = reactive({
})
const formRef = ref() // 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 CardBaseApi.getCardBase(id)
} finally {
formLoading.value = false
}
}
}
defineExpose({ open }) // open
/** 提交表单 */
const emit = defineEmits(['success']) // success
const submitForm = async () => {
//
await formRef.value.validate()
//
formLoading.value = true
try {
const data = formData.value as unknown as CardBaseVO
if (formType.value === 'create') {
await CardBaseApi.createCardBase(data)
message.success(t('common.createSuccess'))
} else {
await CardBaseApi.updateCardBase(data)
message.success(t('common.updateSuccess'))
}
dialogVisible.value = false
//
emit('success')
} finally {
formLoading.value = false
}
}
/** 重置表单 */
const resetForm = () => {
formData.value = {
id: undefined,
cardNum: undefined,
scret: undefined,
parentId: undefined,
subId: undefined,
}
formRef.value?.resetFields()
}
</script>

View File

@ -0,0 +1,220 @@
<template>
<ContentWrap>
<!-- 搜索工作栏 -->
<el-form
class="-mb-15px"
:model="queryParams"
ref="queryFormRef"
:inline="true"
label-width="68px"
>
<el-form-item label="卡号" prop="cardNum">
<el-input
v-model="queryParams.cardNum"
placeholder="请输入卡号"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="卡密" prop="scret">
<el-input
v-model="queryParams.scret"
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 label="上级id" prop="parentId">-->
<!-- <el-input-->
<!-- v-model="queryParams.parentId"-->
<!-- placeholder="请输入上级id"-->
<!-- clearable-->
<!-- @keyup.enter="handleQuery"-->
<!-- class="!w-240px"-->
<!-- />-->
<!-- </el-form-item>-->
<!-- <el-form-item label="下级id" prop="subId">-->
<!-- <el-input-->
<!-- v-model="queryParams.subId"-->
<!-- placeholder="请输入下级id"-->
<!-- clearable-->
<!-- @keyup.enter="handleQuery"-->
<!-- 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-button
type="primary"
plain
@click="openForm('create')"
v-hasPermi="['mall:card-base:create']"
>
<Icon icon="ep:plus" class="mr-5px" /> 新增
</el-button>
<el-button
type="success"
plain
@click="handleExport"
:loading="exportLoading"
v-hasPermi="['mall:card-base:export']"
>
<Icon icon="ep:download" 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" />
<el-table-column label="会员卡号" align="center" prop="cardNum" />
<el-table-column label="卡密" align="center" prop="scret" />
<el-table-column
label="创建时间"
align="center"
prop="createTime"
:formatter="dateFormatter"
width="180px"
/>
<!-- <el-table-column label="上级id" align="center" prop="parentId" />-->
<!-- <el-table-column label="下级id" align="center" prop="subId" />-->
<el-table-column label="操作" align="center">
<template #default="scope">
<el-button
link
type="primary"
@click="openForm('update', scope.row.id)"
v-hasPermi="['mall:card-base:update']"
>
编辑
</el-button>
<el-button
link
type="danger"
@click="handleDelete(scope.row.id)"
v-hasPermi="['mall:card-base:delete']"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<Pagination
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</ContentWrap>
<!-- 表单弹窗添加/修改 -->
<CardBaseForm ref="formRef" @success="getList" />
</template>
<script setup lang="ts">
import { dateFormatter } from '@/utils/formatTime'
import download from '@/utils/download'
import { CardBaseApi, CardBaseVO } from '@/api/cardbase'
import CardBaseForm from './CardBaseForm.vue'
/** 会员卡档案 列表 */
defineOptions({ name: 'CardBase' })
const message = useMessage() //
const { t } = useI18n() //
const loading = ref(true) //
const list = ref<CardBaseVO[]>([]) //
const total = ref(0) //
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
cardNum: undefined,
scret: undefined,
createTime: [],
parentId: undefined,
subId: undefined,
})
const queryFormRef = ref() //
const exportLoading = ref(false) //
/** 查询列表 */
const getList = async () => {
loading.value = true
try {
const data = await CardBaseApi.getCardBasePage(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 formRef = ref()
const openForm = (type: string, id?: number) => {
formRef.value.open(type, id)
}
/** 删除按钮操作 */
const handleDelete = async (id: number) => {
try {
//
await message.delConfirm()
//
await CardBaseApi.deleteCardBase(id)
message.success(t('common.delSuccess'))
//
await getList()
} catch {}
}
/** 导出按钮操作 */
const handleExport = async () => {
try {
//
await message.exportConfirm()
//
exportLoading.value = true
const data = await CardBaseApi.exportCardBase(queryParams)
download.excel(data, '会员卡档案.xls')
} catch {
} finally {
exportLoading.value = false
}
}
/** 初始化 **/
onMounted(() => {
getList()
})
</script>

View File

@ -1,20 +1,20 @@
<template> <template>
<Dialog title="修改用户余额" v-model="dialogVisible" width="600"> <Dialog v-model="dialogVisible" title="修改用户余额" width="600">
<el-form <el-form
ref="formRef" ref="formRef"
v-loading="formLoading"
:model="formData" :model="formData"
:rules="formRules" :rules="formRules"
label-width="100px" label-width="130px"
v-loading="formLoading"
> >
<el-form-item label="用户编号" prop="userId"> <el-form-item label="用户编号" prop="id">
<el-input v-model="formData.userId" class="!w-240px" disabled /> <el-input v-model="formData.id" class="!w-240px" disabled />
</el-form-item> </el-form-item>
<el-form-item label="用户昵称" prop="nickname"> <el-form-item label="用户昵称" prop="nickname">
<el-input v-model="formData.nickname" class="!w-240px" disabled /> <el-input v-model="formData.nickname" class="!w-240px" disabled />
</el-form-item> </el-form-item>
<el-form-item label="变动前余额" prop="balance"> <el-form-item label="变动前余额(元)" prop="balance">
<el-input-number v-model="formData.balance" class="!w-240px" :precision="2" disabled /> <el-input :model-value="formData.balance" class="!w-240px" disabled />
</el-form-item> </el-form-item>
<el-form-item label="变动类型" prop="changeType"> <el-form-item label="变动类型" prop="changeType">
<el-radio-group v-model="formData.changeType"> <el-radio-group v-model="formData.changeType">
@ -22,24 +22,32 @@
<el-radio :label="-1">减少</el-radio> <el-radio :label="-1">减少</el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-form-item label="变动余额" prop="changePoint"> <el-form-item label="变动余额(元)" prop="changeBalance">
<el-input-number v-model="formData.changePoint" class="!w-240px" :min="0" :precision="2" /> <el-input-number
v-model="formData.changeBalance"
:min="0"
:precision="2"
:step="0.1"
class="!w-240px"
/>
</el-form-item> </el-form-item>
<el-form-item label="变动后余额"> <el-form-item label="变动后余额(元)">
<el-input-number v-model="pointResult" class="!w-240px" :precision="2" disabled /> <el-input :model-value="balanceResult" class="!w-240px" disabled />
</el-form-item> </el-form-item>
</el-form> </el-form>
<template #footer> <template #footer>
<el-button @click="submitForm" type="primary" :disabled="formLoading"> </el-button> <el-button :disabled="formLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="dialogVisible = false"> </el-button> <el-button @click="dialogVisible = false"> </el-button>
</template> </template>
</Dialog> </Dialog>
</template> </template>
<script setup lang="ts"> <script lang="ts" setup>
import * as UserApi from '@/api/pay/wallet/balance' import * as UserApi from '@/api/member/user'
import * as UserApi2 from '@/api/member/user' import * as WalletApi from '@/api/pay/wallet/balance'
import { convertToInteger, formatToFraction } from '@/utils'
/** 修改用户余额表单 */ /** 修改用户余额表单 */
defineOptions({ name: 'UpdatePointForm' }) defineOptions({ name: 'UpdateBalanceForm' })
const { t } = useI18n() // const { t } = useI18n() //
const message = useMessage() // const message = useMessage() //
@ -48,14 +56,13 @@ const dialogVisible = ref(false) // 弹窗的是否展示
const formLoading = ref(false) // 12 const formLoading = ref(false) // 12
const formData = ref({ const formData = ref({
id: undefined, id: undefined,
userId: undefined,
nickname: undefined, nickname: undefined,
balance: 0, balance: '0',
changePoint: 0, changeBalance: 0,
changeType: 1 changeType: 1
}) })
const formRules = reactive({ const formRules = reactive({
changePoint: [{ required: true, message: '变动余额不能为空', trigger: 'blur' }] changeBalance: [{ required: true, message: '变动余额不能为空', trigger: 'blur' }]
}) })
const formRef = ref() // Ref const formRef = ref() // Ref
@ -67,14 +74,13 @@ const open = async (id?: number) => {
if (id) { if (id) {
formLoading.value = true formLoading.value = true
try { try {
const param = { userId: id } const user = await UserApi.getUser(id)
const wallet = await UserApi.getWallet(param) const wallet = await WalletApi.getWallet({ userId: user.id || 0 })
formData.value = wallet formData.value.id = user.id
formData.value.balance = wallet.balance / 100.0; formData.value.nickname = user.nickname
const user = await UserApi2.getUser(id); formData.value.balance = formatToFraction(wallet.balance)
formData.value.nickname = user.nickname;
formData.value.changeType = 1 // formData.value.changeType = 1 //
formData.value.changePoint = 0 // 0 formData.value.changeBalance = 0 // 0
} finally { } finally {
formLoading.value = false formLoading.value = false
} }
@ -90,11 +96,11 @@ const submitForm = async () => {
const valid = await formRef.value.validate() const valid = await formRef.value.validate()
if (!valid) return if (!valid) return
if (formData.value.changePoint < 1) { if (formData.value.changeBalance <= 0) {
message.error('变动余额不能小于 1') message.error('变动余额不能为零')
return return
} }
if (pointResult.value < 0) { if (convertToInteger(balanceResult.value) < 0) {
message.error('变动后的余额不能小于 0') message.error('变动后的余额不能小于 0')
return return
} }
@ -102,9 +108,9 @@ const submitForm = async () => {
// //
formLoading.value = true formLoading.value = true
try { try {
await UserApi.updateWalletBalance({ await WalletApi.updateWalletBalance({
id: formData.value.id, userId: formData.value.id,
balance: formData.value.changePoint * formData.value.changeType balance: convertToInteger(formData.value.changeBalance) * formData.value.changeType
}) })
message.success(t('common.updateSuccess')) message.success(t('common.updateSuccess'))
@ -121,14 +127,18 @@ const resetForm = () => {
formData.value = { formData.value = {
id: undefined, id: undefined,
nickname: undefined, nickname: undefined,
balance: undefined, balance: '0',
reason: undefined changeBalance: 0,
changeType: 1
} }
formRef.value?.resetFields() formRef.value?.resetFields()
} }
/** 变动后的余额 */ /** 变动后的余额 */
const pointResult = computed( const balanceResult = computed(() =>
() => formData.value.balance + formData.value.changePoint * formData.value.changeType formatToFraction(
convertToInteger(formData.value.balance) +
convertToInteger(formData.value.changeBalance) * formData.value.changeType
)
) )
</script> </script>

View File

@ -0,0 +1,124 @@
<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="cardNumber">
<el-input v-model="formData.cardNumber" placeholder="请输入会员卡号" />
</el-form-item>
<!-- <el-form-item label="合伙人" prop="assignorId">-->
<!-- <el-input v-model="formData.assignorId" placeholder="请输入合伙人" />-->
<!-- </el-form-item>-->
<!-- <el-form-item label="会员" prop="transfereeId">-->
<!-- <el-input v-model="formData.transfereeId" placeholder="请输入会员" />-->
<!-- </el-form-item>-->
<el-form-item label="合伙人电话" prop="assignorPhone">
<el-input v-model="formData.assignorPhone" placeholder="请输入合伙人电话" />
</el-form-item>
<el-form-item label="会员电话" prop="transfereePhone">
<el-input v-model="formData.transfereePhone" placeholder="请输入会员电话" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="formData.status" placeholder="请选择状态">
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.CARD_STATUS)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</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 { getIntDictOptions, DICT_TYPE } from '@/utils/dict'
import { TransferApi, TransferVO } from '@/api/transferCard'
/** 会员卡划拨 表单 */
defineOptions({ name: 'TransferForm' })
const { t } = useI18n() //
const message = useMessage() //
const dialogVisible = ref(false) //
const dialogTitle = ref('') //
const formLoading = ref(false) // 12
const formType = ref('') // create - update -
const formData = ref({
id: undefined,
cardNumber: undefined,
assignorId: undefined,
transfereeId: undefined,
assignorPhone: undefined,
transfereePhone: undefined,
status: undefined
})
const formRules = reactive({
})
const formRef = ref() // 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 TransferApi.getTransfer(id)
} finally {
formLoading.value = false
}
}
}
defineExpose({ open }) // open
/** 提交表单 */
const emit = defineEmits(['success']) // success
const submitForm = async () => {
//
await formRef.value.validate()
//
formLoading.value = true
try {
const data = formData.value as unknown as TransferVO
if (formType.value === 'create') {
await TransferApi.createTransfer(data)
message.success(t('common.createSuccess'))
} else {
await TransferApi.updateTransfer(data)
message.success(t('common.updateSuccess'))
}
dialogVisible.value = false
//
emit('success')
} finally {
formLoading.value = false
}
}
/** 重置表单 */
const resetForm = () => {
formData.value = {
id: undefined,
cardNumber: undefined,
assignorId: undefined,
transfereeId: undefined,
assignorPhone: undefined,
transfereePhone: undefined,
status: undefined
}
formRef.value?.resetFields()
}
</script>

View File

@ -0,0 +1,289 @@
<template>
<ContentWrap>
<!-- 搜索工作栏 -->
<el-form
class="-mb-15px"
:model="queryParams"
ref="queryFormRef"
:inline="true"
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 label="会员卡号" prop="cardNumber">
<el-input
v-model="queryParams.cardNumber"
placeholder="请输入会员卡号"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="合伙人" prop="assignorId">
<el-input
v-model="queryParams.assignorId"
placeholder="请输入合伙人"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="会员" prop="transfereeId">
<el-input
v-model="queryParams.transfereeId"
placeholder="请输入会员"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="合伙人电话" prop="assignorPhone">
<el-input
v-model="queryParams.assignorPhone"
placeholder="请输入合伙人电话"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="会员电话" prop="transfereePhone">
<el-input
v-model="queryParams.transfereePhone"
placeholder="请输入会员电话"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select
v-model="queryParams.status"
placeholder="请选择状态"
clearable
class="!w-240px"
>
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.CARD_STATUS)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</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-button
type="primary"
plain
@click="openForm('create')"
v-hasPermi="['card:transfer:create']"
>
<Icon icon="ep:plus" class="mr-5px" /> 新增
</el-button>
<el-button
type="success"
plain
@click="handleExport"
:loading="exportLoading"
v-hasPermi="['card:transfer:export']"
>
<Icon icon="ep:download" 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" />-->
<el-table-column label="会员卡号" align="center" prop="cardNumber" />
<!-- <el-table-column label="合伙人" align="center" prop="assignorId" />-->
<!-- <el-table-column label="会员" align="center" prop="transfereeId" />-->
<el-table-column label="合伙人电话" align="center" prop="assignorPhone" />
<el-table-column label="会员电话" align="center" prop="transfereePhone" />
<el-table-column label="状态" align="center" prop="status">
<template #default="scope">
<dict-tag :type="DICT_TYPE.CARD_STATUS" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column
label="创建时间"
align="center"
prop="createTime"
:formatter="dateFormatter"
width="180px"
/>
<el-table-column label="操作" align="center">
<template #default="scope" >
<div v-if="scope.row.status == 0">
<el-button
link
type="primary"
@click="handlePass(scope.row)"
v-hasPermi="['card:transfer:delete']"
>
通过
</el-button>
<el-button
link
type="danger"
@click="handleDelete(scope.row)"
v-hasPermi="['card:transfer:delete']"
>
驳回
</el-button>
</div>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<Pagination
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</ContentWrap>
<!-- 表单弹窗添加/修改 -->
<TransferForm ref="formRef" @success="getList" />
</template>
<script setup lang="ts">
import { getIntDictOptions, DICT_TYPE } from '@/utils/dict'
import { dateFormatter } from '@/utils/formatTime'
import download from '@/utils/download'
import { TransferApi, TransferVO } from '@/api/transferCard'
import TransferForm from './TransferForm.vue'
/** 会员卡划拨 列表 */
defineOptions({ name: 'Transfer' })
const message = useMessage() //
const { t } = useI18n() //
const loading = ref(true) //
const list = ref<TransferVO[]>([]) //
const total = ref(0) //
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
createTime: [],
cardNumber: undefined,
assignorId: undefined,
transfereeId: undefined,
assignorPhone: undefined,
transfereePhone: undefined,
status: undefined
})
const formData = ref({
id: undefined,
cardNumber: undefined,
assignorId: undefined,
transfereeId: undefined,
assignorPhone: undefined,
transfereePhone: undefined,
status: undefined
})
const queryFormRef = ref() //
const exportLoading = ref(false) //
/** 查询列表 */
const getList = async () => {
loading.value = true
try {
const data = await TransferApi.getTransferPage(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 formRef = ref()
const openForm = (type: string, id?: number) => {
formRef.value.open(type, id)
}
/** 审核驳回按钮操作 */
const handleDelete = async (list: any) => {
try {
//
await message.delConfirm('确定驳回该请求吗','审核确认')
//
const data = formData.value as unknown as TransferVO
data.cardNumber = list.cardNumber;
data.transfereeId = list.transfereeId;
data.transfereePhone = list.transfereePhone;
data.status = -1;
data.id = list.id;
await TransferApi.updateTransfer(data)
message.success(t('common.examineReject'))
//
await getList()
} catch {}
}
/** 审核通过按钮操作 */
const handlePass = async (list: any) => {
try {
//
await message.delConfirm('确定通过该审核吗?','审核确认')
//
const data = formData.value as unknown as TransferVO
data.cardNumber = list.cardNumber;
data.transfereeId = list.transfereeId;
data.transfereePhone = list.transfereePhone;
data.status = 1;
data.id = list.id;
await TransferApi.updateTransfer(data)
message.success(t('common.examinePass'))
//
await getList()
} catch {}
}
/** 导出按钮操作 */
const handleExport = async () => {
try {
//
await message.exportConfirm()
//
exportLoading.value = true
const data = await TransferApi.exportTransfer(queryParams)
download.excel(data, '会员卡划拨.xls')
} catch {
} finally {
exportLoading.value = false
}
}
/** 初始化 **/
onMounted(() => {
getList()
})
</script>

View File

@ -0,0 +1,124 @@
<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="cardNumber">
<el-input v-model="formData.cardNumber" placeholder="请输入会员卡号" />
</el-form-item>
<el-form-item label="发起人" prop="assignorId">
<el-input v-model="formData.assignorId" placeholder="请输入发起人" />
</el-form-item>
<el-form-item label="划拨人" prop="transfereeId">
<el-input v-model="formData.transfereeId" placeholder="请输入划拨人" />
</el-form-item>
<el-form-item label="发起人手机" prop="assignorPhone">
<el-input v-model="formData.assignorPhone" placeholder="请输入发起人手机" />
</el-form-item>
<el-form-item label="划拨人手机" prop="transfereePhone">
<el-input v-model="formData.transfereePhone" placeholder="请输入划拨人手机" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="formData.status" placeholder="请选择状态">
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.CARD_STATUS)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</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 { getIntDictOptions, DICT_TYPE } from '@/utils/dict'
import { TransferLogApi, TransferLogVO } from '@/api/transferlog'
/** 会员卡划拨记录 表单 */
defineOptions({ name: 'TransferLogForm' })
const { t } = useI18n() //
const message = useMessage() //
const dialogVisible = ref(false) //
const dialogTitle = ref('') //
const formLoading = ref(false) // 12
const formType = ref('') // create - update -
const formData = ref({
id: undefined,
cardNumber: undefined,
assignorId: undefined,
transfereeId: undefined,
assignorPhone: undefined,
transfereePhone: undefined,
status: undefined,
})
const formRules = reactive({
})
const formRef = ref() // 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 TransferLogApi.getTransferLog(id)
} finally {
formLoading.value = false
}
}
}
defineExpose({ open }) // open
/** 提交表单 */
const emit = defineEmits(['success']) // success
const submitForm = async () => {
//
await formRef.value.validate()
//
formLoading.value = true
try {
const data = formData.value as unknown as TransferLogVO
if (formType.value === 'create') {
await TransferLogApi.createTransferLog(data)
message.success(t('common.createSuccess'))
} else {
await TransferLogApi.updateTransferLog(data)
message.success(t('common.updateSuccess'))
}
dialogVisible.value = false
//
emit('success')
} finally {
formLoading.value = false
}
}
/** 重置表单 */
const resetForm = () => {
formData.value = {
id: undefined,
cardNumber: undefined,
assignorId: undefined,
transfereeId: undefined,
assignorPhone: undefined,
transfereePhone: undefined,
status: undefined,
}
formRef.value?.resetFields()
}
</script>

View File

@ -0,0 +1,253 @@
<template>
<ContentWrap>
<!-- 搜索工作栏 -->
<el-form
class="-mb-15px"
:model="queryParams"
ref="queryFormRef"
:inline="true"
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 label="会员卡号" prop="cardNumber">
<el-input
v-model="queryParams.cardNumber"
placeholder="请输入会员卡号"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="发起人" prop="assignorId">
<el-input
v-model="queryParams.assignorId"
placeholder="请输入发起人"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="划拨人" prop="transfereeId">
<el-input
v-model="queryParams.transfereeId"
placeholder="请输入划拨人"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="发起人手机" prop="assignorPhone">
<el-input
v-model="queryParams.assignorPhone"
placeholder="请输入发起人手机"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="划拨人手机" prop="transfereePhone">
<el-input
v-model="queryParams.transfereePhone"
placeholder="请输入划拨人手机"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select
v-model="queryParams.status"
placeholder="请选择状态"
clearable
class="!w-240px"
>
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.CARD_STATUS)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</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-button
type="primary"
plain
@click="openForm('create')"
v-hasPermi="['card:transfer-log:create']"
>
<Icon icon="ep:plus" class="mr-5px" /> 新增
</el-button>
<el-button
type="success"
plain
@click="handleExport"
:loading="exportLoading"
v-hasPermi="['card:transfer-log:export']"
>
<Icon icon="ep:download" 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="划拨id" align="center" prop="id" />-->
<el-table-column label="会员卡号" align="center" prop="cardNumber" />
<el-table-column label="发起人" align="center" prop="assignorId" />
<el-table-column label="划拨人" align="center" prop="transfereeId" />
<el-table-column label="发起人手机" align="center" prop="assignorPhone" />
<el-table-column label="划拨人手机" align="center" prop="transfereePhone" />
<!-- <el-table-column label="状态" align="center" prop="status">-->
<!-- <template #default="scope">-->
<!-- <dict-tag :type="DICT_TYPE.CARD_STATUS" :value="scope.row.status" />-->
<!-- </template>-->
<!-- </el-table-column>-->
<el-table-column
label="创建时间"
align="center"
prop="createTime"
:formatter="dateFormatter"
width="180px"
/>
<el-table-column label="操作" align="center">
<template #default="scope">
<el-button
link
type="primary"
@click="openForm('update', scope.row.id)"
v-hasPermi="['card:transfer-log:update']"
>
编辑
</el-button>
<el-button
link
type="danger"
@click="handleDelete(scope.row.id)"
v-hasPermi="['card:transfer-log:delete']"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<Pagination
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</ContentWrap>
<!-- 表单弹窗添加/修改 -->
<TransferLogForm ref="formRef" @success="getList" />
</template>
<script setup lang="ts">
import { getIntDictOptions, DICT_TYPE } from '@/utils/dict'
import { dateFormatter } from '@/utils/formatTime'
import download from '@/utils/download'
import { TransferLogApi, TransferLogVO } from '@/api/transferlog'
import TransferLogForm from './TransferLogForm.vue'
/** 会员卡划拨记录 列表 */
defineOptions({ name: 'TransferLog' })
const message = useMessage() //
const { t } = useI18n() //
const loading = ref(true) //
const list = ref<TransferLogVO[]>([]) //
const total = ref(0) //
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
createTime: [],
cardNumber: undefined,
assignorId: undefined,
transfereeId: undefined,
assignorPhone: undefined,
transfereePhone: undefined,
status: undefined,
})
const queryFormRef = ref() //
const exportLoading = ref(false) //
/** 查询列表 */
const getList = async () => {
loading.value = true
try {
const data = await TransferLogApi.getTransferLogPage(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 formRef = ref()
const openForm = (type: string, id?: number) => {
formRef.value.open(type, id)
}
/** 删除按钮操作 */
const handleDelete = async (id: number) => {
try {
//
await message.delConfirm()
//
await TransferLogApi.deleteTransferLog(id)
message.success(t('common.delSuccess'))
//
await getList()
} catch {}
}
/** 导出按钮操作 */
const handleExport = async () => {
try {
//
await message.exportConfirm()
//
exportLoading.value = true
const data = await TransferLogApi.exportTransferLog(queryParams)
download.excel(data, '会员卡划拨记录.xls')
} catch {
} finally {
exportLoading.value = false
}
}
/** 初始化 **/
onMounted(() => {
getList()
})
</script>

View File

@ -59,4 +59,8 @@ public class BrokerageUserDO extends BaseDO {
* 冻结佣金 * 冻结佣金
*/ */
private Integer frozenPrice; private Integer frozenPrice;
/**
* 二级绑定
*/
private Long bindSecondUserId;
} }

View File

@ -143,4 +143,9 @@ public interface BrokerageUserService {
*/ */
PageResult<AppBrokerageUserChildSummaryRespVO> getBrokerageUserChildSummaryPage(AppBrokerageUserChildSummaryPageReqVO pageReqVO, Long userId); PageResult<AppBrokerageUserChildSummaryRespVO> getBrokerageUserChildSummaryPage(AppBrokerageUserChildSummaryPageReqVO pageReqVO, Long userId);
boolean createBrokerageUser(@NotNull Long userId, Long bindUserId);
void updateBrokerageByUserId(Long id, Long bindUserId);
void updateBrokerageBySecondUserId(Long id, Long secondBindUserId);
} }

View File

@ -25,6 +25,7 @@ import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageEnabledConditionEn
import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum; import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum;
import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordStatusEnum; import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordStatusEnum;
import cn.iocoder.yudao.module.trade.service.config.TradeConfigService; import cn.iocoder.yudao.module.trade.service.config.TradeConfigService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
@ -264,6 +265,39 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
return new PageResult<>(pageResult.getRecords(), pageResult.getTotal()); return new PageResult<>(pageResult.getRecords(), pageResult.getTotal());
} }
@Override
public boolean createBrokerageUser(Long userId, Long bindUserId) {
BrokerageUserDO brokerageUserDO = new BrokerageUserDO();
brokerageUserDO.setId(userId);
brokerageUserDO.setBindUserId(bindUserId);
brokerageUserDO.setBindUserTime(LocalDateTime.now());
brokerageUserDO.setBrokerageEnabled(true);
brokerageUserDO.setDeleted(false);
brokerageUserDO.setBindUserTime(LocalDateTime.now());
brokerageUserMapper.insert(brokerageUserDO);
return true;
}
@Override
public void updateBrokerageByUserId(Long id, Long bindUserId) {
// 校验存在
BrokerageUserDO brokerageUser = validateBrokerageUserExists(id);
brokerageUser.setBindUserId(bindUserId);
QueryWrapper queryWrapper = new QueryWrapper();
queryWrapper.eq("id",brokerageUser.getId());
brokerageUserMapper.update(brokerageUser,queryWrapper);
}
@Override
public void updateBrokerageBySecondUserId(Long id, Long secondBindUserId) {
// 校验存在
BrokerageUserDO brokerageUser = validateBrokerageUserExists(id);
brokerageUser.setBindSecondUserId(secondBindUserId);
QueryWrapper queryWrapper = new QueryWrapper();
queryWrapper.eq("id",brokerageUser.getId());
brokerageUserMapper.update(brokerageUser,queryWrapper);
}
private boolean isUserCanBind(BrokerageUserDO user) { private boolean isUserCanBind(BrokerageUserDO user) {
// 校验分销功能是否启用 // 校验分销功能是否启用
TradeConfigDO tradeConfig = tradeConfigService.getTradeConfig(); TradeConfigDO tradeConfig = tradeConfigService.getTradeConfig();

View File

@ -0,0 +1,8 @@
package cn.iocoder.yudao.module.member.api.clubCard;
import cn.iocoder.yudao.module.member.api.clubCard.vo.ClubCardApiVo;
public interface ClubCardApi {
ClubCardApiVo getCard(Integer id);
ClubCardApiVo getCardBySubId(Integer subId);
}

View File

@ -0,0 +1,57 @@
package cn.iocoder.yudao.module.member.api.clubCard.vo;
import lombok.Data;
import java.time.LocalDateTime;
/**
* 会员卡 DO
*
* @author 管理员
*/
@Data
public class ClubCardApiVo {
/**
* 会员卡编号
*/
private Integer id;
/**
* 上级用户id
*/
private Integer parentId;
/**
* 下级用户id
*/
private Integer subId;
/**
* 会员卡号
*/
private String cardNumber;
/**
* 是否已激活0未激活 1已激活
*
*/
private Integer isActivate;
/**
* 昵称后面改用成了合伙人手机号
*/
private String nickName;
/**
* 手机号会员的
*/
private String phone;
/**
* 激活时间
*/
private LocalDateTime activateTime;
/**
* 卡密
*/
private String scret;
}

View File

@ -17,6 +17,10 @@ public class MemberUserRespDTO {
* 用户ID * 用户ID
*/ */
private Long id; private Long id;
/**
* 真实名字
*/
private String name;
/** /**
* 用户昵称 * 用户昵称
*/ */

View File

@ -50,9 +50,19 @@ public interface ErrorCodeConstants {
ErrorCode LEVEL_HAS_USER = new ErrorCode(1_004_011_005, "用户等级下存在用户,无法删除"); ErrorCode LEVEL_HAS_USER = new ErrorCode(1_004_011_005, "用户等级下存在用户,无法删除");
ErrorCode EXPERIENCE_BIZ_NOT_SUPPORT = new ErrorCode(1_004_011_201, "用户经验业务类型不支持"); ErrorCode EXPERIENCE_BIZ_NOT_SUPPORT = new ErrorCode(1_004_011_201, "用户经验业务类型不支持");
ErrorCode PAID_MEMBER_BENEFIT_NOT_EXISTS = new ErrorCode(1_004_011_202, "付费会员权益不存在");
ErrorCode PAID_MEMBER_BENEFIT_LEVEL_RELATION_NOT_EXISTS = new ErrorCode(1_004_011_202, "会员权益和等级关系不存在");
//========== 用户分组 1-004-012-000 ========== //========== 用户分组 1-004-012-000 ==========
ErrorCode GROUP_NOT_EXISTS = new ErrorCode(1_004_012_000, "用户分组不存在"); ErrorCode GROUP_NOT_EXISTS = new ErrorCode(1_004_012_000, "用户分组不存在");
ErrorCode GROUP_HAS_USER = new ErrorCode(1_004_012_001, "用户分组下存在用户,无法删除"); ErrorCode GROUP_HAS_USER = new ErrorCode(1_004_012_001, "用户分组下存在用户,无法删除");
//============================================
ErrorCode CARD_LOG_NOT_EXISTS = new ErrorCode(1_004_013_000, "发卡记录不存在");
ErrorCode AFTER_VERIFICATION_NOT_EXISTS = new ErrorCode(1_004_014_000, "核销记录不存在");
ErrorCode CARD_BASE_NOT_EXISTS = new ErrorCode(1_004_015_000, "会员卡档案不存在");
ErrorCode INTEREST_NOT_EXISTS = new ErrorCode(1_004_016_000, "权益通知不存在");
ErrorCode TRANSFER_NOT_EXISTS = new ErrorCode(1_004_017_000, "会员卡划拨不存在");
ErrorCode TRANSFER_LOG_NOT_EXISTS = new ErrorCode(1_004_018_000, "会员卡划拨记录不存在");
// ========== ==========
ErrorCode INPUTCODE_NOT_EXISTS = new ErrorCode(1_004_019_000, "进件码不存在");
} }

View File

@ -18,7 +18,9 @@ public enum MemberPointBizTypeEnum implements IntArrayValuable {
SIGN(1, "签到", "签到获得 {} 积分", true), SIGN(1, "签到", "签到获得 {} 积分", true),
ADMIN(2, "管理员修改", "管理员修改 {} 积分", true), ADMIN(2, "管理员修改", "管理员修改 {} 积分", true),
JOIN_AS_A_PARTNER(33,"加入合伙人","加入合伙人获得 {} 积分",true),
BIND_MEMBERSHIP_CARD(34,"绑定会员卡","绑定会员卡获得 {} 积分",true),
MEMBERSHIP_LEVEL_PROMOTION(35,"等级提升","等级提升获得 {} 积分",true),
ORDER_USE(11, "订单积分抵扣", "下单使用 {} 积分", false), // 下单时扣减积分 ORDER_USE(11, "订单积分抵扣", "下单使用 {} 积分", false), // 下单时扣减积分
ORDER_USE_CANCEL(12, "订单积分抵扣(整单取消)", "订单取消,退还 {} 积分", true), // ORDER_USE 的取消 ORDER_USE_CANCEL(12, "订单积分抵扣(整单取消)", "订单取消,退还 {} 积分", true), // ORDER_USE 的取消
ORDER_USE_CANCEL_ITEM(13, "订单积分抵扣(单个退款)", "订单退款,退还 {} 积分", true), // ORDER_USE 的取消 ORDER_USE_CANCEL_ITEM(13, "订单积分抵扣(单个退款)", "订单退款,退还 {} 积分", true), // ORDER_USE 的取消

View File

@ -90,7 +90,12 @@
<groupId>cn.iocoder.boot</groupId> <groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-spring-boot-starter-biz-ip</artifactId> <artifactId>yudao-spring-boot-starter-biz-ip</artifactId>
</dependency> </dependency>
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-module-trade-biz</artifactId>
<scope>compile</scope>
<version>${revision}</version>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -0,0 +1,28 @@
package cn.iocoder.yudao.module.member.api.clubCard;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.member.api.clubCard.vo.ClubCardApiVo;
import cn.iocoder.yudao.module.member.dal.dataobject.clubCard.ClubCardDO;
import cn.iocoder.yudao.module.member.service.clubCard.ClubCardService;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
@Service
@Validated
public class clubCardApiImpl implements ClubCardApi{
@Resource
private ClubCardService cardService;
@Override
public ClubCardApiVo getCard(Integer id) {
ClubCardDO card = cardService.getCard(id);
return BeanUtils.toBean(card, ClubCardApiVo.class);
}
@Override
public ClubCardApiVo getCardBySubId(Integer subId) {
ClubCardDO cardBySubId = cardService.getCardBySubId(subId);
return BeanUtils.toBean(cardBySubId, ClubCardApiVo.class);
}
}

View File

@ -0,0 +1,176 @@
package cn.iocoder.yudao.module.member.controller.admin.afterverification;
import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
import cn.iocoder.yudao.module.member.controller.admin.afterverification.vo.AfterVerificationPageReqVO;
import cn.iocoder.yudao.module.member.controller.admin.afterverification.vo.AfterVerificationRespVO;
import cn.iocoder.yudao.module.member.controller.admin.afterverification.vo.AfterVerificationSaveReqVO;
import cn.iocoder.yudao.module.member.dal.dataobject.afterverification.AfterVerificationDO;
import cn.iocoder.yudao.module.member.dal.mysql.afterverification.AfterVerificationMapper;
import cn.iocoder.yudao.module.member.service.afterverification.AfterVerificationService;
import cn.iocoder.yudao.module.member.service.interest.InterestService;
import cn.iocoder.yudao.module.member.service.user.MemberUserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - 核销记录")
@RestController
@RequestMapping("/cancel/after-verification")
@Validated
public class AfterVerificationController {
@Resource
private AfterVerificationService afterVerificationService;
@Resource
private InterestService interestService;
@Resource
private MemberUserService memberUserService;
@Resource
private MemberUserApi memberUserApi;
@Resource
private AfterVerificationMapper afterVerificationMapper;
@PostMapping("/create")
@Operation(summary = "创建核销记录")
@PreAuthorize("@ss.hasPermission('cancel:after-verification:create')")
public CommonResult<Long> createAfterVerification(@Valid @RequestBody AfterVerificationSaveReqVO createReqVO) {
return success(afterVerificationService.createAfterVerification(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "更新核销记录")
@PreAuthorize("@ss.hasPermission('cancel:after-verification:update')")
public CommonResult<Boolean> updateAfterVerification(@Valid @RequestBody AfterVerificationSaveReqVO updateReqVO) {
afterVerificationService.updateAfterVerification(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除核销记录")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('cancel:after-verification:delete')")
public CommonResult<Boolean> deleteAfterVerification(@RequestParam("id") Long id) {
afterVerificationService.deleteAfterVerification(id);
return success(true);
}
@GetMapping("/get")
@Operation(summary = "获得核销记录")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('cancel:after-verification:query')")
public CommonResult<AfterVerificationRespVO> getAfterVerification(@RequestParam("id") Long id) {
AfterVerificationDO afterVerification = afterVerificationService.getAfterVerification(id);
return success(BeanUtils.toBean(afterVerification, AfterVerificationRespVO.class));
}
@GetMapping("/page")
@Operation(summary = "获得核销记录分页")
@PreAuthorize("@ss.hasPermission('cancel:after-verification:query')")
public CommonResult<PageResult<AfterVerificationRespVO>> getAfterVerificationPage(@Valid AfterVerificationPageReqVO pageReqVO) {
PageResult<AfterVerificationDO> pageResult = afterVerificationService.getAfterVerificationPage(pageReqVO);
PageResult<AfterVerificationRespVO> result = BeanUtils.toBean(pageResult, AfterVerificationRespVO.class);
ArrayList<Long> list = new ArrayList<>();
for (AfterVerificationRespVO respVO : result.getList()) {
list.add(respVO.getMemberUserId());
}
Map<Long, MemberUserRespDTO> userMap = memberUserApi.getUserMap(list);
for (AfterVerificationRespVO respVO : result.getList()) {
if (userMap.get(respVO.getMemberUserId()) != null){
respVO.setName(userMap.get(respVO.getMemberUserId()).getName());
}
}
return success(result);
}
@GetMapping("/export-excel")
@Operation(summary = "导出核销记录 Excel")
@PreAuthorize("@ss.hasPermission('cancel:after-verification:export')")
@ApiAccessLog(operateType = EXPORT)
public void exportAfterVerificationExcel(@Valid AfterVerificationPageReqVO pageReqVO,
HttpServletResponse response) throws IOException {
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<AfterVerificationDO> list = afterVerificationService.getAfterVerificationPage(pageReqVO).getList();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
List<AfterVerificationRespVO> voList = BeanUtils.toBean(list, AfterVerificationRespVO.class);
ArrayList<Long> arrayList = new ArrayList<>();
for (AfterVerificationRespVO respVO : voList) {
respVO.setCreateTimeToString(respVO.getCreateTime().format(formatter));
arrayList.add(respVO.getMemberUserId());
}
Map<Long, MemberUserRespDTO> userMap = memberUserApi.getUserMap(arrayList);
for (AfterVerificationRespVO respVO : voList) {
if (userMap.get(respVO.getMemberUserId()) != null){
respVO.setName(userMap.get(respVO.getMemberUserId()).getName());
}
}
// 导出 Excel
ExcelUtils.write(response, "核销记录.xls", "数据", AfterVerificationRespVO.class,
voList);
}
// @GetMapping("/test")
// public void test(AfterVerificationPageReqVO pageReqVO){
// pageReqVO.setPageNo(1);
// pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
// List<AfterVerificationDO> list = afterVerificationService.getAfterVerificationPage(pageReqVO).getList();
// Collections.reverse(list);
// ArrayList<String> arrayList = new ArrayList<>();
// for (AfterVerificationDO verificationDO : list) {
// MemberUserDO user = memberUserService.getUser(verificationDO.getMemberUserId());
// if (user != null){
// long count = arrayList.stream()
// .filter(s -> s.equals(verificationDO.getCardNumber()))
// .count();
// verificationDO.setSurplusCounts(interestService.getInterest(user.getNoticeInterestId()).getIsUsed().longValue() - count - 1);
// arrayList.add(verificationDO.getCardNumber());
// }
// }
// afterVerificationMapper.updateBatch(list);
// }
//
// @GetMapping("/test1")
// public void test1(){
// List<String> list = new ArrayList<>();
// list.add("commercial");
// list.add("commer");
// list.add("commer");
// list.add("commerce");
// list.add("commer");
//
// // 统计包含 "commer" 的字符串的数量
// long count = list.stream()
// .filter(s -> s.equals("commer"))
// .count();
//
// System.out.println("Number of strings containing 'commer': " + count);
// }
}

View File

@ -0,0 +1,39 @@
package cn.iocoder.yudao.module.member.controller.admin.afterverification.vo;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Schema(description = "管理后台 - 核销记录分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class AfterVerificationPageReqVO extends PageParam {
@Schema(description = "核销时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
@Schema(description = "会员id", example = "25415")
private Long memberUserId;
@Schema(description = "商品名称", example = "芋艿")
private String goodsName;
@Schema(description = "会员卡号")
private String cardNumber;
@Schema(description = "昵称", example = "王五")
private String nickName;
@Schema(description = "手机号")
private String phone;
}

View File

@ -0,0 +1,55 @@
package cn.iocoder.yudao.module.member.controller.admin.afterverification.vo;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - 核销记录 Response VO")
@Data
@ExcelIgnoreUnannotated
public class AfterVerificationRespVO {
@Schema(description = "核销编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "16608")
// @ExcelProperty("核销编号")
private Long id;
@Schema(description = "会员卡号")
@ExcelProperty("会员卡号")
private String cardNumber;
@Schema(description = "昵称", example = "王五")
@ExcelProperty("昵称")
private String nickName;
@Schema(description = "姓名", example = "王五")
@ExcelProperty("姓名")
private String name;
@Schema(description = "手机号")
@ExcelProperty("手机号")
private String phone;
@Schema(description = "商品名称", example = "芋艿")
@ExcelProperty("商品名称")
private String goodsName;
@Schema(description = "会员id", example = "25415")
// @ExcelProperty("会员id")
private Long memberUserId;
@Schema(description = "核销时间")
// @ExcelProperty("核销时间")
private LocalDateTime createTime;
@Schema(description = "核销时间")
@ExcelProperty("核销时间")
private String createTimeToString;
@Schema(description = "核销时间")
@ExcelProperty("剩余核销次数")
private Long surplusCounts;
}

View File

@ -0,0 +1,33 @@
package cn.iocoder.yudao.module.member.controller.admin.afterverification.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Schema(description = "管理后台 - 核销记录新增/修改 Request VO")
@Data
public class AfterVerificationSaveReqVO {
// @Schema(description = "核销编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "16608")
private Long id;
@Schema(description = "会员id", example = "25415")
private Long memberUserId;
@Schema(description = "商品名称", example = "芋艿")
private String goodsName;
@Schema(description = "会员卡号")
private String cardNumber;
@Schema(description = "会员昵称", example = "王五")
private String nickName;
@Schema(description = "手机号")
private String phone;
@Schema(description = "剩余次数")
private Long surplusCounts;
}

View File

@ -0,0 +1,94 @@
package cn.iocoder.yudao.module.member.controller.admin.cardbase;
import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.module.member.controller.admin.cardbase.vo.CardBasePageReqVO;
import cn.iocoder.yudao.module.member.controller.admin.cardbase.vo.CardBaseRespVO;
import cn.iocoder.yudao.module.member.controller.admin.cardbase.vo.CardBaseSaveReqVO;
import cn.iocoder.yudao.module.member.dal.dataobject.cardbase.CardBaseDO;
import cn.iocoder.yudao.module.member.service.cardbase.CardBaseService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.util.List;
import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - 会员卡档案")
@RestController
@RequestMapping("/mall/card-base")
@Validated
public class CardBaseController {
@Resource
private CardBaseService cardBaseService;
@PostMapping("/create")
@Operation(summary = "创建会员卡档案")
@PreAuthorize("@ss.hasPermission('mall:card-base:create')")
public CommonResult<Long> createCardBase(@Valid @RequestBody CardBaseSaveReqVO createReqVO) {
return success(cardBaseService.createCardBase(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "更新会员卡档案")
@PreAuthorize("@ss.hasPermission('mall:card-base:update')")
public CommonResult<Boolean> updateCardBase(@Valid @RequestBody CardBaseSaveReqVO updateReqVO) {
cardBaseService.updateCardBase(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除会员卡档案")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('mall:card-base:delete')")
public CommonResult<Boolean> deleteCardBase(@RequestParam("id") Long id) {
cardBaseService.deleteCardBase(id);
return success(true);
}
@GetMapping("/get")
@Operation(summary = "获得会员卡档案")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('mall:card-base:query')")
public CommonResult<CardBaseRespVO> getCardBase(@RequestParam("id") Long id) {
CardBaseDO cardBase = cardBaseService.getCardBase(id);
return success(BeanUtils.toBean(cardBase, CardBaseRespVO.class));
}
@GetMapping("/page")
@Operation(summary = "获得会员卡档案分页")
@PreAuthorize("@ss.hasPermission('mall:card-base:query')")
public CommonResult<PageResult<CardBaseRespVO>> getCardBasePage(@Valid CardBasePageReqVO pageReqVO) {
PageResult<CardBaseDO> pageResult = cardBaseService.getCardBasePage(pageReqVO);
return success(BeanUtils.toBean(pageResult, CardBaseRespVO.class));
}
@GetMapping("/export-excel")
@Operation(summary = "导出会员卡档案 Excel")
@PreAuthorize("@ss.hasPermission('mall:card-base:export')")
@ApiAccessLog(operateType = EXPORT)
public void exportCardBaseExcel(@Valid CardBasePageReqVO pageReqVO,
HttpServletResponse response) throws IOException {
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<CardBaseDO> list = cardBaseService.getCardBasePage(pageReqVO).getList();
// 导出 Excel
ExcelUtils.write(response, "会员卡档案.xls", "数据", CardBaseRespVO.class,
BeanUtils.toBean(list, CardBaseRespVO.class));
}
}

View File

@ -0,0 +1,36 @@
package cn.iocoder.yudao.module.member.controller.admin.cardbase.vo;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Schema(description = "管理后台 - 会员卡档案分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class CardBasePageReqVO extends PageParam {
@Schema(description = "卡号")
private String cardNum;
@Schema(description = "卡密")
private String scret;
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
@Schema(description = "上级id", example = "15709")
private Integer parentId;
@Schema(description = "下级id", example = "2163")
private Integer subId;
}

View File

@ -0,0 +1,39 @@
package cn.iocoder.yudao.module.member.controller.admin.cardbase.vo;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - 会员卡档案 Response VO")
@Data
@ExcelIgnoreUnannotated
public class CardBaseRespVO {
@Schema(description = "档案编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "28190")
@ExcelProperty("档案编号")
private Long id;
@Schema(description = "卡号")
@ExcelProperty("卡号")
private String cardNum;
@Schema(description = "卡密")
@ExcelProperty("卡密")
private String scret;
@Schema(description = "创建时间")
@ExcelProperty("创建时间")
private LocalDateTime createTime;
@Schema(description = "上级id", example = "15709")
@ExcelProperty("上级id")
private Integer parentId;
@Schema(description = "下级id", example = "2163")
@ExcelProperty("下级id")
private Integer subId;
}

View File

@ -0,0 +1,25 @@
package cn.iocoder.yudao.module.member.controller.admin.cardbase.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Schema(description = "管理后台 - 会员卡档案新增/修改 Request VO")
@Data
public class CardBaseSaveReqVO {
@Schema(description = "档案编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "28190")
private Long id;
@Schema(description = "卡号")
private String cardNum;
@Schema(description = "卡密")
private String scret;
@Schema(description = "上级id", example = "15709")
private Integer parentId;
@Schema(description = "下级id", example = "2163")
private Integer subId;
}

View File

@ -0,0 +1,97 @@
package cn.iocoder.yudao.module.member.controller.admin.cardlog;
import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.module.member.controller.admin.cardlog.vo.CardLogPageReqVO;
import cn.iocoder.yudao.module.member.controller.admin.cardlog.vo.CardLogRespVO;
import cn.iocoder.yudao.module.member.controller.admin.cardlog.vo.CardLogSaveReqVO;
import cn.iocoder.yudao.module.member.dal.dataobject.cardlog.CardLogDO;
import cn.iocoder.yudao.module.member.service.cardlog.CardLogService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.util.List;
import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - 发卡记录")
@RestController
@RequestMapping("/send/card-log")
@Validated
public class CardLogController {
@Resource
private CardLogService cardLogService;
@PostMapping("/create")
@Operation(summary = "创建发卡记录")
@PreAuthorize("@ss.hasPermission('send:card-log:create')")
public CommonResult<Integer> createCardLog(@Valid @RequestBody CardLogSaveReqVO createReqVO) {
return success(cardLogService.createCardLog(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "更新发卡记录")
@PreAuthorize("@ss.hasPermission('send:card-log:update')")
public CommonResult<Boolean> updateCardLog(@Valid @RequestBody CardLogSaveReqVO updateReqVO) {
cardLogService.updateCardLog(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除发卡记录")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('send:card-log:delete')")
public CommonResult<Boolean> deleteCardLog(@RequestParam("id") Integer id) {
cardLogService.deleteCardLog(id);
return success(true);
}
@GetMapping("/get")
@Operation(summary = "获得发卡记录")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('send:card-log:query')")
public CommonResult<CardLogRespVO> getCardLog(@RequestParam("id") Integer id) {
CardLogDO cardLog = cardLogService.getCardLog(id);
return success(BeanUtils.toBean(cardLog, CardLogRespVO.class));
}
@GetMapping("/page")
@Operation(summary = "获得发卡记录分页")
@PreAuthorize("@ss.hasPermission('send:card-log:query')")
public CommonResult<PageResult<CardLogRespVO>> getCardLogPage(@Valid CardLogPageReqVO pageReqVO) {
PageResult<CardLogDO> pageResult = cardLogService.getCardLogPage(pageReqVO);
System.out.println("--------------------------");
System.out.println(pageResult);
System.out.println("--------------------------");
return success(BeanUtils.toBean(pageResult, CardLogRespVO.class));
}
@GetMapping("/export-excel")
@Operation(summary = "导出发卡记录 Excel")
@PreAuthorize("@ss.hasPermission('send:card-log:export')")
@ApiAccessLog(operateType = EXPORT)
public void exportCardLogExcel(@Valid CardLogPageReqVO pageReqVO,
HttpServletResponse response) throws IOException {
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<CardLogDO> list = cardLogService.getCardLogPage(pageReqVO).getList();
// 导出 Excel
ExcelUtils.write(response, "发卡记录.xls", "数据", CardLogRespVO.class,
BeanUtils.toBean(list, CardLogRespVO.class));
}
}

View File

@ -0,0 +1,42 @@
package cn.iocoder.yudao.module.member.controller.admin.cardlog.vo;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Schema(description = "管理后台 - 发卡记录分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class CardLogPageReqVO extends PageParam {
@Schema(description = "会员昵称", example = "芋艿")
private String nickName;
@Schema(description = "手机号")
private String phone;
@Schema(description = "数量")
private Integer countNumber;
@Schema(description = "发卡时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
@Schema(description = "起始卡号")
private String starNumber;
@Schema(description = "结束卡号")
private String endNumber;
@Schema(description = "卡号区间")
private String cardSection;
}

View File

@ -0,0 +1,47 @@
package cn.iocoder.yudao.module.member.controller.admin.cardlog.vo;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - 发卡记录 Response VO")
@Data
@ExcelIgnoreUnannotated
public class CardLogRespVO {
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "9984")
@ExcelProperty("编号")
private Integer id;
@Schema(description = "会员昵称", example = "芋艿")
@ExcelProperty("会员昵称")
private String nickName;
@Schema(description = "手机号")
@ExcelProperty("手机号")
private String phone;
@Schema(description = "数量")
@ExcelProperty("数量")
private Integer countNumber;
@Schema(description = "发卡时间")
@ExcelProperty("发卡时间")
private LocalDateTime createTime;
@Schema(description = "起始卡号")
@ExcelProperty("起始卡号")
private String starNumber;
@Schema(description = "结束卡号")
@ExcelProperty("结束卡号")
private String endNumber;
@Schema(description = "卡号区间")
@ExcelProperty("卡号区间")
private String cardSection;
}

View File

@ -0,0 +1,31 @@
package cn.iocoder.yudao.module.member.controller.admin.cardlog.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Schema(description = "管理后台 - 发卡记录新增/修改 Request VO")
@Data
public class CardLogSaveReqVO {
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "9984")
private Integer id;
@Schema(description = "会员昵称", example = "芋艿")
private String nickName;
@Schema(description = "手机号")
private String phone;
@Schema(description = "数量")
private Integer countNumber;
@Schema(description = "起始卡号")
private String starNumber;
@Schema(description = "结束卡号")
private String endNumber;
@Schema(description = "卡号区间")
private String cardSection;
}

View File

@ -0,0 +1,136 @@
package cn.iocoder.yudao.module.member.controller.admin.clubCard;
import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
import cn.iocoder.yudao.module.member.controller.admin.clubCard.vo.ClubCardPageReqVO;
import cn.iocoder.yudao.module.member.controller.admin.clubCard.vo.ClubCardRespVO;
import cn.iocoder.yudao.module.member.controller.admin.clubCard.vo.ClubCardSaveReqVO;
import cn.iocoder.yudao.module.member.dal.dataobject.clubCard.ClubCardDO;
import cn.iocoder.yudao.module.member.service.clubCard.ClubCardService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - 会员卡")
@RestController
@RequestMapping("/club/card")
@Validated
public class ClubCardController {
@Resource
private ClubCardService cardService;
@Resource
private MemberUserApi memberUserApi;
@PostMapping("/create")
@Operation(summary = "创建会员卡")
@PreAuthorize("@ss.hasPermission('club:card:create')")
public CommonResult<Integer> createCard(@Valid @RequestBody ClubCardSaveReqVO createReqVO) {
return success(cardService.createCard(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "更新会员卡")
@PreAuthorize("@ss.hasPermission('club:card:update')")
public CommonResult<Boolean> updateCard(@Valid @RequestBody ClubCardSaveReqVO updateReqVO) {
cardService.updateCard(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除会员卡")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('club:card:delete')")
public CommonResult<Boolean> deleteCard(@RequestParam("id") Integer id) {
ClubCardDO card = cardService.getCard(id);
if (card.getIsActivate() == 0){
cardService.deleteCard(id);
return success(true);
}else {
return success(false);
}
}
@GetMapping("/get")
@Operation(summary = "获得会员卡")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('club:card:query')")
public CommonResult<ClubCardRespVO> getCard(@RequestParam("id") Integer id) {
ClubCardDO card = cardService.getCard(id);
return success(BeanUtils.toBean(card, ClubCardRespVO.class));
}
@GetMapping("/page")
@Operation(summary = "获得会员卡分页")
@PreAuthorize("@ss.hasPermission('club:card:query')")
public CommonResult<PageResult<ClubCardRespVO>> getCardPage(@Valid ClubCardPageReqVO pageReqVO) {
PageResult<ClubCardDO> pageResult = cardService.getCardPage(pageReqVO);
PageResult<ClubCardRespVO> clubCardRespVOPageResult = BeanUtils.toBean(pageResult, ClubCardRespVO.class);
for (ClubCardRespVO respVO : clubCardRespVOPageResult.getList()) {
MemberUserRespDTO user = memberUserApi.getUser(respVO.getParentId().longValue());
if (respVO.getSubId() != null){
MemberUserRespDTO dto = memberUserApi.getUser(respVO.getSubId().longValue());
respVO.setSubName(dto.getName());
}
respVO.setParentName(user.getName());
}
return success(clubCardRespVOPageResult);
}
@GetMapping("/export-excel")
@Operation(summary = "导出会员卡 Excel")
@PreAuthorize("@ss.hasPermission('club:card:export')")
@ApiAccessLog(operateType = EXPORT)
public void exportCardExcel(@Valid ClubCardPageReqVO pageReqVO,
HttpServletResponse response) throws IOException {
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<ClubCardDO> list = cardService.getCardPage(pageReqVO).getList();
ArrayList<Long> parIds = new ArrayList<>();
ArrayList<Long> subIds = new ArrayList<>();
for (ClubCardDO cardDO : list) {
if (cardDO.getParentId() != null){
parIds.add(cardDO.getParentId().longValue());
}
if (cardDO.getSubId() != null){
subIds.add(cardDO.getSubId().longValue());
}
}
List<ClubCardRespVO> voList = BeanUtils.toBean(list, ClubCardRespVO.class);
Map<Long, MemberUserRespDTO> parMap = memberUserApi.getUserMap(parIds);
Map<Long, MemberUserRespDTO> subMap = memberUserApi.getUserMap(subIds);
for (ClubCardRespVO vo : voList) {
if (vo.getParentId() != null && parMap != null){
vo.setParentName(parMap.get(vo.getParentId().longValue()).getName());
}
if (vo.getSubId() != null && subMap != null){
vo.setSubName(subMap.get(vo.getSubId().longValue()).getName());
}
}
// 导出 Excel
ExcelUtils.write(response, "会员卡.xls", "数据", ClubCardRespVO.class,
voList);
}
}

View File

@ -0,0 +1,45 @@
package cn.iocoder.yudao.module.member.controller.admin.clubCard.vo;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Schema(description = "管理后台 - 会员卡分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class ClubCardPageReqVO extends PageParam {
@Schema(description = "上级用户id", example = "31810")
private Integer parentId;
@Schema(description = "下级用户id", example = "18337")
private Integer subId;
@Schema(description = "会员卡号")
private String cardNumber;
@Schema(description = "是否已激活0未激活 1已激活")
private Integer isActivate;
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
@Schema(description = "昵称")
private String nickName;
@Schema(description = "手机号")
private String phone;
@Schema(description = "激活时间")
private LocalDateTime activateTime;
}

View File

@ -0,0 +1,62 @@
package cn.iocoder.yudao.module.member.controller.admin.clubCard.vo;
import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - 会员卡 Response VO")
@Data
@ExcelIgnoreUnannotated
public class ClubCardRespVO {
@Schema(description = "会员卡编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "27892")
@ExcelProperty("会员卡编号")
private Integer id;
@Schema(description = "上级用户id", example = "31810")
@ExcelProperty("上级用户id")
private Integer parentId;
@Schema(description = "下级用户id", example = "18337")
@ExcelProperty("下级用户id")
private Integer subId;
@Schema(description = "会员卡号")
@ExcelProperty("会员卡号")
private String cardNumber;
@Schema(description = "是否已激活")
@ExcelProperty(value = "是否已激活", converter = DictConvert.class)
@DictFormat("is_activate") // TODO 代码优化建议设置到对应的 DictTypeConstants 枚举类中
private Integer isActivate;
@Schema(description = "创建时间")
@ExcelProperty("创建时间")
private LocalDateTime createTime;
@Schema(description = "合伙人手机")
@ExcelProperty("合伙人手机")
private String nickName;
@Schema(description = "手机号")
@ExcelProperty("手机号")
private String phone;
@Schema(description = "合伙人姓名")
@ExcelProperty("合伙人姓名")
private String parentName;
@Schema(description = "领取人姓名")
@ExcelProperty("领取人姓名")
private String subName;
@Schema(description = "激活时间")
@ExcelProperty("激活时间")
private LocalDateTime activateTime;
}

View File

@ -0,0 +1,37 @@
package cn.iocoder.yudao.module.member.controller.admin.clubCard.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Schema(description = "管理后台 - 会员卡新增/修改 Request VO")
@Data
public class ClubCardSaveReqVO {
@Schema(description = "会员卡编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "27892")
private Integer id;
// @Schema(description = "上级用户id", example = "31810")
// private Integer parentId;
//
// @Schema(description = "下级用户id", example = "18337")
// private Integer subId;
@Schema(description = "会员卡号")
private String cardNumber;
@Schema(description = "昵称")
private String nickName;
@Schema(description = "手机号")
private String phone;
@Schema(description = "是否已激活0未激活 1已激活")
private Integer isActivate;
@Schema(description = "卡密")
private String secret;
@Schema(description = "会员权益id")
private Long noticeInterestId;
}

View File

@ -0,0 +1,107 @@
package cn.iocoder.yudao.module.member.controller.admin.interest;
import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.module.member.controller.admin.interest.vo.InterestPageReqVO;
import cn.iocoder.yudao.module.member.controller.admin.interest.vo.InterestRespVO;
import cn.iocoder.yudao.module.member.controller.admin.interest.vo.InterestSaveReqVO;
import cn.iocoder.yudao.module.member.dal.dataobject.interest.InterestDO;
import cn.iocoder.yudao.module.member.service.interest.InterestService;
import cn.iocoder.yudao.module.system.api.dict.DictDataApi;
import cn.iocoder.yudao.module.system.api.dict.dto.DictDataSaveReqApiVO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.util.List;
import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - 权益通知")
@RestController
@RequestMapping("/notice/interest")
@Validated
public class InterestController {
@Resource
private InterestService interestService;
@Resource
private DictDataApi dictDataApi;
@PostMapping("/create")
@Operation(summary = "创建权益通知")
@PreAuthorize("@ss.hasPermission('notice:interest:create')")
public CommonResult<Long> createInterest(@Valid @RequestBody InterestSaveReqVO createReqVO) {
Long interest = interestService.createInterest(createReqVO);
DictDataSaveReqApiVO apiVO = new DictDataSaveReqApiVO();
apiVO.setLabel(createReqVO.getTitle());
apiVO.setDictType("member_meal");
apiVO.setSort(1);
apiVO.setValue(interest.toString());
apiVO.setStatus(0);
apiVO.setColorType("default");
dictDataApi.createDictDataApi(apiVO);
return success(interest);
}
@PutMapping("/update")
@Operation(summary = "更新权益通知")
@PreAuthorize("@ss.hasPermission('notice:interest:update')")
public CommonResult<Boolean> updateInterest(@Valid @RequestBody InterestSaveReqVO updateReqVO) {
interestService.updateInterest(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除权益通知")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('notice:interest:delete')")
public CommonResult<Boolean> deleteInterest(@RequestParam("id") Long id) {
interestService.deleteInterest(id);
return success(true);
}
@GetMapping("/get")
@Operation(summary = "获得权益通知")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('notice:interest:query')")
public CommonResult<InterestRespVO> getInterest(@RequestParam("id") Long id) {
InterestDO interest = interestService.getInterest(id);
return success(BeanUtils.toBean(interest, InterestRespVO.class));
}
@GetMapping("/page")
@Operation(summary = "获得权益通知分页")
@PreAuthorize("@ss.hasPermission('notice:interest:query')")
public CommonResult<PageResult<InterestRespVO>> getInterestPage(@Valid InterestPageReqVO pageReqVO) {
PageResult<InterestDO> pageResult = interestService.getInterestPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, InterestRespVO.class));
}
@GetMapping("/export-excel")
@Operation(summary = "导出权益通知 Excel")
@PreAuthorize("@ss.hasPermission('notice:interest:export')")
@ApiAccessLog(operateType = EXPORT)
public void exportInterestExcel(@Valid InterestPageReqVO pageReqVO,
HttpServletResponse response) throws IOException {
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<InterestDO> list = interestService.getInterestPage(pageReqVO).getList();
// 导出 Excel
ExcelUtils.write(response, "权益通知.xls", "数据", InterestRespVO.class,
BeanUtils.toBean(list, InterestRespVO.class));
}
}

View File

@ -0,0 +1,42 @@
package cn.iocoder.yudao.module.member.controller.admin.interest.vo;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Schema(description = "管理后台 - 权益通知分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class InterestPageReqVO extends PageParam {
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
@Schema(description = "权益标题")
private String title;
@Schema(description = "权益描述")
private String description;
@Schema(description = "权益内容")
private String equity;
@Schema(description = "须知内容")
private String notice;
@Schema(description = "权益次数")
private Integer isUsed;
@Schema(description = "商品名称")
private String goodsName;
}

View File

@ -0,0 +1,46 @@
package cn.iocoder.yudao.module.member.controller.admin.interest.vo;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - 权益通知 Response VO")
@Data
@ExcelIgnoreUnannotated
public class InterestRespVO {
@Schema(description = "权益编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "12188")
@ExcelProperty("权益编号")
private Long id;
@Schema(description = "创建时间")
@ExcelProperty("创建时间")
private LocalDateTime createTime;
@Schema(description = "权益标题")
@ExcelProperty("权益标题")
private String title;
@Schema(description = "权益描述")
@ExcelProperty("权益描述")
private String description;
@Schema(description = "权益内容")
@ExcelProperty("权益内容")
private String equity;
@Schema(description = "须知内容")
@ExcelProperty("须知内容")
private String notice;
@Schema(description = "权益次数")
private Integer isUsed;
@Schema(description = "商品名称")
private String goodsName;
}

View File

@ -0,0 +1,38 @@
package cn.iocoder.yudao.module.member.controller.admin.interest.vo;
import com.mzt.logapi.starter.annotation.DiffLogField;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Schema(description = "管理后台 - 权益通知新增/修改 Request VO")
@Data
public class InterestSaveReqVO {
@Schema(description = "权益编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "12188")
private Long id;
@Schema(description = "权益标题")
@DiffLogField(name = "权益标题")
private String title;
@Schema(description = "权益描述")
@DiffLogField(name = "权益描述")
private String description;
@Schema(description = "权益内容")
@DiffLogField(name = "权益内容")
private String equity;
@Schema(description = "须知内容")
@DiffLogField(name = "须知内容")
private String notice;
@Schema(description = "权益次数")
@DiffLogField(name = "权益次数")
private Integer isUsed;
@Schema(description = "商品名称")
@DiffLogField(name = "商品名称")
private String goodsName;
}

View File

@ -0,0 +1,105 @@
package cn.iocoder.yudao.module.member.controller.admin.memberbenefit;
import cn.iocoder.yudao.module.member.controller.admin.memberbenefit.vo.PaidMemberBenefitPageReqVO;
import cn.iocoder.yudao.module.member.controller.admin.memberbenefit.vo.PaidMemberBenefitRespVO;
import cn.iocoder.yudao.module.member.controller.admin.memberbenefit.vo.PaidMemberBenefitSaveReqVO;
import cn.iocoder.yudao.module.member.controller.admin.memberbenefit.vo.PaidMemberBenefitStatusReqVO;
import cn.iocoder.yudao.module.member.dal.dataobject.memberbenefit.PaidMemberBenefitDO;
import cn.iocoder.yudao.module.member.service.memberbenefit.PaidMemberBenefitService;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.security.access.prepost.PreAuthorize;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Operation;
import javax.validation.constraints.*;
import javax.validation.*;
import javax.servlet.http.*;
import java.util.*;
import java.io.IOException;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*;
@Tag(name = "管理后台 - 付费会员权益")
@RestController
@RequestMapping("/paidmemberbenefit/paid-member-benefit")
@Validated
public class PaidMemberBenefitController {
@Resource
private PaidMemberBenefitService paidMemberBenefitService;
@PostMapping("/create")
@Operation(summary = "创建付费会员权益")
@PreAuthorize("@ss.hasPermission('paidmemberbenefit:paid-member-benefit:create')")
public CommonResult<Long> createPaidMemberBenefit(@Valid @RequestBody PaidMemberBenefitSaveReqVO createReqVO) {
return success(paidMemberBenefitService.createPaidMemberBenefit(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "更新付费会员权益")
@PreAuthorize("@ss.hasPermission('paidmemberbenefit:paid-member-benefit:update')")
public CommonResult<Boolean> updatePaidMemberBenefit(@Valid @RequestBody PaidMemberBenefitSaveReqVO updateReqVO) {
paidMemberBenefitService.updatePaidMemberBenefit(updateReqVO);
return success(true);
}
@PutMapping("/updateStatus")
@Operation(summary = "更新付费会员权益状态")
@PreAuthorize("@ss.hasPermission('paidmemberbenefit:paid-member-benefit:update')")
public CommonResult<Boolean> updatePaidMemberBenefitStatus(@RequestBody PaidMemberBenefitStatusReqVO req) {
paidMemberBenefitService.updatePaidMemberBenefitStatus(req);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除付费会员权益")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('paidmemberbenefit:paid-member-benefit:delete')")
public CommonResult<Boolean> deletePaidMemberBenefit(@RequestParam("id") Long id) {
paidMemberBenefitService.deletePaidMemberBenefit(id);
return success(true);
}
@GetMapping("/get")
@Operation(summary = "获得付费会员权益")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('paidmemberbenefit:paid-member-benefit:query')")
public CommonResult<PaidMemberBenefitRespVO> getPaidMemberBenefit(@RequestParam("id") Long id) {
PaidMemberBenefitDO paidMemberBenefit = paidMemberBenefitService.getPaidMemberBenefit(id);
return success(BeanUtils.toBean(paidMemberBenefit, PaidMemberBenefitRespVO.class));
}
@GetMapping("/page")
@Operation(summary = "获得付费会员权益分页")
@PreAuthorize("@ss.hasPermission('paidmemberbenefit:paid-member-benefit:query')")
public CommonResult<PageResult<PaidMemberBenefitRespVO>> getPaidMemberBenefitPage(@Valid PaidMemberBenefitPageReqVO pageReqVO) {
PageResult<PaidMemberBenefitDO> pageResult = paidMemberBenefitService.getPaidMemberBenefitPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, PaidMemberBenefitRespVO.class));
}
@GetMapping("/export-excel")
@Operation(summary = "导出付费会员权益 Excel")
@PreAuthorize("@ss.hasPermission('paidmemberbenefit:paid-member-benefit:export')")
@ApiAccessLog(operateType = EXPORT)
public void exportPaidMemberBenefitExcel(@Valid PaidMemberBenefitPageReqVO pageReqVO,
HttpServletResponse response) throws IOException {
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<PaidMemberBenefitDO> list = paidMemberBenefitService.getPaidMemberBenefitPage(pageReqVO).getList();
// 导出 Excel
ExcelUtils.write(response, "付费会员权益.xls", "数据", PaidMemberBenefitRespVO.class,
BeanUtils.toBean(list, PaidMemberBenefitRespVO.class));
}
}

View File

@ -0,0 +1,28 @@
package cn.iocoder.yudao.module.member.controller.admin.memberbenefit.vo;
import lombok.*;
import java.util.*;
import io.swagger.v3.oas.annotations.media.Schema;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Schema(description = "管理后台 - 会员权益和等级关系分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class MemberBenefitLevelRelationPageReqVO extends PageParam {
@Schema(description = "会员等级编号", example = "234")
private Long memberLevelId;
@Schema(description = "会员权益编号", example = "8416")
private Long memberBenefitId;
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
}

View File

@ -0,0 +1,32 @@
package cn.iocoder.yudao.module.member.controller.admin.memberbenefit.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.*;
import java.util.*;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import com.alibaba.excel.annotation.*;
@Schema(description = "管理后台 - 会员权益和等级关系 Response VO")
@Data
@ExcelIgnoreUnannotated
public class MemberBenefitLevelRelationRespVO {
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "30308")
@ExcelProperty("编号")
private Long id;
@Schema(description = "会员等级编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "234")
@ExcelProperty("会员等级编号")
private Long memberLevelId;
@Schema(description = "会员权益编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "8416")
@ExcelProperty("会员权益编号")
private Long memberBenefitId;
@Schema(description = "创建时间")
@ExcelProperty("创建时间")
private LocalDateTime createTime;
}

View File

@ -0,0 +1,23 @@
package cn.iocoder.yudao.module.member.controller.admin.memberbenefit.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.*;
import javax.validation.constraints.*;
@Schema(description = "管理后台 - 会员权益和等级关系新增/修改 Request VO")
@Data
public class MemberBenefitLevelRelationSaveReqVO {
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "30308")
private Long id;
@Schema(description = "会员等级编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "234")
@NotNull(message = "会员等级编号不能为空")
private Long memberLevelId;
@Schema(description = "会员权益编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "8416")
@NotNull(message = "会员权益编号不能为空")
private Long memberBenefitId;
}

View File

@ -0,0 +1,37 @@
package cn.iocoder.yudao.module.member.controller.admin.memberbenefit.vo;
import lombok.*;
import java.util.*;
import io.swagger.v3.oas.annotations.media.Schema;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Schema(description = "管理后台 - 付费会员权益分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class PaidMemberBenefitPageReqVO extends PageParam {
@Schema(description = "名称", example = "王五")
private String name;
@Schema(description = "图标地址", example = "https://www.iocoder.cn")
private String iconUrl;
@Schema(description = "描述")
private String intro;
@Schema(description = "状态:(默认)0隐藏 1显示", example = "1")
private Integer status;
@Schema(description = "排序")
private Integer sort;
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
}

View File

@ -0,0 +1,44 @@
package cn.iocoder.yudao.module.member.controller.admin.memberbenefit.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.*;
import java.util.*;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import com.alibaba.excel.annotation.*;
@Schema(description = "管理后台 - 付费会员权益 Response VO")
@Data
@ExcelIgnoreUnannotated
public class PaidMemberBenefitRespVO {
@Schema(description = " 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "29131")
@ExcelProperty(" 编号")
private Long id;
@Schema(description = "名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五")
@ExcelProperty("名称")
private String name;
@Schema(description = "图标地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn")
@ExcelProperty("图标地址")
private String iconUrl;
@Schema(description = "描述")
@ExcelProperty("描述")
private String intro;
@Schema(description = "状态:(默认)0隐藏 1显示", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@ExcelProperty("状态:(默认)0隐藏 1显示")
private Integer status;
@Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("排序")
private Integer sort;
@Schema(description = "创建时间")
@ExcelProperty("创建时间")
private LocalDateTime createTime;
}

View File

@ -0,0 +1,37 @@
package cn.iocoder.yudao.module.member.controller.admin.memberbenefit.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.*;
import javax.validation.constraints.*;
@Schema(description = "管理后台 - 付费会员权益新增/修改 Request VO")
@Data
public class PaidMemberBenefitSaveReqVO {
@Schema(description = " 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "29131")
private Long id;
@Schema(description = "名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五")
@NotEmpty(message = "名称不能为空")
private String name;
@Schema(description = "图标地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn")
@NotEmpty(message = "图标地址不能为空")
private String iconUrl;
@Schema(description = "描述")
private String intro;
@Schema(description = "状态:(默认)0隐藏 1显示", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "状态:(默认)0隐藏 1显示不能为空")
private Integer status;
@Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "排序不能为空")
private Integer sort;
@Schema(description = "等级Id列表", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "等级Id不能为空")
private List<Long> levelIdList;
}

View File

@ -0,0 +1,19 @@
package cn.iocoder.yudao.module.member.controller.admin.memberbenefit.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
@Schema(description = "管理后台 - 付费会员权益新增/修改 Request VO")
@Data
public class PaidMemberBenefitStatusReqVO {
@Schema(description = " 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "29131")
private Long id;
@Schema(description = "状态:(默认)0隐藏 1显示", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "状态:(默认)0隐藏 1显示不能为空")
private Integer status;
}

View File

@ -0,0 +1,127 @@
package cn.iocoder.yudao.module.member.controller.admin.transfer;
import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.module.member.controller.admin.transfer.vo.TransferPageReqVO;
import cn.iocoder.yudao.module.member.controller.admin.transfer.vo.TransferRespVO;
import cn.iocoder.yudao.module.member.controller.admin.transfer.vo.TransferSaveReqVO;
import cn.iocoder.yudao.module.member.dal.dataobject.clubCard.ClubCardDO;
import cn.iocoder.yudao.module.member.dal.dataobject.transfer.TransferDO;
import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
import cn.iocoder.yudao.module.member.service.clubCard.ClubCardService;
import cn.iocoder.yudao.module.member.service.transfer.TransferService;
import cn.iocoder.yudao.module.member.service.user.MemberUserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - 会员卡划拨")
@RestController
@RequestMapping("/card/transfer")
@Validated
public class TransferController {
@Resource
private TransferService transferService;
@Resource
private ClubCardService cardService;
@Resource
private MemberUserService userService;
@PostMapping("/create")
@Operation(summary = "创建会员卡划拨")
@PreAuthorize("@ss.hasPermission('card:transfer:create')")
public CommonResult<Long> createTransfer(@Valid @RequestBody TransferSaveReqVO createReqVO) {
return success(transferService.createTransfer(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "通过或者驳回会员卡划拨")
@PreAuthorize("@ss.hasPermission('card:transfer:update')")
public CommonResult<Boolean> updateTransfer(@Valid @RequestBody TransferSaveReqVO updateReqVO) {
if (updateReqVO.getStatus() == 1){
MemberUserDO userByMobile = userService.getUserByMobile(updateReqVO.getTransfereePhone());
if (userByMobile == null){
return success(false);
}
ArrayList<ClubCardDO> list = new ArrayList<>();
String str = updateReqVO.getCardNumber();
//划拨卡号数组
String[] array = str.split(",");
for (String element : array) {
ClubCardDO clubCardDO = cardService.getCardByCardNumber(element);
if (clubCardDO != null){
clubCardDO.setNickName(updateReqVO.getTransfereePhone());
clubCardDO.setParentId(userByMobile.getId().intValue());
clubCardDO.setUpdateTime(LocalDateTime.now());
clubCardDO.setIsActivate(0);
list.add(clubCardDO);
}else {
return success(false);
}
}
cardService.updateCards(list);
}
transferService.updateTransfer(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除会员卡划拨")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('card:transfer:delete')")
public CommonResult<Boolean> deleteTransfer(@RequestParam("id") Long id) {
transferService.deleteTransfer(id);
return success(true);
}
@GetMapping("/get")
@Operation(summary = "获得会员卡划拨")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('card:transfer:query')")
public CommonResult<TransferRespVO> getTransfer(@RequestParam("id") Long id) {
TransferDO transfer = transferService.getTransfer(id);
return success(BeanUtils.toBean(transfer, TransferRespVO.class));
}
@GetMapping("/page")
@Operation(summary = "获得会员卡划拨分页")
@PreAuthorize("@ss.hasPermission('card:transfer:query')")
public CommonResult<PageResult<TransferRespVO>> getTransferPage(@Valid TransferPageReqVO pageReqVO) {
PageResult<TransferDO> pageResult = transferService.getTransferPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, TransferRespVO.class));
}
@GetMapping("/export-excel")
@Operation(summary = "导出会员卡划拨 Excel")
@PreAuthorize("@ss.hasPermission('card:transfer:export')")
@ApiAccessLog(operateType = EXPORT)
public void exportTransferExcel(@Valid TransferPageReqVO pageReqVO,
HttpServletResponse response) throws IOException {
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<TransferDO> list = transferService.getTransferPage(pageReqVO).getList();
// 导出 Excel
ExcelUtils.write(response, "会员卡划拨.xls", "数据", TransferRespVO.class,
BeanUtils.toBean(list, TransferRespVO.class));
}
}

View File

@ -0,0 +1,42 @@
package cn.iocoder.yudao.module.member.controller.admin.transfer.vo;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Schema(description = "管理后台 - 会员卡划拨分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class TransferPageReqVO extends PageParam {
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
@Schema(description = "会员卡号")
private String cardNumber;
@Schema(description = "合伙人", example = "23016")
private Long assignorId;
@Schema(description = "会员", example = "24204")
private Long transfereeId;
@Schema(description = "合伙人电话")
private String assignorPhone;
@Schema(description = "会员电话")
private String transfereePhone;
@Schema(description = "状态", example = "1")
private Integer status;
}

View File

@ -0,0 +1,50 @@
package cn.iocoder.yudao.module.member.controller.admin.transfer.vo;
import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - 会员卡划拨 Response VO")
@Data
@ExcelIgnoreUnannotated
public class TransferRespVO {
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "8595")
@ExcelProperty("编号")
private Long id;
@Schema(description = "创建时间")
@ExcelProperty("创建时间")
private LocalDateTime createTime;
@Schema(description = "会员卡号")
@ExcelProperty("会员卡号")
private String cardNumber;
@Schema(description = "合伙人", example = "23016")
@ExcelProperty("合伙人")
private Long assignorId;
@Schema(description = "会员", example = "24204")
@ExcelProperty("会员")
private Long transfereeId;
@Schema(description = "合伙人电话")
@ExcelProperty("合伙人电话")
private String assignorPhone;
@Schema(description = "会员电话")
@ExcelProperty("会员电话")
private String transfereePhone;
@Schema(description = "状态", example = "1")
@ExcelProperty(value = "状态", converter = DictConvert.class)
@DictFormat("card_status") // TODO 代码优化建议设置到对应的 DictTypeConstants 枚举类中
private Integer status;
}

View File

@ -0,0 +1,31 @@
package cn.iocoder.yudao.module.member.controller.admin.transfer.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Schema(description = "管理后台 - 会员卡划拨新增/修改 Request VO")
@Data
public class TransferSaveReqVO {
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "8595")
private Long id;
@Schema(description = "会员卡号")
private String cardNumber;
@Schema(description = "合伙人", example = "23016")
private Long assignorId;
@Schema(description = "会员", example = "24204")
private Long transfereeId;
@Schema(description = "合伙人电话")
private String assignorPhone;
@Schema(description = "会员电话")
private String transfereePhone;
@Schema(description = "状态", example = "1")
private Integer status;
}

View File

@ -0,0 +1,94 @@
package cn.iocoder.yudao.module.member.controller.admin.transferlog;
import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.module.member.controller.admin.transferlog.vo.TransferLogPageReqVO;
import cn.iocoder.yudao.module.member.controller.admin.transferlog.vo.TransferLogRespVO;
import cn.iocoder.yudao.module.member.controller.admin.transferlog.vo.TransferLogSaveReqVO;
import cn.iocoder.yudao.module.member.dal.dataobject.transferlog.TransferLogDO;
import cn.iocoder.yudao.module.member.service.transferlog.TransferLogService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.util.List;
import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - 会员卡划拨记录")
@RestController
@RequestMapping("/card/transfer-log")
@Validated
public class TransferLogController {
@Resource
private TransferLogService transferLogService;
@PostMapping("/create")
@Operation(summary = "创建会员卡划拨记录")
@PreAuthorize("@ss.hasPermission('card:transfer-log:create')")
public CommonResult<Long> createTransferLog(@Valid @RequestBody TransferLogSaveReqVO createReqVO) {
return success(transferLogService.createTransferLog(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "更新会员卡划拨记录")
@PreAuthorize("@ss.hasPermission('card:transfer-log:update')")
public CommonResult<Boolean> updateTransferLog(@Valid @RequestBody TransferLogSaveReqVO updateReqVO) {
transferLogService.updateTransferLog(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除会员卡划拨记录")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('card:transfer-log:delete')")
public CommonResult<Boolean> deleteTransferLog(@RequestParam("id") Long id) {
transferLogService.deleteTransferLog(id);
return success(true);
}
@GetMapping("/get")
@Operation(summary = "获得会员卡划拨记录")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('card:transfer-log:query')")
public CommonResult<TransferLogRespVO> getTransferLog(@RequestParam("id") Long id) {
TransferLogDO transferLog = transferLogService.getTransferLog(id);
return success(BeanUtils.toBean(transferLog, TransferLogRespVO.class));
}
@GetMapping("/page")
@Operation(summary = "获得会员卡划拨记录分页")
@PreAuthorize("@ss.hasPermission('card:transfer-log:query')")
public CommonResult<PageResult<TransferLogRespVO>> getTransferLogPage(@Valid TransferLogPageReqVO pageReqVO) {
PageResult<TransferLogDO> pageResult = transferLogService.getTransferLogPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, TransferLogRespVO.class));
}
@GetMapping("/export-excel")
@Operation(summary = "导出会员卡划拨记录 Excel")
@PreAuthorize("@ss.hasPermission('card:transfer-log:export')")
@ApiAccessLog(operateType = EXPORT)
public void exportTransferLogExcel(@Valid TransferLogPageReqVO pageReqVO,
HttpServletResponse response) throws IOException {
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<TransferLogDO> list = transferLogService.getTransferLogPage(pageReqVO).getList();
// 导出 Excel
ExcelUtils.write(response, "会员卡划拨记录.xls", "数据", TransferLogRespVO.class,
BeanUtils.toBean(list, TransferLogRespVO.class));
}
}

View File

@ -0,0 +1,42 @@
package cn.iocoder.yudao.module.member.controller.admin.transferlog.vo;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Schema(description = "管理后台 - 会员卡划拨记录分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class TransferLogPageReqVO extends PageParam {
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
@Schema(description = "会员卡号")
private String cardNumber;
@Schema(description = "发起人", example = "10999")
private Long assignorId;
@Schema(description = "划拨人", example = "25483")
private Long transfereeId;
@Schema(description = "发起人手机")
private String assignorPhone;
@Schema(description = "划拨人手机")
private String transfereePhone;
@Schema(description = "状态", example = "2")
private Integer status;
}

View File

@ -0,0 +1,50 @@
package cn.iocoder.yudao.module.member.controller.admin.transferlog.vo;
import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - 会员卡划拨记录 Response VO")
@Data
@ExcelIgnoreUnannotated
public class TransferLogRespVO {
@Schema(description = "划拨id", requiredMode = Schema.RequiredMode.REQUIRED, example = "29512")
@ExcelProperty("划拨id")
private Long id;
@Schema(description = "创建时间")
@ExcelProperty("创建时间")
private LocalDateTime createTime;
@Schema(description = "会员卡号")
@ExcelProperty("会员卡号")
private String cardNumber;
@Schema(description = "发起人", example = "10999")
@ExcelProperty("发起人")
private Long assignorId;
@Schema(description = "划拨人", example = "25483")
@ExcelProperty("划拨人")
private Long transfereeId;
@Schema(description = "发起人手机")
@ExcelProperty("发起人手机")
private String assignorPhone;
@Schema(description = "划拨人手机")
@ExcelProperty("划拨人手机")
private String transfereePhone;
@Schema(description = "状态", example = "2")
@ExcelProperty(value = "状态", converter = DictConvert.class)
@DictFormat("card_status") // TODO 代码优化建议设置到对应的 DictTypeConstants 枚举类中
private Integer status;
}

View File

@ -0,0 +1,31 @@
package cn.iocoder.yudao.module.member.controller.admin.transferlog.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Schema(description = "管理后台 - 会员卡划拨记录新增/修改 Request VO")
@Data
public class TransferLogSaveReqVO {
@Schema(description = "划拨id", requiredMode = Schema.RequiredMode.REQUIRED, example = "29512")
private Long id;
@Schema(description = "会员卡号")
private String cardNumber;
@Schema(description = "发起人", example = "10999")
private Long assignorId;
@Schema(description = "划拨人", example = "25483")
private Long transfereeId;
@Schema(description = "发起人手机")
private String assignorPhone;
@Schema(description = "划拨人手机")
private String transfereePhone;
@Schema(description = "状态", example = "2")
private Integer status;
}

View File

@ -1,15 +1,25 @@
package cn.iocoder.yudao.module.member.controller.admin.user; package cn.iocoder.yudao.module.member.controller.admin.user;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.IdUtil;
import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
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.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.module.member.controller.admin.afterverification.vo.AfterVerificationSaveReqVO;
import cn.iocoder.yudao.module.member.controller.admin.user.vo.*; import cn.iocoder.yudao.module.member.controller.admin.user.vo.*;
import cn.iocoder.yudao.module.member.convert.user.MemberUserConvert; import cn.iocoder.yudao.module.member.convert.user.MemberUserConvert;
import cn.iocoder.yudao.module.member.dal.dataobject.clubCard.ClubCardDO;
import cn.iocoder.yudao.module.member.dal.dataobject.group.MemberGroupDO; import cn.iocoder.yudao.module.member.dal.dataobject.group.MemberGroupDO;
import cn.iocoder.yudao.module.member.dal.dataobject.level.MemberLevelDO; import cn.iocoder.yudao.module.member.dal.dataobject.level.MemberLevelDO;
import cn.iocoder.yudao.module.member.dal.dataobject.memberCode.MemberCodeDo;
import cn.iocoder.yudao.module.member.dal.dataobject.tag.MemberTagDO; import cn.iocoder.yudao.module.member.dal.dataobject.tag.MemberTagDO;
import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO; import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
import cn.iocoder.yudao.module.member.dal.mysql.memberCode.MemberCodeMapper;
import cn.iocoder.yudao.module.member.enums.point.MemberPointBizTypeEnum; import cn.iocoder.yudao.module.member.enums.point.MemberPointBizTypeEnum;
import cn.iocoder.yudao.module.member.service.clubCard.ClubCardService;
import cn.iocoder.yudao.module.member.service.group.MemberGroupService; import cn.iocoder.yudao.module.member.service.group.MemberGroupService;
import cn.iocoder.yudao.module.member.service.level.MemberLevelService; import cn.iocoder.yudao.module.member.service.level.MemberLevelService;
import cn.iocoder.yudao.module.member.service.point.MemberPointRecordService; import cn.iocoder.yudao.module.member.service.point.MemberPointRecordService;
@ -24,14 +34,14 @@ import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid; import javax.validation.Valid;
import java.io.IOException;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.Collection; import java.util.*;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId; import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId;
@ -54,7 +64,10 @@ public class MemberUserController {
private MemberPointRecordService memberPointRecordService; private MemberPointRecordService memberPointRecordService;
@Resource @Resource
private PayWalletApi payWalletApi; private PayWalletApi payWalletApi;
@Resource
private ClubCardService cardService;
@Resource
private MemberCodeMapper memberCodeMapper;
@PutMapping("/update") @PutMapping("/update")
@Operation(summary = "更新会员用户") @Operation(summary = "更新会员用户")
@PreAuthorize("@ss.hasPermission('member:user:update')") @PreAuthorize("@ss.hasPermission('member:user:update')")
@ -84,7 +97,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);
} }
@ -125,5 +138,35 @@ public class MemberUserController {
} }
return success(convertPage); return success(convertPage);
} }
@GetMapping("/verificationCode")
@Operation(summary = "核销码")
@PreAuthorize("@ss.hasPermission('member:user:code')")
public CommonResult<String> verificationCode(@RequestParam("id") Long id){
MemberUserDO user = memberUserService.getUser(id);
if (user.getActivate() == 0){
return success("error");
}
AfterVerificationSaveReqVO appMemberUserVerificationCodeVo = new AfterVerificationSaveReqVO();
appMemberUserVerificationCodeVo.setMemberUserId(id);
appMemberUserVerificationCodeVo.setId(System.currentTimeMillis());
ClubCardDO cardBySubId = cardService.getCardBySubId(id.intValue());
appMemberUserVerificationCodeVo.setCardNumber(cardBySubId.getCardNumber());
String encodedString = Base64.getEncoder().encodeToString(appMemberUserVerificationCodeVo.toString().getBytes());
// String key = "verificationCode_" + id;
// redisTemplate.delete(key);
// // 将数据添加到 Redis
// redisTemplate.opsForValue().set(key,encodedString);
// // 设置数据的过期时间为10秒
//// redisTemplate.expire(key, 60*60*24, TimeUnit.SECONDS);
// DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
// LocalDateTime now = LocalDateTime.now();
// System.out.println("获取核销码:"+encodedString+" 当前时间"+now.format(formatter));
String uuid = IdUtil.fastSimpleUUID();
MemberCodeDo memberCodeDo = new MemberCodeDo();
memberCodeDo.setRealCode(encodedString);
memberCodeDo.setGetCodeType(1);
memberCodeDo.setModelCode(uuid);
memberCodeMapper.insert(memberCodeDo);
return success(uuid);
}
} }

View File

@ -41,8 +41,15 @@ public class MemberUserPageReqVO extends PageParam {
@Schema(description = "用户分组编号", example = "1") @Schema(description = "用户分组编号", example = "1")
private Long groupId; private Long groupId;
@Schema(description = "权益id", example = "1")
private Long noticeInterestId;
@Schema(description = "是否绑过卡", example = "1")
private Integer activate;
// TODO 芋艿注册用户类型 // TODO 芋艿注册用户类型
// TODO 芋艿登录用户类型 // TODO 芋艿登录用户类型
} }

View File

@ -0,0 +1,54 @@
package cn.iocoder.yudao.module.member.controller.app.interest;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated;
import cn.iocoder.yudao.module.member.controller.admin.interest.vo.InterestPageReqVO;
import cn.iocoder.yudao.module.member.controller.admin.interest.vo.InterestRespVO;
import cn.iocoder.yudao.module.member.dal.dataobject.interest.InterestDO;
import cn.iocoder.yudao.module.member.service.interest.InterestService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@Tag(name = "APP - 权益通知")
@RestController
@RequestMapping("/notice/interest")
@Validated
public class AppInterestController {
@Resource
private InterestService interestService;
@GetMapping("/page")
@Operation(summary = "获得权益通知分页")
@PreAuthenticated
public CommonResult<List<InterestRespVO>> getInterestPage(@Valid InterestPageReqVO pageReqVO) {
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
PageResult<InterestDO> pageResult = interestService.getInterestPage(pageReqVO);
PageResult<InterestRespVO> interestRespVOPageResult = BeanUtils.toBean(pageResult, InterestRespVO.class);
return success(interestRespVOPageResult.getList());
}
@GetMapping("/get")
@Operation(summary = "获得权益通知")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthenticated
public CommonResult<InterestRespVO> getInterest(@RequestParam("id") Long id) {
InterestDO interest = interestService.getInterest(id);
return success(BeanUtils.toBean(interest, InterestRespVO.class));
}
}

View File

@ -1,13 +1,39 @@
package cn.iocoder.yudao.module.member.controller.app.user; package cn.iocoder.yudao.module.member.controller.app.user;
import cn.hutool.core.util.IdUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated;
import cn.iocoder.yudao.module.member.controller.admin.afterverification.vo.AfterVerificationSaveReqVO;
import cn.iocoder.yudao.module.member.controller.admin.clubCard.vo.ClubCardPageReqVO;
import cn.iocoder.yudao.module.member.controller.admin.clubCard.vo.ClubCardRespVO;
import cn.iocoder.yudao.module.member.controller.admin.clubCard.vo.ClubCardSaveReqVO;
import cn.iocoder.yudao.module.member.controller.admin.interest.vo.InterestRespVO;
import cn.iocoder.yudao.module.member.controller.admin.transfer.vo.TransferSaveReqVO;
import cn.iocoder.yudao.module.member.controller.app.user.vo.*; import cn.iocoder.yudao.module.member.controller.app.user.vo.*;
import cn.iocoder.yudao.module.member.convert.user.MemberUserConvert; import cn.iocoder.yudao.module.member.convert.user.MemberUserConvert;
import cn.iocoder.yudao.module.member.dal.dataobject.afterverification.AfterVerificationDO;
import cn.iocoder.yudao.module.member.dal.dataobject.cardbase.CardBaseDO;
import cn.iocoder.yudao.module.member.dal.dataobject.clubCard.ClubCardDO;
import cn.iocoder.yudao.module.member.dal.dataobject.interest.InterestDO;
import cn.iocoder.yudao.module.member.dal.dataobject.level.MemberLevelDO; import cn.iocoder.yudao.module.member.dal.dataobject.level.MemberLevelDO;
import cn.iocoder.yudao.module.member.dal.dataobject.memberCode.MemberCodeDo;
import cn.iocoder.yudao.module.member.dal.dataobject.transferlog.TransferLogDO;
import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO; import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
import cn.iocoder.yudao.module.member.dal.mysql.memberCode.MemberCodeMapper;
import cn.iocoder.yudao.module.member.enums.point.MemberPointBizTypeEnum;
import cn.iocoder.yudao.module.member.service.afterverification.AfterVerificationService;
import cn.iocoder.yudao.module.member.service.cardbase.CardBaseService;
import cn.iocoder.yudao.module.member.service.clubCard.ClubCardService;
import cn.iocoder.yudao.module.member.service.interest.InterestService;
import cn.iocoder.yudao.module.member.service.level.MemberLevelService; import cn.iocoder.yudao.module.member.service.level.MemberLevelService;
import cn.iocoder.yudao.module.member.service.point.MemberPointRecordService;
import cn.iocoder.yudao.module.member.service.transfer.TransferService;
import cn.iocoder.yudao.module.member.service.transferlog.TransferLogService;
import cn.iocoder.yudao.module.member.service.user.MemberUserService; import cn.iocoder.yudao.module.member.service.user.MemberUserService;
import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.BrokerageUserDO;
import cn.iocoder.yudao.module.trade.service.brokerage.BrokerageUserService;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -17,6 +43,9 @@ import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.validation.Valid; import javax.validation.Valid;
import java.time.LocalDateTime;
import java.util.*;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
@ -31,7 +60,24 @@ public class AppMemberUserController {
private MemberUserService userService; private MemberUserService userService;
@Resource @Resource
private MemberLevelService levelService; private MemberLevelService levelService;
@Resource
private ClubCardService cardService;
@Resource
private CardBaseService cardBaseService;
@Resource
private BrokerageUserService brokerageUserService;
@Resource
private TransferService transferService;
@Resource
private TransferLogService transferLogService;
@Resource
private AfterVerificationService afterVerificationService;
@Resource
private InterestService interestService;
@Resource
private MemberPointRecordService pointRecordService;
@Resource
private MemberCodeMapper memberCodeMapper;
@GetMapping("/get") @GetMapping("/get")
@Operation(summary = "获得基本信息") @Operation(summary = "获得基本信息")
@PreAuthenticated @PreAuthenticated
@ -79,6 +125,323 @@ public class AppMemberUserController {
userService.resetUserPassword(reqVO); userService.resetUserPassword(reqVO);
return success(true); return success(true);
} }
@PostMapping("/activate")
@Operation(summary = "激活会员")
@PreAuthenticated
public CommonResult<String> activateCard(@RequestBody ClubCardSaveReqVO createReqVO) {
String s = createReqVO.getCardNumber().toUpperCase();
createReqVO.setCardNumber(s);
// System.out.println("--------------------------- "+s);
// System.out.println("-------------------------- "+createReqVO);
ClubCardDO cardByCardNumber = cardService.getCardByCardNumber(createReqVO.getCardNumber());
// System.out.println("=================");
// System.out.println(cardByCardNumber);
// System.out.println("=================0");
if (cardByCardNumber == null){
if(cardBaseService.getCardBaseByCardNumber("NO:"+createReqVO.getCardNumber()) != null){
return success("该卡号未申领");
}
return success("非法卡号!请输入正确的卡号");
}
if (cardByCardNumber.getIsActivate() == 2){
return success("绑定失败,该卡号正在审核中");
}
if (cardByCardNumber.getIsActivate() == 0){
CardBaseDO cardBaseByCardNumber = cardBaseService.getCardBaseByCardNumber("NO:"+createReqVO.getCardNumber());
if (cardBaseByCardNumber.getScret().equals(createReqVO.getSecret())){
MemberUserDO user = userService.getUser(getLoginUserId());
cardByCardNumber.setPhone(user.getMobile());
cardByCardNumber.setSubId(Integer.parseInt(getLoginUserId().toString()));
cardByCardNumber.setActivateTime(LocalDateTime.now());
cardService.updateCardByIsActivate(cardByCardNumber);
//查询是否已绑定
BrokerageUserDO brokerageUser = brokerageUserService.getBrokerageUser(getLoginUserId());
if (brokerageUser == null){
//未绑定直接绑定
brokerageUserService.createBrokerageUser(getLoginUserId(),Long.parseLong(cardByCardNumber.getParentId().toString()));
}else {
if (brokerageUser.getBindUserId() == null){
//已绑定但上级为空
brokerageUserService.updateBrokerageByUserId(getLoginUserId(),cardByCardNumber.getParentId().longValue());
}else {
//已绑定但上级不为空
brokerageUserService.updateBrokerageBySecondUserId(getLoginUserId(),cardByCardNumber.getParentId().longValue());
}
}
if (cardByCardNumber.getParentId().longValue() != getLoginUserId()){
pointRecordService.createPointRecord(user.getId(),299, MemberPointBizTypeEnum.BIND_MEMBERSHIP_CARD,"661");
}
user.setActivate(1);
if (user.getPoint() != null || cardByCardNumber.getParentId().longValue() != getLoginUserId()){
user.setPoint(user.getPoint()+299);
}
user.setNoticeInterestId(createReqVO.getNoticeInterestId());
user.setName(createReqVO.getNickName());
userService.updateUserDo(user);
return success("绑定成功");
}else {
return success("绑定失败!卡密错误");
}
}else {
return success("绑定失败!该会员卡已被绑定");
}
}
@GetMapping("/getWxCard")
@Operation(summary = "获得会员卡")
@PreAuthenticated
public CommonResult<ClubCardRespVO> getWxCard(@RequestParam("id") Integer id) {
ClubCardDO card = cardService.getCard(id);
return success(BeanUtils.toBean(card, ClubCardRespVO.class));
}
@GetMapping("/getAfterVerificationList")
@Operation(summary = "核销记录")
@PreAuthenticated
public CommonResult<List<AfterVerificationDO>> getAfterVerificationList(){
return success(afterVerificationService.getAfterVerificationList(getLoginUserId()));
}
@GetMapping("/verificationCode")
@Operation(summary = "核销码")
@PreAuthenticated
public CommonResult<String> verificationCode(AfterVerificationSaveReqVO appMemberUserVerificationCodeVo){
appMemberUserVerificationCodeVo.setMemberUserId(getLoginUserId());
appMemberUserVerificationCodeVo.setId(System.currentTimeMillis());
ClubCardDO cardBySubId = cardService.getCardBySubId(getLoginUserId().intValue());
appMemberUserVerificationCodeVo.setCardNumber(cardBySubId.getCardNumber());
String encodedString = Base64.getEncoder().encodeToString(appMemberUserVerificationCodeVo.toString().getBytes());
// String key = "verificationCode_" + getLoginUserId();
// redisTemplate.delete(key);
// // 将数据添加到 Redis
// redisTemplate.opsForValue().set(key,encodedString);
// // 设置数据的过期时间为10秒
//// redisTemplate.expire(key, 60*60*24, TimeUnit.SECONDS);
// DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
// LocalDateTime now = LocalDateTime.now();
// System.out.println("获取核销码:"+encodedString+" 当前时间"+now.format(formatter));
// =========================================================================================
String uuid = IdUtil.fastSimpleUUID();
MemberCodeDo memberCodeDo = new MemberCodeDo();
memberCodeDo.setRealCode(encodedString);
memberCodeDo.setGetCodeType(0);
memberCodeDo.setModelCode(uuid);
memberCodeMapper.insert(memberCodeDo);
return success(uuid);
}
@PostMapping("/doVerification")
@Operation(summary = "核销操作")
@PreAuthenticated
public CommonResult<String> doVerificationCode(@RequestBody AppMemberUserDoVerificationVo appMemberUserVerificationVo){
MemberUserDO serviceUser = userService.getUser(getLoginUserId());
if (serviceUser.getRoleId() != 1 && serviceUser.getRoleId() != 2){
return success("非法人员禁止核销");
}
MemberCodeDo memberModel = memberCodeMapper.selectOne("model_code", appMemberUserVerificationVo.getCode());
if (memberModel == null){
return success("核销码已过期");
}
// 解码Base64编码的字符串
byte[] decodedBytes = Base64.getDecoder().decode(memberModel.getRealCode());
String decodedString = new String(decodedBytes);
// 将字符串转换回对象
// 使用字符串分割方法将字符串分割为属性值数组
String[] parts = decodedString.replaceAll("\\s", "").replaceAll("\\)", "").split("\\(")[1].split(",");
// 创建 AfterVerificationSaveReqVO 对象
AfterVerificationSaveReqVO verificationCodeVo = new AfterVerificationSaveReqVO();
for (String part : parts) {
String[] keyValue = part.split("=");
String key = keyValue[0];
String value = keyValue.length > 1 ? keyValue[1] : null;
switch (key) {
case "id":
verificationCodeVo.setId(Long.parseLong("1"));
break;
case "memberUserId":
verificationCodeVo.setMemberUserId(Long.parseLong(value));
break;
case "goodsName":
verificationCodeVo.setGoodsName("鲜鸡蛋20个");
break;
case "cardNumber":
verificationCodeVo.setCardNumber(value);
break;
case "nickName":
verificationCodeVo.setNickName(value);
break;
case "phone":
verificationCodeVo.setPhone(value);
break;
default:
// 如果出现了未知的属性可以选择忽略或者进行其他处理
break;
}
}
//查询会员信息
MemberUserDO user = userService.getUser(verificationCodeVo.getMemberUserId());
verificationCodeVo.setPhone(user.getMobile());
verificationCodeVo.setNickName(user.getNickname());
InterestDO interest = interestService.getInterest(user.getNoticeInterestId());
if (interest != null){
verificationCodeVo.setGoodsName(interest.getGoodsName());
}
// String key = "verificationCode_" + verificationCodeVo.getMemberUserId();
// String encodedStrings = redisTemplate.opsForValue().get(key);
// if (encodedStrings == null || "".equals(encodedStrings) || !appMemberUserVerificationVo.getCode().equals(encodedStrings)) {
// // 如果集合为空则表示没有找到相应的验证码数据
// return success("核销码已过期");
// }
//查询核销对应用户的核销列表用于计数
List<AfterVerificationDO> list = afterVerificationService.getAfterVerificationList(verificationCodeVo.getMemberUserId());
InterestDO countNum = interestService.getInterest(user.getNoticeInterestId());
if (countNum.getIsUsed() - list.size() > 0){
if (serviceUser.getRoleId() == 1){
//查询当月是否已经核销过
List<AfterVerificationDO> afterVerificationListByDate = afterVerificationService.getAfterVerificationListByDate(verificationCodeVo.getMemberUserId());
if (afterVerificationListByDate.size() == 0){
//插入核销记录
appMemberUserVerificationVo.setMemberUserId(getLoginUserId());
verificationCodeVo.setSurplusCounts(countNum.getIsUsed().longValue() - afterVerificationService.getCountByUserId(verificationCodeVo.getMemberUserId()) - 1);
afterVerificationService.createAfterVerificationByGun(verificationCodeVo,appMemberUserVerificationVo);
// redisTemplate.delete(key);
return success("核销成功");
}else {
return success("核销失败,本月权益已领取");
}
}
if (serviceUser.getRoleId() == 2){
//插入核销记录
appMemberUserVerificationVo.setMemberUserId(getLoginUserId());
verificationCodeVo.setSurplusCounts(countNum.getIsUsed().longValue() - afterVerificationService.getCountByUserId(verificationCodeVo.getMemberUserId()) - 1);
afterVerificationService.createAfterVerificationByGun(verificationCodeVo,appMemberUserVerificationVo);
// redisTemplate.delete(key);
return success("核销成功");
}
return success("服务器繁忙,请及时联系管理员");
}else {
return success("核销失败,您的核销次数已用完");
}
}
@GetMapping("/MemberUserIndexCard")
@Operation(summary = "会员卡详情")
@PreAuthenticated
public CommonResult<Map<String,Object>> MemberUserIndexCard(){
Map<String, Object> map = new HashMap<>();
ClubCardDO cardBySubId = cardService.getCardBySubId(Integer.parseInt(getLoginUserId().toString()));
MemberUserDO user = userService.getUser(getLoginUserId());
// System.out.println("--------------------------");
// System.out.println(user);
// System.out.println(getLoginUserId());
// System.out.println("--------------------------");
if (cardBySubId == null){
map.put("isActivate",false);
map.put("cardNumber",null);
map.put("count",null);
}else {
map.put("isActivate",true);
map.put("cardNumber",cardBySubId.getCardNumber());
List<AfterVerificationDO> list = afterVerificationService.getAfterVerificationList(getLoginUserId());
if (user.getNoticeInterestId() != null){
InterestDO countNum = interestService.getInterest(user.getNoticeInterestId());
if (countNum != null){
map.put("count",countNum.getIsUsed() - list.size());
}
}
}
if (user.getRoleId() == 1 || user.getRoleId() == 2){
map.put("isJob",true);
}
if (user.getRoleId() == 0 || user.getRoleId() == null){
map.put("isJob",false);
}
if (user.getLevelId() != null && user.getLevelId() != 1){
map.put("total",cardService.getCardPageByMemberCount(getLoginUserId()));
}
// System.out.println("========================");
// System.out.println(map);
// System.out.println("========================");
return success(map);
}
@GetMapping("/getInterest")
@Operation(summary = "获取权益")
@PreAuthenticated
public CommonResult<InterestRespVO> getInterest() {
MemberUserDO user = userService.getUser(getLoginUserId());
if (user.getNoticeInterestId() != null){
InterestDO interest = interestService.getInterest(user.getNoticeInterestId());
return success(BeanUtils.toBean(interest, InterestRespVO.class));
}else {
return null;
}
}
@GetMapping("/getClubCardByMember")
@Operation(summary = "合伙人卡片展示")
@PreAuthenticated
public CommonResult<PageResult<ClubCardDO>> getClubCardDOByMember(@Valid ClubCardPageReqVO pageReqVO) {
pageReqVO.setParentId(Integer.parseInt(getLoginUserId()+""));
PageResult<ClubCardDO> cardPageByMember = cardService.getCardPageByMember(pageReqVO);
for (ClubCardDO clubCardDO : cardPageByMember.getList()) {
clubCardDO.setScret(cardBaseService.getCardBaseByCardNumber("NO:"+clubCardDO.getCardNumber()).getScret());
}
return success(cardPageByMember);
}
@PostMapping("/transferCard")
@Operation(summary = "合伙人卡片划拨")
@PreAuthenticated
public CommonResult<String> transferCard(@RequestBody TransferSaveReqVO createReqVO) {
createReqVO.setAssignorId(getLoginUserId());
if (createReqVO.getCardNumber() == null || createReqVO.getCardNumber().equals("")){
return success("请先勾选要划拨的卡号");
}
MemberUserDO user = userService.getUser(getLoginUserId());
if (user != null){
createReqVO.setAssignorPhone(userService.getUser(getLoginUserId()).getMobile());
}else {
return success("数据异常请联系管理员排查");
}
if (user.getMobile().equals(createReqVO.getTransfereePhone())){
return success("划拨失败,禁止划拨给自己");
}
MemberUserDO userByMobile = userService.getUserByMobile(createReqVO.getTransfereePhone());
if (userByMobile != null){
createReqVO.setTransfereeId(userService.getUserByMobile(createReqVO.getTransfereePhone()).getId());
}else {
return success("划拨失败,请填写正确的合伙人手机号");
}
if (userByMobile.getLevelId() == 1 || userByMobile.getLevelId() == 5 ){
return success("划拨失败,划拨人不是合伙人");
}
ArrayList<TransferLogDO> list = new ArrayList<>();
ArrayList<ClubCardDO> clubCardList = new ArrayList<>();
TransferLogDO transferLogSaveReqVO = new TransferLogDO();
String str = createReqVO.getCardNumber();
//划拨卡号数组
String[] array = str.split(",");
for (String s : array) {
transferLogSaveReqVO.setAssignorId(createReqVO.getAssignorId());
transferLogSaveReqVO.setAssignorPhone(user.getMobile());
transferLogSaveReqVO.setCardNumber(s);
transferLogSaveReqVO.setStatus(0);
transferLogSaveReqVO.setTransfereePhone(createReqVO.getTransfereePhone());
transferLogSaveReqVO.setTransfereeId(userByMobile.getId());
list.add(transferLogSaveReqVO);
ClubCardDO cardByCardNumber = cardService.getCardByCardNumber(s);
cardByCardNumber.setIsActivate(2);
cardByCardNumber.setUpdateTime(LocalDateTime.now());
clubCardList.add(cardByCardNumber);
}
cardService.updateCards(clubCardList);
transferLogService.createTransferLogs(list);
transferService.createTransfer(createReqVO);
return success("划拨成功");
}
} }

View File

@ -0,0 +1,11 @@
package cn.iocoder.yudao.module.member.controller.app.user.vo;
import lombok.Data;
@Data
public class AppMemberUserDoVerificationVo {
private Long memberUserId;//核销员id
private String nickName;//核销员昵称
private String phone;//核销员手机号
private String code;//核销码
}

View File

@ -35,6 +35,9 @@ public class AppMemberUserInfoRespVO {
@Schema(description = "用户等级") @Schema(description = "用户等级")
private Level level; private Level level;
@Schema(description = "是否绑过卡")
private Integer activate;
@Schema(description = "是否成为推广员", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") @Schema(description = "是否成为推广员", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
private Boolean brokerageEnabled; private Boolean brokerageEnabled;

View File

@ -0,0 +1,69 @@
package cn.iocoder.yudao.module.member.dal.dataobject.afterverification;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
/**
* 核销记录 DO
*
* @author 管理员
*/
@TableName("cancel_after_verification")
@KeySequence("cancel_after_verification_seq") // 用于 OraclePostgreSQLKingbaseDB2H2 数据库的主键自增如果是 MySQL 等数据库可不写
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class AfterVerificationDO extends BaseDO {
/**
* 核销编号
*/
@TableId(type = IdType.AUTO)
private Long id;
/**
* 会员id
*/
private Long memberUserId;
/**
* 商品名称
*/
private String goodsName;
/**
* 会员卡号
*/
private String cardNumber;
/**
* 昵称
*/
private String nickName;
/**
* 手机号
*/
private String phone;
/**
* 核销员姓名
*/
private String verificationName;
/**
* 核销员id
*/
private Long verificationId;
/**
* 核销员手机号
*/
private String verificationPhone;
/**
* 剩余次数
*/
private Long surplusCounts;
}

View File

@ -0,0 +1,46 @@
package cn.iocoder.yudao.module.member.dal.dataobject.cardbase;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
/**
* 会员卡档案 DO
*
* @author 管理员
*/
@TableName("mall_card_base")
@KeySequence("mall_card_base_seq") // 用于 OraclePostgreSQLKingbaseDB2H2 数据库的主键自增如果是 MySQL 等数据库可不写
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class CardBaseDO extends BaseDO {
/**
* 档案编号
*/
@TableId
private Long id;
/**
* 卡号
*/
private String cardNum;
/**
* 卡密
*/
private String scret;
/**
* 上级id
*/
private Integer parentId;
/**
* 下级id
*/
private Integer subId;
}

View File

@ -0,0 +1,57 @@
package cn.iocoder.yudao.module.member.dal.dataobject.cardlog;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
/**
* 发卡记录 DO
*
* @author 管理员
*/
@TableName("send_card_log")
@KeySequence("send_card_log_seq") // 用于 OraclePostgreSQLKingbaseDB2H2 数据库的主键自增如果是 MySQL 等数据库可不写
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class CardLogDO extends BaseDO {
/**
* 编号
*/
@TableId
private Integer id;
/**
* 会员昵称
*/
private String nickName;
/**
* 手机号
*/
private String phone;
/**
* 数量
*/
private Integer countNumber;
/**
* 起始卡号
*/
private String starNumber;
/**
*结束卡号
*/
private String endNumber;
/**
*卡号区间
*/
private String cardSection;
}

View File

@ -0,0 +1,70 @@
package cn.iocoder.yudao.module.member.dal.dataobject.clubCard;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
import java.time.LocalDateTime;
/**
* 会员卡 DO
*
* @author 管理员
*/
@TableName("club_card")
@KeySequence("club_card_seq") // 用于 OraclePostgreSQLKingbaseDB2H2 数据库的主键自增如果是 MySQL 等数据库可不写
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ClubCardDO extends BaseDO {
/**
* 会员卡编号
*/
@TableId
private Integer id;
/**
* 上级用户id
*/
private Integer parentId;
/**
* 下级用户id
*/
private Integer subId;
/**
* 会员卡号
*/
private String cardNumber;
/**
* 是否已激活0未激活 1已激活
*
* 枚举 {@link TODO is_activate 对应的类}
*/
private Integer isActivate;
/**
* 昵称后面改用成了合伙人手机号
*/
private String nickName;
/**
* 手机号会员的
*/
private String phone;
/**
* 激活时间
*/
private LocalDateTime activateTime;
/**
* 卡密
*/
private String scret;
}

Some files were not shown because too many files have changed in this diff Show More