feate:添加拼单类型接口
This commit is contained in:
@@ -59,3 +59,118 @@ export const joinGroupBuy = (groupBuyId, data) => {
|
|||||||
export const deleteGroupBuy = (groupBuyId) => {
|
export const deleteGroupBuy = (groupBuyId) => {
|
||||||
return request.delete(`/api/v1/group-buy/${groupBuyId}`)
|
return request.delete(`/api/v1/group-buy/${groupBuyId}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ==================== 拼团类型管理接口 ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取拼团活动类型列表
|
||||||
|
* @param {Object} params - 查询参数
|
||||||
|
* @param {number} [params.page=1] - 页码
|
||||||
|
* @param {number} [params.count=10] - 每页条数
|
||||||
|
* @param {string} [params.key] - 关键词筛选
|
||||||
|
* @param {number} [params.expire_time] - 过期时间筛选(时间戳)
|
||||||
|
* @param {string} [params.tag] - 标签筛选
|
||||||
|
* @returns {Promise} 返回拼团类型列表
|
||||||
|
*/
|
||||||
|
export const getGroupBuyTypeList = (params) => {
|
||||||
|
return request.get("/api/v1/admin/activity/group_buy/type/list", params)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取拼团活动类型标签列表
|
||||||
|
* @returns {Promise} 返回标签列表
|
||||||
|
*/
|
||||||
|
export const getGroupBuyTypeTags = () => {
|
||||||
|
return request.get("/api/v1/admin/activity/group_buy/type/tags")
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增拼团活动类型
|
||||||
|
* @param {Object} data - 类型数据
|
||||||
|
* @param {string} data.name - 名称
|
||||||
|
* @param {string} [data.note] - 备注
|
||||||
|
* @param {string} data.price - 价格(分)
|
||||||
|
* @param {string} [data.renew_price] - 续费价格(分)
|
||||||
|
* @param {string} data.max_person - 拼团需要人数
|
||||||
|
* @param {string} [data.tag] - 标签
|
||||||
|
* @param {number} [data.expire_time] - 活动过期时间
|
||||||
|
* @returns {Promise} 返回新增结果
|
||||||
|
*/
|
||||||
|
export const addGroupBuyType = (data) => {
|
||||||
|
return request.post("/api/v1/admin/activity/group_buy/type/add", data,{
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改拼团活动类型
|
||||||
|
* @param {Object} data - 类型数据
|
||||||
|
* @param {string} data.id - ID编号
|
||||||
|
* @param {string} [data.name] - 名称
|
||||||
|
* @param {string} [data.note] - 备注
|
||||||
|
* @param {string} [data.price] - 价格(分)
|
||||||
|
* @param {string} [data.renew_price] - 续费价格(分)
|
||||||
|
* @param {string} [data.max_person] - 拼团需要人数
|
||||||
|
* @param {string} [data.tag] - 标签
|
||||||
|
* @param {number} [data.expire_time] - 活动过期时间
|
||||||
|
* @returns {Promise} 返回修改结果
|
||||||
|
*/
|
||||||
|
export const updateGroupBuyType = (data) => {
|
||||||
|
return request.post("/api/v1/admin/activity/group_buy/type/update", data)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除拼团活动类型
|
||||||
|
* @param {string} id - 类型ID
|
||||||
|
* @returns {Promise} 返回删除结果
|
||||||
|
*/
|
||||||
|
export const deleteGroupBuyType = (id) => {
|
||||||
|
return request.delete("/api/v1/admin/activity/group_buy/type/delete", { params: { id } })
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 拼团队伍管理接口 ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查队伍列表
|
||||||
|
* @returns {Promise} 返回队伍检查结果
|
||||||
|
*/
|
||||||
|
export const checkGroupBuyTeams = () => {
|
||||||
|
return request.get("/api/v1/admin/activity/group_buy/check")
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 为队伍添加随机伪人
|
||||||
|
* @param {string} groupBuyId - 队伍ID
|
||||||
|
* @returns {Promise} 返回添加结果
|
||||||
|
*/
|
||||||
|
export const addRandomUser = (groupBuyId) => {
|
||||||
|
return request.post("/api/v1/admin/activity/group_buy/add_random_user", { group_buy_id: groupBuyId })
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建随机伪人队伍
|
||||||
|
* @param {Object} data - 队伍数据
|
||||||
|
* @param {string} data.name - 队伍名称
|
||||||
|
* @param {string} data.group_buy_type_id - 队伍类型ID
|
||||||
|
* @returns {Promise} 返回创建结果
|
||||||
|
*/
|
||||||
|
export const addRandomGroup = (data) => {
|
||||||
|
return request.post("/api/v1/admin/activity/group_buy/add_random_group", data)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导出成功队伍信息
|
||||||
|
* @returns {Promise} 返回导出数据
|
||||||
|
*/
|
||||||
|
export const exportGroupBuyIdcInfo = () => {
|
||||||
|
return request.get("/api/v1/admin/activity/group_buy/export_idc_info")
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 为指定队伍下发订单
|
||||||
|
* @param {string} groupBuyId - 队伍ID
|
||||||
|
* @returns {Promise} 返回下发结果
|
||||||
|
*/
|
||||||
|
export const setGroupBuyOrder = (groupBuyId) => {
|
||||||
|
return request.post("/api/v1/admin/activity/group_buy/set_order", { group_buy_id: groupBuyId })
|
||||||
|
}
|
||||||
|
|||||||
@@ -88,6 +88,9 @@ export const menus = [
|
|||||||
},{
|
},{
|
||||||
path:'/activity/groupbuy',
|
path:'/activity/groupbuy',
|
||||||
title:'拼团活动',
|
title:'拼团活动',
|
||||||
|
},{
|
||||||
|
path:'/activity/groupbuy-type',
|
||||||
|
title:'拼团类型'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -337,6 +337,14 @@ const routes = [
|
|||||||
meta: {
|
meta: {
|
||||||
title: '拼团活动'
|
title: '拼团活动'
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/activity/groupbuy-type',
|
||||||
|
name: 'GroupBuyType',
|
||||||
|
component: () => import('../views/activity/GroupBuyType.vue'),
|
||||||
|
meta: {
|
||||||
|
title: '拼团类型'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -94,8 +94,8 @@ class Request {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DELETE 请求
|
// DELETE 请求
|
||||||
delete(url,data={}, config = {}) {
|
delete(url, config = {}) {
|
||||||
return this.instance.delete(url,data, config)
|
return this.instance.delete(url, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PATCH 请求
|
// PATCH 请求
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<div class="group-buy-container">
|
<div class="group-buy-container">
|
||||||
<el-card class="header-card">
|
<el-card class="header-card">
|
||||||
<div class="header-actions">
|
<div class="header-actions">
|
||||||
<el-button type="primary" icon="Plus" @click="showCreateDialog = true">
|
<el-button type="primary" icon="Plus" @click="openCreateDialog">
|
||||||
创建随机队伍
|
创建随机队伍
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button type="success" icon="Download" @click="handleExport" :loading="exportLoading">
|
<el-button type="success" icon="Download" @click="handleExport" :loading="exportLoading">
|
||||||
@@ -18,13 +18,13 @@
|
|||||||
<el-table :data="groupList" v-loading="loading" stripe border>
|
<el-table :data="groupList" v-loading="loading" stripe border>
|
||||||
<el-table-column prop="id" label="队伍ID" />
|
<el-table-column prop="id" label="队伍ID" />
|
||||||
<el-table-column prop="name" label="队伍名称" min-width="150" />
|
<el-table-column prop="name" label="队伍名称" min-width="150" />
|
||||||
<el-table-column label="队伍类型" width="120">
|
<!-- <el-table-column label="队伍类型" width="120">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-tag :type="row.type === 0 ? 'primary' : 'success'">
|
<el-tag :type="row.type === 0 ? 'primary' : 'success'">
|
||||||
{{ row.type === 0 ? '5人队' : '10人队' }}
|
{{ row.type === 0 ? '5人队' : '10人队' }}
|
||||||
</el-tag>
|
</el-tag>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column> -->
|
||||||
<el-table-column prop="currentMembers" label="当前人数" width="100" align="center" />
|
<el-table-column prop="currentMembers" label="当前人数" width="100" align="center" />
|
||||||
<el-table-column prop="maxMembers" label="需要人数" width="100" align="center" />
|
<el-table-column prop="maxMembers" label="需要人数" width="100" align="center" />
|
||||||
<el-table-column label="状态" width="120">
|
<el-table-column label="状态" width="120">
|
||||||
@@ -77,11 +77,15 @@
|
|||||||
<el-form-item label="队伍名称" prop="name">
|
<el-form-item label="队伍名称" prop="name">
|
||||||
<el-input v-model="createForm.name" placeholder="请输入队伍名称" />
|
<el-input v-model="createForm.name" placeholder="请输入队伍名称" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="队伍类型" prop="groupBuyType">
|
<el-form-item label="标签" prop="tag">
|
||||||
<el-radio-group v-model="createForm.groupBuyType">
|
<el-select v-model="createForm.tag" placeholder="请选择标签" style="width: 100%" @change="handleTagChange">
|
||||||
<el-radio :label="0">5人队</el-radio>
|
<el-option v-for="tag in tagList" :key="tag" :label="tag" :value="tag" />
|
||||||
<el-radio :label="1">10人队</el-radio>
|
</el-select>
|
||||||
</el-radio-group>
|
</el-form-item>
|
||||||
|
<el-form-item label="拼团类型" prop="groupBuyTypeId">
|
||||||
|
<el-select v-model="createForm.groupBuyTypeId" placeholder="请先选择标签" :disabled="!createForm.tag" style="width: 100%">
|
||||||
|
<el-option v-for="item in typeList" :key="item.id" :label="`${item.name} (${item.maxPerson}人)`" :value="item.id" />
|
||||||
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
@@ -116,8 +120,8 @@
|
|||||||
<el-tag v-if="row.teamLeader" type="warning" size="small">队长</el-tag>
|
<el-tag v-if="row.teamLeader" type="warning" size="small">队长</el-tag>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="idcUid" label="IDC UID" width="120" />
|
<!-- <el-table-column prop="idcUid" label="IDC UID" width="120" />
|
||||||
<el-table-column prop="idcPhone" label="IDC手机号" width="130" />
|
<el-table-column prop="idcPhone" label="IDC手机号" width="130" /> -->
|
||||||
</el-table>
|
</el-table>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
@@ -134,6 +138,7 @@ import {
|
|||||||
exportIdcInfo,
|
exportIdcInfo,
|
||||||
setOrder
|
setOrder
|
||||||
} from '@/api/admin/activity'
|
} from '@/api/admin/activity'
|
||||||
|
import { getGroupBuyTypeList,getGroupBuyTypeTags } from '@/api/groupBuy'
|
||||||
|
|
||||||
// 数据状态
|
// 数据状态
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
@@ -150,18 +155,67 @@ const currentMembers = ref([])
|
|||||||
const createFormRef = ref(null)
|
const createFormRef = ref(null)
|
||||||
const createForm = reactive({
|
const createForm = reactive({
|
||||||
name: '',
|
name: '',
|
||||||
groupBuyType: 0
|
tag: '',
|
||||||
|
groupBuyTypeId: ''
|
||||||
})
|
})
|
||||||
|
const typeList = ref([])
|
||||||
|
const tagList = ref([])
|
||||||
|
|
||||||
const createRules = {
|
const createRules = {
|
||||||
name: [
|
name: [
|
||||||
{ required: true, message: '请输入队伍名称', trigger: 'blur' }
|
{ required: true, message: '请输入队伍名称', trigger: 'blur' }
|
||||||
],
|
],
|
||||||
groupBuyType: [
|
tag: [
|
||||||
{ required: true, message: '请选择队伍类型', trigger: 'change' }
|
{ required: true, message: '请选择标签', trigger: 'change' }
|
||||||
|
],
|
||||||
|
groupBuyTypeId: [
|
||||||
|
{ required: true, message: '请选择拼团类型', trigger: 'change' }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取标签列表
|
||||||
|
const fetchTags = async () => {
|
||||||
|
try {
|
||||||
|
const res = await getGroupBuyTypeTags()
|
||||||
|
if (res.code === 200) {
|
||||||
|
tagList.value = res.data || []
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取标签失败:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据 tag 获取拼团类型列表
|
||||||
|
const fetchTypeListByTag = async (tag) => {
|
||||||
|
try {
|
||||||
|
const res = await getGroupBuyTypeList({ page: 1, count: 100, tag })
|
||||||
|
if (res.code === 200) {
|
||||||
|
typeList.value = res.data?.data || []
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取拼团类型失败:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// tag 变化时获取对应的拼团类型
|
||||||
|
const handleTagChange = (tag) => {
|
||||||
|
createForm.groupBuyTypeId = ''
|
||||||
|
typeList.value = []
|
||||||
|
if (tag) {
|
||||||
|
fetchTypeListByTag(tag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打开创建对话框
|
||||||
|
const openCreateDialog = () => {
|
||||||
|
createForm.name = ''
|
||||||
|
createForm.tag = ''
|
||||||
|
createForm.groupBuyTypeId = ''
|
||||||
|
typeList.value = []
|
||||||
|
fetchTags()
|
||||||
|
showCreateDialog.value = true
|
||||||
|
}
|
||||||
|
|
||||||
// 获取队伍列表
|
// 获取队伍列表
|
||||||
const fetchGroupList = async () => {
|
const fetchGroupList = async () => {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
@@ -239,25 +293,14 @@ const handleCreate = async () => {
|
|||||||
if (valid) {
|
if (valid) {
|
||||||
createLoading.value = true
|
createLoading.value = true
|
||||||
try {
|
try {
|
||||||
const res = await addRandomGroup(createForm.name, createForm.groupBuyType)
|
const res = await addRandomGroup({ name: createForm.name, group_buy_type_id: String(createForm.groupBuyTypeId) })
|
||||||
console.log('创建队伍响应:', res)
|
console.log('创建队伍响应:', res)
|
||||||
|
|
||||||
if (res.data.code === 200) {
|
if (res.data.code === 200) {
|
||||||
// API 返回的数据结构:
|
|
||||||
// {
|
|
||||||
// group_buy_id: "17670733070-5",
|
|
||||||
// name: "发士大夫",
|
|
||||||
// maxPerson: 5,
|
|
||||||
// createTime: "2025-12-30T13:41:47.216888773+08:00",
|
|
||||||
// users: [{...}]
|
|
||||||
// }
|
|
||||||
|
|
||||||
ElMessage.success(`创建成功!队伍ID: ${res.data.group_buy_id}`)
|
ElMessage.success(`创建成功!队伍ID: ${res.data.group_buy_id}`)
|
||||||
showCreateDialog.value = false
|
showCreateDialog.value = false
|
||||||
createForm.name = ''
|
createForm.name = ''
|
||||||
createForm.groupBuyType = 0
|
createForm.groupBuyTypeId = ''
|
||||||
|
|
||||||
// 刷新列表
|
|
||||||
fetchGroupList()
|
fetchGroupList()
|
||||||
} else {
|
} else {
|
||||||
ElMessage.error(res.message || '创建失败')
|
ElMessage.error(res.message || '创建失败')
|
||||||
|
|||||||
@@ -0,0 +1,226 @@
|
|||||||
|
<template>
|
||||||
|
<div class="group-buy-type-container">
|
||||||
|
<el-card class="header-card">
|
||||||
|
<div class="header-actions">
|
||||||
|
<el-button type="primary" icon="Plus" @click="handleAdd">新增类型</el-button>
|
||||||
|
<el-select v-model="searchTag" placeholder="请选择标签" style="width: 180px; margin-left: 12px" @change="handleTagChange">
|
||||||
|
<el-option v-for="tag in tagList" :key="tag" :label="tag" :value="tag" />
|
||||||
|
</el-select>
|
||||||
|
<el-input v-model="searchKey" placeholder="关键词搜索" style="width: 200px; margin-left: 12px" clearable :disabled="!searchTag" @keyup.enter="fetchList" />
|
||||||
|
<el-button type="info" icon="Refresh" @click="fetchList" :loading="loading" :disabled="!searchTag" style="margin-left: 12px">刷新</el-button>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
|
||||||
|
<el-card class="table-card">
|
||||||
|
<el-empty v-if="!searchTag" description="请先选择标签" />
|
||||||
|
<template v-else>
|
||||||
|
<el-table :data="tableData" v-loading="loading" stripe border>
|
||||||
|
<el-table-column prop="id" label="ID" width="80" />
|
||||||
|
<el-table-column prop="name" label="名称" min-width="120" />
|
||||||
|
<el-table-column label="价格" width="120">
|
||||||
|
<template #default="{ row }">¥{{ (row.price / 100).toFixed(2) }}</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="续费价格" width="120">
|
||||||
|
<template #default="{ row }">¥{{ (row.renewPrice / 100).toFixed(2) }}</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="maxPerson" label="拼团人数" width="100" align="center" />
|
||||||
|
<el-table-column prop="tag" label="标签" width="120">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-tag v-if="row.tag" type="info">{{ row.tag }}</el-tag>
|
||||||
|
<span v-else>-</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="过期时间" width="180">
|
||||||
|
<template #default="{ row }">{{ row.expireTime ? formatTime(row.expireTime) : '永久' }}</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="note" label="备注" min-width="150" show-overflow-tooltip />
|
||||||
|
<el-table-column label="操作" width="160" fixed="right">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-button type="primary" size="small" @click="handleEdit(row)">编辑</el-button>
|
||||||
|
<el-button type="danger" size="small" @click="handleDelete(row)">删除</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<div class="pagination-wrapper">
|
||||||
|
<el-pagination v-model:current-page="page" v-model:page-size="pageSize" :total="total" :page-sizes="[10, 20, 50]" layout="total, sizes, prev, pager, next" @size-change="fetchList" @current-change="fetchList" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-card>
|
||||||
|
|
||||||
|
<el-dialog v-model="dialogVisible" :title="isEdit ? '编辑拼团类型' : '新增拼团类型'" width="500px" :close-on-click-modal="false">
|
||||||
|
<el-form :model="form" :rules="rules" ref="formRef" label-width="100px">
|
||||||
|
<el-form-item label="名称" prop="name">
|
||||||
|
<el-input v-model="form.name" placeholder="请输入名称" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="价格(分)" prop="price">
|
||||||
|
<el-input-number v-model="form.price" :min="0" style="width: 100%" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="续费价格(分)" prop="renewPrice">
|
||||||
|
<el-input-number v-model="form.renewPrice" :min="0" style="width: 100%" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="拼团人数" prop="maxPerson">
|
||||||
|
<el-input-number v-model="form.maxPerson" :min="2" :max="100" style="width: 100%" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="标签" prop="tag">
|
||||||
|
<el-select v-model="form.tag" placeholder="选择标签" filterable allow-create style="width: 100%">
|
||||||
|
<el-option v-for="tag in tagList" :key="tag" :label="tag" :value="tag" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="过期时间" prop="expireTime">
|
||||||
|
<el-date-picker v-model="form.expireTime" type="datetime" placeholder="选择过期时间" style="width: 100%" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="备注" prop="note">
|
||||||
|
<el-input v-model="form.note" type="textarea" :rows="3" placeholder="请输入备注" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<el-button @click="dialogVisible = false">取消</el-button>
|
||||||
|
<el-button type="primary" @click="handleSubmit" :loading="submitLoading">确定</el-button>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, reactive, onMounted } from 'vue'
|
||||||
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
|
import { getGroupBuyTypeList, getGroupBuyTypeTags, addGroupBuyType, updateGroupBuyType, deleteGroupBuyType } from '@/api/groupBuy'
|
||||||
|
|
||||||
|
const loading = ref(false)
|
||||||
|
const tableData = ref([])
|
||||||
|
const total = ref(0)
|
||||||
|
const page = ref(1)
|
||||||
|
const pageSize = ref(10)
|
||||||
|
const searchKey = ref('')
|
||||||
|
const searchTag = ref('')
|
||||||
|
const tagList = ref([])
|
||||||
|
const dialogVisible = ref(false)
|
||||||
|
const isEdit = ref(false)
|
||||||
|
const submitLoading = ref(false)
|
||||||
|
const formRef = ref(null)
|
||||||
|
|
||||||
|
const form = reactive({ id: '', name: '', price: 0, renewPrice: 0, maxPerson: 5, tag: '', expireTime: null, note: '' })
|
||||||
|
const rules = {
|
||||||
|
name: [{ required: true, message: '请输入名称', trigger: 'blur' }],
|
||||||
|
price: [{ required: true, message: '请输入价格', trigger: 'blur' }],
|
||||||
|
renewPrice: [{ required: true, message: '请输入续费价格', trigger: 'blur' }],
|
||||||
|
maxPerson: [{ required: true, message: '请输入拼团人数', trigger: 'blur' }],
|
||||||
|
tag: [{ required: true, message: '请选择标签', trigger: 'change' }],
|
||||||
|
expireTime: [{ required: true, message: '请选择过期时间', trigger: 'change' }],
|
||||||
|
note: [{ required: true, message: '请输入备注', trigger: 'blur' }]
|
||||||
|
}
|
||||||
|
|
||||||
|
const formatTime = (timeStr) => {
|
||||||
|
if (!timeStr) return '-'
|
||||||
|
return new Date(timeStr).toLocaleString('zh-CN')
|
||||||
|
}
|
||||||
|
|
||||||
|
const fetchList = async () => {
|
||||||
|
loading.value = true
|
||||||
|
try {
|
||||||
|
const res = await getGroupBuyTypeList({ page: page.value, count: pageSize.value, key: searchKey.value || undefined, tag: searchTag.value || undefined })
|
||||||
|
console.log("获取拼团类型列表数据:",res)
|
||||||
|
if (res.code === 200) {
|
||||||
|
tableData.value = res.data?.data || []
|
||||||
|
total.value = res.data?.all_count || 0
|
||||||
|
} else {
|
||||||
|
ElMessage.error(res.data.message || '获取列表失败')
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取列表失败:', error)
|
||||||
|
ElMessage.error('网络错误')
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const fetchTags = async () => {
|
||||||
|
try {
|
||||||
|
const res = await getGroupBuyTypeTags()
|
||||||
|
if (res.code === 200) tagList.value = res.data || []
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取标签失败:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 标签变化时重新获取列表
|
||||||
|
const handleTagChange = (tag) => {
|
||||||
|
page.value = 1
|
||||||
|
searchKey.value = ''
|
||||||
|
tableData.value = []
|
||||||
|
total.value = 0
|
||||||
|
if (tag) {
|
||||||
|
fetchList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleAdd = () => {
|
||||||
|
isEdit.value = false
|
||||||
|
Object.assign(form, { id: '', name: '', price: 0, renewPrice: 0, maxPerson: 5, tag: '', expireTime: null, note: '' })
|
||||||
|
dialogVisible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleEdit = (row) => {
|
||||||
|
isEdit.value = true
|
||||||
|
Object.assign(form, { id: row.id, name: row.name, price: row.price, renewPrice: row.renewPrice, maxPerson: row.maxPerson, tag: row.tag || '', expireTime: row.expireTime || null, note: row.note || '' })
|
||||||
|
dialogVisible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSubmit = async () => {
|
||||||
|
if (!formRef.value) return
|
||||||
|
await formRef.value.validate(async (valid) => {
|
||||||
|
if (!valid) return
|
||||||
|
submitLoading.value = true
|
||||||
|
try {
|
||||||
|
const data = {
|
||||||
|
name: form.name,
|
||||||
|
price: String(form.price),
|
||||||
|
renew_price: String(form.renewPrice),
|
||||||
|
max_person: String(form.maxPerson),
|
||||||
|
tag: form.tag,
|
||||||
|
expire_time: form.expireTime ? Math.floor(new Date(form.expireTime).getTime() / 1000) : 0,
|
||||||
|
note: form.note
|
||||||
|
}
|
||||||
|
if (isEdit.value) data.id = String(form.id)
|
||||||
|
const res = isEdit.value ? await updateGroupBuyType(data) : await addGroupBuyType(data)
|
||||||
|
if (res.code === 200) {
|
||||||
|
ElMessage.success(isEdit.value ? '修改成功' : '新增成功')
|
||||||
|
dialogVisible.value = false
|
||||||
|
fetchList()
|
||||||
|
fetchTags()
|
||||||
|
} else {
|
||||||
|
ElMessage.error(res.message || '操作失败')
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('提交失败:', error)
|
||||||
|
ElMessage.error('网络错误')
|
||||||
|
} finally {
|
||||||
|
submitLoading.value = false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDelete = async (row) => {
|
||||||
|
try {
|
||||||
|
await ElMessageBox.confirm('确定要删除该拼团类型吗?', '确认删除', { type: 'warning' })
|
||||||
|
const res = await deleteGroupBuyType(row.id)
|
||||||
|
if (res.code === 200) {
|
||||||
|
ElMessage.success('删除成功')
|
||||||
|
fetchList()
|
||||||
|
fetchTags()
|
||||||
|
} else {
|
||||||
|
ElMessage.error(res.data.message || '删除失败')
|
||||||
|
}
|
||||||
|
} catch { /* 取消 */ }
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => { fetchTags() })
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.group-buy-type-container { padding: 20px; }
|
||||||
|
.header-card { margin-bottom: 20px; }
|
||||||
|
.header-actions { display: flex; align-items: center; }
|
||||||
|
.table-card { box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); }
|
||||||
|
.pagination-wrapper { margin-top: 20px; display: flex; justify-content: flex-end; }
|
||||||
|
</style>
|
||||||
@@ -1,92 +0,0 @@
|
|||||||
# 商品管理 API 对接完成报告
|
|
||||||
|
|
||||||
## 概述
|
|
||||||
已成功完成 `默认模块.openapi.json` 中所有商品管理相关接口的对接工作。
|
|
||||||
|
|
||||||
## 对接详情
|
|
||||||
|
|
||||||
### 1. API 接口实现 (18个接口)
|
|
||||||
|
|
||||||
#### 商品分组管理 (6个接口)
|
|
||||||
- ✅ `GET /api/v1/admin/good/group/list` - 获取商品分组列表
|
|
||||||
- ✅ `POST /api/v1/admin/good/group/create` - 创建商品分组
|
|
||||||
- ✅ `POST /api/v1/admin/good/group/update` - 更新商品分组
|
|
||||||
- ✅ `POST /api/v1/admin/good/group/disable` - 隐藏商品组
|
|
||||||
- ✅ `POST /api/v1/admin/good/group/enable` - 启用商品组
|
|
||||||
- ✅ `DELETE /api/v1/admin/good/group/delete` - 删除商品分组
|
|
||||||
|
|
||||||
#### 商品管理 (5个接口)
|
|
||||||
- ✅ `GET /api/v1/admin/good/goods/list` - 获取商品列表
|
|
||||||
- ✅ `GET /api/v1/admin/good/goods/tag_list` - 获取商品标签列表 (新增)
|
|
||||||
- ✅ `POST /api/v1/admin/good/goods/create` - 创建商品
|
|
||||||
- ✅ `POST /api/v1/admin/good/goods/update` - 更新商品
|
|
||||||
- ✅ `DELETE /api/v1/admin/good/goods/delete` - 删除商品
|
|
||||||
|
|
||||||
#### 商品参数管理 (7个接口)
|
|
||||||
- ✅ `GET /api/v1/admin/good/spec/list` - 获取商品参数列表
|
|
||||||
- ✅ `POST /api/v1/admin/good/spec/create` - 创建商品参数
|
|
||||||
- ✅ `GET /api/v1/admin/good/spec/detail` - 获取商品参数详情
|
|
||||||
- ✅ `POST /api/v1/admin/good/spec/update` - 更新商品参数
|
|
||||||
- ✅ `DELETE /api/v1/admin/good/spec/delete` - 删除商品参数
|
|
||||||
- ✅ `POST /api/v1/admin/good/spec/add_value` - 增加商品参数值
|
|
||||||
- ✅ `DELETE /api/v1/admin/good/spec/delete_value` - 删除商品参数值
|
|
||||||
- ✅ `POST /api/v1/admin/good/spec/update_value` - 更新商品参数值
|
|
||||||
|
|
||||||
### 2. 页面实现
|
|
||||||
|
|
||||||
#### ProductList.vue (商品列表管理)
|
|
||||||
- ✅ 商品列表展示与分页
|
|
||||||
- ✅ 商品搜索与筛选 (按分组)
|
|
||||||
- ✅ 商品新增/编辑/删除
|
|
||||||
- ✅ 批量删除功能
|
|
||||||
- ✅ 商品参数管理 (完整的参数和参数值管理)
|
|
||||||
- ✅ 商品标签选择 (新增功能)
|
|
||||||
- ✅ 骨架屏加载效果
|
|
||||||
|
|
||||||
#### ProductGroup.vue (商品分组管理)
|
|
||||||
- ✅ 分组列表展示与分页
|
|
||||||
- ✅ 分组新增/编辑/删除
|
|
||||||
- ✅ 分组状态切换 (启用/禁用)
|
|
||||||
- ✅ 骨架屏加载效果
|
|
||||||
|
|
||||||
### 3. 文件修改记录
|
|
||||||
|
|
||||||
#### 新增文件
|
|
||||||
- `src/api/admin/product-test.js` - API 接口测试验证文件
|
|
||||||
|
|
||||||
#### 修改文件
|
|
||||||
- `src/api/admin/product.js` - 新增商品标签列表接口,修正参数接口
|
|
||||||
- `src/views/product/ProductList.vue` - 新增商品标签功能,修复价格处理
|
|
||||||
|
|
||||||
### 4. 技术要点
|
|
||||||
|
|
||||||
#### API 接口规范
|
|
||||||
- 所有 POST/DELETE 接口使用 `multipart/form-data` 格式
|
|
||||||
- 更新商品参数接口使用 query 参数
|
|
||||||
- 统一的错误处理和响应格式
|
|
||||||
|
|
||||||
#### 数据处理
|
|
||||||
- 价格以分为单位存储和传输
|
|
||||||
- 商品标签从专用接口获取
|
|
||||||
- 完整的表单验证和数据校验
|
|
||||||
|
|
||||||
#### 用户体验
|
|
||||||
- 骨架屏加载效果
|
|
||||||
- 批量操作支持
|
|
||||||
- 实时状态切换
|
|
||||||
- 友好的错误提示
|
|
||||||
|
|
||||||
## 完成状态
|
|
||||||
|
|
||||||
- **接口对接完成度**: 100% (18/18)
|
|
||||||
- **页面功能完成度**: 100%
|
|
||||||
- **测试验证**: 已完成
|
|
||||||
- **文档更新**: 已完成
|
|
||||||
|
|
||||||
## 使用说明
|
|
||||||
|
|
||||||
1. **商品分组管理**: 访问 ProductGroup.vue 页面进行分组管理
|
|
||||||
2. **商品管理**: 访问 ProductList.vue 页面进行商品管理
|
|
||||||
3. **参数管理**: 在商品列表页面点击"参数"按钮进行参数管理
|
|
||||||
|
|
||||||
所有功能已完整实现,可以直接投入使用。
|
|
||||||
-268
@@ -1,268 +0,0 @@
|
|||||||
# 拼团 API 对接说明
|
|
||||||
|
|
||||||
## API 文件位置
|
|
||||||
- 管理端接口:`src/api/admin/activity.js`
|
|
||||||
- 用户端接口:`src/api/groupBuy.js`
|
|
||||||
|
|
||||||
## 管理端 API 接口(已更新)
|
|
||||||
|
|
||||||
### 1. 获取拼团列表 ✅ 已更新
|
|
||||||
```javascript
|
|
||||||
import { getGroupBuyList } from '@/api/admin/activity.js'
|
|
||||||
|
|
||||||
// 调用示例
|
|
||||||
const resp = await getGroupBuyList()
|
|
||||||
|
|
||||||
// 接口路径:GET /api/v1/users/activity/group_buy/list
|
|
||||||
|
|
||||||
// 实际返回数据结构:
|
|
||||||
{
|
|
||||||
code: 200,
|
|
||||||
message: "Success",
|
|
||||||
data: {
|
|
||||||
group_buy_list: ["17670726110-5", "17670733070-5"], // 所有队伍ID
|
|
||||||
lack_group_buy_list: ["17670726110-5"], // 未满员队伍ID
|
|
||||||
success_group_buy_list: [] // 已满员队伍ID
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. 获取拼团队伍详情 ✅ 新增
|
|
||||||
```javascript
|
|
||||||
import { getGroupBuyDetail } from '@/api/admin/activity.js'
|
|
||||||
|
|
||||||
// 调用示例
|
|
||||||
const resp = await getGroupBuyDetail('17670733070-5')
|
|
||||||
|
|
||||||
// 接口路径:GET /api/v1/users/activity/group_buy/detail/:id
|
|
||||||
|
|
||||||
// 实际返回数据结构:
|
|
||||||
{
|
|
||||||
code: 200,
|
|
||||||
message: "Success",
|
|
||||||
data: {
|
|
||||||
group_buy_id: "17670733070-5",
|
|
||||||
name: "发士大夫",
|
|
||||||
maxPerson: 5,
|
|
||||||
createTime: "2025-12-30T13:41:47.216888773+08:00",
|
|
||||||
users: [{
|
|
||||||
user_id: 0,
|
|
||||||
user_name: "",
|
|
||||||
team_leader: true,
|
|
||||||
cover: "https://...",
|
|
||||||
idc_phone: "",
|
|
||||||
idc_uid: ""
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. 创建随机伪人队伍 ✅ 已验证
|
|
||||||
```javascript
|
|
||||||
import { addRandomGroup } from '@/api/admin/activity.js'
|
|
||||||
|
|
||||||
// 调用示例
|
|
||||||
const resp = await addRandomGroup('队伍名称', 0) // 0=5人队, 1=10人队
|
|
||||||
|
|
||||||
// 实际返回数据结构:
|
|
||||||
{
|
|
||||||
code: 200,
|
|
||||||
message: "Success",
|
|
||||||
data: {
|
|
||||||
group_buy_id: "17670733070-5",
|
|
||||||
name: "发士大夫",
|
|
||||||
maxPerson: 5,
|
|
||||||
createTime: "2025-12-30T13:41:47.216888773+08:00",
|
|
||||||
users: [{
|
|
||||||
user_id: 0,
|
|
||||||
user_name: "",
|
|
||||||
team_leader: true,
|
|
||||||
cover: "https://...",
|
|
||||||
idc_phone: "",
|
|
||||||
idc_uid: ""
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 4. 为队伍添加随机伪人
|
|
||||||
```javascript
|
|
||||||
import { addRandomUser } from '@/api/admin/activity.js'
|
|
||||||
|
|
||||||
const resp = await addRandomUser(groupBuyId)
|
|
||||||
```
|
|
||||||
|
|
||||||
### 5. 为指定队伍下发订单
|
|
||||||
```javascript
|
|
||||||
import { setOrder } from '@/api/admin/activity.js'
|
|
||||||
|
|
||||||
const resp = await setOrder(groupBuyId)
|
|
||||||
```
|
|
||||||
|
|
||||||
### 6. 导出成功队伍信息
|
|
||||||
```javascript
|
|
||||||
import { exportIdcInfo } from '@/api/admin/activity.js'
|
|
||||||
|
|
||||||
const resp = await exportIdcInfo()
|
|
||||||
// 返回 Excel 文件流
|
|
||||||
```
|
|
||||||
|
|
||||||
## 用户端 API 接口
|
|
||||||
|
|
||||||
### 1. 创建拼团
|
|
||||||
```javascript
|
|
||||||
import { createGroupBuy } from '@/api/groupBuy.js'
|
|
||||||
|
|
||||||
// 调用示例
|
|
||||||
const data = {
|
|
||||||
name: '地擦拭大',
|
|
||||||
maxPerson: 5,
|
|
||||||
cover: 'https://example.com/cover.jpg'
|
|
||||||
}
|
|
||||||
|
|
||||||
const resp = await createGroupBuy(data)
|
|
||||||
|
|
||||||
// 响应数据结构
|
|
||||||
{
|
|
||||||
code: 200,
|
|
||||||
message: "Success",
|
|
||||||
data: {
|
|
||||||
group_buy_id: "17670726110-5",
|
|
||||||
name: "地擦拭大",
|
|
||||||
maxPerson: 5,
|
|
||||||
createTime: "2025-12-30T13:30:11.918394294+08:00",
|
|
||||||
users: [{
|
|
||||||
user_id: 0,
|
|
||||||
user_name: "",
|
|
||||||
team_leader: true,
|
|
||||||
cover: "https://...",
|
|
||||||
idc_phone: "",
|
|
||||||
idc_uid: ""
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. 检查拼团
|
|
||||||
```javascript
|
|
||||||
import { checkGroupBuy } from '@/api/groupBuy.js'
|
|
||||||
|
|
||||||
// 调用示例
|
|
||||||
const groupBuyId = "17670726110-5"
|
|
||||||
const resp = await checkGroupBuy(groupBuyId)
|
|
||||||
|
|
||||||
// 响应数据结构
|
|
||||||
{
|
|
||||||
code: 200,
|
|
||||||
message: "Success",
|
|
||||||
data: "ok"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. 获取拼团详情
|
|
||||||
```javascript
|
|
||||||
import { getGroupBuyDetail } from '@/api/groupBuy.js'
|
|
||||||
|
|
||||||
const resp = await getGroupBuyDetail(groupBuyId)
|
|
||||||
```
|
|
||||||
|
|
||||||
### 4. 获取拼团列表(用户端)
|
|
||||||
```javascript
|
|
||||||
import { getGroupBuyList } from '@/api/groupBuy.js'
|
|
||||||
|
|
||||||
const resp = await getGroupBuyList({ page: 1, pageSize: 20 })
|
|
||||||
|
|
||||||
// 接口路径:GET /api/v1/users/activity/group_buy/list
|
|
||||||
```
|
|
||||||
|
|
||||||
### 5. 加入拼团
|
|
||||||
```javascript
|
|
||||||
import { joinGroupBuy } from '@/api/groupBuy.js'
|
|
||||||
|
|
||||||
const resp = await joinGroupBuy(groupBuyId, {
|
|
||||||
user_id: 123,
|
|
||||||
user_name: "张三"
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
### 6. 删除拼团
|
|
||||||
```javascript
|
|
||||||
import { deleteGroupBuy } from '@/api/groupBuy.js'
|
|
||||||
|
|
||||||
const resp = await deleteGroupBuy(groupBuyId)
|
|
||||||
```
|
|
||||||
|
|
||||||
## 完整示例页面
|
|
||||||
- 管理端页面:`src/views/activity/GroupBuyActivity.vue` ✅ 已存在
|
|
||||||
- 用户端示例:`src/views/marketing/GroupBuyManage.vue`
|
|
||||||
|
|
||||||
管理端页面包含:
|
|
||||||
- ✅ 拼团列表展示(使用正确的接口路径)
|
|
||||||
- ✅ 创建随机伪人队伍
|
|
||||||
- ✅ 添加随机伪人
|
|
||||||
- ✅ 下发订单功能
|
|
||||||
- ✅ 导出成功队伍
|
|
||||||
- ✅ 查看队伍成员
|
|
||||||
|
|
||||||
## 接口路径总结
|
|
||||||
|
|
||||||
### 管理端接口
|
|
||||||
- `GET /api/v1/users/activity/group_buy/list` - 获取拼团列表 ✅ 返回队伍ID数组
|
|
||||||
- `GET /api/v1/users/activity/group_buy/detail/:id` - 获取队伍详情 ✅ 新增
|
|
||||||
- `POST /api/v1/admin/activity/group_buy/add_random_group` - 创建随机队伍 ✅ 已验证
|
|
||||||
- `POST /api/v1/admin/activity/group_buy/add_random_user` - 添加随机伪人
|
|
||||||
- `POST /api/v1/admin/activity/group_buy/set_order` - 下发订单
|
|
||||||
- `GET /api/v1/admin/activity/group_buy/export_idc_info` - 导出信息
|
|
||||||
|
|
||||||
### 用户端接口(根据需要调整)
|
|
||||||
- `POST /api/v1/group-buy/create` - 创建拼团
|
|
||||||
- `GET /api/v1/group-buy/check/:id` - 检查拼团
|
|
||||||
- `GET /api/v1/group-buy/:id` - 获取拼团详情
|
|
||||||
- `GET /api/v1/users/activity/group_buy/list` - 获取拼团列表 ✅
|
|
||||||
- `POST /api/v1/group-buy/:id/join` - 加入拼团
|
|
||||||
- `DELETE /api/v1/group-buy/:id` - 删除拼团
|
|
||||||
|
|
||||||
## 使用方法
|
|
||||||
|
|
||||||
### 在管理端页面使用
|
|
||||||
```vue
|
|
||||||
<script setup>
|
|
||||||
import { getGroupBuyList, addRandomUser } from '@/api/admin/activity.js'
|
|
||||||
import { ElMessage } from 'element-plus'
|
|
||||||
|
|
||||||
// 获取列表
|
|
||||||
const fetchList = async () => {
|
|
||||||
try {
|
|
||||||
const resp = await getGroupBuyList()
|
|
||||||
if (resp && resp.code === 200) {
|
|
||||||
console.log('拼团列表:', resp.data)
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('获取失败:', error)
|
|
||||||
ElMessage.error('获取失败')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 添加伪人
|
|
||||||
const addUser = async (groupBuyId) => {
|
|
||||||
try {
|
|
||||||
const resp = await addRandomUser(groupBuyId)
|
|
||||||
if (resp && resp.code === 200) {
|
|
||||||
ElMessage.success('添加成功')
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('添加失败:', error)
|
|
||||||
ElMessage.error('添加失败')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
```
|
|
||||||
|
|
||||||
## 注意事项
|
|
||||||
|
|
||||||
1. **接口路径已更新**:获取拼团列表接口已更新为 `/api/v1/users/activity/group_buy/list`
|
|
||||||
2. **错误处理**:所有 API 调用都应该包含 try-catch 错误处理
|
|
||||||
3. **响应检查**:始终检查 `resp.code === 200` 来判断请求是否成功
|
|
||||||
4. **空值处理**:使用可选链 `?.` 和空值合并 `||` 来处理可能为空的数据
|
|
||||||
5. **用户提示**:使用 `ElMessage` 给用户友好的提示信息
|
|
||||||
|
|
||||||
-282
@@ -1,282 +0,0 @@
|
|||||||
# 拼团 API 测试示例
|
|
||||||
|
|
||||||
## 实际数据结构(已验证)
|
|
||||||
|
|
||||||
### 1. 获取队伍列表
|
|
||||||
**接口**: `GET /api/v1/users/activity/group_buy/list`
|
|
||||||
|
|
||||||
**返回数据**:
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"code": 200,
|
|
||||||
"message": "Success",
|
|
||||||
"data": {
|
|
||||||
"group_buy_list": ["17670726110-5"], // 所有队伍ID
|
|
||||||
"lack_group_buy_list": ["17670726110-5"], // 未满员队伍ID
|
|
||||||
"success_group_buy_list": [] // 已满员队伍ID
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**数据说明**:
|
|
||||||
- `group_buy_list`: 所有队伍的 ID 列表
|
|
||||||
- `lack_group_buy_list`: 人数不足的队伍 ID(进行中)
|
|
||||||
- `success_group_buy_list`: 已满员的队伍 ID(成功)
|
|
||||||
- 队伍 ID 格式: `时间戳-人数` (如 `17670726110-5` 表示5人队)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 2. 创建队伍
|
|
||||||
**接口**: `POST /api/v1/admin/activity/group_buy/add_random_group`
|
|
||||||
|
|
||||||
**请求参数**:
|
|
||||||
```javascript
|
|
||||||
{
|
|
||||||
name: "发士大夫",
|
|
||||||
group_buy_type: 0 // 0=5人队, 1=10人队
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**返回数据**:
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"code": 200,
|
|
||||||
"message": "Success",
|
|
||||||
"data": {
|
|
||||||
"group_buy_id": "17670733070-5",
|
|
||||||
"name": "发士大夫",
|
|
||||||
"maxPerson": 5,
|
|
||||||
"createTime": "2025-12-30T13:41:47.216888773+08:00",
|
|
||||||
"users": [{
|
|
||||||
"user_id": 0,
|
|
||||||
"user_name": "",
|
|
||||||
"team_leader": true,
|
|
||||||
"cover": "https://oss.hostidc.net/api-server/static/files/...",
|
|
||||||
"idc_phone": "",
|
|
||||||
"idc_uid": ""
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**数据说明**:
|
|
||||||
- 创建成功后会自动添加一个团长(伪人)
|
|
||||||
- `team_leader: true` 表示是团长
|
|
||||||
- 返回完整的队伍信息,包括初始成员
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 3. 获取队伍详情
|
|
||||||
**接口**: `GET /api/v1/users/activity/group_buy/detail/:id`
|
|
||||||
|
|
||||||
**返回数据**: 与创建队伍返回的数据结构相同
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 在代码中使用
|
|
||||||
|
|
||||||
### 完整流程示例
|
|
||||||
|
|
||||||
```vue
|
|
||||||
<script setup>
|
|
||||||
import { ref } from 'vue'
|
|
||||||
import { ElMessage } from 'element-plus'
|
|
||||||
import {
|
|
||||||
getGroupBuyList,
|
|
||||||
getGroupBuyDetail,
|
|
||||||
addRandomGroup,
|
|
||||||
addRandomUser,
|
|
||||||
setOrder
|
|
||||||
} from '@/api/admin/activity.js'
|
|
||||||
|
|
||||||
// 1. 获取队伍列表
|
|
||||||
const fetchList = async () => {
|
|
||||||
try {
|
|
||||||
const res = await getGroupBuyList()
|
|
||||||
console.log('队伍列表:', res)
|
|
||||||
|
|
||||||
if (res.code === 200) {
|
|
||||||
const allIds = res.data.group_buy_list || []
|
|
||||||
const lackIds = res.data.lack_group_buy_list || []
|
|
||||||
const successIds = res.data.success_group_buy_list || []
|
|
||||||
|
|
||||||
console.log('所有队伍:', allIds)
|
|
||||||
console.log('未满员:', lackIds)
|
|
||||||
console.log('已满员:', successIds)
|
|
||||||
|
|
||||||
ElMessage.success(`共 ${allIds.length} 个队伍`)
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('获取失败:', error)
|
|
||||||
ElMessage.error('获取失败')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. 创建队伍
|
|
||||||
const createTeam = async () => {
|
|
||||||
try {
|
|
||||||
const res = await addRandomGroup('测试队伍', 0) // 0=5人队
|
|
||||||
console.log('创建结果:', res)
|
|
||||||
|
|
||||||
if (res.code === 200) {
|
|
||||||
const teamId = res.data.group_buy_id
|
|
||||||
const teamName = res.data.name
|
|
||||||
const memberCount = res.data.users?.length || 0
|
|
||||||
|
|
||||||
ElMessage.success(`创建成功!队伍ID: ${teamId},当前 ${memberCount} 人`)
|
|
||||||
|
|
||||||
// 刷新列表
|
|
||||||
await fetchList()
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('创建失败:', error)
|
|
||||||
ElMessage.error('创建失败')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. 获取队伍详情
|
|
||||||
const getDetail = async (teamId) => {
|
|
||||||
try {
|
|
||||||
const res = await getGroupBuyDetail(teamId)
|
|
||||||
console.log('队伍详情:', res)
|
|
||||||
|
|
||||||
if (res.code === 200) {
|
|
||||||
const team = res.data
|
|
||||||
console.log('队伍名称:', team.name)
|
|
||||||
console.log('最大人数:', team.maxPerson)
|
|
||||||
console.log('当前成员:', team.users)
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('获取详情失败:', error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 4. 添加伪人
|
|
||||||
const addFakeUser = async (teamId) => {
|
|
||||||
try {
|
|
||||||
const res = await addRandomUser(teamId)
|
|
||||||
console.log('添加伪人结果:', res)
|
|
||||||
|
|
||||||
if (res.code === 200) {
|
|
||||||
ElMessage.success('添加伪人成功')
|
|
||||||
// 刷新详情
|
|
||||||
await getDetail(teamId)
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('添加失败:', error)
|
|
||||||
ElMessage.error('添加失败')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 5. 下发订单
|
|
||||||
const sendOrder = async (teamId) => {
|
|
||||||
try {
|
|
||||||
const res = await setOrder(teamId)
|
|
||||||
console.log('下发订单结果:', res)
|
|
||||||
|
|
||||||
if (res.code === 200) {
|
|
||||||
ElMessage.success('订单下发成功')
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('下发失败:', error)
|
|
||||||
ElMessage.error('下发失败')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 测试步骤
|
|
||||||
|
|
||||||
### 步骤 1: 创建队伍
|
|
||||||
```javascript
|
|
||||||
await addRandomGroup('测试5人队', 0)
|
|
||||||
// 返回: { group_buy_id: "xxx-5", name: "测试5人队", maxPerson: 5, users: [1个团长] }
|
|
||||||
```
|
|
||||||
|
|
||||||
### 步骤 2: 查看列表
|
|
||||||
```javascript
|
|
||||||
await getGroupBuyList()
|
|
||||||
// 返回: { group_buy_list: ["xxx-5"], lack_group_buy_list: ["xxx-5"], success_group_buy_list: [] }
|
|
||||||
```
|
|
||||||
|
|
||||||
### 步骤 3: 添加伪人(重复4次,凑满5人)
|
|
||||||
```javascript
|
|
||||||
await addRandomUser("xxx-5") // 第2人
|
|
||||||
await addRandomUser("xxx-5") // 第3人
|
|
||||||
await addRandomUser("xxx-5") // 第4人
|
|
||||||
await addRandomUser("xxx-5") // 第5人
|
|
||||||
```
|
|
||||||
|
|
||||||
### 步骤 4: 再次查看列表
|
|
||||||
```javascript
|
|
||||||
await getGroupBuyList()
|
|
||||||
// 返回: { group_buy_list: ["xxx-5"], lack_group_buy_list: [], success_group_buy_list: ["xxx-5"] }
|
|
||||||
// 注意: 队伍从 lack_group_buy_list 移到了 success_group_buy_list
|
|
||||||
```
|
|
||||||
|
|
||||||
### 步骤 5: 下发订单
|
|
||||||
```javascript
|
|
||||||
await setOrder("xxx-5")
|
|
||||||
// 为满员队伍下发订单
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 队伍状态判断逻辑
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
const getTeamStatus = (teamId, lackList, successList) => {
|
|
||||||
if (successList.includes(teamId)) {
|
|
||||||
return 'success' // 已满员
|
|
||||||
} else if (lackList.includes(teamId)) {
|
|
||||||
return 'pending' // 进行中(未满员)
|
|
||||||
} else {
|
|
||||||
return 'empty' // 空队伍(理论上不会出现)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 队伍类型判断
|
|
||||||
|
|
||||||
根据队伍 ID 判断类型:
|
|
||||||
```javascript
|
|
||||||
const getTeamType = (teamId) => {
|
|
||||||
if (teamId.includes('-5')) {
|
|
||||||
return { type: 0, maxPerson: 5, typeName: '5人队' }
|
|
||||||
} else if (teamId.includes('-10')) {
|
|
||||||
return { type: 1, maxPerson: 10, typeName: '10人队' }
|
|
||||||
}
|
|
||||||
return { type: 0, maxPerson: 5, typeName: '未知' }
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 注意事项
|
|
||||||
|
|
||||||
1. **列表接口只返回 ID**:需要调用详情接口获取完整信息
|
|
||||||
2. **队伍 ID 格式**:`时间戳-人数`,可以从 ID 判断队伍类型
|
|
||||||
3. **状态判断**:通过 `lack_group_buy_list` 和 `success_group_buy_list` 判断队伍状态
|
|
||||||
4. **创建即有团长**:创建队伍时会自动添加一个团长(伪人)
|
|
||||||
5. **满员条件**:5人队需要5人,10人队需要10人
|
|
||||||
6. **下发订单**:只能对已满员的队伍下发订单
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 当前页面功能
|
|
||||||
|
|
||||||
`src/views/activity/GroupBuyActivity.vue` 已实现:
|
|
||||||
|
|
||||||
✅ 获取队伍列表(显示所有队伍及状态)
|
|
||||||
✅ 创建随机伪人队伍
|
|
||||||
✅ 添加随机伪人到队伍
|
|
||||||
✅ 查看队伍成员详情
|
|
||||||
✅ 为满员队伍下发订单
|
|
||||||
✅ 导出成功队伍信息
|
|
||||||
✅ 实时状态更新
|
|
||||||
|
|
||||||
所有功能都已根据实际 API 数据结构进行了适配!
|
|
||||||
+332
-2
@@ -7,6 +7,336 @@
|
|||||||
},
|
},
|
||||||
"tags": [],
|
"tags": [],
|
||||||
"paths": {
|
"paths": {
|
||||||
|
"/api/v1/admin/activity/group_buy/type/list": {
|
||||||
|
"get": {
|
||||||
|
"summary": "获取拼团活动类型列表",
|
||||||
|
"deprecated": false,
|
||||||
|
"description": "",
|
||||||
|
"tags": [],
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "page",
|
||||||
|
"in": "query",
|
||||||
|
"description": "获取页码 默认 1",
|
||||||
|
"required": false,
|
||||||
|
"example": "",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "count",
|
||||||
|
"in": "query",
|
||||||
|
"description": "获取条数 默认 10",
|
||||||
|
"required": false,
|
||||||
|
"example": "",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "key",
|
||||||
|
"in": "query",
|
||||||
|
"description": "关键词筛选",
|
||||||
|
"required": false,
|
||||||
|
"example": "",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "expire_time",
|
||||||
|
"in": "query",
|
||||||
|
"description": "过期时间筛选 时间戳",
|
||||||
|
"required": false,
|
||||||
|
"example": 0,
|
||||||
|
"schema": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "tag",
|
||||||
|
"in": "query",
|
||||||
|
"description": "标签筛选",
|
||||||
|
"required": false,
|
||||||
|
"example": "",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Authorization",
|
||||||
|
"in": "header",
|
||||||
|
"description": "",
|
||||||
|
"example": "Bearer {{token}}",
|
||||||
|
"schema": {
|
||||||
|
"type": "string",
|
||||||
|
"default": "Bearer {{token}}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"headers": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"security": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/v1/admin/activity/group_buy/type/tags": {
|
||||||
|
"get": {
|
||||||
|
"summary": "获取拼团活动类型tag列表",
|
||||||
|
"deprecated": false,
|
||||||
|
"description": "",
|
||||||
|
"tags": [],
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "Authorization",
|
||||||
|
"in": "header",
|
||||||
|
"description": "",
|
||||||
|
"example": "Bearer {{token}}",
|
||||||
|
"schema": {
|
||||||
|
"type": "string",
|
||||||
|
"default": "Bearer {{token}}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"security": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/v1/admin/activity/group_buy/type/add": {
|
||||||
|
"post": {
|
||||||
|
"summary": "新增拼团活动类型",
|
||||||
|
"deprecated": false,
|
||||||
|
"description": "",
|
||||||
|
"tags": [],
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "Authorization",
|
||||||
|
"in": "header",
|
||||||
|
"description": "",
|
||||||
|
"example": "Bearer {{token}}",
|
||||||
|
"schema": {
|
||||||
|
"type": "string",
|
||||||
|
"default": "Bearer {{token}}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"requestBody": {
|
||||||
|
"content": {
|
||||||
|
"multipart/form-data": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"description": "名称",
|
||||||
|
"example": "",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"note": {
|
||||||
|
"description": "备注",
|
||||||
|
"example": "",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"price": {
|
||||||
|
"description": "价格 /分",
|
||||||
|
"example": "",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"renew_price": {
|
||||||
|
"description": "续费价格 /分",
|
||||||
|
"example": "",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"max_person": {
|
||||||
|
"description": "拼团需要人数",
|
||||||
|
"example": "",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"tag": {
|
||||||
|
"description": "标签",
|
||||||
|
"example": "",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"expire_time": {
|
||||||
|
"description": "活动过期时间",
|
||||||
|
"example": 0,
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"headers": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"security": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/v1/admin/activity/group_buy/type/update": {
|
||||||
|
"post": {
|
||||||
|
"summary": "修改拼团活动类型",
|
||||||
|
"deprecated": false,
|
||||||
|
"description": "",
|
||||||
|
"tags": [],
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "Authorization",
|
||||||
|
"in": "header",
|
||||||
|
"description": "",
|
||||||
|
"example": "Bearer {{token}}",
|
||||||
|
"schema": {
|
||||||
|
"type": "string",
|
||||||
|
"default": "Bearer {{token}}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"requestBody": {
|
||||||
|
"content": {
|
||||||
|
"multipart/form-data": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"description": "ID 编号",
|
||||||
|
"example": "",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"description": "名称",
|
||||||
|
"example": "",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"note": {
|
||||||
|
"description": "备注",
|
||||||
|
"example": "",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"price": {
|
||||||
|
"description": "价格 /分",
|
||||||
|
"example": "",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"renew_price": {
|
||||||
|
"description": "续费价格 /分",
|
||||||
|
"example": "",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"max_person": {
|
||||||
|
"description": "拼团需要人数",
|
||||||
|
"example": "",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"tag": {
|
||||||
|
"description": "标签",
|
||||||
|
"example": "",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"expire_time": {
|
||||||
|
"description": "活动过期时间",
|
||||||
|
"example": 0,
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"headers": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"security": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/v1/admin/activity/group_buy/type/delete": {
|
||||||
|
"delete": {
|
||||||
|
"summary": "删除拼团活动类型",
|
||||||
|
"deprecated": false,
|
||||||
|
"description": "",
|
||||||
|
"tags": [],
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "id",
|
||||||
|
"in": "query",
|
||||||
|
"description": "",
|
||||||
|
"required": false,
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Authorization",
|
||||||
|
"in": "header",
|
||||||
|
"description": "",
|
||||||
|
"example": "Bearer {{token}}",
|
||||||
|
"schema": {
|
||||||
|
"type": "string",
|
||||||
|
"default": "Bearer {{token}}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"headers": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"security": []
|
||||||
|
}
|
||||||
|
},
|
||||||
"/api/v1/admin/activity/group_buy/check": {
|
"/api/v1/admin/activity/group_buy/check": {
|
||||||
"get": {
|
"get": {
|
||||||
"summary": "检查队伍列表",
|
"summary": "检查队伍列表",
|
||||||
@@ -121,8 +451,8 @@
|
|||||||
"example": "",
|
"example": "",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"group_buy_type": {
|
"group_buy_type_id": {
|
||||||
"description": "队伍类型(0为5人队;1为10人队)",
|
"description": "队伍类型id",
|
||||||
"example": "",
|
"example": "",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user