|
@@ -8,16 +8,16 @@
|
|
|
<sa-search-simple
|
|
|
:searchFields="searchFields"
|
|
|
:defaultValues="defaultSearchValues"
|
|
|
- @search="(val) => getData(1, val)"
|
|
|
- @reset="getData(1)"
|
|
|
+ @search="handleSearch"
|
|
|
+ @reset="handleReset"
|
|
|
>
|
|
|
</sa-search-simple>
|
|
|
</div>
|
|
|
<el-tabs class="sa-tabs" v-model="currentStatus" @tab-change="handleTabChange">
|
|
|
- <el-tab-pane :label="`全部(${statusCount.all})`" name="all"></el-tab-pane>
|
|
|
- <el-tab-pane :label="`待开始(${statusCount.pending})`" name="pending"></el-tab-pane>
|
|
|
- <el-tab-pane :label="`进行中(${statusCount.active})`" name="active"></el-tab-pane>
|
|
|
- <el-tab-pane :label="`已结束(${statusCount.ended})`" name="ended"></el-tab-pane>
|
|
|
+ <el-tab-pane label="全部" name=""></el-tab-pane>
|
|
|
+ <el-tab-pane label="待开始" name="0"></el-tab-pane>
|
|
|
+ <el-tab-pane label="进行中" name="1"></el-tab-pane>
|
|
|
+ <el-tab-pane label="已结束" name="2"></el-tab-pane>
|
|
|
</el-tabs>
|
|
|
<div class="sa-title sa-flex sa-row-between">
|
|
|
<div class="label sa-flex">
|
|
@@ -47,45 +47,56 @@
|
|
|
<template #empty>
|
|
|
<sa-empty></sa-empty>
|
|
|
</template>
|
|
|
- <el-table-column type="selection" width="48" align="center"></el-table-column>
|
|
|
+ <el-table-column type="selection" align="center"></el-table-column>
|
|
|
<el-table-column
|
|
|
sortable="custom"
|
|
|
- prop="activity_no"
|
|
|
+ prop="id"
|
|
|
label="活动编号"
|
|
|
align="center"
|
|
|
></el-table-column>
|
|
|
- <el-table-column label="活动标题">
|
|
|
- <template #default="scope">
|
|
|
- <span class="sa-table-line-1">
|
|
|
- {{ scope.row.title || '--' }}
|
|
|
- </span>
|
|
|
- </template>
|
|
|
- </el-table-column>
|
|
|
+ <el-table-column label="活动标题" prop="name" width="150px" />
|
|
|
+
|
|
|
<el-table-column label="活动状态" align="center">
|
|
|
<template #default="scope">
|
|
|
- <el-tag :type="statusList.color[scope.row.status]">
|
|
|
- {{ scope.row.status_text || '--' }}
|
|
|
+ <el-tag :type="getStatusType(scope.row.activeState)">
|
|
|
+ {{ getStatusText(scope.row.activeState) }}
|
|
|
</el-tag>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
- <el-table-column sortable="custom" prop="start_time" label="开始时间" align="center">
|
|
|
+ <el-table-column label="拼团配置" align="center" width="220">
|
|
|
<template #default="scope">
|
|
|
- {{ scope.row.start_time || '--' }}
|
|
|
+ <div class="group-config">
|
|
|
+ <div class="config-item">
|
|
|
+ <span class="config-label">成团默认人数:</span>
|
|
|
+ <span class="config-value">{{ getGroupNumber(scope.row.content) }}人团</span>
|
|
|
+ </div>
|
|
|
+ <div class="config-item mt-6px">
|
|
|
+ <span class="config-label">开团倒计时结束:</span>
|
|
|
+ <span class="config-value"
|
|
|
+ >{{ getCountdownTime(scope.row.content) }}小时</span
|
|
|
+ >
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
- <el-table-column sortable="custom" prop="end_time" label="结束时间" align="center">
|
|
|
+ <el-table-column
|
|
|
+ sortable="custom"
|
|
|
+ prop="startTime"
|
|
|
+ label="活动开始时间"
|
|
|
+ align="center"
|
|
|
+ >
|
|
|
<template #default="scope">
|
|
|
- {{ scope.row.end_time || '--' }}
|
|
|
+ {{ scope.row.startTime || '--' }}
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
- <el-table-column label="商品数量" align="center">
|
|
|
+ <el-table-column sortable="custom" prop="endTime" label="活动结束时间" align="center">
|
|
|
<template #default="scope">
|
|
|
- <el-tag type="info" size="small"> {{ scope.row.goods_count || 0 }}个商品 </el-tag>
|
|
|
+ {{ scope.row.endTime || '--' }}
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
- <el-table-column label="预警通知" align="center">
|
|
|
+ <el-table-column label="创建时间" align="center">
|
|
|
<template #default="scope">
|
|
|
- {{ scope.row.warning_notice || '--' }}
|
|
|
+ {{ scope.row.createTime || '--' }}
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
<el-table-column label="操作" fixed="right">
|
|
@@ -139,42 +150,60 @@
|
|
|
import { onMounted, reactive, ref } from 'vue';
|
|
|
import { ElMessage, ElMessageBox } from 'element-plus';
|
|
|
import { useModal, usePagination } from '@/sheep/hooks';
|
|
|
- import { groupMockData } from '@/sheep/mock/group';
|
|
|
+ import { api } from '../marketing.service';
|
|
|
import groupEdit from './edit.vue';
|
|
|
import GoodsSelect from '@/app/shop/admin/goods/goods/select.vue';
|
|
|
|
|
|
const { pageData } = usePagination();
|
|
|
|
|
|
// 当前状态Tab
|
|
|
- const currentStatus = ref('all');
|
|
|
-
|
|
|
- // 状态统计
|
|
|
- const statusCount = ref({
|
|
|
- all: 0,
|
|
|
- pending: 0,
|
|
|
- active: 0,
|
|
|
- ended: 0,
|
|
|
- });
|
|
|
+ const currentStatus = ref('');
|
|
|
|
|
|
- // 状态列表配置
|
|
|
- const statusList = reactive({
|
|
|
- color: {
|
|
|
- all: '',
|
|
|
- pending: 'warning',
|
|
|
- active: 'success',
|
|
|
- ended: 'info',
|
|
|
- },
|
|
|
- });
|
|
|
+ // 状态配置
|
|
|
+ const statusConfig = {
|
|
|
+ 0: { text: '待开始', type: 'warning' },
|
|
|
+ 1: { text: '进行中', type: 'success' },
|
|
|
+ 2: { text: '已结束', type: 'info' },
|
|
|
+ };
|
|
|
+
|
|
|
+ // 获取状态显示
|
|
|
+ const getStatusType = (status) => statusConfig[status]?.type || 'info';
|
|
|
+ const getStatusText = (status) => statusConfig[status]?.text || '未知';
|
|
|
+
|
|
|
+ // 安全解析 content 字段
|
|
|
+ const parseContent = (content) => {
|
|
|
+ if (!content || content === '') {
|
|
|
+ return {};
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ return JSON.parse(content);
|
|
|
+ } catch (e) {
|
|
|
+ console.warn('Failed to parse content:', content, e);
|
|
|
+ return {};
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ // 获取成团人数
|
|
|
+ const getGroupNumber = (content) => {
|
|
|
+ const parsed = parseContent(content);
|
|
|
+ return parsed.groupNumber || '--';
|
|
|
+ };
|
|
|
+
|
|
|
+ // 获取倒计时时间
|
|
|
+ const getCountdownTime = (content) => {
|
|
|
+ const parsed = parseContent(content);
|
|
|
+ return parsed.countdownTime || '--';
|
|
|
+ };
|
|
|
|
|
|
// 搜索字段配置
|
|
|
const searchFields = reactive({
|
|
|
- title: {
|
|
|
+ name: {
|
|
|
type: 'input',
|
|
|
label: '活动标题',
|
|
|
placeholder: '请输入活动标题',
|
|
|
width: 200,
|
|
|
},
|
|
|
- activity_no: {
|
|
|
+ id: {
|
|
|
type: 'input',
|
|
|
label: '活动编号',
|
|
|
placeholder: '请输入活动编号',
|
|
@@ -184,9 +213,12 @@
|
|
|
|
|
|
// 默认搜索值
|
|
|
const defaultSearchValues = reactive({
|
|
|
- title: '',
|
|
|
- activity_no: '',
|
|
|
+ name: '',
|
|
|
+ id: '',
|
|
|
});
|
|
|
+
|
|
|
+ // 当前搜索条件
|
|
|
+ const currentSearchParams = ref({});
|
|
|
// 列表
|
|
|
const table = reactive({
|
|
|
data: [],
|
|
@@ -202,40 +234,34 @@
|
|
|
loading.value = true;
|
|
|
|
|
|
try {
|
|
|
- // 使用mock数据
|
|
|
- let mockData = [...groupMockData.list];
|
|
|
-
|
|
|
- // 根据当前状态过滤数据
|
|
|
- if (currentStatus.value !== 'all') {
|
|
|
- mockData = mockData.filter((item) => item.status === currentStatus.value);
|
|
|
- }
|
|
|
+ // 构建请求参数
|
|
|
+ const params = {
|
|
|
+ page: pageData.page,
|
|
|
+ size: pageData.size,
|
|
|
+ ...searchParams,
|
|
|
+ };
|
|
|
|
|
|
- // 根据搜索条件过滤
|
|
|
- if (searchParams.title) {
|
|
|
- mockData = mockData.filter((item) =>
|
|
|
- item.title.toLowerCase().includes(searchParams.title.toLowerCase()),
|
|
|
- );
|
|
|
+ // 根据当前状态添加筛选条件
|
|
|
+ if (currentStatus.value) {
|
|
|
+ params.activeState = parseInt(currentStatus.value);
|
|
|
}
|
|
|
- if (searchParams.activity_no) {
|
|
|
- mockData = mockData.filter((item) =>
|
|
|
- item.activity_no.toLowerCase().includes(searchParams.activity_no.toLowerCase()),
|
|
|
- );
|
|
|
- }
|
|
|
-
|
|
|
- // 模拟分页
|
|
|
- const total = mockData.length;
|
|
|
- const start = (pageData.page - 1) * pageData.size;
|
|
|
- const end = start + pageData.size;
|
|
|
- const paginatedData = mockData.slice(start, end);
|
|
|
|
|
|
- // 设置数据
|
|
|
- table.data = paginatedData;
|
|
|
- pageData.total = total;
|
|
|
+ // 使用 CRUD 的 list 方法
|
|
|
+ const { code, data, message } = await api.group.list(params);
|
|
|
|
|
|
- // 更新状态统计
|
|
|
- statusCount.value = { ...groupMockData.statusCount };
|
|
|
+ if (code === '200') {
|
|
|
+ table.data = data.list || data || [];
|
|
|
+ pageData.total = data.total || 0;
|
|
|
+ } else {
|
|
|
+ ElMessage.error(message || '获取数据失败');
|
|
|
+ table.data = [];
|
|
|
+ pageData.total = 0;
|
|
|
+ }
|
|
|
} catch (error) {
|
|
|
console.error('获取数据失败:', error);
|
|
|
+ ElMessage.error('获取数据失败');
|
|
|
+ table.data = [];
|
|
|
+ pageData.total = 0;
|
|
|
} finally {
|
|
|
loading.value = false;
|
|
|
}
|
|
@@ -244,7 +270,33 @@
|
|
|
// Tab切换处理
|
|
|
const handleTabChange = (tabName) => {
|
|
|
currentStatus.value = tabName;
|
|
|
- getData(1);
|
|
|
+
|
|
|
+ // 构建筛选参数
|
|
|
+ const statusParams = tabName ? { activeState: parseInt(tabName) } : {};
|
|
|
+ const allParams = { ...currentSearchParams.value, ...statusParams };
|
|
|
+
|
|
|
+ getData(1, allParams);
|
|
|
+ };
|
|
|
+
|
|
|
+ // 搜索处理
|
|
|
+ const handleSearch = (searchParams) => {
|
|
|
+ currentSearchParams.value = searchParams;
|
|
|
+
|
|
|
+ // 构建筛选参数
|
|
|
+ const statusParams = currentStatus.value ? { activeState: parseInt(currentStatus.value) } : {};
|
|
|
+ const allParams = { ...searchParams, ...statusParams };
|
|
|
+
|
|
|
+ getData(1, allParams);
|
|
|
+ };
|
|
|
+
|
|
|
+ // 重置搜索
|
|
|
+ const handleReset = () => {
|
|
|
+ currentSearchParams.value = {};
|
|
|
+
|
|
|
+ // 构建筛选参数
|
|
|
+ const statusParams = currentStatus.value ? { activeState: parseInt(currentStatus.value) } : {};
|
|
|
+
|
|
|
+ getData(1, statusParams);
|
|
|
};
|
|
|
// table 字段排序
|
|
|
function fieldFilter({ prop, order }) {
|
|
@@ -294,36 +346,42 @@
|
|
|
}
|
|
|
|
|
|
// 设置商品
|
|
|
- function setGoods(row) {
|
|
|
- useModal(
|
|
|
- GoodsSelect,
|
|
|
- {
|
|
|
- title: '选择商品',
|
|
|
- multiple: true,
|
|
|
- ids: row.goods_ids || [], // 已选择的商品ID
|
|
|
- },
|
|
|
- {
|
|
|
- confirm: (res) => {
|
|
|
- // 更新活动的商品列表
|
|
|
- updateActivityGoods(row.id, res.data);
|
|
|
+ async function setGoods(row) {
|
|
|
+ const { code, data } = await api.group.getActivityProductIds(row.id);
|
|
|
+ if (code == '200') {
|
|
|
+ console.log(data);
|
|
|
+ useModal(
|
|
|
+ GoodsSelect,
|
|
|
+ {
|
|
|
+ title: '选择商品',
|
|
|
+ multiple: true,
|
|
|
+ ids: data || [], // 已选择的商品ID
|
|
|
},
|
|
|
- },
|
|
|
- );
|
|
|
+ {
|
|
|
+ confirm: (res) => {
|
|
|
+ console.log(res);
|
|
|
+ return;
|
|
|
+ // 更新活动的商品列表
|
|
|
+ updateActivityGoods(row.id, res.data);
|
|
|
+ },
|
|
|
+ },
|
|
|
+ );
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
// 更新活动商品
|
|
|
async function updateActivityGoods(activityId, goodsList) {
|
|
|
try {
|
|
|
- // 这里可以调用API更新活动商品
|
|
|
- // 暂时使用mock数据模拟
|
|
|
- const goodsIds = goodsList.map((item) => item.id);
|
|
|
- const result = groupMockData.updateGoods(activityId, goodsIds, goodsList);
|
|
|
+ // 使用 CRUD 的 edit 方法更新活动商品
|
|
|
+ const productIds = goodsList.map((item) => ({ productId: item.id }));
|
|
|
|
|
|
- if (result.code == '200') {
|
|
|
+ const { code, message } = await api.group.addActivityProduct(activityId, productIds);
|
|
|
+
|
|
|
+ if (code === '200') {
|
|
|
ElMessage.success('商品设置成功');
|
|
|
getData(); // 刷新列表
|
|
|
} else {
|
|
|
- ElMessage.error(result.msg);
|
|
|
+ ElMessage.error(message || '设置商品失败');
|
|
|
}
|
|
|
} catch (error) {
|
|
|
console.error('设置商品失败:', error);
|
|
@@ -333,13 +391,14 @@
|
|
|
|
|
|
// 删除单条记录
|
|
|
async function deleteRow(id) {
|
|
|
+ console.log(api.group);
|
|
|
try {
|
|
|
- const result = groupMockData.delete(id);
|
|
|
- if (result.code == '200') {
|
|
|
- ElMessage.success(result.msg);
|
|
|
+ const { code, message } = await api.group.delete({ id });
|
|
|
+ if (code === '200') {
|
|
|
+ ElMessage.success('删除成功');
|
|
|
getData();
|
|
|
} else {
|
|
|
- ElMessage.error(result.msg);
|
|
|
+ ElMessage.error(message || '删除失败');
|
|
|
}
|
|
|
} catch (error) {
|
|
|
console.error('删除失败:', error);
|
|
@@ -370,13 +429,13 @@
|
|
|
// 批量删除方法
|
|
|
async function batchDeleteRows(ids) {
|
|
|
try {
|
|
|
- const result = groupMockData.batchDelete(ids);
|
|
|
- if (result.code == '200') {
|
|
|
- ElMessage.success(result.msg);
|
|
|
+ const { code, message } = await api.group.batchDelete(ids);
|
|
|
+ if (code === '200') {
|
|
|
+ ElMessage.success('批量删除成功');
|
|
|
getData();
|
|
|
table.selected = []; // 清空选中项
|
|
|
} else {
|
|
|
- ElMessage.error(result.msg);
|
|
|
+ ElMessage.error(message || '批量删除失败');
|
|
|
}
|
|
|
} catch (error) {
|
|
|
console.error('批量删除失败:', error);
|
|
@@ -422,9 +481,15 @@
|
|
|
display: -webkit-box;
|
|
|
-webkit-box-orient: vertical;
|
|
|
-webkit-line-clamp: 1;
|
|
|
+ line-clamp: 1;
|
|
|
overflow: hidden;
|
|
|
text-overflow: ellipsis;
|
|
|
word-break: break-all;
|
|
|
}
|
|
|
+
|
|
|
+ .activity-info {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ }
|
|
|
}
|
|
|
</style>
|