147 lines
6.8 KiB
Vue
147 lines
6.8 KiB
Vue
<script setup lang="ts">
|
|
/**
|
|
* F006 拼团活动 - W10 A3 标准化
|
|
*
|
|
* W10 A3: 套 PageHeader/SearchBar 标准化模板
|
|
*
|
|
* 沿用老 vue other/groupbuy.vue 116 行:
|
|
* - 搜索: 活动名称
|
|
* - 表格列: name/enterpriseName/groupBeginTime/groupEndTime/type/createDate (+ status 1启用2停用)
|
|
* - 操作: 查看 / 启用停用 / 删除
|
|
* - 批量删除
|
|
* - /other/groupbuy 后端 404 → FALLBACK mock
|
|
*/
|
|
import { ref, onMounted, reactive } from 'vue'
|
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
|
import { httpGet, httpPost } from '@/utils/request'
|
|
import PageHeader from '@/components/PageHeader/PageHeader.vue'
|
|
import SearchBar from '@/components/SearchBar/SearchBar.vue'
|
|
|
|
interface Groupbuy {
|
|
id: string
|
|
name: string
|
|
enterpriseName: string
|
|
groupBeginTime: string
|
|
groupEndTime: string
|
|
type: string
|
|
status: number
|
|
createDate: string
|
|
raw: any
|
|
}
|
|
|
|
const STATUS_MAP: Record<number, { label: string; type: string }> = {
|
|
1: { label: '启用', type: 'success' },
|
|
2: { label: '停用', type: 'danger' }
|
|
}
|
|
|
|
const FALLBACK: Groupbuy[] = [
|
|
{ id: 'G001', name: '7月钢材拼团 - 三人成团', enterpriseName: '深圳科技股份有限公司', groupBeginTime: '2026-07-01 10:00:00', groupEndTime: '2026-07-15 18:00:00', type: '螺纹钢/盘螺/线材', status: 1, createDate: '2026-06-28 14:20:00', raw: {} },
|
|
{ id: 'G002', name: '水泥团购专场', enterpriseName: '上海制造企业', groupBeginTime: '2026-07-05 09:00:00', groupEndTime: '2026-07-20 18:00:00', type: '普通硅酸盐水泥 P.O 42.5', status: 1, createDate: '2026-06-30 11:15:00', raw: {} },
|
|
{ id: 'G003', name: '夏季建材促销', enterpriseName: '北京电子有限公司', groupBeginTime: '2026-06-15 00:00:00', groupEndTime: '2026-06-30 23:59:59', type: '砂石/水泥/砖块', status: 2, createDate: '2026-06-10 16:30:00', raw: {} },
|
|
{ id: 'G004', name: '装修材料拼团', enterpriseName: '广州工厂', groupBeginTime: '2026-07-10 10:00:00', groupEndTime: '2026-07-25 18:00:00', type: '板材/五金/涂料', status: 1, createDate: '2026-07-02 09:00:00', raw: {} },
|
|
{ id: 'G005', name: '企业大批量采购 - 钢材', enterpriseName: '杭州电子', groupBeginTime: '2026-08-01 10:00:00', groupEndTime: '2026-08-31 18:00:00', type: '热轧钢板', status: 1, createDate: '2026-07-03 14:45:00', raw: {} }
|
|
]
|
|
|
|
const list = ref<Groupbuy[]>([])
|
|
const total = ref(0)
|
|
const loading = ref(false)
|
|
const error = ref<string | null>(null)
|
|
const page = ref(1)
|
|
const limit = ref(10)
|
|
const filters = reactive({ name: '' })
|
|
const selection = ref<Groupbuy[]>([])
|
|
|
|
const viewVisible = ref(false)
|
|
const viewData = ref<Groupbuy | null>(null)
|
|
|
|
async function load() {
|
|
loading.value = true
|
|
error.value = null
|
|
try {
|
|
await new Promise(r => setTimeout(r, 200))
|
|
let rows = [...FALLBACK]
|
|
if (filters.name) rows = rows.filter(r => r.name.includes(filters.name))
|
|
list.value = rows
|
|
total.value = rows.length
|
|
} catch (e: any) {
|
|
error.value = e?.msg || e?.message || '加载失败'
|
|
list.value = FALLBACK
|
|
total.value = FALLBACK.length
|
|
} finally { loading.value = false }
|
|
}
|
|
|
|
function onSearch() { page.value = 1; load() }
|
|
function onReset() { filters.name = ''; load() }
|
|
function onPageChange(p: number) { page.value = p; load() }
|
|
function onLimitChange(l: number) { limit.value = l; load() }
|
|
function onSelectionChange(rows: Groupbuy[]) { selection.value = rows }
|
|
function onView(row: Groupbuy) { viewData.value = row; viewVisible.value = true }
|
|
function onToggleStatus(row: Groupbuy) {
|
|
const newStatus = row.status === 1 ? 2 : 1
|
|
ElMessageBox.confirm(`确认${newStatus === 1 ? '启用' : '停用'}「${row.name}」?`, '提示', { type: 'warning' }).then(async () => {
|
|
try { await httpPost('/other/groupbuy/update', { id: row.id, status: newStatus }); ElMessage.success(`${newStatus === 1 ? '启用' : '停用'}成功`); load() }
|
|
catch (e: any) { ElMessage.error(e?.msg || '操作失败') }
|
|
}).catch(() => {})
|
|
}
|
|
function onDelete(row: Groupbuy) {
|
|
ElMessageBox.confirm(`确认删除「${row.name}」?`, '提示', { type: 'warning' }).then(async () => {
|
|
try { await httpPost('/other/groupbuy/delete', { id: row.id }); ElMessage.success('已删除'); load() }
|
|
catch (e: any) { ElMessage.error(e?.msg || '删除失败') }
|
|
}).catch(() => {})
|
|
}
|
|
function onBatchDelete() {
|
|
if (selection.value.length === 0) { ElMessage.warning('请先选择要删除的活动'); return }
|
|
ElMessageBox.confirm(`确认批量删除选中的 ${selection.value.length} 个活动?`, '提示', { type: 'warning' }).then(async () => {
|
|
try { await httpPost('/other/groupbuy/delete', selection.value.map(s => s.id)); ElMessage.success(`已批量删除 ${selection.value.length} 个`); load() }
|
|
catch (e: any) { ElMessage.error(e?.msg || '批量删除失败') }
|
|
}).catch(() => {})
|
|
}
|
|
|
|
onMounted(load)
|
|
</script>
|
|
|
|
<template>
|
|
<div class="rr-page">
|
|
<PageHeader title="拼团活动" :sub="`拼团/团购活动管理 (共 ${total} 个)`">
|
|
<el-button type="danger" :disabled="selection.length === 0" @click="onBatchDelete">批量删除 ({{ selection.length }})</el-button>
|
|
</PageHeader>
|
|
|
|
<SearchBar
|
|
v-model:filters="filters"
|
|
:fields="[
|
|
{ key: 'name', label: '活动名称', type: 'text', placeholder: '请输入活动名称' }
|
|
]"
|
|
@search="onSearch"
|
|
@reset="onReset"
|
|
/>
|
|
|
|
<div class="rr-card">
|
|
<div class="rr-pagination">
|
|
<el-pagination :current-page="page" :page-sizes="[10, 20, 50, 100]" :page-size="limit" :total="total" layout="total, sizes, prev, pager, next, jumper" @size-change="onLimitChange" @current-change="onPageChange" />
|
|
</div>
|
|
</div>
|
|
|
|
<el-dialog v-model="viewVisible" title="活动详情" width="640px">
|
|
<el-descriptions v-if="viewData" :column="2" border>
|
|
<el-descriptions-item label="活动名称">{{ viewData.name }}</el-descriptions-item>
|
|
<el-descriptions-item label="活动商家">{{ viewData.enterpriseName }}</el-descriptions-item>
|
|
<el-descriptions-item label="开始时间">{{ viewData.groupBeginTime }}</el-descriptions-item>
|
|
<el-descriptions-item label="结束时间">{{ viewData.groupEndTime }}</el-descriptions-item>
|
|
<el-descriptions-item label="活动商品" :span="2">{{ viewData.type }}</el-descriptions-item>
|
|
<el-descriptions-item label="状态">
|
|
<el-tag :type="(STATUS_MAP[viewData.status]?.type as any)" size="small">{{ STATUS_MAP[viewData.status]?.label }}</el-tag>
|
|
</el-descriptions-item>
|
|
<el-descriptions-item label="创建时间">{{ viewData.createDate }}</el-descriptions-item>
|
|
</el-descriptions>
|
|
<template #footer>
|
|
<el-button @click="viewVisible = false">关闭</el-button>
|
|
</template>
|
|
</el-dialog>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped lang="scss">
|
|
.rr-page { max-width: 1400px; }
|
|
.rr-pagination { padding: 12px 20px; display: flex; justify-content: flex-end; border-top: 1px solid var(--border); }
|
|
</style>
|