Browse Source

Merge branch 'songjie' into dev

dev
宋杰 3 weeks ago
parent
commit
a55a800e50
  1. 13
      package-lock.json
  2. 4
      package.json
  3. 13
      src/api/homeApi.js
  4. 5
      src/api/index.js
  5. 86
      src/assets/base.css
  6. 6
      src/assets/main.css
  7. 25
      src/main.js
  8. 7
      src/router/index.js
  9. 276
      src/views/ActivityManagement.vue

13
package-lock.json

@ -8,8 +8,10 @@
"name": "vue", "name": "vue",
"version": "0.0.0", "version": "0.0.0",
"dependencies": { "dependencies": {
"@element-plus/icons-vue": "^2.3.1",
"axios": "^1.9.0", "axios": "^1.9.0",
"element-plus": "^2.9.9",
"element-plus": "^2.9.8",
"moment": "^2.30.1",
"pinia": "^3.0.1", "pinia": "^3.0.1",
"vue": "^3.5.13", "vue": "^3.5.13",
"vue-router": "^4.5.0", "vue-router": "^4.5.0",
@ -2705,6 +2707,15 @@
"integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/moment": {
"version": "2.30.1",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz",
"integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==",
"license": "MIT",
"engines": {
"node": "*"
}
},
"node_modules/mrmime": { "node_modules/mrmime": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz",

4
package.json

@ -9,8 +9,10 @@
"preview": "vite preview" "preview": "vite preview"
}, },
"dependencies": { "dependencies": {
"@element-plus/icons-vue": "^2.3.1",
"axios": "^1.9.0", "axios": "^1.9.0",
"element-plus": "^2.9.9",
"element-plus": "^2.9.8",
"moment": "^2.30.1",
"pinia": "^3.0.1", "pinia": "^3.0.1",
"vue": "^3.5.13", "vue": "^3.5.13",
"vue-router": "^4.5.0", "vue-router": "^4.5.0",

13
src/api/homeApi.js

@ -0,0 +1,13 @@
import service from ".";
const homeApi = {
//分页查询
getHomeData(PageNo,PageSize) {
return service.post("/api/activity",{
params:{
PageNo,
PageSize
}
});
}
};
export default homeApi;

5
src/api/index.js

@ -0,0 +1,5 @@
import axios from "axios";
const service = axios.create({
baseURL:"http://192.168.8.235:8000"
});
export default service;

86
src/assets/base.css

@ -1,86 +0,0 @@
/* color palette from <https://github.com/vuejs/theme> */
:root {
--vt-c-white: #ffffff;
--vt-c-white-soft: #f8f8f8;
--vt-c-white-mute: #f2f2f2;
--vt-c-black: #181818;
--vt-c-black-soft: #222222;
--vt-c-black-mute: #282828;
--vt-c-indigo: #2c3e50;
--vt-c-divider-light-1: rgba(60, 60, 60, 0.29);
--vt-c-divider-light-2: rgba(60, 60, 60, 0.12);
--vt-c-divider-dark-1: rgba(84, 84, 84, 0.65);
--vt-c-divider-dark-2: rgba(84, 84, 84, 0.48);
--vt-c-text-light-1: var(--vt-c-indigo);
--vt-c-text-light-2: rgba(60, 60, 60, 0.66);
--vt-c-text-dark-1: var(--vt-c-white);
--vt-c-text-dark-2: rgba(235, 235, 235, 0.64);
}
/* semantic color variables for this project */
:root {
--color-background: var(--vt-c-white);
--color-background-soft: var(--vt-c-white-soft);
--color-background-mute: var(--vt-c-white-mute);
--color-border: var(--vt-c-divider-light-2);
--color-border-hover: var(--vt-c-divider-light-1);
--color-heading: var(--vt-c-text-light-1);
--color-text: var(--vt-c-text-light-1);
--section-gap: 160px;
}
@media (prefers-color-scheme: dark) {
:root {
--color-background: var(--vt-c-black);
--color-background-soft: var(--vt-c-black-soft);
--color-background-mute: var(--vt-c-black-mute);
--color-border: var(--vt-c-divider-dark-2);
--color-border-hover: var(--vt-c-divider-dark-1);
--color-heading: var(--vt-c-text-dark-1);
--color-text: var(--vt-c-text-dark-2);
}
}
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
font-weight: normal;
}
body {
min-height: 100vh;
color: var(--color-text);
background: var(--color-background);
transition:
color 0.5s,
background-color 0.5s;
line-height: 1.6;
font-family:
Inter,
-apple-system,
BlinkMacSystemFont,
'Segoe UI',
Roboto,
Oxygen,
Ubuntu,
Cantarell,
'Fira Sans',
'Droid Sans',
'Helvetica Neue',
sans-serif;
font-size: 15px;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}

6
src/assets/main.css

@ -1,5 +1,5 @@
@import './base.css';
/* @import './base.css'; */
/*
#app { #app {
max-width: 1280px; max-width: 1280px;
margin: 0 auto; margin: 0 auto;
@ -32,4 +32,4 @@ a,
grid-template-columns: 1fr 1fr; grid-template-columns: 1fr 1fr;
padding: 0 2rem; padding: 0 2rem;
} }
}
} */

25
src/main.js

@ -8,8 +8,33 @@ import 'element-plus/dist/index.css'
const app = createApp(App) // 创建vue实例 const app = createApp(App) // 创建vue实例
app.use(router) // 添加路由 app.use(router) // 添加路由
app.component('VotingManagement', VotingManagement) // 注册组件 app.component('VotingManagement', VotingManagement) // 注册组件
app.config.globalProperties.axios = axios; // 全局挂载axios app.config.globalProperties.axios = axios; // 全局挂载axios
app.mount('#app') // 挂载到id为app的div上 app.mount('#app') // 挂载到id为app的div上
app.use(ElementPlus) app.use(ElementPlus)
import App from './App.vue'
import router from './router'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
import zhCn from 'element-plus/es/locale/lang/zh-cn'
const app = createApp(App)
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component)
}
app.use(ElementPlus, {
locale: zhCn,
})
app.use(createPinia())
app.use(router)
app.use(ElementPlus)
app.mount('#app')

7
src/router/index.js

@ -1,9 +1,14 @@
import { createRouter, createWebHistory } from 'vue-router' import { createRouter, createWebHistory } from 'vue-router'
import ActivityManagement from '@/views/ActivityManagement.vue'
const router = createRouter({ const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL), history: createWebHistory(import.meta.env.BASE_URL),
routes: [ routes: [
{
path: '/',
name: 'activityManagement',
component: ActivityManagement,
},
], ],
}) })

276
src/views/ActivityManagement.vue

@ -0,0 +1,276 @@
<template>
<el-container>
<el-header>
<h1>活动管理后台</h1>
</el-header>
<el-main>
<el-row justify="start" align="middle">
<el-col :span="24" class="header-actions">
<el-button type="danger" @click="openAddActivityDialog">添加活动</el-button>
</el-col>
</el-row>
<el-table :data="paginatedActivities" style="width: 100%">
<!-- <el-table-column label="序号" type="index" width="80" align="center" header-align="center">
<template #default="{ $index }">
{{ $index + 1 }}
</template>
</el-table-column> -->
<el-table-column type="index" :index="indexMethod" width="80" label="活动标题" />
<el-table-column prop="title" label="活动标题" />
<el-table-column prop="detail" label="活动详情" />
<el-table-column prop="visit_count" label="访问人数" width="120" />
<el-table-column prop="vote_count" label="投票人数" width="120" />
<el-table-column prop="start" label="活动开始时间" />
<el-table-column prop="end" label="活动结束时间" />
<el-table-column prop="created_at" label="活动创建时间" />
<el-table-column prop="status" label="活动状态">
<template #default="scope">
<span v-if="scope.row.status === 1">未开始</span>
<span v-if="scope.row.status === 2">进行中</span>
<span v-if="scope.row.status === 3">已结束</span>
</template>
</el-table-column>
<el-table-column label="操作" width="180">
<template #default="scope">
<div class="operation-buttons">
<el-button size="mini" type="default" @click="editActivity(scope.row)">修改</el-button>
<el-button size="mini" type="primary" @click="viewDetails(scope.row)">查看详情</el-button>
</div>
</template>
</el-table-column>
</el-table>
<div class="pagination-container">
<el-pagination background layout="prev, pager, next" :total="total" :page-size="itemsPerPage"
v-model:current-page="currentPage" @current-change="handlePageChange">
</el-pagination>
</div>
</el-main>
<!-- 添加活动对话框开始 -->
<el-dialog v-model="showAddActivityDialog" title="添加活动">
<el-form :model="newActivity" ref="activityForm" label-width="120px">
<el-form-item label="活动标题" :rules="[{ required: true, message: '请输入活动标题' }]">
<el-input v-model="newActivity.title"></el-input>
</el-form-item>
<el-form-item label="活动详情" :rules="[{ required: true, message: '请输入活动详情' }]">
<el-input type="textarea" v-model="newActivity.details"></el-input>
</el-form-item>
<el-form-item label="活动图标">
<el-upload action="#" list-type="picture-card" :on-preview="handlePictureCardPreview"
:on-remove="handleRemove" :on-success="handleSuccess" :before-upload="beforeUpload">
<el-icon class="avatar-uploader-icon">
<Plus />
</el-icon>
</el-upload>
</el-form-item>
<el-form-item label="活动时间" :locale="zhCn" :rules="[{ required: true, message: '请选择活动时间' }]">
<el-date-picker v-model="newActivity.date" type="datetimerange" start-placeholder="开始日期"
end-placeholder="结束日期"></el-date-picker>
</el-form-item>
<el-form-item label="活动网址" :rules="[{ required: true, message: '请输入活动网址' }]">
<el-input v-model="newActivity.url"></el-input>
</el-form-item>
<el-form-item label="选择市场" :rules="[{ required: true, message: '请选择活动面向的市场' }]">
<el-select v-model="newActivity.market" placeholder="请选择市场">
<el-option label="市场1" value="market1"></el-option>
<el-option label="市场2" value="market2"></el-option>
</el-select>
</el-form-item>
<el-form-item label="客户权限" :rules="[{ required: true, message: '请选择面向客户的级别' }]">
<el-radio-group v-model="newActivity.clientLevel">
<el-radio label="非网">非网</el-radio>
<el-radio label="半年版">半年版</el-radio>
<el-radio label="终免">终免</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="showAddActivityDialog = false"> </el-button>
<el-button type="primary" @click="addActivity"> </el-button>
</span>
</el-dialog>
<!-- 添加活动对话框结束 -->
</el-container>
</template>
<script setup>
import { ref, computed } from 'vue';
import { ElMessage } from 'element-plus';
import zhCn from 'element-plus/es/locale/lang/zh-cn'
import homeApi from '@/api/homeApi';
function indexMethod(index){
return itemsPerPage*(currentPage.value-1)+index+1;
}
//id
const fakeId = ref(1);
//
const activities = ref([]);
//
function getAllActivities(currentPage, itemsPerPage) {
homeApi.getHomeData(currentPage, itemsPerPage)
.then(response => {
activities.value = response.data.data.list;
total.value = response.data.data.total;
console.log(activities.value);
console.log(total.value);
});
};
// 1
const currentPage = ref(1);
// 10
const itemsPerPage = 10;
//
const total = ref(0);
getAllActivities(currentPage.value, itemsPerPage);
//
const paginatedActivities = computed(() => {
const start = (currentPage.value - 1) * itemsPerPage;
const end = start + itemsPerPage;
return activities.value.slice(start, end);
});
//
const handlePageChange = (newPage) => {
getAllActivities(newPage, itemsPerPage);
};
//
const newActivity = ref({
id: null,
title: '',
details: '',
date: '',
url: '',
market: '',
clientLevel: ''
});
//
const showAddActivityDialog = ref(false);
//
const addActivity = () => {
newActivity.value.id = activities.value.length + 1;
newActivity.value.create_at = new Date().toISOString().split('T')[0]; //
activities.value.push({ ...newActivity.value });
newActivity.value = {
id: null,
title: '',
details: '',
date: '',
url: '',
market: '',
clientLevel: ''
};
showAddActivityDialog.value = true;
ElMessage.success('活动添加成功');
};
//
const editActivity = (activity) => {
newActivity.value = { ...activity };
showAddActivityDialog.value = true;
};
//
const viewDetails = (activity) => {
ElMessage.info(`活动ID: ${activity.id}, 活动标题: ${activity.title}, 日期: ${activity.start} - ${activity.end}, 访问人数: ${activity.visit_count}`);
};
const handlePictureCardPreview = (file) => {
console.log('Preview:', file);
};
const handleRemove = (file, fileList) => {
console.log('Remove:', file, fileList);
};
const handleSuccess = (response, file, fileList) => {
console.log('Success:', response, file, fileList);
};
const beforeUpload = (file) => {
const isJPG = file.type === 'image/jpeg';
const isPNG = file.type === 'image/png';
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isJPG && !isPNG) {
ElMessage.error('上传头像图片只能是 JPG 或 PNG 格式!');
}
if (!isLt2M) {
ElMessage.error('上传头像图片大小不能超过 2MB!');
}
return isJPG || isPNG && isLt2M;
};
//
const statusClassMap = {
'进行中': 'status-active',
'已完成': 'status-finished',
};
//
const getStatusClass = (status) => {
return statusClassMap[status] || 'status-default';
};
//
const openAddActivityDialog = () => {
newActivity.value = {
id: null,
title: '',
details: '',
date: '',
url: '',
market: '',
clientLevel: ''
};
showAddActivityDialog.value = true;
};
</script>
<style>
.header-actions {
margin-left: 20px;
/* 调整按钮与标题之间的距离 */
}
.pagination-container {
position: absolute;
display: flex;
justify-content: center;
margin-top: 10rem;
left: 45%;
}
.dialog-footer {
text-align: right;
}
.operation-buttons {
display: flex;
justify-content: space-between;
}
.status-active {
color: #409eff;
}
.status-finished {
color: #6c757d;
text-decoration: line-through;
}
.status-default {
color: #000;
}
</style>
Loading…
Cancel
Save