<template>
|
<div class="activity-management">
|
<Card>
|
<!-- 搜索表单 -->
|
<Form
|
ref="searchForm"
|
@keydown.enter.native="handleSearch"
|
:model="searchForm"
|
inline
|
:label-width="80"
|
class="search-form"
|
>
|
<FormItem label="活动名称" prop="activityName">
|
<Input
|
type="text"
|
v-model="searchForm.activityName"
|
placeholder="请输入活动名称"
|
clearable
|
@on-clear="handleSearch"
|
style="width: 180px"
|
/>
|
</FormItem>
|
<FormItem label="活动类型" prop="activityType">
|
<Select
|
v-model="searchForm.activityType"
|
placeholder="请选择活动类型"
|
style="width: 180px"
|
clearable
|
@on-clear="handleSearch"
|
@on-change="handleSearch"
|
>
|
<Option
|
v-for="item in typeSelect"
|
:value="item.value"
|
:key="item.id"
|
>
|
{{ item.label }}
|
</Option>
|
</Select>
|
</FormItem>
|
<FormItem label="报名开始时间" prop="reportStartTime">
|
<DatePicker
|
:value="searchForm.reportStartTime"
|
type="datetime"
|
placeholder="选择开始时间"
|
style="width: 180px"
|
@on-change="handleSearch('reportStart', $event)"
|
@on-clear="handleSearch"
|
></DatePicker>
|
</FormItem>
|
<FormItem label="报名结束时间" prop="reportEndTime">
|
<DatePicker
|
:value="searchForm.reportEndTime"
|
type="datetime"
|
placeholder="选择结束时间"
|
style="width: 180px"
|
@on-clear="handleSearch"
|
@on-change="handleSearch('reportEnd', $event)"
|
></DatePicker>
|
</FormItem>
|
<Button
|
@click="handleSearch"
|
type="primary"
|
icon="ios-search"
|
class="search-btn"
|
>搜索</Button>
|
<Button
|
@click="resetSearch"
|
icon="md-refresh"
|
style="margin-left: 8px"
|
>重置</Button>
|
</Form>
|
|
<!-- 操作按钮 -->
|
<Row class="operation">
|
<Button @click="openAdd" type="primary" icon="md-add">新增活动</Button>
|
<Button @click="delBatch" type="error" icon="md-trash" :disabled="selectCount === 0">批量删除</Button>
|
</Row>
|
|
<!-- 活动表格 -->
|
<Table
|
:loading="loading"
|
border
|
:columns="columns"
|
:data="activityList"
|
ref="table"
|
@on-selection-change="showSelect"
|
class="activity-table"
|
>
|
<!-- 封面展示插槽 -->
|
<template slot-scope="{ row }" slot="url">
|
<div class="media-container">
|
<!-- 图片类型 -->
|
<template v-if="row.coverType === 'image'">
|
<img
|
:src="row.url"
|
alt="活动封面"
|
class="thumbnail"
|
@click="previewImage(row.url)"
|
>
|
</template>
|
<!-- 视频类型 -->
|
<template v-else-if="row.coverType === 'video'">
|
<video
|
:src="row.url"
|
class="video-player"
|
controls
|
></video>
|
</template>
|
<!-- 文字类型 -->
|
<template v-else>
|
<div class="text-cover">{{ row.cover || '暂无封面内容' }}</div>
|
</template>
|
</div>
|
</template>
|
|
<!-- 操作按钮插槽 -->
|
<template slot-scope="{ row }" slot="action">
|
<div class="action-btns">
|
<Button
|
type="primary"
|
size="small"
|
@click="changeRecommend(row, row.recommend ? '取消推荐' : '推荐')"
|
:loading="row.recommendLoading"
|
>
|
{{ row.recommend ? '取消推荐' : '推荐' }}
|
</Button>
|
<Button
|
type="primary"
|
size="small"
|
@click="changeStatus(row, row.publish ? '下架' : '发布')"
|
:loading="row.statusLoading"
|
>
|
{{ row.publish ? '下架' : '发布' }}
|
</Button>
|
<Button
|
type="info"
|
size="small"
|
@click="detail(row)"
|
>详情</Button>
|
<Button
|
type="info"
|
size="small"
|
@click="openEdit(row)"
|
>编辑</Button>
|
<Button
|
type="error"
|
size="small"
|
@click="delById(row)"
|
>删除</Button>
|
<Button
|
type="success"
|
size="small"
|
@click="openMembersModal(row)"
|
>报名人员</Button>
|
</div>
|
</template>
|
</Table>
|
|
<!-- 分页 -->
|
<Row type="flex" justify="end" class="page-footer">
|
<Page
|
:current="searchForm.pageNumber"
|
:total="total"
|
:page-size="searchForm.pageSize"
|
@on-change="changePage"
|
@on-page-size-change="changePageSize"
|
:page-size-opts="[10, 20, 50]"
|
size="small"
|
show-total
|
show-elevator
|
show-sizer
|
></Page>
|
</Row>
|
|
<!-- 活动编辑/新增模态框 -->
|
<Modal
|
v-model="modelShow"
|
:title="modelTitle"
|
@on-cancel="modelClose"
|
width="800"
|
:mask-closable="false"
|
>
|
<Form ref="form" :model="activityFrom" :label-width="100" :rules="rules">
|
<Row :gutter="16">
|
<Col span="12">
|
<FormItem label="活动名称" prop="activityName">
|
<Input
|
v-model="activityFrom.activityName"
|
placeholder="请输入活动名称"
|
clearable
|
/>
|
</FormItem>
|
</Col>
|
<Col span="12">
|
<FormItem label="活动类型" prop="activityType" :label-width="100">
|
<Select
|
v-model="activityFrom.activityType"
|
placeholder="请选择活动类型"
|
clearable
|
>
|
<Option
|
v-for="item in typeSelect"
|
:value="item.value"
|
:key="item.id"
|
>
|
{{ item.label }}
|
</Option>
|
</Select>
|
</FormItem>
|
</Col>
|
<Col span="12">
|
<FormItem label="报名时间段" prop="reportTime">
|
<DatePicker
|
v-model="activityFrom.reportTime"
|
type="datetimerange"
|
format="yyyy-MM-dd HH:mm"
|
placeholder="请选择报名时间段"
|
style="width: 100%"
|
></DatePicker>
|
</FormItem>
|
</Col>
|
<Col span="12">
|
<FormItem label="活动时间段" prop="time">
|
<DatePicker
|
v-model="activityFrom.time"
|
type="datetimerange"
|
format="yyyy-MM-dd HH:mm"
|
placeholder="请选择活动时间段"
|
style="width: 100%"
|
></DatePicker>
|
</FormItem>
|
</Col>
|
<Col span="12">
|
<FormItem label="封面类型" prop="coverType" :labelWidth="100">
|
<Select
|
v-model="coverType"
|
placeholder="请选择封面类型"
|
@on-change="handleCoverTypeChange"
|
>
|
<Option
|
v-for="item in coverTypeOptions"
|
:value="item.value"
|
:key="item.id"
|
>
|
{{ item.value }}
|
</Option>
|
</Select>
|
</FormItem>
|
</Col>
|
<Col span="24" v-if="coverType === '输入文字封面'">
|
<FormItem label="封面文字" prop="cover">
|
<Input
|
v-model="activityFrom.cover"
|
type="textarea"
|
:rows="2"
|
placeholder="请输入封面文字"
|
style="width: 50%"
|
/>
|
</FormItem>
|
</Col>
|
<Col span="24" v-if="coverType === '选择文件封面'">
|
<FormItem label="上传封面" prop="cover">
|
<Upload
|
:before-upload="handleBeforeUpload"
|
:format="['jpg','jpeg','png','gif','mp4','mov']"
|
:max-size="20480"
|
action=""
|
accept="image/*,video/*"
|
>
|
<Button icon="ios-cloud-upload-outline">上传封面文件</Button>
|
<div class="upload-tip">支持图片或视频文件,最大20MB</div>
|
</Upload>
|
<div v-if="file" class="upload-file-info">
|
已选文件: {{ file.name }}
|
<Button type="text" @click="handleRemove">删除</Button>
|
</div>
|
</FormItem>
|
</Col>
|
<!-- 这两个表单项在同一Row内,会显示在同一行 -->
|
<Col span="12">
|
<FormItem label="人数限制" prop="limitUserNum">
|
<InputNumber
|
v-model="activityFrom.limitUserNum"
|
:min="1"
|
placeholder="请输入最大人数"
|
style="width: 100%"
|
/>
|
</FormItem>
|
</Col>
|
<Col span="12">
|
<FormItem label="活动地点" prop="activityLocation">
|
<Input
|
v-model="activityFrom.activityLocation"
|
placeholder="请输入活动地点"
|
/>
|
</FormItem>
|
</Col>
|
<Col span="24">
|
<FormItem label="活动内容:" prop="activityContent">
|
<editor ref="editor" @input="getReason" />
|
</FormItem>
|
</Col>
|
</Row>
|
</Form>
|
|
<div slot="footer">
|
<Button @click="modelClose">取消</Button>
|
<Button type="primary" :loading="submitLoading" @click="saveOrUpdate">提交</Button>
|
</div>
|
</Modal>
|
|
<!-- 报名人员模态框 -->
|
<Modal
|
v-model="membersModelShow"
|
:title="membersModelTitle"
|
@on-cancel="membersModelClose"
|
width="1000"
|
class="members-modal"
|
>
|
<Table
|
:loading="membersLoading"
|
border
|
:columns="membersColumns"
|
:data="membersList"
|
class="members-table"
|
></Table>
|
<Row type="flex" justify="end" class="page-footer">
|
<Page
|
:current="memberForm.pageNumber"
|
:total="memberTotal"
|
:page-size="memberForm.pageSize"
|
@on-change="memberChangePage"
|
@on-page-size-change="memberChangePageSize"
|
:page-size-opts="[10, 20, 50]"
|
size="small"
|
show-total
|
show-elevator
|
show-sizer
|
></Page>
|
</Row>
|
</Modal>
|
|
<Modal
|
v-model="infoModelShow"
|
:title="modelTitle"
|
@on-cancel="infoModelClose"
|
width="800"
|
:mask-closable="false"
|
>
|
<div class="detail-container">
|
<Row :gutter="16">
|
<Col span="12">
|
<div class="detail-item">
|
<label>活动名称:</label>
|
<span>{{ activityInfo.activityName || '-' }}</span>
|
</div>
|
</Col>
|
<Col span="12">
|
<div class="detail-item">
|
<label>活动类型:</label>
|
<span>{{activityInfo.activityType === 'online' ? '线上':'线下'}}</span>
|
</div>
|
</Col>
|
<Col span="12">
|
<div class="detail-item">
|
<label>报名时间段:</label>
|
<span>{{ activityInfo.reportStartTime }} - {{ activityInfo.reportEndTime }}</span>
|
</div>
|
</Col>
|
<Col span="12">
|
<div class="detail-item">
|
<label>活动时间段:</label>
|
<span>{{ activityInfo.startTime }} - {{ activityInfo.endTime }}</span>
|
</div>
|
</Col>
|
|
<Col span="24" v-if="coverType === '输入文字封面'">
|
<div class="detail-item">
|
<label>封面文字:</label>
|
<span>{{ activityInfo.cover || '-' }}</span>
|
</div>
|
</Col>
|
<Col span="24" v-if="coverType === '选择文件封面'">
|
<div class="detail-item">
|
<label>上传封面:</label>
|
<span>{{ activityInfo.cover }}</span>
|
</div>
|
</Col>
|
<Col span="12">
|
<div class="detail-item">
|
<label>人数限制:</label>
|
<span>{{ activityInfo.limitUserNum || '无限制' }}</span>
|
</div>
|
</Col>
|
<Col span="12">
|
<div class="detail-item">
|
<label>活动地点:</label>
|
<span>{{ activityInfo.activityLocation || '-' }}</span>
|
</div>
|
</Col>
|
<Col span="24">
|
<div class="detail-item">
|
<label>活动内容:</label>
|
<div
|
class="activity-content"
|
v-html="activityInfo.activityContent || '无内容'"
|
></div>
|
</div>
|
</Col>
|
</Row>
|
</div>
|
|
<div slot="footer">
|
<Button @click="infoModelClose">关闭</Button>
|
</div>
|
</Modal>
|
|
|
<!-- 图片预览模态框 -->
|
<Modal v-model="previewVisible" title="图片预览" footer-hide>
|
<img :src="previewImageUrl" style="width: 100%">
|
</Modal>
|
</Card>
|
</div>
|
</template>
|
|
<script>
|
import {
|
getActivityList,
|
addActivity,
|
editActivity,
|
delActivityById,
|
activityChangeStatus,
|
activityChangeRecommend,
|
activityMembersPage
|
} from "@/api/activity.js"
|
import Editor from '@/components/editor/index.vue'
|
import { uploadFileByLmk, delByKey } from "@/api/common.js"
|
export default {
|
name: "ActivityManagement",
|
components: {Editor},
|
data() {
|
return {
|
infoModelShow:false,
|
|
loading: false,
|
membersLoading: false,
|
submitLoading: false,
|
|
// 搜索表单
|
searchForm: {
|
activityName: '',
|
activityType: '',
|
reportStartTime: '',
|
reportEndTime: '',
|
pageNumber: 1,
|
pageSize: 10
|
},
|
|
// 活动列表数据
|
activityList: [],
|
total: 0,
|
selectList: [],
|
selectCount: 0,
|
|
// 活动类型选项
|
typeSelect: [
|
{ id: 1, value: 'online',label:'线上' },
|
{ id: 2, value: 'offline',label:'线下' }
|
],
|
|
// 封面类型选项
|
coverTypeOptions: [
|
{ id: 1, value: '输入文字封面' },
|
{ id: 2, value: '选择文件封面' }
|
],
|
coverType: '',
|
file: null,
|
|
// 活动表单
|
activityFrom: {
|
id: '',
|
activityName: '',
|
activityType: '',
|
reportTime: [],
|
time: [],
|
activityContent: '',
|
cover: '',
|
coverType: '',
|
status: '',
|
reportStartTime: '',
|
reportEndTime: '',
|
startTime: '',
|
endTime: '',
|
recommend: false,
|
limitUserNum: 0,
|
activityLocation: '',
|
},
|
activityInfo: {
|
id: '',
|
activityName: '',
|
activityType: '',
|
reportTime: [],
|
time: [],
|
activityContent: '',
|
cover: '',
|
coverType: '',
|
status: '',
|
reportStartTime: '',
|
reportEndTime: '',
|
startTime: '',
|
endTime: '',
|
recommend: false,
|
limitUserNum: 0,
|
activityLocation: '',
|
},
|
|
// 表单验证规则
|
rules: {
|
activityName: [
|
{ required: true, message: '请输入活动名称', trigger: 'blur' },
|
{ max: 50, message: '长度不能超过50个字符', trigger: 'blur' }
|
],
|
activityType: [
|
{ required: true, message: '请选择活动类型', trigger: 'change' }
|
],
|
reportTime: [
|
{ type: 'array', required: true, message: '请选择报名时间段', trigger: 'change' },
|
{ validator: this.validateReportTime, trigger: 'change' }
|
],
|
time: [
|
{ type: 'array', required: true, message: '请选择活动时间段', trigger: 'change' },
|
{ validator: this.validateActivityTime, trigger: 'change' }
|
],
|
cover: [
|
{ required: true, message: '请输入封面内容', trigger: 'blur' }
|
],
|
coverType: [
|
{ required: true, message: '请选择封面类型', trigger: 'blur' }
|
],
|
limitUserNum: [
|
{ required: true, type: 'number', message: '请输入人数限制', trigger: 'blur' },
|
{ type: 'number', min: 1, message: '人数不能少于1人', trigger: 'blur' }
|
],
|
activityLocation: [
|
{ required: true, message: '请输入活动地点', trigger: 'blur' },
|
{ max: 100, message: '长度不能超过100个字符', trigger: 'blur' }
|
],
|
activityContent: [
|
{ required: true, message: '请输入活动内容', trigger: 'blur' }
|
]
|
},
|
|
// 表格列配置
|
columns: [
|
{
|
type: 'selection',
|
width: 60,
|
align: 'center'
|
},
|
{
|
title: '活动名称',
|
key: 'activityName',
|
minWidth: 120,
|
tooltip: true
|
},
|
{
|
title: '活动类型',
|
key: 'activityType',
|
width: 100,
|
align: 'center',
|
render: (h, params) => {
|
return h('Tag', {
|
}, params.row.activityType === 'online' ? '线上' : '线下')
|
}
|
},
|
{
|
title: '推荐',
|
key: 'recommend',
|
width: 80,
|
align: 'center',
|
render: (h, params) => {
|
return h('Tag', {
|
props: {
|
color: params.row.recommend ? 'green' : 'default'
|
}
|
}, params.row.recommend ? '是' : '否')
|
}
|
},
|
{
|
title: '发布',
|
key: 'publish',
|
width: 100,
|
align: 'center',
|
render: (h, params) => {
|
return h('Tag', {
|
props: {
|
color: params.row.publish ? 'green' : 'default'
|
}
|
}, params.row.publish ? '已发布' : '未发布')
|
}
|
},
|
{
|
title: '状态',
|
key: 'status',
|
width: 100,
|
align: 'center',
|
render: (h, params) => {
|
const status = params.row.status;
|
const statusMap = {
|
'noStart': { text: '未开始', color: 'default' },
|
'report': { text: '报名中', color: 'green' },
|
'inProgress':{ text:'进行中',color:'cyan'},
|
'end': { text: '已结束', color: 'red' }
|
};
|
const currentStatus = statusMap[status] || { text: status, color: 'default' };
|
return h('Tag', {
|
props: {
|
color: currentStatus.color
|
}
|
}, currentStatus.text);
|
}
|
},
|
{
|
title: '活动时间段',
|
key: 'activityTimeRange',
|
width: 300,
|
render: (h, params) => {
|
return h('div', [
|
h('div', `开始: ${this.formatDate(params.row.startTime)}`),
|
h('div', `结束: ${this.formatDate(params.row.endTime)}`)
|
])
|
}
|
},
|
{
|
title: '封面',
|
key: 'url',
|
slot: 'url',
|
width: 150,
|
align: 'center'
|
},
|
{
|
title: '封面类型',
|
key: 'coverType',
|
width: 100,
|
align: 'center',
|
render: (h, params) => {
|
const typeMap = {
|
text: '文本',
|
video: '视频',
|
image: '图片'
|
};
|
const text = typeMap[params.row.coverType] || params.row.coverType;
|
return h('span', text);
|
}
|
},
|
{
|
title: '人数限制',
|
key: 'limitUserNum',
|
width: 100,
|
align: 'center'
|
},
|
{
|
title: '活动地点',
|
key: 'activityLocation',
|
minWidth: 120,
|
tooltip: true
|
},
|
{
|
title: '操作',
|
slot: 'action',
|
width: 280,
|
align: 'center',
|
fixed: 'right'
|
}
|
],
|
|
// 报名人员相关
|
membersModelShow: false,
|
membersModelTitle: '',
|
membersList: [],
|
memberForm: {
|
id: '',
|
pageNumber: 1,
|
pageSize: 10
|
},
|
memberTotal: 0,
|
membersColumns: [
|
{
|
type: 'selection',
|
width: 60,
|
align: 'center'
|
},
|
{
|
title: '用户名',
|
key: 'username',
|
minWidth: 100
|
},
|
{
|
title: '昵称',
|
key: 'nickName',
|
minWidth: 100
|
},
|
{
|
title: '性别',
|
key: 'sex',
|
width: 80,
|
render: (h, params) => {
|
return h('Tag', {
|
props: {
|
color: params.row.sex === 1 ? 'blue' : 'magenta'
|
}
|
}, params.row.sex === 1 ? '男' : '女')
|
}
|
},
|
{
|
title: '地区',
|
key: 'region',
|
minWidth: 120
|
},
|
{
|
title: '状态',
|
key: 'disabled',
|
width: 100,
|
render: (h, params) => {
|
return h('Tag', {
|
props: {
|
color: params.row.disabled ? 'red' : 'green'
|
}
|
}, params.row.disabled ? '禁用' : '正常')
|
}
|
}
|
],
|
|
// 图片预览
|
previewVisible: false,
|
previewImageUrl: '',
|
|
// 模态框控制
|
modelShow: false,
|
modelTitle: ''
|
}
|
},
|
mounted() {
|
this.init()
|
},
|
methods: {
|
detail(row){
|
this.modelTitle = '活动详情'
|
this.infoModelShow = true
|
this.activityInfo = row
|
},
|
// 获取富文本编辑器的内容
|
getReason(content) {
|
this.activityFrom.activityContent = content
|
},
|
// 初始化数据
|
init() {
|
this.getActivityList()
|
},
|
|
// 获取活动列表
|
getActivityList() {
|
this.loading = true
|
getActivityList(this.searchForm).then(res => {
|
this.loading = false
|
if (res.code === 200) {
|
// 为每一行添加loading状态
|
this.activityList = res.data.map(item => ({
|
...item,
|
recommendLoading: false,
|
statusLoading: false
|
}))
|
this.total = res.total
|
}
|
}).catch(() => {
|
this.loading = false
|
})
|
},
|
|
// 搜索活动
|
handleSearch(type, value) {
|
if (type === 'reportStart') {
|
this.searchForm.reportStartTime = value
|
} else if (type === 'reportEnd') {
|
this.searchForm.reportEndTime = value
|
}
|
|
this.searchForm.pageNumber = 1
|
this.getActivityList()
|
},
|
|
// 重置搜索
|
resetSearch() {
|
this.$refs.searchForm.resetFields()
|
this.searchForm.pageNumber = 1
|
this.getActivityList()
|
},
|
|
// 改变页码
|
changePage(page) {
|
this.searchForm.pageNumber = page
|
this.getActivityList()
|
},
|
|
// 改变每页条数
|
changePageSize(pageSize) {
|
this.searchForm.pageNumber = 1
|
this.searchForm.pageSize = pageSize
|
this.getActivityList()
|
},
|
|
// 表格选择变化
|
showSelect(selection) {
|
this.selectList = selection.map(item => item.id)
|
this.selectCount = selection.length
|
},
|
|
// 打开新增模态框
|
openAdd() {
|
this.modelTitle = '新增活动'
|
this.modelShow = true
|
this.coverType = '输入文字封面'
|
this.file = null
|
this.$refs.form.resetFields()
|
this.activityFrom.id = ''
|
},
|
|
// 打开编辑模态框
|
openEdit(row) {
|
this.modelTitle = '编辑活动'
|
this.modelShow = true
|
this.$nextTick(() => {
|
this.$refs.form.resetFields()
|
// 填充表单数据
|
this.activityFrom = {
|
id: row.id,
|
activityName: row.activityName,
|
activityType: row.activityType,
|
reportTime: [
|
this.formatDate(row.reportStartTime, 'YYYY-MM-DD HH:mm:ss'),
|
this.formatDate(row.reportEndTime, 'YYYY-MM-DD HH:mm:ss')
|
],
|
time: [
|
this.formatDate(row.startTime, 'YYYY-MM-DD HH:mm:ss'),
|
this.formatDate(row.endTime, 'YYYY-MM-DD HH:mm:ss')
|
],
|
activityContent: row.activityContent,
|
cover: row.cover,
|
coverType: row.coverType,
|
status: row.status,
|
reportStartTime: row.reportStartTime,
|
reportEndTime: row.reportEndTime,
|
startTime: row.startTime,
|
endTime: row.endTime,
|
recommend: row.recommend,
|
limitUserNum: row.limitUserNum,
|
activityLocation: row.activityLocation
|
}
|
this.$refs.editor.setContent(this.activityFrom.activityLocation)
|
// 设置封面类型
|
this.coverType = row.coverType === 'text' ? '输入文字封面' : '选择文件封面'
|
})
|
},
|
infoModelClose(){
|
this.infoModelShow = false
|
},
|
// 关闭模态框
|
modelClose() {
|
this.modelShow = false
|
this.file = null
|
this.submitLoading = false
|
this.handleRemove();
|
this.$refs.form.resetFields()
|
},
|
|
// 保存或更新活动
|
saveOrUpdate() {
|
// 设置封面类型
|
this.activityFrom.coverType = this.coverType === '输入文字封面' ? '文字' :
|
this.file ? this.getFileCategory(this.file.type) :
|
this.activityFrom.coverType
|
this.$refs.form.validate(valid => {
|
if (valid) {
|
this.submitLoading = true
|
|
// 处理时间数据
|
if (this.activityFrom.reportTime && this.activityFrom.reportTime.length === 2) {
|
this.activityFrom.reportStartTime = this.formatDate(this.activityFrom.reportTime[0], 'YYYY-MM-DD HH:mm:ss')
|
this.activityFrom.reportEndTime = this.formatDate(this.activityFrom.reportTime[1], 'YYYY-MM-DD HH:mm:ss')
|
}
|
|
if (this.activityFrom.time && this.activityFrom.time.length === 2) {
|
this.activityFrom.startTime = this.formatDate(this.activityFrom.time[0], 'YYYY-MM-DD HH:mm:ss')
|
this.activityFrom.endTime = this.formatDate(this.activityFrom.time[1], 'YYYY-MM-DD HH:mm:ss')
|
}
|
|
const api = this.activityFrom.id ? editActivity : addActivity
|
api(this.activityFrom).then(res => {
|
this.submitLoading = false
|
if (res.code === 200) {
|
this.$Message.success(res.msg)
|
this.modelClose()
|
this.getActivityList()
|
}
|
}).catch(() => {
|
this.submitLoading = false
|
})
|
}
|
})
|
},
|
|
// 删除活动
|
delById(row) {
|
this.$Modal.confirm({
|
title: '确认删除',
|
content: `确定要删除活动 "${row.activityName}" 吗?`,
|
onOk: () => {
|
delActivityById(row.id).then(res => {
|
if (res.code === 200) {
|
this.$Message.success(res.msg)
|
this.getActivityList()
|
}
|
})
|
}
|
})
|
},
|
|
// 批量删除
|
delBatch() {
|
if (this.selectCount === 0) {
|
this.$Message.warning('请至少选择一条数据')
|
return
|
}
|
|
this.$Modal.confirm({
|
title: '确认删除',
|
content: `确定要删除选中的 ${this.selectCount} 条数据吗?`,
|
onOk: () => {
|
delActivityBatch({ ids: this.selectList }).then(res => {
|
if (res.code === 200) {
|
this.$Message.success(res.msg)
|
this.selectList = []
|
this.selectCount = 0
|
this.getActivityList()
|
} else {
|
this.$Message.error(res.msg || '删除失败')
|
}
|
})
|
}
|
})
|
},
|
|
// 改变推荐状态
|
changeRecommend(row, action) {
|
row.recommendLoading = true
|
const recommend = action === '推荐'
|
|
activityChangeRecommend({
|
id: row.id,
|
recommend: recommend
|
}).then(res => {
|
row.recommendLoading = false
|
if (res.code === 200) {
|
this.$Message.success(res.msg)
|
row.recommend = recommend
|
}
|
}).catch(() => {
|
row.recommendLoading = false
|
})
|
},
|
|
// 改变活动状态
|
changeStatus(row, action) {
|
row.statusLoading = true
|
const publish = action === '发布'
|
|
activityChangeStatus({
|
id: row.id,
|
publish: publish
|
}).then(res => {
|
row.statusLoading = false
|
if (res.code === 200) {
|
this.$Message.success(res.msg)
|
row.publish = publish
|
}
|
}).catch(() => {
|
row.statusLoading = false
|
})
|
},
|
|
// 打开报名人员模态框
|
openMembersModal(row) {
|
this.membersModelTitle = `${row.activityName} - 报名人员`
|
this.membersModelShow = true
|
this.memberForm.id = row.id
|
this.memberForm.pageNumber = 1
|
this.activityMembersPage()
|
},
|
|
// 获取报名人员列表
|
activityMembersPage() {
|
this.membersLoading = true
|
activityMembersPage(this.memberForm).then(res => {
|
this.membersLoading = false
|
if (res.code === 200) {
|
this.membersList = res.data
|
this.memberTotal = res.total
|
}
|
}).catch(() => {
|
this.membersLoading = false
|
})
|
},
|
|
// 改变报名人员页码
|
memberChangePage(page) {
|
this.memberForm.pageNumber = page
|
this.activityMembersPage()
|
},
|
|
// 改变报名人员每页条数
|
memberChangePageSize(pageSize) {
|
this.memberForm.pageNumber = 1
|
this.memberForm.pageSize = pageSize
|
this.activityMembersPage()
|
},
|
|
// 关闭报名人员模态框
|
membersModelClose() {
|
this.membersModelShow = false
|
},
|
|
// 封面类型变化处理
|
handleCoverTypeChange(type) {
|
if (type === '选择文件封面') {
|
this.activityFrom.cover = ''
|
} else {
|
this.file = null
|
}
|
},
|
|
// 文件上传前处理
|
handleBeforeUpload(file) {
|
const fileType = file.type
|
const isImage = fileType.includes('image')
|
const isVideo = fileType.includes('video')
|
|
if (!isImage && !isVideo) {
|
this.$Message.error('请上传图片或视频文件')
|
return false
|
}
|
|
if (file.size > 20 * 1024 * 1024) {
|
this.$Message.error('文件大小不能超过20MB')
|
return false
|
}
|
|
this.file = file
|
this.uploadFile()
|
return false
|
},
|
|
// 上传文件
|
uploadFile() {
|
if (!this.file) return
|
|
this.submitLoading = true
|
const formData = new FormData()
|
formData.append('file', this.file)
|
|
uploadFileByLmk(formData).then(res => {
|
this.submitLoading = false
|
if (res.code === 200) {
|
this.activityFrom.cover = res.data.fileKey
|
this.$Message.success('上传成功')
|
}
|
}).catch(() => {
|
this.submitLoading = false
|
})
|
},
|
|
// 删除文件
|
handleRemove() {
|
//点击关闭窗口时确保文件已被清除
|
if(this.file === null){
|
return;
|
}
|
if (!this.activityFrom.cover) {
|
this.file = null
|
return
|
}
|
delByKey(this.activityFrom.cover).then(res => {
|
if (res.code === 200) {
|
this.file = null
|
this.activityFrom.cover = ''
|
}
|
})
|
},
|
|
// 预览图片
|
previewImage(url) {
|
this.previewImageUrl = url
|
this.previewVisible = true
|
},
|
|
// 获取文件分类
|
getFileCategory(mimeType) {
|
const typeMap = {
|
'image': 'image',
|
'video': 'video',
|
'audio': 'audio',
|
'application': 'application'
|
}
|
|
const typePrefix = mimeType.split('/')[0]
|
return typeMap[typePrefix] || 'unknown'
|
},
|
|
// 格式化日期
|
formatDate(date, format = 'YYYY-MM-DD HH:mm:ss') {
|
if (!date) return '';
|
|
const d = new Date(date);
|
if (isNaN(d.getTime())) return '';
|
|
const padZero = (num) => String(num).padStart(2, '0'); // 更可靠的补零方法
|
|
const year = d.getFullYear();
|
const month = padZero(d.getMonth() + 1); // 月份 0-11 → +1
|
const day = padZero(d.getDate());
|
const hours = padZero(d.getHours());
|
const minutes = padZero(d.getMinutes());
|
const seconds = padZero(d.getSeconds());
|
return format
|
.replace('YYYY', year)
|
.replace('MM', month)
|
.replace('DD', day)
|
.replace('HH', hours)
|
.replace('mm', minutes)
|
.replace('ss', seconds);
|
},
|
|
// 验证报名时间
|
validateReportTime(rule, value, callback) {
|
if (!value || value.length !== 2) {
|
callback(new Error('请选择完整的报名时间段'))
|
return
|
}
|
|
const [start, end] = value
|
if (new Date(start) >= new Date(end)) {
|
callback(new Error('报名结束时间必须晚于开始时间'))
|
return
|
}
|
|
if (this.activityFrom.time && this.activityFrom.time.length === 2) {
|
const activityStart = this.activityFrom.time[0]
|
if (new Date(end) > new Date(activityStart)) {
|
callback(new Error('报名结束时间不能晚于活动开始时间'))
|
return
|
}
|
}
|
|
callback()
|
},
|
|
// 验证活动时间
|
validateActivityTime(rule, value, callback) {
|
if (!value || value.length !== 2) {
|
callback(new Error('请选择完整的活动时间段'))
|
return
|
}
|
|
const [start, end] = value
|
if (new Date(start) >= new Date(end)) {
|
callback(new Error('活动结束时间必须晚于开始时间'))
|
return
|
}
|
|
if (this.activityFrom.reportTime && this.activityFrom.reportTime.length === 2) {
|
const reportEnd = this.activityFrom.reportTime[1]
|
if (new Date(reportEnd) > new Date(start)) {
|
callback(new Error('活动开始时间必须晚于报名结束时间'))
|
return
|
}
|
}
|
|
callback()
|
}
|
}
|
}
|
</script>
|
|
<style lang="scss" scoped>
|
.activity-management {
|
.search-form {
|
padding: 16px;
|
background: #f8f8f9;
|
border-radius: 4px;
|
margin-bottom: 16px;
|
|
.ivu-form-item {
|
margin-bottom: 16px;
|
margin-right: 16px;
|
}
|
|
.search-btn {
|
margin-left: 8px;
|
}
|
}
|
|
.operation {
|
margin-bottom: 16px;
|
|
.ivu-btn {
|
margin-right: 8px;
|
}
|
}
|
|
.activity-table {
|
.media-container {
|
display: flex;
|
justify-content: center;
|
align-items: center;
|
height: 100px;
|
|
.thumbnail {
|
max-width: 100%;
|
max-height: 100%;
|
object-fit: contain;
|
cursor: pointer;
|
transition: all 0.3s;
|
|
&:hover {
|
transform: scale(1.05);
|
box-shadow: 0 0 8px rgba(0, 0, 0, 0.2);
|
}
|
}
|
|
.video-player {
|
max-width: 100%;
|
max-height: 100px;
|
background: #000;
|
}
|
|
.text-cover {
|
padding: 8px;
|
background: #f8f8f9;
|
border-radius: 4px;
|
max-width: 100%;
|
word-break: break-all;
|
}
|
}
|
|
.action-btns {
|
display: flex;
|
flex-wrap: wrap;
|
justify-content: center;
|
|
.ivu-btn {
|
margin: 4px;
|
font-size: 12px;
|
padding: 2px 6px;
|
min-width: 60px;
|
}
|
}
|
}
|
|
.page-footer {
|
margin-top: 16px;
|
padding: 8px 0;
|
}
|
|
.members-modal {
|
.members-table {
|
margin-bottom: 16px;
|
}
|
}
|
|
.upload-file-info {
|
margin-top: 8px;
|
padding: 8px;
|
background: #f8f8f9;
|
border-radius: 4px;
|
}
|
|
.upload-tip {
|
font-size: 12px;
|
color: #999;
|
margin-top: 4px;
|
}
|
}
|
.detail-container {
|
padding: 16px;
|
}
|
|
.detail-item {
|
margin-bottom: 18px;
|
line-height: 1.5;
|
|
label {
|
display: inline-block;
|
width: 100px;
|
color: #666;
|
font-weight: bold;
|
vertical-align: top;
|
}
|
|
span {
|
display: inline-block;
|
width: calc(100% - 110px);
|
}
|
}
|
|
.activity-content {
|
border: 1px solid #dcdee2;
|
border-radius: 4px;
|
padding: 12px;
|
min-height: 100px;
|
margin-top: 8px;
|
}
|
</style>
|