diff --git a/src/api/mall/promotion/bargain/bargainActivity.ts b/src/api/mall/promotion/bargain/bargainActivity.ts
new file mode 100644
index 00000000..a23477d9
--- /dev/null
+++ b/src/api/mall/promotion/bargain/bargainActivity.ts
@@ -0,0 +1,62 @@
+import request from '@/config/axios'
+import { Sku, Spu } from '@/api/mall/product/spu'
+
+export interface BargainActivityVO {
+ id?: number
+ name?: string
+ startTime?: Date
+ endTime?: Date
+ status?: number
+ spuId?: number
+ userSize?: number // 达到该人数,才能砍到低价
+ bargainCount?: number // 最大帮砍次数
+ totalLimitCount?: number // 最大购买次数
+ stock?: number // 活动总库存
+ randomMinPrice?: number // 用户每次砍价的最小金额,单位:分
+ randomMaxPrice?: number // 用户每次砍价的最大金额,单位:分
+ successCount?: number // 砍价成功数量
+ products?: BargainProductVO[]
+}
+
+// 砍价活动所需属性
+export interface BargainProductVO {
+ spuId: number
+ skuId: number
+ bargainFirstPrice: number // 砍价起始价格,单位分
+ bargainPrice: number // 砍价底价
+ stock: number // 活动库存
+}
+
+// 扩展 Sku 配置
+export type SkuExtension = Sku & {
+ productConfig: BargainProductVO
+}
+
+export interface SpuExtension extends Spu {
+ skus: SkuExtension[] // 重写类型
+}
+
+// 查询砍价活动列表
+export const getBargainActivityPage = async (params: any) => {
+ return await request.get({ url: '/promotion/bargain-activity/page', params })
+}
+
+// 查询砍价活动详情
+export const getBargainActivity = async (id: number) => {
+ return await request.get({ url: '/promotion/bargain-activity/get?id=' + id })
+}
+
+// 新增砍价活动
+export const createBargainActivity = async (data: BargainActivityVO) => {
+ return await request.post({ url: '/promotion/bargain-activity/create', data })
+}
+
+// 修改砍价活动
+export const updateBargainActivity = async (data: BargainActivityVO) => {
+ return await request.put({ url: '/promotion/bargain-activity/update', data })
+}
+
+// 删除砍价活动
+export const deleteBargainActivity = async (id: number) => {
+ return await request.delete({ url: '/promotion/bargain-activity/delete?id=' + id })
+}
diff --git a/src/views/mall/promotion/bargain/BargainActivityForm.vue b/src/views/mall/promotion/bargain/BargainActivityForm.vue
new file mode 100644
index 00000000..91bb52d0
--- /dev/null
+++ b/src/views/mall/promotion/bargain/BargainActivityForm.vue
@@ -0,0 +1,220 @@
+
+
+
+
+
diff --git a/src/views/mall/promotion/bargain/bargainActivity.data.ts b/src/views/mall/promotion/bargain/bargainActivity.data.ts
new file mode 100644
index 00000000..209fb468
--- /dev/null
+++ b/src/views/mall/promotion/bargain/bargainActivity.data.ts
@@ -0,0 +1,165 @@
+import type { CrudSchema } from '@/hooks/web/useCrudSchemas'
+import { dateFormatter2 } from '@/utils/formatTime'
+
+// 表单校验
+export const rules = reactive({
+ name: [required],
+ startTime: [required],
+ endTime: [required],
+ userSize: [required],
+ bargainCount: [required],
+ singleLimitCount: [required]
+})
+
+// CrudSchema https://doc.iocoder.cn/vue3/crud-schema/
+const crudSchemas = reactive([
+ {
+ label: '砍价活动名称',
+ field: 'name',
+ isSearch: true,
+ isTable: false,
+ form: {
+ colProps: {
+ span: 24
+ }
+ }
+ },
+ {
+ label: '活动开始时间',
+ field: 'startTime',
+ formatter: dateFormatter2,
+ isSearch: true,
+ search: {
+ component: 'DatePicker',
+ componentProps: {
+ valueFormat: 'YYYY-MM-DD',
+ type: 'daterange'
+ }
+ },
+ form: {
+ component: 'DatePicker',
+ componentProps: {
+ type: 'date',
+ valueFormat: 'x'
+ }
+ },
+ table: {
+ width: 120
+ }
+ },
+ {
+ label: '活动结束时间',
+ field: 'endTime',
+ formatter: dateFormatter2,
+ isSearch: true,
+ search: {
+ component: 'DatePicker',
+ componentProps: {
+ valueFormat: 'YYYY-MM-DD',
+ type: 'daterange'
+ }
+ },
+ form: {
+ component: 'DatePicker',
+ componentProps: {
+ type: 'date',
+ valueFormat: 'x'
+ }
+ },
+ table: {
+ width: 120
+ }
+ },
+ {
+ label: '砍价人数',
+ field: 'userSize',
+ isSearch: false,
+ form: {
+ component: 'InputNumber',
+ labelMessage: '参与人数不能少于两人',
+ value: 2
+ }
+ },
+ {
+ label: '最大帮砍次数',
+ field: 'bargainCount',
+ isSearch: false,
+ form: {
+ component: 'InputNumber',
+ labelMessage: '参与人数不能少于两人',
+ value: 2
+ }
+ },
+ {
+ label: '总限购数量',
+ field: 'totalLimitCount',
+ isSearch: false,
+ form: {
+ component: 'InputNumber',
+ labelMessage: '用户最大能发起砍价的次数',
+ value: 0
+ }
+ },
+ {
+ label: '砍价的最小金额',
+ field: 'randomMinPrice',
+ isSearch: false,
+ isTable: false,
+ form: {
+ component: 'InputNumber',
+ componentProps: {
+ min: 0,
+ precision: 2,
+ step: 0.1
+ },
+ labelMessage: '用户每次砍价的最小金额',
+ value: 0
+ }
+ },
+ {
+ label: '砍价的最大金额',
+ field: 'randomMaxPrice',
+ isSearch: false,
+ isTable: false,
+ form: {
+ component: 'InputNumber',
+ componentProps: {
+ min: 0,
+ precision: 2,
+ step: 0.1
+ },
+ labelMessage: '用户每次砍价的最大金额',
+ value: 0
+ }
+ },
+ {
+ label: '砍价成功数量',
+ field: 'successCount',
+ isSearch: false,
+ isForm: false
+ },
+ {
+ label: '活动状态',
+ field: 'status',
+ dictType: DICT_TYPE.COMMON_STATUS,
+ dictClass: 'number',
+ isSearch: true,
+ isForm: false
+ },
+ {
+ label: '拼团商品',
+ field: 'spuId',
+ isSearch: false,
+ form: {
+ colProps: {
+ span: 24
+ }
+ }
+ },
+ {
+ label: '操作',
+ field: 'action',
+ isForm: false
+ }
+])
+export const { allSchemas } = useCrudSchemas(crudSchemas)
diff --git a/src/views/mall/promotion/bargain/index.vue b/src/views/mall/promotion/bargain/index.vue
new file mode 100644
index 00000000..42222f45
--- /dev/null
+++ b/src/views/mall/promotion/bargain/index.vue
@@ -0,0 +1,117 @@
+
+
+
+
+
+
+
+
+ 新增
+
+
+
+
+
+
+
+
+
+
+ {{ row.spuName }}
+
+
+
+ 编辑
+
+
+ 删除
+
+
+
+
+
+
+
+
+