Compare commits

..

12 Commits

Author SHA1 Message Date
6de437634c 修改积分商城订单提交报错,增加后台积分订单记录 2024-10-16 14:35:09 +08:00
af92c1ca00 Merge pull request '1.后台前端-隐藏优惠券折扣选项2.后台前端-优惠券有效期显示调整' (#46) from cxw into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: http://101.43.112.107:3000/root/allLikeMall/pulls/46
2024-10-16 13:57:33 +08:00
53128f0685 Merge pull request 'khy' (#45) from khy into master
Some checks are pending
continuous-integration/drone/push Build is running
Reviewed-on: http://101.43.112.107:3000/root/allLikeMall/pulls/45
2024-10-16 13:57:22 +08:00
13eb6a75a9 1.后台前端-隐藏优惠券折扣选项
2.后台前端-优惠券有效期显示调整
2024-10-16 13:41:12 +08:00
khy
78d3175151 Merge remote-tracking branch 'origin/master' 2024-10-15 19:51:27 +08:00
b7f71f6018 Merge pull request 'Branch_csl' (#44) from Branch_csl into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: http://101.43.112.107:3000/root/allLikeMall/pulls/44
2024-10-15 19:50:53 +08:00
khy
da363831e8 付费会员类型,权益 2024-10-15 19:49:01 +08:00
77
02cc14d9f6 替换图标与宫格导航添加一排五个的按钮 2024-10-15 09:38:32 +08:00
00551ec8fe Merge pull request '秒杀列表改回获取全部商品' (#43) from cxw into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: http://101.43.112.107:3000/root/allLikeMall/pulls/43
2024-10-14 18:45:01 +08:00
0da862a180 秒杀列表改回获取全部商品 2024-10-14 18:20:13 +08:00
8fc219ad38 Merge pull request '修改预约提交接口' (#42) from sjy-two into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: http://101.43.112.107:3000/root/allLikeMall/pulls/42
2024-10-14 13:52:08 +08:00
77
d13cfad70c 个人中心装修页面优化与组件图标替换 2024-10-12 15:20:19 +08:00
148 changed files with 4105 additions and 1576 deletions

View File

@ -3,7 +3,8 @@ import request from '@/config/axios'
// 付费会员权益 VO
export interface PaidMemberBenefitVO {
id: number // 编号
name: string // 名称
benName: string // 权益名称
showName: string // 展示名称
iconUrl: string // 图标地址
intro: string // 描述
status: boolean // 状态:(默认)0隐藏 1显示

View File

@ -0,0 +1,49 @@
import request from '@/config/axios'
// 兑换记录 VO
export interface PointOrderVO {
id: number // id
orderNumber: string // 订单号
userId: number // 用户id
productId: number // 商品id
integral: number // 兑换积分
orderStatus: number // 订单状态
orderTime: Date // 下单时间
userName: string
productName: string
imageUrl: string
}
// 兑换记录 API
export const PointOrderApi = {
// 查询兑换记录分页
getPointOrderPage: async (params: any) => {
return await request.get({ url: `/promotion/point-order/page`, params })
},
// 查询兑换记录详情
getPointOrder: async (id: number) => {
return await request.get({ url: `/promotion/point-order/get?id=` + id })
},
// 新增兑换记录
createPointOrder: async (data: PointOrderVO) => {
return await request.post({ url: `/promotion/point-order/create`, data })
},
// 修改兑换记录
updatePointOrder: async (data: PointOrderVO) => {
return await request.put({ url: `/promotion/point-order/update`, data })
},
// 删除兑换记录
deletePointOrder: async (id: number) => {
return await request.delete({ url: `/promotion/point-order/delete?id=` + id })
},
// 导出兑换记录 Excel
exportPointOrder: async (params) => {
return await request.download({ url: `/promotion/point-order/export-excel`, params })
},
}

View File

@ -0,0 +1,45 @@
import request from '@/config/axios'
// 会员卡类型 VO
export interface cardVO {
id: number // id
name: string // 会员名
vid: string // 有效期
originalPrice: number // 原价
specialPrice: number // 优惠价
sort: string // 排序
status: number// 是否禁用
}
// 会员卡类型 API
export const cardApi = {
// 查询会员卡类型分页
getcardPage: async (params: any) => {
return await request.get({ url: `/paid/member/card/type/page`, params })
},
// 查询会员卡类型详情
getcard: async (id: number) => {
return await request.get({ url: `/paid/member/card/type/get?id=` + id })
},
// 新增会员卡类型
createcard: async (data: cardVO) => {
return await request.post({ url: `/paid/member/card/type/create`, data })
},
// 修改会员卡类型
updatecard: async (data: cardVO) => {
return await request.put({ url: `/paid/member/card/type/update`, data })
},
// 删除会员卡类型
deletecard: async (id: number) => {
return await request.delete({ url: `/paid/member/card/type/delete?id=` + id })
},
// 导出会员卡类型 Excel
exportcard: async (params) => {
return await request.download({ url: `/paid/member/card/type/export-excel`, params })
},
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 640 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 573 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 462 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 615 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 369 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 534 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 466 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 480 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 514 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 404 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 545 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 335 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 529 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 759 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 609 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 440 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 821 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 814 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 604 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 339 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 573 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

View File

@ -23,8 +23,11 @@
<div>
<div class="drag-placement">组件放置区域</div>
<div class="component">
<Icon :icon="element.icon" :size="32" />
<span class="mt-4px text-12px">{{ element.name }}</span>
<!-- <Icon :icon="element.icon" :size="32" /> -->
<div>
<img :src="element.icon" />
</div>
<span class="text-12px">{{ element.name }}</span>
</div>
</div>
</template>
@ -142,8 +145,9 @@ const handleCloneComponent = (component: DiyComponent<any>) => {
.component.active,
.component:hover {
color: var(--el-color-white);
background: var(--el-color-primary);
// color: var(--el-color-white);
// background: var(--el-color-primary);
background: #f6f6f6;
.el-icon {
color: var(--el-color-white);

View File

@ -26,12 +26,13 @@ export interface CarouselItemProperty {
// 跳转链接
url: string
}
import logo from '@/assets/imgs/DiyEditorImges/组件图标-09.png'
// 定义组件
export const component = {
id: 'Carousel',
name: '轮播图',
icon: 'system-uicons:carousel',
// icon: 'system-uicons:carousel',
icon: logo,
property: {
type: 'default',
indicator: 'dot',

View File

@ -67,7 +67,8 @@ export const CouponValidTerm = defineComponent({
coupon.validEndTime,
'YYYY-MM-DD'
)}`
: `领取后第 ${coupon.fixedStartTerm} - ${coupon.fixedEndTerm} 天内可用`
// : `领取后第 ${coupon.fixedStartTerm} - ${coupon.fixedEndTerm} 天内可用`
: `领取后 ${coupon.fixedEndTerm} 天内可用`
return () => <div>{text}</div>
}
})

View File

@ -22,12 +22,13 @@ export interface CouponCardProperty {
// 组件样式
style: ComponentStyle
}
import logo from '@/assets/imgs/DiyEditorImges/组件图标-19.png'
// 定义组件
export const component = {
id: 'CouponCard',
name: '优惠券',
icon: 'ep:ticket',
// icon: 'ep:ticket',
icon: logo,
property: {
columns: 1,
bgImg: '',

View File

@ -13,12 +13,13 @@ export interface DividerProperty {
// 类型
borderType: 'solid' | 'dashed' | 'dotted' | 'none'
}
import logo from '@/assets/imgs/DiyEditorImges/组件图标-12.png'
// 定义组件
export const component = {
id: 'Divider',
name: '分割线',
icon: 'tdesign:component-divider-vertical',
// icon: 'tdesign:component-divider-vertical',
icon: logo,
property: {
height: 30,
lineWidth: 1,

View File

@ -21,12 +21,13 @@ export interface FloatingActionButtonItemProperty {
// 文字颜色
textColor: string
}
import logo from '@/assets/imgs/DiyEditorImges/组件图标-07.png'
// 定义组件
export const component = {
id: 'FloatingActionButton',
name: '悬浮按钮',
icon: 'tabler:float-right',
// icon: 'tabler:float-right',
icon: logo,
position: 'fixed',
property: {
direction: 'vertical',

View File

@ -25,12 +25,13 @@ export interface HotZoneItemProperty {
// 左
left: number
}
import logo from '@/assets/imgs/DiyEditorImges/组件图标-14.png'
// 定义组件
export const component = {
id: 'HotZone',
name: '热区',
icon: 'tabler:hand-click',
// icon: 'tabler:hand-click',
icon: logo,
property: {
imgUrl: '',
list: [] as HotZoneItemProperty[],

View File

@ -9,12 +9,13 @@ export interface ImageBarProperty {
// 组件样式
style: ComponentStyle
}
import logo from '@/assets/imgs/DiyEditorImges/组件图标-08.png'
// 定义组件
export const component = {
id: 'ImageBar',
name: '图片展示',
icon: 'ep:picture',
// icon: 'ep:picture',
icon: logo,
property: {
imgUrl: '',
url: '',

View File

@ -29,12 +29,13 @@ export interface MagicCubeItemProperty {
// 左
left: number
}
import logo from '@/assets/imgs/DiyEditorImges/组件图标-13.png'
// 定义组件
export const component = {
id: 'MagicCube',
name: '广告魔方',
icon: 'bi:columns',
// icon: 'bi:columns',
icon: logo,
property: {
borderRadiusTop: 0,
borderRadiusBottom: 0,

View File

@ -49,12 +49,13 @@ export const EMPTY_MENU_GRID_ITEM_PROPERTY = {
bgColor: '#FF6000'
}
} as MenuGridItemProperty
import logo from '@/assets/imgs/DiyEditorImges/组件图标-04.png'
// 定义组件
export const component = {
id: 'MenuGrid',
name: '宫格导航',
icon: 'bi:grid-3x3-gap',
// icon: 'bi:grid-3x3-gap',
icon: logo,
property: {
column: 3,
list: [cloneDeep(EMPTY_MENU_GRID_ITEM_PROPERTY)],

View File

@ -6,6 +6,7 @@
<el-radio-group v-model="formData.column">
<el-radio :label="3">3</el-radio>
<el-radio :label="4">4</el-radio>
<el-radio :label="5">5</el-radio>
</el-radio-group>
</el-form-item>

View File

@ -31,12 +31,13 @@ export const EMPTY_MENU_LIST_ITEM_PROPERTY = {
subtitle: '副标题',
subtitleColor: '#bbb'
}
import logo from '@/assets/imgs/DiyEditorImges/组件图标-05.png'
// 定义组件
export const component = {
id: 'MenuList',
name: '列表导航',
icon: 'fa-solid:list',
// icon: 'fa-solid:list',
icon: logo,
property: {
list: [cloneDeep(EMPTY_MENU_LIST_ITEM_PROPERTY)],
style: {

View File

@ -46,12 +46,13 @@ export const EMPTY_MENU_SWIPER_ITEM_PROPERTY = {
bgColor: '#FF6000'
}
} as MenuSwiperItemProperty
import logo from '@/assets/imgs/DiyEditorImges/组件图标-03.png'
// 定义组件
export const component = {
id: 'MenuSwiper',
name: '菜单导航',
icon: 'bi:grid-3x2-gap',
// icon: 'bi:grid-3x2-gap',
icon: logo,
property: {
layout: 'iconText',
row: 1,

View File

@ -21,12 +21,13 @@ export interface NoticeContentProperty {
// 链接地址
url: string
}
import logo from '@/assets/imgs/DiyEditorImges/组件图标-02.png'
// 定义组件
export const component = {
id: 'NoticeBar',
name: '公告栏',
icon: 'ep:bell',
// icon: 'ep:bell',
icon: logo,
property: {
iconUrl: 'http://mall.yudao.iocoder.cn/static/images/xinjian.png',
contents: [

View File

@ -13,12 +13,13 @@ export interface PopoverItemProperty {
// 显示类型:仅显示一次、每次启动都会显示
showType: 'once' | 'always'
}
import logo from '@/assets/imgs/DiyEditorImges/组件图标-06.png'
// 定义组件
export const component = {
id: 'Popover',
name: '弹窗广告',
icon: 'carbon:popup',
// icon: 'carbon:popup',
icon: logo,
position: 'fixed',
property: {
list: [{ showType: 'once' }]

View File

@ -57,12 +57,13 @@ export interface ProductCardFieldProperty {
// 颜色
color: string
}
import logo from '@/assets/imgs/DiyEditorImges/组件图标-15.png'
// 定义组件
export const component = {
id: 'ProductCard',
name: '商品卡片',
icon: 'fluent:text-column-two-left-24-filled',
// icon: 'fluent:text-column-two-left-24-filled',
icon: logo,
property: {
layoutType: 'oneColBigImg',
fields: {

View File

@ -36,12 +36,13 @@ export interface ProductListFieldProperty {
// 颜色
color: string
}
import logo from '@/assets/imgs/DiyEditorImges/组件图标-16.png'
// 定义组件
export const component = {
id: 'ProductList',
name: '商品栏',
icon: 'fluent:text-column-two-24-filled',
// icon: 'fluent:text-column-two-24-filled',
icon: logo,
property: {
layoutType: 'twoCol',
fields: {

View File

@ -7,12 +7,13 @@ export interface PromotionArticleProperty {
// 组件样式
style: ComponentStyle
}
import logo from '@/assets/imgs/DiyEditorImges/组件图标-20.png'
// 定义组件
export const component = {
id: 'PromotionArticle',
name: '营销文章',
icon: 'ph:article-medium',
// icon: 'ph:article-medium',
icon: logo,
property: {
style: {
bgType: 'color',

View File

@ -37,12 +37,13 @@ export interface PromotionCombinationFieldProperty {
// 颜色
color: string
}
import logo from '@/assets/imgs/DiyEditorImges/组件图标-17.png'
// 定义组件
export const component = {
id: 'PromotionCombination',
name: '拼团',
icon: 'mdi:account-group',
// icon: 'mdi:account-group',
icon: logo,
property: {
layoutType: 'oneCol',
fields: {

View File

@ -58,12 +58,13 @@ export interface PromotionPointFieldProperty {
// 颜色
color: string
}
import logo from '@/assets/imgs/DiyEditorImges/组件图标-21.png'
// 定义组件
export const component = {
id: 'PromotionPoint',
name: '积分商城',
icon: 'ep:present',
// icon: 'ep:present',
icon: logo,
property: {
layoutType: 'oneColBigImg',
fields: {

View File

@ -36,12 +36,13 @@ export interface PromotionSeckillFieldProperty {
// 颜色
color: string
}
import logo from '@/assets/imgs/DiyEditorImges/组件图标-18.png'
// 定义组件
export const component = {
id: 'PromotionSeckill',
name: '秒杀',
icon: 'mdi:calendar-time',
// icon: 'mdi:calendar-time',
icon: logo,
property: {
activityId: undefined,
layoutType: 'oneCol',

View File

@ -15,12 +15,12 @@ export interface SearchProperty {
// 文字位置
export type PlaceholderPosition = 'left' | 'center'
import logo from '@/assets/imgs/DiyEditorImges/组件图标-01.png'
// 定义组件
export const component = {
id: 'SearchBar',
name: '搜索框',
icon: 'ep:search',
icon: logo,
property: {
height: 28,
showScan: false,

View File

@ -38,12 +38,13 @@ export interface TitleBarProperty {
// 组件样式
style: ComponentStyle
}
import logo from '@/assets/imgs/DiyEditorImges/组件图标-10.png'
// 定义组件
export const component = {
id: 'TitleBar',
name: '标题栏',
icon: 'material-symbols:line-start',
icon: logo,
property: {
title: '主标题',
description: '副标题',

View File

@ -1,29 +1,115 @@
<template>
<div class="flex flex-col">
<div class="flex items-center justify-between p-x-18px p-y-24px">
<div class="flex flex-1 items-center gap-16px">
<el-avatar :size="60">
<Icon icon="ep:avatar" :size="60" />
</el-avatar>
<span class="text-18px font-bold">芋道源码</span>
</div>
<Icon icon="tdesign:qrcode" :size="20" />
</div>
<div
<div class="flex flex-col" style=" margin-bottom: 27px;">
<div class="new-main">
<div class="flex items-center justify-between p-x-18px p-y-24px " style="padding-bottom:15px;">
<div class="flex flex-1 items-center gap-16px">
<el-avatar :size="60">
<Icon icon="ep:avatar" :size="60" />
</el-avatar>
<span class="text-18px font-bold">用户名称</span>
</div>
<Icon icon="tdesign:qrcode" :size="20" />
</div>
<div class="new-usercard" style="z-index: 9999;">
<div class="menu-item ss-flex-1 ss-flex-col ss-row-center ss-col-center">
<div class="value-box ss-flex ss-col-bottom">
<div class="value-text ss-line-1">0.00</div>
<div class="unit-text ss-m-l-6">
<!-- -->
</div>
</div>
<div class="menu-title ss-m-t-28">余额</div>
</div>
<div class="menu-item ss-flex-1 ss-flex-col ss-row-center ss-col-center">
<div class="value-box ss-flex ss-col-bottom">
<div class="value-text">0</div>
<div class="unit-text ss-m-l-6">
<!-- -->
</div>
</div>
<div class="menu-title ss-m-t-28">优惠券</div>
</div>
<div class="menu-item ss-flex-1 ss-flex-col ss-row-center ss-col-center">
<div class="value-box ss-flex ss-col-bottom">
<div class="value-text">0</div>
<div class="unit-text ss-m-l-6">
<!-- -->
</div>
</div>
<div class="menu-title ss-m-t-28">积分</div>
</div>
</div>
<div class="new-bottom">
<img src="https://zysc.fjptzykj.com:3000/shangcheng/64776e2edc3c2f15295e7c3976ba301e08f9170f99a2e845d8f33bd65179b177.png"
alt="" />
<div class="btn">
立即开通
</div>
</div>
</div>
<!-- <div
class="flex items-center justify-between justify-between bg-white p-x-20px p-y-8px text-12px"
>
<span class="color-#ff690d">点击绑定手机号</span>
<span class="rounded-26px bg-#ff6100 p-x-8px p-y-5px color-white">去绑定</span>
</div>
</div>
</div> -->
</div>
</template>
<script setup lang="ts">
import { UserCardProperty } from './config'
import { UserCardProperty } from './config'
/** 用户卡片 */
defineOptions({ name: 'UserCard' })
//
defineProps<{ property: UserCardProperty }>()
/** 用户卡片 */
defineOptions({ name: 'UserCard' })
//
defineProps<{ property : UserCardProperty }>()
</script>
<style scoped lang="scss"></style>
<style scoped lang="scss">
.new-main {
position: relative;
background: url('@/assets/imgs/userCar/seckilbg.png') no-repeat;
background-size: cover;
padding-bottom: 53px;
.value-box {
margin-bottom: 6px;
}
.new-usercard {
width: 100%;
display: flex;
justify-content: space-around;
}
div {
text-align: center;
color: white;
}
.new-bottom {
position: absolute;
bottom: -28px;
width: 100%;
z-index: 999999999999999;
img {
width: 92%;
}
.btn {
position: absolute;
bottom: 19px;
right: 29px;
background: white;
border-radius: 12px;
padding: 4px 8px;
font-size: 14px;
color: #946d2d;
}
}
}
</style>

View File

@ -1,5 +1,6 @@
<template>
<el-image src="https://shopro.sheepjs.com/admin/static/images/shop/decorate/orderCardStyle.png" />
<!-- <el-image src="https://shopro.sheepjs.com/admin/static/images/shop/decorate/orderCardStyle.png" /> -->
<el-image src=" https://zysc.fjptzykj.com:3000/shangcheng/0ba158a1a2de7d39c6cec22cfe54736237438f63893b09c7453b5b5e3482f826.png" />
</template>
<script setup lang="ts">
import { UserOrderProperty } from './config'

View File

@ -17,12 +17,13 @@ export interface VideoPlayerStyle extends ComponentStyle {
// 视频高度
height: number
}
import logo from '@/assets/imgs/DiyEditorImges/组件图标-11.png'
// 定义组件
export const component = {
id: 'VideoPlayer',
name: '视频播放',
icon: 'ep:video-play',
// icon: 'ep:video-play',
icon: logo,
property: {
videoUrl: '',
posterUrl: '',

File diff suppressed because it is too large Load Diff

View File

@ -28,7 +28,8 @@ export const validityTypeFormat = (row: CouponTemplateVO) => {
return `${formatDate(row.validStartTime)}${formatDate(row.validEndTime)}`
}
if (row.validityType === CouponTemplateValidityTypeEnum.TERM.type) {
return `领取后第 ${row.fixedStartTerm} - ${row.fixedEndTerm} 天内可用`
// return `领取后第 ${row.fixedStartTerm} - ${row.fixedEndTerm} 天内可用`
return `领取后 ${row.fixedEndTerm + 1} 天内可用`
}
return '未知【' + row.validityType + '】'
}

View File

@ -38,7 +38,7 @@
<el-form-item label="优惠类型" prop="discountType">
<el-radio-group v-model="formData.discountType">
<el-radio
v-for="dict in getIntDictOptions(DICT_TYPE.PROMOTION_DISCOUNT_TYPE)"
v-for="dict in filteredDictOptions()"
:key="dict.value"
:label="dict.value"
>
@ -151,10 +151,10 @@
</el-form-item>
<el-form-item
v-if="formData.validityType === CouponTemplateValidityTypeEnum.TERM.type"
label="领取日期"
label="有效日期"
prop="fixedStartTerm"
>
<!--
<el-input-number
v-model="formData.fixedStartTerm"
:min="0"
@ -162,13 +162,13 @@
class="mx-2"
placeholder="0 为今天生效"
/>
-->
<el-input-number
v-model="formData.fixedEndTerm"
:min="0"
:min="1"
:precision="0"
class="mx-2"
placeholder="请输入结束天数"
placeholder="请输入有效天数"
/>
天有效
</el-form-item>
@ -215,7 +215,7 @@ const formData = ref({
validTimes: [],
validStartTime: undefined,
validEndTime: undefined,
fixedStartTerm: undefined,
fixedStartTerm: 0,
fixedEndTerm: undefined,
productScope: PromotionProductScopeEnum.ALL.scope,
productScopeValues: [], //
@ -255,6 +255,7 @@ const open = async (type: string, id?: number) => {
const data = await CouponTemplateApi.getCouponTemplate(id)
formData.value = {
...data,
fixedEndTerm: data.fixedEndTerm - data.fixedStartTerm + 1, // +1
discountPrice: formatToFraction(data.discountPrice),
discountPercent:
data.discountPercent !== undefined ? data.discountPercent / 10.0 : undefined,
@ -283,6 +284,7 @@ const submitForm = async () => {
try {
const data = {
...formData.value,
fixedEndTerm: (formData.value.fixedEndTerm || 0) + formData.value.fixedStartTerm - 1, //
discountPrice: convertToInteger(formData.value.discountPrice),
discountPercent:
formData.value.discountPercent !== undefined
@ -335,7 +337,7 @@ const resetForm = () => {
validTimes: [],
validStartTime: undefined,
validEndTime: undefined,
fixedStartTerm: undefined,
fixedStartTerm: 0,
fixedEndTerm: undefined,
productScope: PromotionProductScopeEnum.ALL.scope,
productScopeValues: [],
@ -383,6 +385,12 @@ function setProductScopeValues(data: CouponTemplateApi.CouponTemplateVO) {
break
}
}
/** 暂时隐藏掉字典中的折扣 */
function filteredDictOptions() {
return getIntDictOptions(DICT_TYPE.PROMOTION_DISCOUNT_TYPE).filter(
dict => dict.value !== 2 // value 2
);
}
</script>
<style lang="scss" scoped></style>

View File

@ -2,19 +2,19 @@
<DiyEditor v-if="formData && !formLoading" v-model="currentFormData!.property"
:title="templateItems[selectedTemplateItem].name" :libs="libs" :show-page-config="selectedTemplateItem !== 0"
:show-tab-bar="selectedTemplateItem === 0" :show-navigation-bar="selectedTemplateItem !== 0"
:preview-url="previewUrl" @save="submitForm" @reset="handleEditorReset">
:preview-url="previewUrl" @save="submitForm" @reset="handleEditorReset" :isShow="false">
<template #toolBarLeft>
<!-- <el-radio-group
v-model="selectedTemplateItem"
class="h-full!"
@change="handleTemplateItemChange"
>
<el-tooltip v-for="(item, index) in templateItems" :key="index" :content="item.name">
<el-radio-button :label="index">
<Icon :icon="item.icon" :size="24" />
</el-radio-button>
</el-tooltip>
</el-radio-group> -->
v-model="selectedTemplateItem"
class="h-full!"
@change="handleTemplateItemChange"
>
<el-tooltip v-for="(item, index) in templateItems" :key="index" :content="item.name">
<el-radio-button :label="index">
<Icon :icon="item.icon" :size="24" />
</el-radio-button>
</el-tooltip>
</el-radio-group> -->
</template>
</DiyEditor>
</template>
@ -147,7 +147,7 @@
}
}
//#endregion
onMounted(async () => {
resetForm()
@ -167,7 +167,7 @@
console.log(currentRoute.value.params.id, "currentRoute.value.params.id");
})
// watch(() => route.path, (newPath, oldPath) => {
// console.log(newPath,'newPathnewPath');
// // handleTemplateItemChange()

View File

@ -22,8 +22,8 @@
<div class="ml-10px w-100%">
<div class="flex justify-between items-center w-100%">
<span class="username">{{ item.userNickname }}</span>
<span class="color-[#989EA6]">
{{ formatPast(item.lastMessageTime, 'YYYY-mm-dd') }}
<span class="color-[var(--left-menu-text-color)]" style="font-size: 13px">
{{ formatPast(item.lastMessageTime, 'YYYY-MM-DD') }}
</span>
</div>
<!-- 最后聊天内容 -->
@ -31,8 +31,9 @@
v-dompurify-html="
getConversationDisplayText(item.lastMessageContentType, item.lastMessageContent)
"
class="last-message flex items-center color-[#989EA6]"
></div>
class="last-message flex items-center color-[var(--left-menu-text-color)]"
>
</div>
</div>
</div>
</div>
@ -182,7 +183,7 @@ watch(showRightMenu, (val) => {
&-conversation {
height: 60px;
padding: 10px;
background-color: #fff;
//background-color: #fff;
transition: border-left 0.05s ease-in-out; /* 设置过渡效果 */
.username {
@ -196,6 +197,7 @@ watch(showRightMenu, (val) => {
}
.last-message {
font-size: 13px;
width: 200px;
overflow: hidden; //
white-space: nowrap; //
@ -205,17 +207,17 @@ watch(showRightMenu, (val) => {
.active {
border-left: 5px #3271ff solid;
background-color: #eff0f1;
background-color: var(--login-bg-color);
}
.pinned {
background-color: #eff0f1;
background-color: var(--left-menu-bg-active-color);
}
.right-menu-ul {
position: absolute;
background-color: #fff;
padding: 10px;
background-color: var(--app-content-bg-color);
padding: 5px;
margin: 0;
list-style-type: none; /* 移除默认的项目符号 */
border-radius: 12px;
@ -228,7 +230,7 @@ watch(showRightMenu, (val) => {
border-radius: 12px;
transition: background-color 0.3s; /* 平滑过渡 */
&:hover {
background-color: #e0e0e0; /* 悬停时的背景颜色 */
background-color: var(--left-menu-bg-active-color); /* 悬停时的背景颜色 */
}
}
}

View File

@ -71,6 +71,7 @@
<MessageItem :message="item">
<ProductItem
v-if="KeFuMessageContentTypeEnum.PRODUCT === item.contentType"
:spuId="getMessageContent(item).spuId"
:picUrl="getMessageContent(item).picUrl"
:price="getMessageContent(item).price"
:skuText="getMessageContent(item).introduction"
@ -85,7 +86,7 @@
<OrderItem
v-if="KeFuMessageContentTypeEnum.ORDER === item.contentType"
:message="item"
class="max-w-70%"
class="max-w-100%"
/>
</MessageItem>
</div>
@ -369,9 +370,10 @@ const showTime = computed(() => (item: KeFuMessageRespVO, index: number) => {
position: absolute;
bottom: 35px;
right: 35px;
background-color: #fff;
background-color: var(--app-content-bg-color);
padding: 10px;
border-radius: 30px;
font-size: 12px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); /* 阴影效果 */
}
@ -392,7 +394,7 @@ const showTime = computed(() => (item: KeFuMessageRespVO, index: number) => {
border-left: 5px solid transparent;
border-bottom: 5px solid transparent;
border-top: 5px solid transparent;
border-right: 5px solid #ffffff;
border-right: 5px solid var(--app-content-bg-color);
}
}
}
@ -411,7 +413,7 @@ const showTime = computed(() => (item: KeFuMessageRespVO, index: number) => {
right: -19px;
top: calc(50% - 10px);
position: absolute;
border-left: 5px solid #ffffff;
border-left: 5px solid var(--app-content-bg-color);
border-bottom: 5px solid transparent;
border-top: 5px solid transparent;
border-right: 5px solid transparent;
@ -421,9 +423,9 @@ const showTime = computed(() => (item: KeFuMessageRespVO, index: number) => {
//
.kefu-message {
color: #333;
color: #a9a9a9;
border-radius: 5px;
box-shadow: 3px 5px 15px rgba(0, 0, 0, 0.2);
box-shadow: 3px 3px 5px rgba(220, 220, 220, 0.1);
padding: 5px 10px;
width: auto;
max-width: 50%;
@ -431,7 +433,7 @@ const showTime = computed(() => (item: KeFuMessageRespVO, index: number) => {
display: inline-block !important;
position: relative;
word-break: break-all;
background-color: #ffffff;
background-color: var(--app-content-bg-color);
transition: all 0.2s;
&:hover {
@ -445,7 +447,7 @@ const showTime = computed(() => (item: KeFuMessageRespVO, index: number) => {
border-radius: 12rpx;
padding: 8rpx 16rpx;
margin-bottom: 16rpx;
background-color: #e8e8e8;
//background-color: #e8e8e8;
color: #999;
font-size: 24rpx;
}
@ -453,7 +455,7 @@ const showTime = computed(() => (item: KeFuMessageRespVO, index: number) => {
.chat-tools {
width: 100%;
border: #e4e0e0 solid 1px;
border: var(--el-border-color) solid 1px;
border-radius: 10px;
height: 44px;
}

View File

@ -7,7 +7,7 @@
<el-tab-pane label="订单列表" name="b" />
</el-tabs>
<div>
<el-scrollbar ref="scrollbarRef" always height="calc(100vh - 400px)" @scroll="handleScroll">
<el-scrollbar ref="scrollbarRef" always height="calc(115vh - 400px)" @scroll="handleScroll">
<!-- 最近浏览 -->
<ProductBrowsingHistory v-if="activeName === 'a'" ref="productBrowsingHistoryRef" />
<!-- 订单列表 -->
@ -25,7 +25,7 @@ import OrderBrowsingHistory from './OrderBrowsingHistory.vue'
import { KeFuConversationRespVO } from '@/api/mall/promotion/kefu/conversation'
import { isEmpty } from '@/utils/is'
import { debounce } from 'lodash-es'
import { ElScrollbar as ElScrollbarType } from 'element-plus/es/components/scrollbar'
import { ElScrollbar as ElScrollbarType } from 'element-plus/es/components/scrollbar/index'
defineOptions({ name: 'MemberBrowsingHistory' })

View File

@ -1,6 +1,7 @@
<template>
<ProductItem
v-for="item in list"
:spu-id="item.spuId"
:key="item.id"
:picUrl="item.picUrl"
:price="item.price"

View File

@ -1,14 +1,20 @@
<template>
<div v-if="isObject(getMessageContent)">
<div :key="getMessageContent.id" class="order-list-card-box mt-14px">
<div class="order-card-header flex items-center justify-between p-x-20px">
<div class="order-no">订单号{{ getMessageContent.no }}</div>
<div class="order-card-header flex items-center justify-between p-x-5px">
<div class="order-no">
订单号
<span style="cursor: pointer" @click="openDetail(getMessageContent.id)">
{{ getMessageContent.no }}
</span>
</div>
<div :class="formatOrderColor(getMessageContent)" class="order-state font-16">
{{ formatOrderStatus(getMessageContent) }}
</div>
</div>
<div v-for="item in getMessageContent.items" :key="item.id" class="border-bottom">
<ProductItem
:spu-id="item.spuId"
:num="item.count"
:picUrl="item.picUrl"
:price="item.price"
@ -16,7 +22,7 @@
:title="item.spuName"
/>
</div>
<div class="pay-box flex justify-end pr-20px">
<div class="pay-box flex justify-end pr-5px">
<div class="flex items-center">
<div class="discounts-title pay-color"
> {{ getMessageContent?.productCount }} 件商品,总金额:
@ -36,6 +42,8 @@ import { KeFuMessageRespVO } from '@/api/mall/promotion/kefu/message'
import { isObject } from '@/utils/is'
import ProductItem from '@/views/mall/promotion/kefu/components/message/ProductItem.vue'
const { push } = useRouter()
defineOptions({ name: 'OrderItem' })
const props = defineProps<{
message?: KeFuMessageRespVO
@ -46,6 +54,12 @@ const getMessageContent = computed(() =>
typeof props.message !== 'undefined' ? jsonParse(props!.message!.content) : props.order
)
/** 查看订单详情 */
const openDetail = (id: number) => {
console.log(getMessageContent)
push({ name: 'TradeOrderDetail', params: { id } })
}
/**
* 格式化订单状态的颜色
*
@ -97,18 +111,28 @@ function formatOrderStatus(order: any) {
.order-list-card-box {
border-radius: 10px;
padding: 10px;
background-color: #e2e2e2;
border: 1px var(--el-border-color) solid;
background-color: var(--app-content-bg-color);
.order-card-header {
height: 28px;
.order-no {
font-size: 16px;
font-size: 12px;
font-weight: 500;
span {
&:hover {
text-decoration: underline;
color: var(--left-menu-bg-active-color);
}
}
}
}
.pay-box {
padding-top: 10px;
.discounts-title {
font-size: 16px;
line-height: normal;
@ -123,24 +147,33 @@ function formatOrderStatus(order: any) {
}
.pay-color {
color: #333;
font-size: 13px;
color: var(--left-menu-text-color);
}
}
}
.warning-color {
color: #faad14;
font-size: 11px;
font-weight: bold;
}
.danger-color {
color: #ff3000;
font-size: 11px;
font-weight: bold;
}
.success-color {
color: #52c41a;
font-size: 11px;
font-weight: bold;
}
.info-color {
color: #999999;
font-size: 11px;
font-weight: bold;
}
</style>

View File

@ -1,5 +1,5 @@
<template>
<div>
<div @click.stop="openDetail(props.spuId)" style="cursor: pointer;">
<div>
<slot name="top"></slot>
</div>
@ -15,6 +15,7 @@
class="order-img"
fit="contain"
preview-teleported
@click.stop
/>
</div>
<div
@ -53,8 +54,14 @@
<script lang="ts" setup>
import { fenToYuan } from '@/utils'
const { push } = useRouter()
defineOptions({ name: 'ProductItem' })
const props = defineProps({
spuId: {
type: Number,
default: 0
},
picUrl: {
type: String,
default: 'https://img1.baidu.com/it/u=1601695551,235775011&fm=26&fmt=auto'
@ -107,13 +114,20 @@ const skuString = computed(() => {
}
return props.skuText
})
/** 查看商品详情 */
const openDetail = (spuId: number) => {
console.log(props.spuId)
push({ name: 'ProductSpuDetail', params: { id: spuId } })
}
</script>
<style lang="scss" scoped>
.ss-order-card-warp {
padding: 20px;
border-radius: 10px;
background-color: #e2e2e2;
border: 1px var(--el-border-color) solid;
background-color: var(--app-content-bg-color);
.img-box {
width: 80px;
@ -133,19 +147,19 @@ const skuString = computed(() => {
.tool-box {
position: absolute;
right: 0px;
right: 0;
bottom: -10px;
}
}
.title-text {
font-size: 16px;
font-size: 13px;
font-weight: 500;
line-height: 20px;
}
.spec-text {
font-size: 16px;
font-size: 10px;
font-weight: 400;
color: #999999;
min-width: 0;
@ -157,13 +171,13 @@ const skuString = computed(() => {
}
.price-text {
font-size: 16px;
font-size: 11px;
font-weight: 500;
font-family: OPPOSANS;
}
.total-text {
font-size: 16px;
font-size: 10px;
font-weight: 400;
line-height: 16px;
color: #999999;

View File

@ -66,7 +66,7 @@ export const useEmoji = () => {
)
for (const path in pathList) {
const imageModule: any = await pathList[path]()
emojiPathList.value.push(imageModule.default)
emojiPathList.value.push({ path: path, src: imageModule.default })
}
}
@ -80,8 +80,8 @@ export const useEmoji = () => {
/**
*
*
* @param data
* @return
* @param content
*/
const replaceEmoji = (content: string) => {
let newData = content
@ -93,7 +93,7 @@ export const useEmoji = () => {
const emojiFile = getEmojiFileByName(item)
newData = newData.replace(
item,
`<img class="chat-img" style="width: 24px;height: 24px;margin: 0 3px;" src="${emojiFile}"/>`
`<img class="chat-img" style="width: 24px;height: 24px;margin: 0 3px;" src="${emojiFile}" alt=""/>`
)
})
}
@ -116,7 +116,10 @@ export const useEmoji = () => {
function getEmojiFileByName(name: string) {
for (const emoji of emojiList) {
if (emoji.name === name) {
return emojiPathList.value.find((item: string) => item.indexOf(emoji.file) > -1)
const emojiPath = emojiPathList.value.find(
(item: { path: string; src: string }) => item.path.indexOf(emoji.file) > -1
)
return emojiPath ? emojiPath.src : undefined
}
}
return false

View File

@ -22,119 +22,118 @@
</template>
<script lang="ts" setup>
import { KeFuConversationList, KeFuMessageList, MemberBrowsingHistory } from './components'
import { WebSocketMessageTypeConstants } from './components/tools/constants'
import { KeFuConversationRespVO } from '@/api/mall/promotion/kefu/conversation'
import { getAccessToken } from '@/utils/auth'
import { useWebSocket } from '@vueuse/core'
import { KeFuConversationList, KeFuMessageList, MemberBrowsingHistory } from './components'
import { WebSocketMessageTypeConstants } from './components/tools/constants'
import { KeFuConversationRespVO } from '@/api/mall/promotion/kefu/conversation'
import { getRefreshToken } from '@/utils/auth'
import { useWebSocket } from '@vueuse/core'
defineOptions({ name: 'KeFu' })
defineOptions({ name: 'KeFu' })
const message = useMessage() //
const message = useMessage() //
// ======================= WebSocket start =======================
const server = ref(
(import.meta.env.VITE_BASE_URL + '/infra/ws').replace('http', 'ws') + '?token=' + getAccessToken()
) // WebSocket
// ======================= WebSocket start =======================
const server = ref(
(import.meta.env.VITE_BASE_URL + '/infra/ws').replace('http', 'ws') +
'?token=' +
getRefreshToken() // 使 getRefreshToken() 使 getAccessToken() WebSocket 便访
) // WebSocket
/** 发起 WebSocket 连接 */
const { data, close, open } = useWebSocket(server.value, {
autoReconnect: true,
heartbeat: true
})
/** 发起 WebSocket 连接 */
const { data, close, open } = useWebSocket(server.value, {
autoReconnect: true,
heartbeat: true
})
/** 监听 WebSocket 数据 */
watchEffect(() => {
if (!data.value) {
console.log('111')
return
/** 监听 WebSocket 数据 */
watchEffect(() => {
if (!data.value) {
return
}
try {
// 1.
if (data.value === 'pong') {
return
}
// 2.1 type
const jsonMessage = JSON.parse(data.value)
const type = jsonMessage.type
if (!type) {
message.error('未知的消息类型:' + data.value)
return
}
// 2.2 KEFU_MESSAGE_TYPE
if (type === WebSocketMessageTypeConstants.KEFU_MESSAGE_TYPE) {
//
// TODO @puhui999 update
getConversationList()
//
keFuChatBoxRef.value?.refreshMessageList(JSON.parse(jsonMessage.content))
return
}
// 2.3 KEFU_MESSAGE_ADMIN_READ
if (type === WebSocketMessageTypeConstants.KEFU_MESSAGE_ADMIN_READ) {
//
// TODO @puhui999 update
getConversationList()
}
} catch (error) {
console.error(error)
}
})
// ======================= WebSocket end =======================
/** 加载会话列表 */
const keFuConversationRef = ref<InstanceType<typeof KeFuConversationList>>()
const getConversationList = () => {
keFuConversationRef.value?.getConversationList()
}
try {
// 1.
if (data.value === 'pong') {
console.log('666')
return
}
console.log('777')
// 2.1 type
const jsonMessage = JSON.parse(data.value)
const type = jsonMessage.type
if (!type) {
message.error('未知的消息类型:' + data.value)
return
}
// 2.2 KEFU_MESSAGE_TYPE
if (type === WebSocketMessageTypeConstants.KEFU_MESSAGE_TYPE) {
//
// TODO @puhui999 update
getConversationList()
//
keFuChatBoxRef.value?.refreshMessageList(JSON.parse(jsonMessage.content))
return
}
// 2.3 KEFU_MESSAGE_ADMIN_READ
if (type === WebSocketMessageTypeConstants.KEFU_MESSAGE_ADMIN_READ) {
//
// TODO @puhui999 update
getConversationList()
}
} catch (error) {
console.error(error)
/** 加载指定会话的消息列表 */
const keFuChatBoxRef = ref<InstanceType<typeof KeFuMessageList>>()
const memberBrowsingHistoryRef = ref<InstanceType<typeof MemberBrowsingHistory>>()
const handleChange = (conversation: KeFuConversationRespVO) => {
keFuChatBoxRef.value?.getNewMessageList(conversation)
memberBrowsingHistoryRef.value?.initHistory(conversation)
}
})
// ======================= WebSocket end =======================
/** 加载会话列表 */
const keFuConversationRef = ref<InstanceType<typeof KeFuConversationList>>()
const getConversationList = () => {
keFuConversationRef.value?.getConversationList()
}
/** 加载指定会话的消息列表 */
const keFuChatBoxRef = ref<InstanceType<typeof KeFuMessageList>>()
const memberBrowsingHistoryRef = ref<InstanceType<typeof MemberBrowsingHistory>>()
const handleChange = (conversation: KeFuConversationRespVO) => {
keFuChatBoxRef.value?.getNewMessageList(conversation)
memberBrowsingHistoryRef.value?.initHistory(conversation)
}
/** 初始化 */
onMounted(() => {
getConversationList()
// websocket
open()
})
/** 初始化 */
onMounted(() => {
getConversationList()
// websocket
open()
})
/** 销毁 */
onBeforeUnmount(() => {
// websocket
close()
})
/** 销毁 */
onBeforeUnmount(() => {
// websocket
close()
})
</script>
<style lang="scss">
.kefu {
height: calc(100vh - 165px);
overflow: auto; /* 确保内容可滚动 */
}
.kefu {
height: calc(100vh - 165px);
overflow: auto; /* 确保内容可滚动 */
}
/* 定义滚动条样式 */
::-webkit-scrollbar {
width: 10px;
height: 6px;
}
/* 定义滚动条样式 */
::-webkit-scrollbar {
width: 10px;
height: 6px;
}
/* 定义滚动条轨道 内阴影+圆角 */
::-webkit-scrollbar-track {
box-shadow: inset 0 0 0 rgba(240, 240, 240, 0.5);
border-radius: 10px;
background-color: #fff;
}
/* 定义滚动条轨道 内阴影+圆角 */
::-webkit-scrollbar-track {
box-shadow: inset 0 0 0 rgba(240, 240, 240, 0.5);
border-radius: 10px;
background-color: #fff;
}
/* 定义滑块 内阴影+圆角 */
::-webkit-scrollbar-thumb {
border-radius: 10px;
box-shadow: inset 0 0 0 rgba(240, 240, 240, 0.5);
background-color: rgba(240, 240, 240, 0.5);
}
/* 定义滑块 内阴影+圆角 */
::-webkit-scrollbar-thumb {
border-radius: 10px;
box-shadow: inset 0 0 0 rgba(240, 240, 240, 0.5);
background-color: rgba(240, 240, 240, 0.5);
}
</style>

View File

@ -7,15 +7,15 @@
label-width="100px"
v-loading="formLoading"
>
<el-form-item label="名称" prop="name">
<el-input v-model="formData.name" placeholder="请输入名称" />
<el-form-item label="权益名称" prop="benName">
<el-input v-model="formData.benName" placeholder="请输入权益名称" />
</el-form-item>
<el-form-item label="展示名称" prop="showName">
<el-input v-model="formData.showName" 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
@ -26,7 +26,7 @@
/>
</el-select>
</el-form-item>
<el-form-item label="会员等级" prop="levelIdList">
<!-- <el-form-item label="会员等级" prop="levelIdList">
<el-checkbox-group v-model="formData.levelIdList">
<el-checkbox
v-for="dict in memberLevelList"
@ -36,12 +36,14 @@
{{ dict.name }}
</el-checkbox>
</el-checkbox-group>
</el-form-item> -->
<el-form-item label="权益简介" prop="intro">
<el-input v-model="formData.intro" placeholder="请输入描述" />
</el-form-item>
<el-form-item label="排序" prop="sort">
<!-- <el-form-item label="排序" prop="sort">
<el-input v-model="formData.sort" placeholder="请输入排序" />
</el-form-item>
</el-form-item> -->
</el-form>
<template #footer>
<el-button @click="submitForm" type="primary" :disabled="formLoading"> </el-button>
@ -65,7 +67,8 @@ const formLoading = ref(false) // 表单的加载中1修改时的数据加
const formType = ref('') // create - update -
const formData = ref({
id: undefined,
name: undefined,
benName: undefined,
showName: undefined,
iconUrl: undefined,
intro: undefined,
status: undefined,
@ -73,10 +76,10 @@ const formData = ref({
levelIdList: []
})
const formRules = reactive({
name: [{ required: true, message: '名称不能为空', trigger: 'blur' }],
benName: [{ required: true, message: '权益名称不能为空', trigger: 'blur' }],
showName: [{ 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() //
@ -136,7 +139,8 @@ const submitForm = async () => {
const resetForm = () => {
formData.value = {
id: undefined,
name: undefined,
benName: undefined,
showName: undefined,
iconUrl: undefined,
intro: undefined,
status: undefined,

View File

@ -8,10 +8,10 @@
:inline="true"
label-width="68px"
>
<el-form-item label="名称" prop="name">
<el-form-item label="权益名称" prop="benName">
<el-input
v-model="queryParams.name"
placeholder="请输入名称"
v-model="queryParams.benName"
placeholder="请输入权益名称"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
@ -35,7 +35,7 @@
class="!w-240px"
/>
</el-form-item> -->
<el-form-item label="状态" prop="status">
<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)"
@ -45,7 +45,7 @@
/>
</el-select>
</el-form-item>
<el-form-item label="会员等级" prop="levelId">
<!-- <el-form-item label="会员等级" prop="levelId">
<el-select v-model="queryParams.levelId" class="!w-240px" placeholder="请选择" clearable>
<el-option
v-for="dict in memberLevelList"
@ -54,7 +54,7 @@
:value="dict.id"
/>
</el-select>
</el-form-item>
</el-form-item> -->
<!-- <el-form-item label="排序" prop="sort">
<el-input
v-model="queryParams.sort"
@ -102,35 +102,35 @@
<!-- 列表 -->
<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">
<el-table-column label="权益名称" align="center" prop="benName" />
<el-table-column label="展示名称" align="center" prop="showName" />
<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">
<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="隐藏"
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="sort" />
<el-table-column
label="创建时间"
align="center"
prop="createTime"
:formatter="dateFormatter"
width="180px"
/>
/> -->
<el-table-column label="操作" align="center">
<template #default="scope">
<el-button
@ -193,7 +193,7 @@ const queryParams = reactive({
createTime: [],
levelId: undefined
})
const memberLevelList = ref() //
// const memberLevelList = ref() //
const queryFormRef = ref() //
const exportLoading = ref(false) //
/** 查询列表 */
@ -208,14 +208,14 @@ const getList = async () => {
}
}
/**查询等级列表 */
const getMemberLevelList = async () => {
const queryLevelParams = reactive({
status: 0
})
const resultData = await LevelApi.getLevelList(queryLevelParams)
memberLevelList.value = resultData
}
// /** */
// const getMemberLevelList = async () => {
// const queryLevelParams = reactive({
// status: 0
// })
// const resultData = await LevelApi.getLevelList(queryLevelParams)
// memberLevelList.value = resultData
// }
/** 搜索按钮操作 */
const handleQuery = () => {
@ -265,18 +265,18 @@ const handleExport = async () => {
/** 初始化 **/
onMounted(() => {
getMemberLevelList()
// getMemberLevelList()
getList()
})
/** 更新显示/隐藏状态 */
const handleStatusChange = async (row: any) => {
try {
//
const text = row.status ? '显示' : '隐藏'
await message.confirm(`确认要${text}"${row.name}"吗?`)
// const text = row.status ? '' : ''
// await message.confirm(`${text}"${row.name}"`)
//
await PaidMemberBenefitApi.updatePaidMemberBenefitStatus({id: row.id, status: row.status })
message.success(text + '成功')
// message.success(text + '')
//
await getList()
} catch {

View File

@ -0,0 +1,123 @@
<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="orderNumber">
<el-input v-model="formData.orderNumber" placeholder="请输入订单号" />
</el-form-item>
<el-form-item label="用户id" prop="userId">
<el-input v-model="formData.userId" placeholder="请输入用户" />
</el-form-item>
<el-form-item label="商品id" prop="productId">
<el-input v-model="formData.productId" placeholder="请输入商品" />
</el-form-item>
<el-form-item label="兑换积分" prop="integral">
<el-input v-model="formData.integral" placeholder="请输入兑换积分" />
</el-form-item>
<el-form-item label="订单状态" prop="orderStatus">
<el-radio-group v-model="formData.orderStatus">
<el-radio label="1">请选择字典生成</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="下单时间" prop="orderTime">
<el-date-picker
v-model="formData.orderTime"
type="date"
value-format="x"
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 { PointOrderApi, PointOrderVO } from '@/api/mall/promotion/pointorder'
/** 兑换记录 表单 */
defineOptions({ name: 'PointOrderForm' })
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,
orderNumber: undefined,
userId: undefined,
productId: undefined,
integral: undefined,
orderStatus: undefined,
orderTime: 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 PointOrderApi.getPointOrder(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 PointOrderVO
if (formType.value === 'create') {
await PointOrderApi.createPointOrder(data)
message.success(t('common.createSuccess'))
} else {
await PointOrderApi.updatePointOrder(data)
message.success(t('common.updateSuccess'))
}
dialogVisible.value = false
//
emit('success')
} finally {
formLoading.value = false
}
}
/** 重置表单 */
const resetForm = () => {
formData.value = {
id: undefined,
orderNumber: undefined,
userId: undefined,
productId: undefined,
integral: undefined,
orderStatus: undefined,
orderTime: 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="orderNumber">
<el-input v-model="queryParams.orderNumber" placeholder="请输入订单号" clearable @keyup.enter="handleQuery"
class="!w-240px" />
</el-form-item>
<!-- <el-form-item label="用户" prop="userId">
<el-input
v-model="queryParams.userId"
placeholder="请输入用户"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="商品id" prop="productId">
<el-input
v-model="queryParams.productId"
placeholder="请输入商品id"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item> -->
<el-form-item label="兑换积分" prop="integral">
<el-input v-model="queryParams.integral" placeholder="请输入兑换积分" clearable @keyup.enter="handleQuery"
class="!w-240px" />
</el-form-item>
<el-form-item label="订单状态" prop="orderStatus">
<el-select v-model="queryParams.orderStatus" 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="orderTime">
<el-date-picker
v-model="queryParams.orderTime"
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="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="['promotion:point-order:create']">
<Icon icon="ep:plus" class="mr-5px" /> 新增
</el-button> -->
<el-button type="success" plain @click="handleExport" :loading="exportLoading"
v-hasPermi="['promotion:point-order: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="orderNumber" />
<el-table-column label="用户" align="center" prop="userName" />
<el-table-column label="商品信息" align="center">
<template #default="{ row }">
<div style="display: flex; align-items: center;">
<img :src="row.imageUrl" alt="Product Image" style="width: 50px; height: 50px; margin-right: 10px;" />
<span>{{ row.productName }}</span>
</div>
</template>
</el-table-column>
<el-table-column label="兑换积分" align="center" prop="integral" />
<!-- <el-table-column label="订单状态" align="center" prop="orderStatus" /> -->
<el-table-column label="订单状态" align="center" prop="orderStatus">
<template #default="scope">
<dict-tag :type="DICT_TYPE.TRADE_ORDER_STATUS" :value="scope.row.orderStatus" />
</template>
</el-table-column>
<el-table-column label="下单时间" align="center" prop="orderTime" :formatter="dateFormatter" width="180px" />
<!-- <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="['promotion:point-order:update']">
编辑
</el-button> -->
<el-button link type="danger" @click="handleDelete(scope.row.id)"
v-hasPermi="['promotion:point-order: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>
<!-- 表单弹窗添加/修改 -->
<PointOrderForm ref="formRef" @success="getList" />
</template>
<script setup lang="ts">
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
import { dateFormatter } from '@/utils/formatTime'
import download from '@/utils/download'
import { PointOrderApi, PointOrderVO } from '@/api/mall/promotion/pointorder'
import PointOrderForm from './PointOrderForm.vue'
/** 兑换记录 列表 */
defineOptions({ name: 'PointOrder' })
const message = useMessage() //
const { t } = useI18n() //
const loading = ref(true) //
const list = ref<PointOrderVO[]>([]) //
const total = ref(0) //
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
orderNumber: undefined,
userId: undefined,
productId: undefined,
integral: undefined,
orderStatus: undefined,
orderTime: [],
createTime: [],
})
const queryFormRef = ref() //
const exportLoading = ref(false) //
/** 查询列表 */
const getList = async () => {
loading.value = true
try {
const data = await PointOrderApi.getPointOrderPage(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 PointOrderApi.deletePointOrder(id)
message.success(t('common.delSuccess'))
//
await getList()
} catch { }
}
/** 导出按钮操作 */
const handleExport = async () => {
try {
//
await message.exportConfirm()
//
exportLoading.value = true
const data = await PointOrderApi.exportPointOrder(queryParams)
download.excel(data, '兑换记录.xls')
} catch {
} finally {
exportLoading.value = false
}
}
/** 初始化 **/
onMounted(() => {
getList()
})
</script>
<style>
</style>

View File

@ -0,0 +1,112 @@
<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="vid">
<el-input v-model="formData.vid" placeholder="请输入会员有效期(天)" />
</el-form-item>
<el-form-item label="会员卡原价" prop="originalPrice">
<el-input v-model="formData.originalPrice" placeholder="请输入会员卡原价" />
</el-form-item>
<el-form-item label="会员卡优惠价" prop="specialPrice">
<el-input v-model="formData.specialPrice" 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 { getIntDictOptions, DICT_TYPE } from '@/utils/dict'
import { cardApi, cardVO } from '@/api/member/type'
/** 会员卡类型 表单 */
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,
name: undefined,
vid: undefined,
originalPrice: undefined,
specialPrice: undefined,
status: undefined,
})
const formRules = reactive({
name: [{ required: true, message: '会员卡名称不能为空', trigger: 'blur' }],
vid: [{ required: true, message: '会员有效期(天)不能为空', trigger: 'blur' }],
originalPrice: [{ required: true, message: '会员卡原价不能为空', trigger: 'blur' }],
})
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,
name: undefined,
vid: undefined,
originalPrice: undefined,
specialPrice: undefined,
status: undefined,
}
formRef.value?.resetFields()
}
</script>

View File

@ -0,0 +1,251 @@
<template>
<ContentWrap>
<!-- 搜索工作栏 -->
<el-form
class="-mb-15px"
:model="queryParams"
ref="queryFormRef"
:inline="true"
label-width="140px"
>
<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="vid">
<el-input
v-model="queryParams.vid"
placeholder="请输入会员有效期(天)"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="会员卡原价" prop="originalPrice">
<el-input
v-model="queryParams.originalPrice"
placeholder="请输入会员卡原价"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="会员卡优惠价" prop="specialPrice">
<el-input
v-model="queryParams.specialPrice"
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.COMMON_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="['member:paid-member-card-type:create']"
>
<Icon icon="ep:plus" class="mr-5px" /> 新增
</el-button>
<el-button
type="success"
plain
@click="handleExport"
:loading="exportLoading"
v-hasPermi="['member:paid-member-card-type: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="name" />
<el-table-column label="会员有效期(天)" align="center" prop="vid" />
<el-table-column label="会员卡原价" align="center" prop="originalPrice" />
<el-table-column label="会员卡优惠价" align="center" prop="specialPrice" />
<el-table-column label="是否启用" align="center" prop="status">
<template #default="{row}">
<template v-if="row.status >= 0">
<el-switch
v-model="row.status"
inline-prompt
:active-value=1
:inactive-value=0
active-text="是"
inactive-text="否"
@change="handleStatusChange(row)"
/>
</template>
</template>
</el-table-column>
<el-table-column label="操作" align="center">
<template #default="scope">
<el-button
link
type="primary"
@click="openForm('update', scope.row.id)"
v-hasPermi="['member:paid-member-card-type:update']"
>
编辑
</el-button>
<el-button
link
type="danger"
@click="handleDelete(scope.row.id)"
v-hasPermi="['member:paid-member-card-type: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 download from '@/utils/download'
import { cardApi, cardVO } from '@/api/member/type'
import * as typeapi from '@/api/member/type'
import cardForm from './cardForm.vue'
import { any } from 'vue-types'
/** 会员卡类型 列表 */
defineOptions({ name: 'Membercard' })
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,
name: undefined,
vid: undefined,
originalPrice: undefined,
specialPrice: undefined,
sort: undefined,
status: undefined,
})
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: int, id?: number) => {
formRef.value.open(type, id)
}
/** 状态操作: 启用/禁用 */
const handleStatusChange = async (row: any) =>{
const originalStatus = row.status
try{
//
await cardApi.updatecard(row)
// //
await getList()
}
catch{
row.status = originalStatus
}
}
/** 删除按钮操作 */
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)
download.excel(data, '会员卡类型.xls')
} catch {
} finally {
exportLoading.value = false
}
}
/** 初始化 **/
onMounted(() => {
getList()
})
</script>

View File

@ -6,6 +6,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.SortablePageParam;
import cn.iocoder.yudao.framework.common.pojo.SortingField;
import cn.iocoder.yudao.framework.mybatis.core.enums.SqlConstants;
import cn.iocoder.yudao.framework.mybatis.core.util.JdbcUtils;
import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
@ -151,7 +152,8 @@ public interface BaseMapperX<T> extends MPJBaseMapper<T> {
*/
default Boolean insertBatch(Collection<T> entities) {
// 特殊SQL Server 批量插入后获取 id 会报错因此通过循环处理
if (Objects.equals(SqlConstants.DB_TYPE, DbType.SQL_SERVER)) {
DbType dbType = JdbcUtils.getDbType();
if (JdbcUtils.isSQLServer(dbType)) {
entities.forEach(this::insert);
return CollUtil.isNotEmpty(entities);
}

View File

@ -1,9 +1,11 @@
package cn.iocoder.yudao.framework.mybatis.core.util;
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
import cn.iocoder.yudao.framework.common.util.spring.SpringUtils;
import cn.iocoder.yudao.framework.mybatis.core.enums.DbTypeEnum;
import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import com.baomidou.mybatisplus.annotation.DbType;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import javax.sql.DataSource;
import java.sql.Connection;
@ -43,14 +45,28 @@ public class JdbcUtils {
return com.baomidou.mybatisplus.extension.toolkit.JdbcUtils.getDbType(url);
}
/**
* 判断 JDBC 连接是否为 SQLServer 数据库
*
* @param dbType DB 类型
* @return 是否为 SQLServer 数据库
*/
public static boolean isSQLServer(DbType dbType) {
return ObjectUtils.equalsAny(dbType, DbType.SQL_SERVER, DbType.SQL_SERVER2005);
}
/**
* 通过当前数据库连接获得对应的 DB 类型
*
* @return DB 类型
*/
public static DbType getDbType() {
DynamicRoutingDataSource dynamicRoutingDataSource = SpringUtils.getBean(DynamicRoutingDataSource.class);
DataSource dataSource = dynamicRoutingDataSource.determineDataSource();
DataSource dataSource;
try {
DynamicRoutingDataSource dynamicRoutingDataSource = SpringUtils.getBean(DynamicRoutingDataSource.class);
dataSource = dynamicRoutingDataSource.determineDataSource();
} catch (NoSuchBeanDefinitionException e) {
dataSource = SpringUtils.getBean(DataSource.class);
}
try (Connection conn = dataSource.getConnection()) {
return DbTypeEnum.find(conn.getMetaData().getDatabaseProductName());
} catch (SQLException e) {

View File

@ -3,6 +3,8 @@ package cn.iocoder.yudao.module.product.api.spu.dto;
import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum;
import lombok.Data;
import java.util.List;
// TODO @LeeYan9: ProductSpuRespDTO
/**
* 商品 SPU 信息 Response DTO
@ -69,6 +71,13 @@ public class ProductSpuRespDTO {
// ========== 物流相关字段 =========
/**
* 配送方式数组
*
* 对应 DeliveryTypeEnum 枚举
*/
private List<Integer> deliveryTypes;
/**
* 物流配置模板编号
*

View File

@ -5,6 +5,7 @@ import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponUseReqDTO;
import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponValidReqDTO;
import javax.validation.Valid;
import java.util.List;
/**
* 优惠劵 API 接口
@ -20,6 +21,15 @@ public interface CouponApi {
*/
void useCoupon(@Valid CouponUseReqDTO useReqDTO);
/**
* 获得用户的优惠劵列表
*
* @param userId 用户编号
* @param status 优惠劵状态
* @return 优惠劵列表
*/
List<CouponRespDTO> getCouponListByUserId(Long userId, Integer status);
/**
* 退还已使用的优惠券
*

View File

@ -27,4 +27,6 @@ public interface RewardActivityApi {
*/
RewardActivityDTO getRewardActivityById(Long id);
}

View File

@ -1,9 +1,14 @@
package cn.iocoder.yudao.module.promotion.api.reward.dto;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.module.promotion.enums.common.PromotionConditionTypeEnum;
import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
/**
* 满减送活动的匹配 Response DTO
@ -13,6 +18,12 @@ import java.util.List;
@Data
public class RewardActivityMatchRespDTO {
/**
* 匹配的 SPU 数组
*/
private List<Long> spuIds;
/**
* 活动编号主键自增
*/
@ -21,28 +32,50 @@ public class RewardActivityMatchRespDTO {
* 活动标题
*/
private String name;
/**
* 状态
*
* 枚举 {@link CommonStatusEnum}
*/
private Integer status;
/**
* 开始时间
*/
private LocalDateTime startTime;
/**
* 结束时间
*/
private LocalDateTime endTime;
/**
* 备注
*/
private String remark;
/**
* 条件类型
*
* 枚举 {@link PromotionConditionTypeEnum}
*/
private Integer conditionType;
/**
* 商品范围
*
* 枚举 {@link PromotionProductScopeEnum}
*/
private Integer productScope;
/**
* 商品 SPU 编号的数组
*/
private List<Long> productScopeValues;
/**
* 优惠规则的数组
*/
private List<Rule> rules;
/**
* 商品 SPU 编号的数组
*/
private List<Long> spuIds;
// TODO 芋艿后面 RewardActivityRespDTO 有了之后Rule 可以放过去
/**
* 优惠规则
*/
@Data
public static class Rule {
public static class Rule implements Serializable {
/**
* 优惠门槛
@ -64,13 +97,21 @@ public class RewardActivityMatchRespDTO {
*/
private Integer point;
/**
* 赠送的优惠劵编号的数组
* 赠送的优惠劵
*
* key: 优惠劵模版编号
* value对应的优惠券数量
*
* 目的用于订单支付后赠送优惠券
*/
private List<Long> couponIds;
private Map<Long, Integer> giveCouponTemplateCounts;
/**
* 赠送的优惠券数量的数组
* 规则描述
*
* 通过 {@link #limit}{@link #discountPrice} 等字段进行拼接
*/
private List<Integer> couponCounts;
private String description;
}

View File

@ -16,6 +16,9 @@ public interface ErrorCodeConstants {
ErrorCode DISCOUNT_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED = new ErrorCode(1_013_001_003, "限时折扣活动未关闭,不能删除");
ErrorCode DISCOUNT_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1_013_001_004, "限时折扣活动已关闭,不能重复关闭");
// ========== 兑换记录 TODO 补充编号 ==========
ErrorCode POINT_ORDER_NOT_EXISTS = new ErrorCode(11111, "兑换记录不存在");
// ========== Banner 相关 1-013-002-000 ============
ErrorCode BANNER_NOT_EXISTS = new ErrorCode(1_013_002_000, "Banner 不存在");

View File

@ -5,6 +5,7 @@ import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
import java.util.Objects;
/**
* 营销的商品范围枚举
@ -15,10 +16,9 @@ import java.util.Arrays;
@AllArgsConstructor
public enum PromotionProductScopeEnum implements IntArrayValuable {
ALL(1, "通用券"), // 全部商品
SPU(2, "商品券"), // 指定商品
CATEGORY(3, "品类券"), // 指定品类
;
ALL(1, "全部商品"),
SPU(2, "指定商品"),
CATEGORY(3, "指定品类");
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(PromotionProductScopeEnum::getScope).toArray();
@ -36,4 +36,17 @@ public enum PromotionProductScopeEnum implements IntArrayValuable {
return ARRAYS;
}
public static boolean isAll(Integer scope) {
return Objects.equals(scope, ALL.scope);
}
public static boolean isSpu(Integer scope) {
return Objects.equals(scope, SPU.scope);
}
public static boolean isCategory(Integer scope) {
return Objects.equals(scope, CATEGORY.scope);
}
}

View File

@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.promotion.api.coupon;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponRespDTO;
import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponUseReqDTO;
import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponValidReqDTO;
@ -11,6 +12,7 @@ import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.util.List;
/**
* 优惠劵 API 实现类
@ -24,6 +26,11 @@ public class CouponApiImpl implements CouponApi {
@Resource
private CouponService couponService;
@Override
public List<CouponRespDTO> getCouponListByUserId(Long userId, Integer status) {
return BeanUtils.toBean(couponService.getCouponList(userId, status), CouponRespDTO.class);
}
@Override
public void useCoupon(CouponUseReqDTO useReqDTO) {
couponService.useCoupon(useReqDTO.getId(), useReqDTO.getUserId(),

View File

@ -1,7 +1,9 @@
package cn.iocoder.yudao.module.promotion.api.discount;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.promotion.api.discount.dto.DiscountProductRespDTO;
import cn.iocoder.yudao.module.promotion.convert.discount.DiscountActivityConvert;
import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO;
import cn.iocoder.yudao.module.promotion.service.discount.DiscountActivityService;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
@ -24,7 +26,7 @@ public class DiscountActivityApiImpl implements DiscountActivityApi {
@Override
public List<DiscountProductRespDTO> getMatchDiscountProductList(Collection<Long> skuIds) {
return DiscountActivityConvert.INSTANCE.convertList02(discountActivityService.getMatchDiscountProductList(skuIds));
}
List<DiscountProductDO> list = discountActivityService.getMatchDiscountProductList(skuIds);
return BeanUtils.toBean(list, DiscountProductRespDTO.class); }
}

View File

@ -0,0 +1,95 @@
package cn.iocoder.yudao.module.promotion.controller.admin.pointorder;
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.*;
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.*;
import cn.iocoder.yudao.module.promotion.controller.admin.pointorder.vo.*;
import cn.iocoder.yudao.module.promotion.dal.dataobject.pointorder.PointOrderDO;
import cn.iocoder.yudao.module.promotion.service.pointorder.PointOrderService;
@Tag(name = "管理后台 - 兑换记录")
@RestController
@RequestMapping("/promotion/point-order")
@Validated
public class PointOrderController {
@Resource
private PointOrderService pointOrderService;
@PostMapping("/create")
@Operation(summary = "创建兑换记录")
@PreAuthorize("@ss.hasPermission('promotion:point-order:create')")
public CommonResult<Long> createPointOrder(@Valid @RequestBody PointOrderSaveReqVO createReqVO) {
return success(pointOrderService.createPointOrder(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "更新兑换记录")
@PreAuthorize("@ss.hasPermission('promotion:point-order:update')")
public CommonResult<Boolean> updatePointOrder(@Valid @RequestBody PointOrderSaveReqVO updateReqVO) {
pointOrderService.updatePointOrder(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除兑换记录")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('promotion:point-order:delete')")
public CommonResult<Boolean> deletePointOrder(@RequestParam("id") Long id) {
pointOrderService.deletePointOrder(id);
return success(true);
}
@GetMapping("/get")
@Operation(summary = "获得兑换记录")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('promotion:point-order:query')")
public CommonResult<PointOrderRespVO> getPointOrder(@RequestParam("id") Long id) {
PointOrderDO pointOrder = pointOrderService.getPointOrder(id);
return success(BeanUtils.toBean(pointOrder, PointOrderRespVO.class));
}
@GetMapping("/page")
@Operation(summary = "获得兑换记录分页")
@PreAuthorize("@ss.hasPermission('promotion:point-order:query')")
public CommonResult<PageResult<PointOrderRespVO>> getPointOrderPage(@Valid PointOrderPageReqVO pageReqVO) {
PageResult<PointOrderDO> pageResult = pointOrderService.getPointOrderPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, PointOrderRespVO.class));
}
@GetMapping("/export-excel")
@Operation(summary = "导出兑换记录 Excel")
@PreAuthorize("@ss.hasPermission('promotion:point-order:export')")
@ApiAccessLog(operateType = EXPORT)
public void exportPointOrderExcel(@Valid PointOrderPageReqVO pageReqVO,
HttpServletResponse response) throws IOException {
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<PointOrderDO> list = pointOrderService.getPointOrderPage(pageReqVO).getList();
// 导出 Excel
ExcelUtils.write(response, "兑换记录.xls", "数据", PointOrderRespVO.class,
BeanUtils.toBean(list, PointOrderRespVO.class));
}
}

View File

@ -0,0 +1,41 @@
package cn.iocoder.yudao.module.promotion.controller.admin.pointorder.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 PointOrderPageReqVO extends PageParam {
@Schema(description = "订单号")
private String orderNumber;
@Schema(description = "用户id", example = "13639")
private Long userId;
@Schema(description = "商品id", example = "2315")
private Long productId;
@Schema(description = "兑换积分")
private Integer integral;
@Schema(description = "订单状态", example = "2")
private Integer orderStatus;
@Schema(description = "下单时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] orderTime;
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
}

View File

@ -0,0 +1,53 @@
package cn.iocoder.yudao.module.promotion.controller.admin.pointorder.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
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 PointOrderRespVO {
@Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED, example = "19849")
@ExcelProperty("id")
private Long id;
@Schema(description = "订单号")
@ExcelProperty("订单号")
private String orderNumber;
@Schema(description = "用户id", example = "13639")
@ExcelProperty("用户id")
private Long userId;
@Schema(description = "商品id", example = "2315")
@ExcelProperty("商品id")
private Long productId;
@Schema(description = "兑换积分")
@ExcelProperty("兑换积分")
private Integer integral;
@Schema(description = "订单状态", example = "2")
@ExcelProperty("订单状态")
private Integer orderStatus;
@Schema(description = "下单时间")
@ExcelProperty("下单时间")
private LocalDateTime orderTime;
@Schema(description = "创建时间")
@ExcelProperty("创建时间")
private LocalDateTime createTime;
private String userName;
private String productName;
private String imageUrl;
}

View File

@ -0,0 +1,35 @@
package cn.iocoder.yudao.module.promotion.controller.admin.pointorder.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.*;
import javax.validation.constraints.*;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - 兑换记录新增/修改 Request VO")
@Data
public class PointOrderSaveReqVO {
@Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED, example = "19849")
private Long id;
@Schema(description = "订单号")
private String orderNumber;
@Schema(description = "用户id", example = "13639")
private Long userId;
@Schema(description = "商品id", example = "2315")
private Long productId;
@Schema(description = "兑换积分")
private Integer integral;
@Schema(description = "订单状态", example = "2")
private Integer orderStatus;
@Schema(description = "下单时间")
private LocalDateTime orderTime;
}

View File

@ -130,16 +130,19 @@ public class AppSeckillActivityController {
@GetMapping("/spuList")
@Parameter(name = "count", description = "需要展示的数量", example = "6")
@Operation(summary = "获得现在进行的秒杀活动分页")
@Operation(summary = "获得秒杀活动分页")
public CommonResult<List<ProductSpuRespDTO>> getSeckillActivitySupList(@RequestParam(name = "count", defaultValue = "3") Integer count) {
AppSeckillActivityPageReqVO pageReqVO = new AppSeckillActivityPageReqVO();
Page<SeckillActivityDO> page = new Page<>(1, 3);
;
if (count != null && count != 0) {
page = new Page<>(1, count);
pageReqVO.setPageNo(1);
pageReqVO.setPageSize(count);
}
// Page<SeckillActivityDO> page = new Page<>(1, 3);
// if (count != null && count != 0) {
// page = new Page<>(1, count);
// }
// 先找出当前时间对应的配置时间段id
List<Long> configIdList = new ArrayList<>();
/* List<Long> configIdList = new ArrayList<>();
try {
List<SeckillConfigDO> timeList = configService.getSeckillConfigListByStatus(CommonStatusEnum.ENABLE.getStatus());
SimpleDateFormat format = new SimpleDateFormat("HH:mm");
@ -159,9 +162,9 @@ public class AppSeckillActivityController {
return success(null);
}
// 获取满足当前正在进行的活动
PageResult<SeckillActivityDO> pageResult = activityService.getRunningActivityByConfigIdsCount(configIdList, page);
PageResult<SeckillActivityDO> pageResult = activityService.getRunningActivityByConfigIdsCount(configIdList, page);*/
// 1. 查询满足当前阶段的活动
// PageResult<SeckillActivityDO> pageResult = activityService.getSeckillActivityAppPageByConfigId(pageReqVO);
PageResult<SeckillActivityDO> pageResult = activityService.getSeckillActivityAppPageByConfigId(pageReqVO);
if (CollUtil.isEmpty(pageResult.getList())) {
return success(null);
}

View File

@ -0,0 +1,71 @@
package cn.iocoder.yudao.module.promotion.dal.dataobject.pointorder;
import lombok.*;
import java.util.*;
import java.time.LocalDateTime;
import java.time.LocalDateTime;
import java.time.LocalDateTime;
import com.baomidou.mybatisplus.annotation.*;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
/**
* 兑换记录 DO
*
* @author 管理员
*/
@TableName("promotion_point_order")
@KeySequence("promotion_point_order_seq") // 用于 OraclePostgreSQLKingbaseDB2H2 数据库的主键自增如果是 MySQL 等数据库可不写
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class PointOrderDO extends BaseDO {
/**
* id
*/
@TableId
private Long id;
/**
* 订单号
*/
private String orderNumber;
/**
* 用户id
*/
private Long userId;
/**
* 商品id
*/
private Long productId;
/**
* 兑换积分
*/
private Integer integral;
/**
* 订单状态
*/
private Integer orderStatus;
/**
* 下单时间
*/
private LocalDateTime orderTime;
/**
* 用户名称
*/
@TableField(exist = false)
private String userName;
/**
* 商品名称
*/
@TableField(exist = false)
private String productName;
@TableField(exist = false)
private String imageUrl;
}

View File

@ -1,11 +1,13 @@
package cn.iocoder.yudao.module.promotion.dal.mysql.discount;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.List;
import java.util.Map;
@ -22,6 +24,15 @@ public interface DiscountProductMapper extends BaseMapperX<DiscountProductDO> {
return selectList(DiscountProductDO::getSkuId, skuIds);
}
default List<DiscountProductDO> selectListBySkuIdsAndStatusAndNow(Collection<Long> skuIds, Integer status) {
LocalDateTime now = LocalDateTime.now();
return selectList(new LambdaQueryWrapperX<DiscountProductDO>()
.in(DiscountProductDO::getSkuId, skuIds)
.eq(DiscountProductDO::getActivityStatus,status)
.lt(DiscountProductDO::getActivityStartTime, now)
.gt(DiscountProductDO::getActivityEndTime, now));
}
default List<DiscountProductDO> selectListByActivityId(Long activityId) {
return selectList(DiscountProductDO::getActivityId, activityId);
}

View File

@ -0,0 +1,32 @@
package cn.iocoder.yudao.module.promotion.dal.mysql.pointorder;
import java.util.*;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.module.promotion.dal.dataobject.pointorder.PointOrderDO;
import org.apache.ibatis.annotations.Mapper;
import cn.iocoder.yudao.module.promotion.controller.admin.pointorder.vo.*;
/**
* 兑换记录 Mapper
*
* @author 管理员
*/
@Mapper
public interface PointOrderMapper extends BaseMapperX<PointOrderDO> {
default PageResult<PointOrderDO> selectPage(PointOrderPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<PointOrderDO>()
.eqIfPresent(PointOrderDO::getOrderNumber, reqVO.getOrderNumber())
.eqIfPresent(PointOrderDO::getUserId, reqVO.getUserId())
.eqIfPresent(PointOrderDO::getProductId, reqVO.getProductId())
.eqIfPresent(PointOrderDO::getIntegral, reqVO.getIntegral())
.eqIfPresent(PointOrderDO::getOrderStatus, reqVO.getOrderStatus())
.betweenIfPresent(PointOrderDO::getOrderTime, reqVO.getOrderTime())
.betweenIfPresent(PointOrderDO::getCreateTime, reqVO.getCreateTime())
.orderByDesc(PointOrderDO::getId));
}
}

View File

@ -0,0 +1,55 @@
package cn.iocoder.yudao.module.promotion.service.pointorder;
import java.util.*;
import javax.validation.*;
import cn.iocoder.yudao.module.promotion.controller.admin.pointorder.vo.*;
import cn.iocoder.yudao.module.promotion.dal.dataobject.pointorder.PointOrderDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
/**
* 兑换记录 Service 接口
*
* @author 管理员
*/
public interface PointOrderService {
/**
* 创建兑换记录
*
* @param createReqVO 创建信息
* @return 编号
*/
Long createPointOrder(@Valid PointOrderSaveReqVO createReqVO);
/**
* 更新兑换记录
*
* @param updateReqVO 更新信息
*/
void updatePointOrder(@Valid PointOrderSaveReqVO updateReqVO);
/**
* 删除兑换记录
*
* @param id 编号
*/
void deletePointOrder(Long id);
/**
* 获得兑换记录
*
* @param id 编号
* @return 兑换记录
*/
PointOrderDO getPointOrder(Long id);
/**
* 获得兑换记录分页
*
* @param pageReqVO 分页查询
* @return 兑换记录分页
*/
PageResult<PointOrderDO> getPointOrderPage(PointOrderPageReqVO pageReqVO);
}

View File

@ -0,0 +1,100 @@
package cn.iocoder.yudao.module.promotion.service.pointorder;
import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import cn.iocoder.yudao.module.promotion.controller.admin.pointorder.vo.*;
import cn.iocoder.yudao.module.promotion.dal.dataobject.pointorder.PointOrderDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.promotion.dal.mysql.pointorder.PointOrderMapper;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
/**
* 兑换记录 Service 实现类
*
* @author 管理员
*/
@Service
@Validated
public class PointOrderServiceImpl implements PointOrderService {
@Resource
private PointOrderMapper pointOrderMapper;
@Resource
private MemberUserApi memberUserApi;
@Resource
private ProductSpuApi productSpuApi;
@Override
public Long createPointOrder(PointOrderSaveReqVO createReqVO) {
// 插入
PointOrderDO pointOrder = BeanUtils.toBean(createReqVO, PointOrderDO.class);
pointOrderMapper.insert(pointOrder);
// 返回
return pointOrder.getId();
}
@Override
public void updatePointOrder(PointOrderSaveReqVO updateReqVO) {
// 校验存在
validatePointOrderExists(updateReqVO.getId());
// 更新
PointOrderDO updateObj = BeanUtils.toBean(updateReqVO, PointOrderDO.class);
pointOrderMapper.updateById(updateObj);
}
@Override
public void deletePointOrder(Long id) {
// 校验存在
validatePointOrderExists(id);
// 删除
pointOrderMapper.deleteById(id);
}
private void validatePointOrderExists(Long id) {
if (pointOrderMapper.selectById(id) == null) {
throw exception(POINT_ORDER_NOT_EXISTS);
}
}
@Override
public PointOrderDO getPointOrder(Long id) {
return pointOrderMapper.selectById(id);
}
@Override
public PageResult<PointOrderDO> getPointOrderPage(PointOrderPageReqVO pageReqVO) {
PageResult<PointOrderDO> pointOrderDOPageResult = pointOrderMapper.selectPage(pageReqVO);
List<PointOrderDO> list = pointOrderDOPageResult.getList();
for (int i = 0; i < list.size(); i++) {
PointOrderDO pointOrderDO = list.get(i);
//设置用户名称
MemberUserRespDTO user = memberUserApi.getUser(pointOrderDO.getUserId());
pointOrderDO.setUserName(user.getNickname());
//获取商品信息
ProductSpuRespDTO spu = productSpuApi.getSpu(pointOrderDO.getProductId());
pointOrderDO.setProductName(spu.getName());
pointOrderDO.setImageUrl(spu.getPicUrl());
}
return pointOrderDOPageResult;
}
}

View File

@ -35,6 +35,7 @@ public interface ErrorCodeConstants {
ErrorCode ORDER_RECEIVE_FAIL_DELIVERY_TYPE_NOT_PICK_UP = new ErrorCode(1_011_000_030, "交易订单自提失败,收货方式不是【用户自提】");
ErrorCode ORDER_UPDATE_ADDRESS_FAIL_STATUS_NOT_DELIVERED = new ErrorCode(1_011_000_031, "交易订单修改收货地址失败,原因:订单不是【待发货】状态");
ErrorCode ORDER_CREATE_FAIL_EXIST_UNPAID = new ErrorCode(1_011_000_032, "交易订单创建失败,原因:存在未付款订单");
ErrorCode ORDER_CANCEL_PAID_FAIL = new ErrorCode(1_011_000_033, "交易订单取消支付失败,原因:订单不是【{}】状态");
// ========== After Sale 模块 1-011-000-100 ==========
ErrorCode AFTER_SALE_NOT_FOUND = new ErrorCode(1_011_000_100, "售后单不存在");
@ -53,12 +54,15 @@ public interface ErrorCodeConstants {
// ========== Cart 模块 1-011-002-000 ==========
ErrorCode CARD_ITEM_NOT_FOUND = new ErrorCode(1_011_002_000, "购物车项不存在");
ErrorCode PRICE_CALCULATE_POINT_TOTAL_LIMIT_COUNT = new ErrorCode(1_011_003_004, "参与积分活动的商品,超过了积分活动商品总限购数量");
// ========== Price 相关 1-011-003-000 ============
ErrorCode PRICE_CALCULATE_PAY_PRICE_ILLEGAL = new ErrorCode(1_011_003_000, "支付价格计算异常,原因:价格小于等于 0");
ErrorCode PRICE_CALCULATE_DELIVERY_PRICE_TEMPLATE_NOT_FOUND = new ErrorCode(1_011_003_002, "计算快递运费异常,找不到对应的运费模板");
ErrorCode PRICE_CALCULATE_COUPON_NOT_MATCH_NORMAL_ORDER = new ErrorCode(1_011_003_004, "参与秒杀、拼团、砍价的营销商品,无法使用优惠劵");
ErrorCode PRICE_CALCULATE_SECKILL_TOTAL_LIMIT_COUNT = new ErrorCode(1_011_003_005, "参与秒杀的商品,超过了秒杀总限购数量");
ErrorCode PRICE_CALCULATE_DELIVERY_PRICE_TYPE_ILLEGAL = new ErrorCode(1_011_003_005, "计算快递运费异常,配送方式不匹配");
ErrorCode PRICE_CALCULATE_COUPON_CAN_NOT_USE = new ErrorCode(1_011_003_006, "该优惠劵无法使用,原因:{}」");
// ========== 物流 Express 模块 1-011-004-000 ==========
ErrorCode EXPRESS_NOT_EXISTS = new ErrorCode(1_011_004_000, "快递公司不存在");

View File

@ -12,5 +12,7 @@ public interface MessageTemplateConstants {
String BROKERAGE_WITHDRAW_AUDIT_APPROVE = "brokerage_withdraw_audit_approve"; // 佣金提现审核通过
String BROKERAGE_WITHDRAW_AUDIT_REJECT = "brokerage_withdraw_audit_reject"; // 佣金提现审核不通过
// ======================= 小程序订阅消息模版 =======================
String WXA_ORDER_DELIVERY = "订单发货通知";
}

View File

@ -17,8 +17,8 @@ public enum TradeOrderCancelTypeEnum implements IntArrayValuable {
PAY_TIMEOUT(10, "超时未支付"),
AFTER_SALE_CLOSE(20, "退款关闭"),
MEMBER_CANCEL(30, "买家取消");
MEMBER_CANCEL(30, "买家取消"),
COMBINATION_CLOSE(40, "拼团关闭");
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(TradeOrderCancelTypeEnum::getType).toArray();
/**

View File

@ -15,11 +15,11 @@ import java.util.Arrays;
@RequiredArgsConstructor
@Getter
public enum TradeOrderTypeEnum implements IntArrayValuable {
NORMAL(0, "普通订单"),
SECKILL(1, "秒杀订单"),
BARGAIN(2, "砍价订单"),
COMBINATION(3, "拼团订单"),
POINT(4, "积分商城"),
;
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(TradeOrderTypeEnum::getType).toArray();
@ -54,4 +54,8 @@ public enum TradeOrderTypeEnum implements IntArrayValuable {
return ObjectUtil.equal(type, COMBINATION.getType());
}
public static boolean isPoint(Integer type) {
return ObjectUtil.equal(type, POINT.getType());
}
}

View File

@ -92,6 +92,11 @@
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-spring-boot-starter-excel</artifactId>
</dependency>
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-module-promotion-biz</artifactId>
<version>${revision}</version>
</dependency>
</dependencies>
</project>

View File

@ -1,33 +0,0 @@
### 获得交易售后分页 => 成功
GET {{baseUrl}}/trade/after-sale/page?pageNo=1&pageSize=10
Authorization: Bearer {{token}}
tenant-id: {{adminTenentId}}
### 同意售后 => 成功
PUT {{baseUrl}}/trade/after-sale/agree?id=7
Authorization: Bearer {{token}}
tenant-id: {{adminTenentId}}
Content-Type: application/json
### 拒绝售后 => 成功
PUT {{baseUrl}}/trade/after-sale/disagree
Authorization: Bearer {{token}}
tenant-id: {{adminTenentId}}
Content-Type: application/json
{
"id": 6,
"auditReason": "阿巴巴"
}
### 确认退款 => 成功
PUT {{baseUrl}}/trade/after-sale/refund?id=6
Authorization: Bearer {{token}}
tenant-id: {{adminTenentId}}
Content-Type: application/json
### 确认收货 => 成功
PUT {{baseUrl}}/trade/after-sale/receive?id=7
Authorization: Bearer {{token}}
tenant-id: {{adminTenentId}}
Content-Type: application/json

View File

@ -1,8 +1,6 @@
package cn.iocoder.yudao.module.trade.controller.admin.order;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
@ -12,13 +10,9 @@ import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert;
import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderLogDO;
import cn.iocoder.yudao.module.trade.service.aftersale.AfterSaleService;
import cn.iocoder.yudao.module.trade.service.order.TradeOrderLogService;
import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService;
import cn.iocoder.yudao.module.trade.service.order.TradeOrderUpdateService;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
@ -28,11 +22,10 @@ import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
@ -121,94 +114,6 @@ public class TradeOrderController {
return success(true);
}
@PostMapping("/test")
public CommonResult<String> test(@RequestBody Map<String, String> map){
System.out.println("==========================================================");
for (String s : map.keySet()) {
System.out.println(map.get(s));
}
System.out.println("==========================================================");
return success("成功");
}
@PostMapping("/test2")
public void test2(){
//获取access_token
String accessTokenApiurl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=wx63c280fe3248a3e7&secret=6f270509224a7ae1296bbf1c8cb97aed";
// JSONObject map = new JSONObject();
// map.put("grant_type","client_credential");
// map.put("appid","wx63c280fe3248a3e7");
// map.put("secret","6f270509224a7ae1296bbf1c8cb97aed");
HttpResponse get = HttpUtil.createGet(accessTokenApiurl).execute();
String body = get.body();
System.out.println("-----------------------------------------------");
// String jsonString = "82_fCctY_2YxIDOQMpk315ZH76M0J49nXlx_aEdbrDfJEF_-E640cLl0_Yu3kAh4eHgAgtTpu2SskXMNFCsraCBvlGlEOKsXtpqEbkrh5Ydi2arCv-MoHWiS45UyzEMDYfAJAYPK";
JSONObject jsonObject = JSON.parseObject(body);
System.out.println(jsonObject);
System.out.println(body);
String token = jsonObject.getString("access_token");
System.out.println(token);
System.out.println("-----------------------------------------------");
//查询小程序是否已开通发货信息管理服务
String apiurlSec = "https://api.weixin.qq.com/wxa/sec/order/is_trade_managed?access_token="+token;
JSONObject mapSec = new JSONObject();
mapSec.put("appid","wx63c280fe3248a3e7");
HttpResponse postSec = HttpUtil.createPost(apiurlSec)
// .header("Authorization","Bearer 8e79d003102a4b5c80fd823c3c04347c")
// .header("tenant-id","1")
.body(mapSec.toJSONString())
.execute();
String bodySec = postSec.body();
System.out.println("-----------------------------------------------6");
System.out.println(bodySec);
System.out.println("-----------------------------------------------6");
// 微信官方发货信息录入接口
// String apiurl = "https://api.weixin.qq.com/wxa/sec/order/upload_shipping_info?access_token="+token;
//
// JSONObject map = new JSONObject();
// map.put("order_id","P202407170517541");
//
// JSONObject orderKey = new JSONObject();
// orderKey.put("order_number_type",1);
//
// map.put("order_key",orderKey);
// map.put("logistics_type",3);
// map.put("delivery_mode",1);
//
// JSONArray shippingList = new JSONArray();
// JSONObject object = new JSONObject();
// object.put("item_desc","测试商品666");
// shippingList.add(object);
//
// map.put("shipping_list",shippingList);
// // 获取当前时间的 OffsetDateTime 对象
// OffsetDateTime currentDateTime = OffsetDateTime.now();
//
// // 定义日期时间格式化器用于格式化成特定格式
// DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
//
// // 格式化 OffsetDateTime 对象为指定格式的字符串
// String formattedDateTime = currentDateTime.format(formatter);
// map.put("upload_time",formattedDateTime);
// JSONObject payer = new JSONObject();
// payer.put("openid","oWKZ063Eb6IGr63vJT9Zgf3jufOY");
// map.put("payer",payer);
//
// HttpResponse post = HttpUtil.createPost(apiurl)
//// .header("Authorization","Bearer 8e79d003102a4b5c80fd823c3c04347c")
//// .header("tenant-id","1")
// .body(map.toJSONString())
// .execute();
// String Pbody = post.body();
// System.out.println("-----------------------------------------------");
// System.out.println(Pbody);
// System.out.println(apiurl);
// System.out.println("-----------------------------------------------");
}
@PutMapping("/update-remark")
@Operation(summary = "订单备注")
@PreAuthorize("@ss.hasPermission('trade:order:update')")

View File

@ -1,42 +0,0 @@
### 请求 /trade/cart/add 接口 => 成功
POST {{appApi}}/trade/cart/add
tenant-id: {{appTenentId}}
Authorization: Bearer {{appToken}}
Content-Type: application/json
{
"skuId": 1,
"count": 10,
"addStatus": true
}
### 请求 /trade/cart/update 接口 => 成功
PUT {{appApi}}/trade/cart/update
tenant-id: {{appTenentId}}
Authorization: Bearer {{appToken}}
Content-Type: application/json
{
"id": 35,
"count": 5
}
### 请求 /trade/cart/delete 接口 => 成功
DELETE {{appApi}}/trade/cart/delete?ids=1
tenant-id: {{appTenentId}}
Authorization: Bearer {{appToken}}
### 请求 /trade/cart/get-count 接口 => 成功
GET {{appApi}}/trade/cart/get-count
tenant-id: {{appTenentId}}
Authorization: Bearer {{appToken}}
### 请求 /trade/cart/get-count-map 接口 => 成功
GET {{appApi}}/trade/cart/get-count-map
tenant-id: {{appTenentId}}
Authorization: Bearer {{appToken}}
### 请求 /trade/cart/list 接口 => 成功
GET {{appApi}}/trade/cart/list
tenant-id: {{appTenentId}}
Authorization: Bearer {{appToken}}

View File

@ -62,3 +62,8 @@ tenant-id: {{appTenentId}}
GET {{appApi}}/trade/order/get-express-track-list?id=70
Authorization: Bearer {{appToken}}
tenant-id: {{appTenentId}}
### /trade-order/settlement-product 获得商品结算信息
GET {{appApi}}/trade/order/settlement-product?spuIds=633
Authorization: Bearer {{appToken}}
tenant-id: {{appTenentId}}

View File

@ -1,12 +1,7 @@
package cn.iocoder.yudao.module.trade.controller.app.order;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated;
import cn.iocoder.yudao.module.member.api.config.MemberConfigApi;
import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
import cn.iocoder.yudao.module.pay.api.notify.dto.PayOrderNotifyReqDTO;
import cn.iocoder.yudao.module.trade.controller.app.order.vo.*;
import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemCommentCreateReqVO;
@ -21,17 +16,18 @@ import cn.iocoder.yudao.module.trade.service.aftersale.AfterSaleService;
import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressService;
import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService;
import cn.iocoder.yudao.module.trade.service.order.TradeOrderUpdateService;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import cn.iocoder.yudao.module.trade.service.price.TradePriceService;
import com.google.common.collect.Maps;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.annotation.security.PermitAll;
import javax.validation.Valid;
import java.util.List;
import java.util.Map;
@ -53,28 +49,24 @@ public class AppTradeOrderController {
private TradeOrderQueryService tradeOrderQueryService;
@Resource
private DeliveryExpressService deliveryExpressService;
@Resource
private AfterSaleService afterSaleService;
@Resource
private TradePriceService priceService;
@Resource
private TradeOrderProperties tradeOrderProperties;
@Resource
private MemberUserApi memberUserApi;
@GetMapping("/settlement")
@Operation(summary = "获得订单结算信息")
@PreAuthenticated
public CommonResult<AppTradeOrderSettlementRespVO> settlementOrder(@Valid AppTradeOrderSettlementReqVO settlementReqVO) {
AppTradeOrderSettlementRespVO order = tradeOrderUpdateService.settlementOrder(getLoginUserId(), settlementReqVO);
order.setTotalPoint(memberUserApi.getUser(getLoginUserId()).getPoint());
order.setUsedPoint(0);
return success(order);
return success(tradeOrderUpdateService.settlementOrder(getLoginUserId(), settlementReqVO));
}
@PostMapping("/create")
@Operation(summary = "创建订单")
@PreAuthenticated
public CommonResult<AppTradeOrderCreateRespVO> createOrder(@Valid @RequestBody AppTradeOrderCreateReqVO createReqVO) {
TradeOrderDO order = tradeOrderUpdateService.createOrder(getLoginUserId(), createReqVO);
return success(new AppTradeOrderCreateRespVO().setId(order.getId()).setPayOrderId(order.getPayOrderId()));
@ -82,6 +74,7 @@ public class AppTradeOrderController {
@PostMapping("/update-paid")
@Operation(summary = "更新订单为已支付") // pay-module 支付服务进行回调可见 PayNotifyJob
@PermitAll
public CommonResult<Boolean> updateOrderPaid(@RequestBody PayOrderNotifyReqDTO notifyReqDTO) {
tradeOrderUpdateService.updateOrderPaid(Long.valueOf(notifyReqDTO.getMerchantOrderId()),
notifyReqDTO.getPayOrderId());
@ -90,20 +83,31 @@ public class AppTradeOrderController {
@GetMapping("/get-detail")
@Operation(summary = "获得交易订单")
@Parameter(name = "id", description = "交易订单编号")
public CommonResult<AppTradeOrderDetailRespVO> getOrder(@RequestParam("id") Long id) {
// 查询订单
@Parameters({
@Parameter(name = "id", description = "交易订单编号"),
@Parameter(name = "sync", description = "是否同步支付状态", example = "true")
})
public CommonResult<AppTradeOrderDetailRespVO> getOrderDetail(@RequestParam("id") Long id,
@RequestParam(value = "sync", required = false) Boolean sync) {
// 1.1 查询订单
TradeOrderDO order = tradeOrderQueryService.getOrder(getLoginUserId(), id);
if (order == null) {
return success(null);
}
// 1.2 sync 仅在等待支付
if (Boolean.TRUE.equals(sync)
&& TradeOrderStatusEnum.isUnpaid(order.getStatus()) && !order.getPayStatus()) {
tradeOrderUpdateService.syncOrderPayStatusQuietly(order.getId(), order.getPayOrderId());
// 重新查询因为同步后可能会有变化
order = tradeOrderQueryService.getOrder(id);
}
// 查询订单项
// 2.1 查询订单项
List<TradeOrderItemDO> orderItems = tradeOrderQueryService.getOrderItemListByOrderId(order.getId());
// 查询物流公司
// 2.2 查询物流公司
DeliveryExpressDO express = order.getLogisticsId() != null && order.getLogisticsId() > 0 ?
deliveryExpressService.getDeliveryExpress(order.getLogisticsId()) : null;
// 最终组合
// 2.3 最终组合
return success(TradeOrderConvert.INSTANCE.convert02(order, orderItems, tradeOrderProperties, express));
}
@ -158,32 +162,6 @@ public class AppTradeOrderController {
return success(true);
}
// @PostMapping("/test")
// public void test(){
// //获取access_token
// String accessTokenApiurl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=wx63c280fe3248a3e7&secret=6f270509224a7ae1296bbf1c8cb97aed";
// HttpResponse get = HttpUtil.createGet(accessTokenApiurl).execute();
// String body = get.body();
// System.out.println("-----------------------------------------------");
// JSONObject jsonObject = JSON.parseObject(body);
// System.out.println(jsonObject);
// System.out.println(body);
// String token = jsonObject.getString("access_token");
// System.out.println(token);
// System.out.println("-----------------------------------------------");
//
// String apiurlSec = "https://api.weixin.qq.com/wxa/sec/order/is_trade_managed?access_token="+token;
// JSONObject mapSec = new JSONObject();
// mapSec.put("out_order_id","wx63c280fe3248a3e7");
// mapSec.put("openid","wx63c280fe3248a3e7");
// HttpResponse postSec = HttpUtil.createPost(apiurlSec)
//// .header("Authorization","Bearer 8e79d003102a4b5c80fd823c3c04347c")
//// .header("tenant-id","1")
// .body(mapSec.toJSONString())
// .execute();
// String bodySec = postSec.body();
// }
@DeleteMapping("/cancel")
@Operation(summary = "取消交易订单")
@Parameter(name = "id", description = "交易订单编号")
@ -216,4 +194,9 @@ public class AppTradeOrderController {
return success(tradeOrderUpdateService.createOrderItemCommentByMember(getLoginUserId(), createReqVO));
}
@GetMapping("/getPointOrder")
public CommonResult<List<AppPointOrderVO>> getPointOrder(){
return success(tradeOrderQueryService.getPointOrder(getLoginUserId()));
}
}

View File

@ -0,0 +1,18 @@
package cn.iocoder.yudao.module.trade.controller.app.order.vo;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.time.LocalDateTime;
@Data
public class AppPointOrderVO {
private String status; //状态
private String label;
private LocalDateTime createTime; //时间
private Integer payPrice; //支付金额
private Integer usePoint; //兑换积分
private String name; //产品名称
private String picUrl; //图片
private Integer count; //兑换数量
}

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